blob: ba3372d543a7180df9ddbc0b9b58a2f2b862be30 [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/local_aggregation.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "src/lib/util/clock.h"
#include "src/lib/util/testing/test_with_files.h"
#include "src/local_aggregation_1_1/aggregation_procedures/aggregation_procedure.h"
#include "src/local_aggregation_1_1/testing/test_registry.cb.h"
#include "src/logger/event_record.h"
#include "src/logger/logger_test_utils.h"
#include "src/logger/observation_writer.h"
#include "src/logger/project_context_factory.h"
#include "src/observation_store/observation_store_internal.pb.h"
#include "src/pb/metadata_builder.h"
#include "src/registry/project.pb.h"
#include "src/system_data/client_secret.h"
#include "src/system_data/fake_system_data.h"
namespace cobalt::local_aggregation {
using ::testing::Contains;
using ::testing::Not;
using TimeInfo = util::TimeInfo;
namespace {
std::unique_ptr<CobaltRegistry> GetRegistry() {
std::string bytes;
if (!absl::Base64Unescape(kCobaltRegistryBase64, &bytes)) {
LOG(ERROR) << "Unable to decode Base64 String";
return nullptr;
}
auto registry = std::make_unique<CobaltRegistry>();
if (!registry->ParseFromString(bytes)) {
LOG(ERROR) << "Unable to parse registry from bytes";
return nullptr;
}
return registry;
}
} // namespace
class LocalAggregationTest : public util::testing::TestWithFiles {
private:
void SetUp() override {
TestWithFiles::SetUp();
global_project_context_factory_ =
std::make_unique<logger::ProjectContextFactory>(GetRegistry());
metadata_builder_ =
std::make_unique<MetadataBuilder>(&system_data_, system_data_cache_path(), fs());
}
protected:
std::unique_ptr<LocalAggregation> MakeLocalAggregation(
const logger::ObservationWriter* observation_writer) {
CobaltConfig cfg = {.local_aggregate_store_dir = local_aggregation_store_path(),
.client_secret = system_data::ClientSecret::GenerateNewSecret()};
return std::make_unique<LocalAggregation>(cfg, global_project_context_factory_.get(),
metadata_builder_.get(), fs(), observation_writer);
}
std::shared_ptr<const logger::ProjectContext> GetProjectContext() {
return global_project_context_factory_->NewProjectContext(kCustomerId, kProjectId);
}
private:
std::unique_ptr<logger::ProjectContextFactory> global_project_context_factory_;
system_data::FakeSystemData system_data_;
std::unique_ptr<MetadataBuilder> metadata_builder_;
};
TEST_F(LocalAggregationTest, AddEventWorks) {
logger::testing::FakeObservationStore test_writer;
logger::ObservationWriter observation_writer(&test_writer, nullptr);
auto aggregation = MakeLocalAggregation(&observation_writer);
ASSERT_THAT(fs()->ListFiles(absl::StrCat(local_aggregation_store_path(), "/", kCustomerId, "/",
kProjectId))
.ConsumeValueOrDie(),
Not(Contains(absl::StrCat(kOccurrenceMetricMetricId))));
logger::EventRecord record(GetProjectContext(), kOccurrenceMetricMetricId);
record.event()->mutable_occurrence_event();
aggregation->AddEvent(record);
ASSERT_THAT(fs()->ListFiles(absl::StrCat(local_aggregation_store_path(), "/", kCustomerId, "/",
kProjectId))
.ConsumeValueOrDie(),
Contains(absl::StrCat(kOccurrenceMetricMetricId)));
}
TEST_F(LocalAggregationTest, DisableWorks) {
logger::testing::FakeObservationStore test_writer;
logger::ObservationWriter observation_writer(&test_writer, nullptr);
auto aggregation = MakeLocalAggregation(&observation_writer);
aggregation->Disable(true);
// Check that the no data is present.
ASSERT_THAT(fs()->ListFiles(absl::StrCat(local_aggregation_store_path(), "/", kCustomerId, "/",
kProjectId))
.ConsumeValueOrDie(),
Not(Contains(absl::StrCat(kOccurrenceMetricMetricId))));
logger::EventRecord record(GetProjectContext(), kOccurrenceMetricMetricId);
record.event()->mutable_occurrence_event();
aggregation->AddEvent(record);
// Check that the data still isn't present.
ASSERT_THAT(fs()->ListFiles(absl::StrCat(local_aggregation_store_path(), "/", kCustomerId, "/",
kProjectId))
.ConsumeValueOrDie(),
Not(Contains(absl::StrCat(kOccurrenceMetricMetricId))));
}
TEST_F(LocalAggregationTest, GenerateObservationsWorks) {
auto project_context = GetProjectContext();
auto metric = project_context->GetMetric(kOccurrenceMetricMetricId);
// This test assumes that this metric has no reports with added privacy.
for (const auto& report : metric->reports()) {
ASSERT_EQ(ReportDefinition::NO_ADDED_PRIVACY, report.privacy_level());
}
logger::testing::FakeObservationStore test_writer;
logger::ObservationWriter observation_writer(&test_writer, nullptr);
auto aggregation = MakeLocalAggregation(&observation_writer);
logger::EventRecord record(project_context, kOccurrenceMetricMetricId);
record.event()->mutable_occurrence_event()->set_count(1);
record.event()->set_day_index(1);
record.event()->set_hour_id(1);
ASSERT_TRUE(aggregation->AddEvent(record).ok());
ASSERT_TRUE(aggregation->AddEvent(record).ok());
ASSERT_TRUE(aggregation->AddEvent(record).ok());
ASSERT_TRUE(aggregation->AddEvent(record).ok());
aggregation->GenerateAggregatedObservations(TimeInfo::FromHourId(1), TimeInfo::FromHourId(1));
ASSERT_EQ(test_writer.num_observations_added(), 2);
ASSERT_EQ(test_writer.metadata_received[0]->customer_id(), kCustomerId);
std::unique_ptr<observation_store::StoredObservation> last_stored_observation =
std::move(test_writer.messages_received[0]);
ASSERT_TRUE(last_stored_observation->has_unencrypted());
Observation last_observation = last_stored_observation->unencrypted();
ASSERT_TRUE(last_observation.has_integer());
ASSERT_GT(last_observation.integer().values_size(), 0);
ASSERT_EQ(last_observation.integer().values(0).value(), 4);
}
} // namespace cobalt::local_aggregation