blob: a013501552d956531dac0ea0be8521a877c33a5b [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_LOGGER_LOGGER_TEST_UTILS_H_
#define COBALT_LOGGER_LOGGER_TEST_UTILS_H_
#include <map>
#include <memory>
#include <set>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "./gtest.h"
#include "config/project_configs.h"
#include "encoder/shipping_manager.h"
#include "logger/encoder.h"
#include "logger/local_aggregation.pb.h"
#include "logger/logger_interface.h"
#include "util/consistent_proto_store.h"
#include "util/posix_file_system.h"
#include "util/status.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.
typedef 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 window sizes of that report.
std::map<MetricReportId, std::set<uint32_t>> window_sizes;
} ExpectedAggregationParams;
// 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.
typedef std::map<std::pair<MetricReportId, uint32_t>,
std::map<uint32_t, std::vector<bool>>>
ExpectedUniqueActivesObservations;
// 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).
typedef std::map<
std::pair<MetricReportId, uint32_t>,
std::map<uint32_t, std::set<std::tuple<std::string, uint64_t, int64_t>>>>
ExpectedPerDeviceNumericObservations;
// 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.
typedef std::set<std::pair<MetricReportId, uint32_t>>
ExpectedReportParticipationObservations;
// A mock ObservationStore.
class FakeObservationStore
: public ::cobalt::encoder::ObservationStoreWriterInterface {
public:
StoreStatus AddEncryptedObservation(
std::unique_ptr<EncryptedMessage> 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<EncryptedMessage>> messages_received;
std::vector<std::unique_ptr<ObservationMetadata>> metadata_received;
size_t num_observations_added() override { return num_observations_added_; }
void ResetObservationCounter() override { num_observations_added_ = 0; }
private:
size_t num_observations_added_ = 0;
};
// A mock ObservationStoreUpdateRecipient.
class TestUpdateRecipient
: public ::cobalt::encoder::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(
filename, std::make_unique<::cobalt::util::PosixFileSystem>()) {
read_count_ = 0;
write_count_ = 0;
}
~MockConsistentProtoStore() {}
// 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_;
int write_count_;
void set_stored_proto(std::unique_ptr<google::protobuf::MessageLite> proto) {
stored_proto_ = std::move(proto);
}
private:
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);
// 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 window size and event code, for a config
// whose locally aggregated reports are all of type UNIQUE_N_DAY_ACTIVES.
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 window size and event code, for a config whose locally
// aggregated reports are all of type PER_DEVICE_NUMERIC_STATS.
bool CheckPerDeviceNumericObservations(
ExpectedPerDeviceNumericObservations expected_per_device_numeric_obs,
ExpectedReportParticipationObservations expected_report_participation_obs,
FakeObservationStore* observation_store,
TestUpdateRecipient* update_recipient);
// An implementation of LoggerInterface that counts how many times the Log*
// methods were called for purposes of testing that internal metrics are being
// collected properly.
class FakeLogger : public LoggerInterface {
public:
Status LogEvent(uint32_t metric_id, uint32_t event_code) override {
call_count_ += 1;
return Status::kOK;
}
Status LogEventCount(uint32_t metric_id,
const std::vector<uint32_t>& event_codes,
const std::string& component,
int64_t period_duration_micros,
uint32_t count) override {
call_count_ += 1;
return Status::kOK;
}
Status LogElapsedTime(uint32_t metric_id,
const std::vector<uint32_t>& event_codes,
const std::string& component,
int64_t elapsed_micros) override {
call_count_ += 1;
return Status::kOK;
}
Status LogFrameRate(uint32_t metric_id,
const std::vector<uint32_t>& event_codes,
const std::string& component, float fps) override {
call_count_ += 1;
return Status::kOK;
}
Status LogMemoryUsage(uint32_t metric_id,
const std::vector<uint32_t>& event_codes,
const std::string& component, int64_t bytes) override {
call_count_ += 1;
return Status::kOK;
}
Status LogIntHistogram(uint32_t metric_id,
const std::vector<uint32_t>& event_codes,
const std::string& component,
HistogramPtr histogram) override {
call_count_ += 1;
return Status::kOK;
}
Status LogString(uint32_t metric_id, const std::string& str) override {
call_count_ += 1;
return Status::kOK;
}
Status LogCustomEvent(uint32_t metric_id,
EventValuesPtr event_values) override {
call_count_ += 1;
return Status::kOK;
}
uint32_t call_count() { return call_count_; }
private:
uint32_t call_count_ = 0;
};
} // namespace testing
} // namespace logger
} // namespace cobalt
#endif // COBALT_LOGGER_LOGGER_TEST_UTILS_H_