blob: dab51799453559c0eda3ed584c5da83a5e9ee046 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COBALT_SRC_LOGGER_LOGGER_TEST_UTILS_H_
#define COBALT_SRC_LOGGER_LOGGER_TEST_UTILS_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "src/lib/util/consistent_proto_store.h"
#include "src/lib/util/posix_file_system.h"
#include "src/lib/util/status.h"
#include "src/local_aggregation/local_aggregation.pb.h"
#include "src/logger/fake_logger.h"
#include "src/logger/logger_interface.h"
#include "src/logger/project_context.h"
#include "src/observation_store/observation_store.h"
#include "src/observation_store/observation_store_update_recipient.h"
#include "src/registry/project_configs.h"
#include "third_party/googletest/googletest/include/gtest/gtest.h"
namespace cobalt {
namespace logger {
namespace testing {
// A container for information about the set of all locally aggregated reports
// in a registry. This is used by tests to check the output of the
// EventAggregator.
using ExpectedAggregationParams = struct ExpectedAggregationParams {
// The total number of locally aggregated Observations which should be
// generated for a single day, assuming that no events have been logged.
size_t daily_num_obs = 0;
// The MetricReportIds of the locally aggregated reports in the registry.
std::set<MetricReportId> metric_report_ids;
// Keys are the MetricReportIds of all locally aggregated reports in the
// registry. The value at a key is the number of Observations which should be
// generated each day for that report, assuming that no events have been
// logged.
std::map<MetricReportId, size_t> num_obs_per_report;
// Keys are the MetricReportIds of all UNIQUE_N_DAY_ACTIVES reports in the
// registry. The value at a key is the number of event codes for that report's
// parent MetricDefinition.
std::map<MetricReportId, size_t> num_event_codes;
// Keys are the MetricReportIds of all locally aggregated reports in the
// registry. The value at a key is the set of aggregation windows with units
// in days for that report.
std::map<MetricReportId, std::set<uint32_t>> aggregation_days;
};
// A representation of a set of expected UniqueActivesObservations. Used to
// check the values of UniqueActivesObservations generated by the
// EventAggregator.
//
// The outer map is keyed by pairs (MetricReportId, day_index), where the day
// index represents the day index of the expected Observation, and the value at
// a pair is a map keyed by window size. The value of the inner map at a window
// size is a vector of size equal to the number of event codes for the parent
// metric of the report, and the i-th element of the vector is |true| if the
// i-th event code occurred on the device during the specified window, or
// |false| if not.
using ExpectedUniqueActivesObservations =
std::map<std::pair<MetricReportId, uint32_t>, std::map<uint32_t, std::vector<bool>>>;
// A representation of a set of expected PerDeviceNumericObservations. Used to
// check the values of PerDeviceNumericObservations generated by the
// EventAggregator.
//
// The outer map is keyed by pairs (MetricReportId, day_index), where the day
// index represents the day index of the expected Observation.
//
// The values of the inner map are tuples (component, packed event code, value).
using ExpectedPerDeviceNumericObservations =
std::map<std::pair<MetricReportId, uint32_t>,
std::map<uint32_t, std::set<std::tuple<std::string, uint64_t, int64_t>>>>;
// A representation of a set of expected ReportParticipationObservations. Used
// to check the values of ReportParticipationObservations generated by the
// EventAggregator. The first element of each pair is the MetricReportId of a
// report, and the second element represents the day index of an expected
// Observation for that report. a pair is a a set of window sizes.
using ExpectedReportParticipationObservations = std::set<std::pair<MetricReportId, uint32_t>>;
// A mock ObservationStore.
class FakeObservationStore : public ::cobalt::observation_store::ObservationStoreWriterInterface {
public:
using ::cobalt::observation_store::ObservationStoreWriterInterface::StoreObservation;
StoreStatus StoreObservation(
std::unique_ptr<::cobalt::observation_store::StoredObservation> message,
std::unique_ptr<ObservationMetadata> metadata) override {
messages_received.emplace_back(std::move(message));
metadata_received.emplace_back(std::move(metadata));
num_observations_added_++;
return kOk;
}
std::vector<std::unique_ptr<::cobalt::observation_store::StoredObservation>>
messages_received; // NOLINT
std::vector<std::unique_ptr<ObservationMetadata>> metadata_received; // NOLINT
size_t num_observations_added() { return num_observations_added_; }
void ResetObservationCounter() { num_observations_added_ = 0; }
private:
size_t num_observations_added_ = 0;
};
// A mock ObservationStoreUpdateRecipient.
class TestUpdateRecipient : public ::cobalt::observation_store::ObservationStoreUpdateRecipient {
public:
void NotifyObservationsAdded() override { invocation_count++; }
int invocation_count = 0;
};
// A mock ConsistentProtoStore. Its Read() and Write() methods increment
// counts of their invocations.
class MockConsistentProtoStore : public ::cobalt::util::ConsistentProtoStore {
public:
explicit MockConsistentProtoStore(std::string filename)
: ::cobalt::util::ConsistentProtoStore(std::move(filename), &fs_) {
read_count_ = 0;
write_count_ = 0;
}
~MockConsistentProtoStore() override = default;
// To set the stored proto in a test, use |set_stored_proto| instead of Write.
::cobalt::util::Status Write(const google::protobuf::MessageLite& /*proto*/) override {
write_count_++;
return ::cobalt::util::Status::OK;
}
::cobalt::util::Status Read(google::protobuf::MessageLite* proto) override {
if (stored_proto_) {
proto->Clear();
proto->CheckTypeAndMergeFrom(*stored_proto_);
}
read_count_++;
return ::cobalt::util::Status::OK;
}
void ResetCounts() {
read_count_ = 0;
write_count_ = 0;
}
int read_count_; // NOLINT
int write_count_; // NOLINT
void set_stored_proto(std::unique_ptr<google::protobuf::MessageLite> proto) {
stored_proto_ = std::move(proto);
}
private:
::cobalt::util::PosixFileSystem fs_;
std::unique_ptr<google::protobuf::MessageLite> stored_proto_;
};
// Creates and returns a ProjectContext from a serialized, base64-encoded Cobalt
// registry.
std::unique_ptr<ProjectContext> GetTestProject(const std::string& registry_base64);
// Returns the ReportAggregationKey associated to a report, given a
// ProjectContext containing the report and the report's MetricReportId.
ReportAggregationKey MakeAggregationKey(const ProjectContext& project_context,
const MetricReportId& metric_report_id);
// Returns the AggregationConfig associated to a report, given a ProjectContext
// containing the report and the report's MetricReportId.
AggregationConfig MakeAggregationConfig(const ProjectContext& project_context,
const MetricReportId& metric_report_id);
// Construct a histogram to log from the indices for buckets, and the counts in that bucket.
HistogramPtr NewHistogram(std::vector<uint32_t> indices, std::vector<uint32_t> counts);
// Construct a custom event to log from the names of dimensions, and the values to log for that
// dimension.
EventValuesPtr NewCustomEvent(std::vector<std::string> dimension_names,
std::vector<CustomDimensionValue> values);
// Given an ExpectedAggregationParams struct populated with information about
// the locally aggregated reports in a config, return an
// ExpectedUniqueActivesObservations map initialized with that config's
// MetricReportIds and window sizes and with a specified day index, with all
// activity indicators set to false.
//
// The ExpectedUniqueActivesObservations map generated by
// MakeNullExpectedObservations represents the set of Observations that should
// be generated for |day_index| in the case where no activity has been logged
// for any report and where no backfill is needed.
ExpectedUniqueActivesObservations MakeNullExpectedUniqueActivesObservations(
const ExpectedAggregationParams& expected_params, uint32_t day_index);
// Given an ExpectedAggregationParams struct |expected_params|, return an
// ExpectedReportParticipationObservations containing a pair
// (|metric_report_id|, |day_index|) for each MetricReportId |metric_report_id|
// in |expected_params|.
ExpectedReportParticipationObservations MakeExpectedReportParticipationObservations(
const ExpectedAggregationParams& expected_params, uint32_t day_index);
// Populates |observations| with the contents of a FakeObservationStore.
// |observations| should be a vector whose size is equal to the number
// of expected observations. Checks the the ObservationStore contains
// the expected number of Observations and that the report_ids of the
// Observations are equal to |expected_report_ids|. Returns true iff all checks
// pass.
bool FetchObservations(std::vector<Observation2>* observations,
const std::vector<uint32_t>& expected_report_ids,
FakeObservationStore* observation_store,
TestUpdateRecipient* update_recipient);
// Populates |observation| with the contents of a FakeObservationStore,
// which is expected to contain a single Observation with a report_id
// of |expected_report_id|. Returns true iff all checks pass.
bool FetchSingleObservation(Observation2* observation, uint32_t expected_report_id,
FakeObservationStore* observation_store,
TestUpdateRecipient* update_recipient);
// Given an ExpectedAggregationParams containing information about the set of
// locally aggregated reports in a config, populates a vector |observations|
// with the contents of a FakeObservationStore and checks that the vector
// contains exactly the number of Observations that the EventAggregator should
// generate for a single day index, for each locally aggregated report in that
// config. Does not assume that the contents of the FakeObservationStore have a
// particular order. The size of |observations| is ignored, and can be 0.
bool FetchAggregatedObservations(std::vector<Observation2>* observations,
const ExpectedAggregationParams& expected_params,
FakeObservationStore* observation_store,
TestUpdateRecipient* update_recipient);
// Checks that the contents of a FakeObservationStore is a sequence of
// IntegerEventObservations specified by the various parameters. Returns
// true if all checks pass.
bool CheckNumericEventObservations(const std::vector<uint32_t>& expected_report_ids,
uint32_t expected_event_code,
const std::string& expected_component_name,
int64_t expected_int_value,
FakeObservationStore* observation_store,
TestUpdateRecipient* update_recipient);
// Checks that the Observations contained in a FakeObservationStore are exactly
// the UniqueActivesObservations that should be generated for a single day index
// given a representation of the expected activity indicators for that day, for
// each UniqueActives report, for each aggregation window and event code, for a config
// whose locally aggregated reports are all of type UNIQUE_N_DAY_ACTIVES.
//
// TODO(pesk): Support hourly OnDeviceAggregationWindows.
bool CheckUniqueActivesObservations(const ExpectedUniqueActivesObservations& expected_obs,
FakeObservationStore* observation_store,
TestUpdateRecipient* update_recipient);
// Checks that the Observations contained in a FakeObservationStore are exactly
// the PerDeviceNumericObservations and ReportParticipationObservations that
// should be generated for a single day index given a representation of the
// expected activity indicators for that day, for each PER_DEVICE_NUMERIC_STATS
// report, for each aggregation window and event code, for a config whose locally
// aggregated reports are all of type PER_DEVICE_NUMERIC_STATS.
//
// TODO(pesk): Support hourly OnDeviceAggregationWindows.
bool CheckPerDeviceNumericObservations(
ExpectedPerDeviceNumericObservations expected_per_device_numeric_obs,
ExpectedReportParticipationObservations expected_report_participation_obs,
FakeObservationStore* observation_store, TestUpdateRecipient* update_recipient);
} // namespace testing
} // namespace logger
} // namespace cobalt
#endif // COBALT_SRC_LOGGER_LOGGER_TEST_UTILS_H_