blob: 61d7e95baad3070cbefa7c09934011d90c310391 [file] [log] [blame]
// Copyright 2020 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.
#include "src/local_aggregation_1_1/aggregation_procedures/select_most_common_aggregation_procedure.h"
#include <memory>
#include <gtest/gtest.h>
#include "src/lib/util/datetime_util.h"
#include "src/local_aggregation_1_1/aggregation_procedures/aggregation_procedure.h"
#include "src/local_aggregation_1_1/aggregation_procedures/testing/test_aggregation_procedure.h"
#include "src/local_aggregation_1_1/testing/test_registry.cb.h"
#include "src/logger/project_context.h"
#include "src/logger/project_context_factory.h"
#include "src/registry/report_definition.pb.h"
namespace cobalt::local_aggregation {
class SelectMostCommonAggregationProcedureTest : public testing::TestAggregationProcedure {
protected:
std::unique_ptr<logger::EventRecord> GetEventRecord(uint32_t metric_id) {
return logger::EventRecord::MakeEventRecord(GetProjectContext(), metric_id).value();
}
std::unique_ptr<SelectMostCommonAggregationProcedure> GetProcedure(uint32_t metric_id,
int report_index) {
return std::make_unique<SelectMostCommonAggregationProcedure>(
GetMetricDef(metric_id), GetReportDef(metric_id, report_index));
}
};
TEST_F(SelectMostCommonAggregationProcedureTest, UpdateAggregate1DayReport) {
uint32_t metric_id = kOccurrenceMetricMetricId;
int report_index = kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex;
ReportDefinition report = GetReportDef(metric_id, report_index);
std::unique_ptr<AggregationProcedure> procedure = GetProcedure(metric_id, report_index);
const uint32_t kDayIndex = 10000;
const uint64_t system_profile_hash = uint64_t{1234568};
uint32_t kNumEventCodes = 100;
ASSERT_GE(report.event_vector_buffer_max(), kNumEventCodes);
ReportAggregate aggregate;
AddOccurrenceEventsForDay(kNumEventCodes, kDayIndex, system_profile_hash, *procedure, aggregate);
ASSERT_EQ(aggregate.daily().by_day_index().count(kDayIndex), 1u);
ASSERT_EQ(aggregate.daily().by_day_index().at(kDayIndex).system_profile_aggregates_size(), 1u);
const SystemProfileAggregate &system_profile_agg =
aggregate.daily().by_day_index().at(kDayIndex).system_profile_aggregates(0);
EXPECT_EQ(system_profile_agg.system_profile_hash(), system_profile_hash);
for (uint32_t i = 0; i < kNumEventCodes; ++i) {
EXPECT_EQ(system_profile_agg.by_event_code(i).data().count(), i + 1)
<< "Incorrect count for event code " << i + 1;
}
}
TEST_F(SelectMostCommonAggregationProcedureTest, MergeAggregateDataBothSet) {
AggregateData data;
data.set_count(100);
AggregateData merged_data;
merged_data.set_count(121);
std::unique_ptr<SelectMostCommonAggregationProcedure> procedure =
GetProcedure(kOccurrenceMetricMetricId,
kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex);
procedure->MergeAggregateData(merged_data, data);
EXPECT_EQ(merged_data.count(), 221);
}
TEST_F(SelectMostCommonAggregationProcedureTest, MergeAggregateDataNeitherSet) {
AggregateData data;
AggregateData merged_data;
std::unique_ptr<SelectMostCommonAggregationProcedure> procedure =
GetProcedure(kOccurrenceMetricMetricId,
kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex);
procedure->MergeAggregateData(merged_data, data);
EXPECT_EQ(merged_data.count(), 0);
}
TEST_F(SelectMostCommonAggregationProcedureTest, MergeAggregateDataFromSet) {
AggregateData data;
data.set_count(100);
AggregateData merged_data;
std::unique_ptr<SelectMostCommonAggregationProcedure> procedure =
GetProcedure(kOccurrenceMetricMetricId,
kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex);
procedure->MergeAggregateData(merged_data, data);
EXPECT_EQ(merged_data.count(), 100);
}
TEST_F(SelectMostCommonAggregationProcedureTest, MergeAggregateDataToSet) {
AggregateData data;
AggregateData merged_data;
merged_data.set_count(121);
std::unique_ptr<SelectMostCommonAggregationProcedure> procedure =
GetProcedure(kOccurrenceMetricMetricId,
kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex);
procedure->MergeAggregateData(merged_data, data);
EXPECT_EQ(merged_data.count(), 121);
}
TEST_F(SelectMostCommonAggregationProcedureTest, GenerateObservation1DayReportNoEvents) {
uint32_t metric_id = kOccurrenceMetricMetricId;
int report_index = kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex;
std::unique_ptr<AggregationProcedure> procedure = GetProcedure(metric_id, report_index);
const uint32_t kDayIndex = 10000;
util::TimeInfo time_info;
time_info.day_index = kDayIndex;
ReportAggregate report_aggregate;
lib::statusor::StatusOr<std::vector<ObservationAndSystemProfile>> observations_or =
procedure->GenerateObservations(time_info, report_aggregate);
ASSERT_EQ(observations_or.status().error_code(), StatusCode::OK);
std::vector<ObservationAndSystemProfile> observations = std::move(observations_or).value();
ASSERT_EQ(observations.size(), 0u);
}
TEST_F(SelectMostCommonAggregationProcedureTest, GenerateObservation1DayReport) {
uint32_t metric_id = kOccurrenceMetricMetricId;
int report_index = kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport1DayReportIndex;
std::unique_ptr<AggregationProcedure> procedure = GetProcedure(metric_id, report_index);
const uint32_t kDayIndex = 10000;
util::TimeInfo time_info;
time_info.day_index = kDayIndex;
const uint64_t system_profile_hash = uint64_t{1234568};
const uint32_t kNumEventCodes = 100;
ASSERT_GE(GetReportDef(metric_id, report_index).event_vector_buffer_max(), kNumEventCodes);
ReportAggregate report_aggregate;
// Log |event_code| OccurrenceEvents, each with a count of 1, for each |event_code| in the range
// [1, kNumEventCodes]. The most common event code will be |kNumEventCodes|.
AddOccurrenceEventsForDay(kNumEventCodes, kDayIndex, system_profile_hash, *procedure,
report_aggregate);
lib::statusor::StatusOr<std::vector<ObservationAndSystemProfile>> observations_or =
procedure->GenerateObservations(time_info, report_aggregate);
ASSERT_EQ(observations_or.status().error_code(), StatusCode::OK);
std::vector<ObservationAndSystemProfile> observations = std::move(observations_or).value();
ASSERT_EQ(observations.size(), 1u);
EXPECT_EQ(observations[0].system_profile_hash, system_profile_hash);
ASSERT_TRUE(observations[0].observation->has_integer());
const IntegerObservation &integer_obs = observations[0].observation->integer();
ASSERT_EQ(integer_obs.values_size(), 1);
EXPECT_EQ(integer_obs.values(0).event_codes_size(), 1);
EXPECT_EQ(integer_obs.values(0).event_codes(0), kNumEventCodes);
EXPECT_EQ(integer_obs.values(0).value(), 1);
// Check that obsolete aggregates get cleaned up.
procedure->ObservationsCommitted(report_aggregate, time_info, system_profile_hash);
EXPECT_EQ(report_aggregate.daily().by_day_index().count(kDayIndex), 0u);
}
TEST_F(SelectMostCommonAggregationProcedureTest, GenerateObservation7DaysReport) {
uint32_t metric_id = kOccurrenceMetricMetricId;
int report_index = kOccurrenceMetricUniqueDeviceCountsSelectMostCommonReport7DaysReportIndex;
std::unique_ptr<AggregationProcedure> procedure = GetProcedure(metric_id, report_index);
const uint32_t kDayIndex = 10000;
util::TimeInfo time_info;
time_info.day_index = kDayIndex;
const uint64_t system_profile_hash = uint64_t{1234568};
const uint32_t kNumEventCodes = 7;
ASSERT_GE(GetReportDef(metric_id, report_index).event_vector_buffer_max(), kNumEventCodes);
ReportAggregate report_aggregate;
const uint32_t kMostCommonEventCode = 1;
// Log |event_code| OccurrenceEvents, each with a count of 1, for each |event_code| in the
// range [1, kNumEventCodes].
AddOccurrenceEventsForDay(kNumEventCodes, kDayIndex - 1, system_profile_hash, *procedure,
report_aggregate);
// For another day in the aggregation period, log |kNumEventCodes| + 1 OccurrenceEvents, each with
// a count of 1, for event code |kMostCommonEventCode|. The most common event code over the
// aggregation period is now |kMostCommonEventCode|.
for (int i = 0; i < kNumEventCodes + 1; ++i) {
AddOccurrenceEventsForDay(kMostCommonEventCode, kDayIndex, system_profile_hash, *procedure,
report_aggregate);
}
lib::statusor::StatusOr<std::vector<ObservationAndSystemProfile>> observations_or =
procedure->GenerateObservations(time_info, report_aggregate);
ASSERT_EQ(observations_or.status().error_code(), StatusCode::OK);
std::vector<ObservationAndSystemProfile> observations = std::move(observations_or).value();
ASSERT_EQ(observations.size(), 1u);
EXPECT_EQ(observations[0].system_profile_hash, system_profile_hash);
ASSERT_TRUE(observations[0].observation->has_integer());
const IntegerObservation &integer_obs = observations[0].observation->integer();
ASSERT_EQ(integer_obs.values_size(), 1);
EXPECT_EQ(integer_obs.values(0).event_codes_size(), 1);
EXPECT_EQ(integer_obs.values(0).event_codes(0), kMostCommonEventCode);
EXPECT_EQ(integer_obs.values(0).value(), 1);
// Check that obsolete aggregates get cleaned up.
procedure->ObservationsCommitted(report_aggregate, time_info, system_profile_hash);
// Days in the 7-day window that had events continue to contain data.
ASSERT_TRUE(report_aggregate.daily().by_day_index().contains(kDayIndex));
ASSERT_EQ(report_aggregate.daily().by_day_index().at(kDayIndex).system_profile_aggregates_size(),
1u);
const SystemProfileAggregate &system_profile_agg =
report_aggregate.daily().by_day_index().at(kDayIndex).system_profile_aggregates(0);
EXPECT_EQ(system_profile_agg.system_profile_hash(), system_profile_hash);
EXPECT_EQ(system_profile_agg.by_event_code_size(), 1);
ASSERT_TRUE(report_aggregate.daily().by_day_index().contains(kDayIndex - 1));
ASSERT_EQ(
report_aggregate.daily().by_day_index().at(kDayIndex - 1).system_profile_aggregates_size(),
1u);
const SystemProfileAggregate &system_profile_agg_prev =
report_aggregate.daily().by_day_index().at(kDayIndex - 1).system_profile_aggregates(0);
EXPECT_EQ(system_profile_agg_prev.system_profile_hash(), system_profile_hash);
EXPECT_EQ(system_profile_agg_prev.by_event_code_size(), kNumEventCodes);
// Days that had no events contain no data.
for (uint32_t day = kDayIndex - 6; day < kDayIndex - 1; ++day) {
EXPECT_FALSE(report_aggregate.daily().by_day_index().contains(day));
}
}
} // namespace cobalt::local_aggregation