blob: 7f9f884f0fcff33cee850d1d172955cc09474100 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/reporting/metrics/periodic_collector.h"
#include <array>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "components/reporting/metrics/fakes/fake_metric_report_queue.h"
#include "components/reporting/metrics/fakes/fake_reporting_settings.h"
#include "components/reporting/metrics/fakes/fake_sampler.h"
#include "components/reporting/metrics/metric_report_queue.h"
#include "components/reporting/proto/synced/metric_data.pb.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Eq;
namespace reporting {
namespace {
constexpr char kEnableSettingPath[] = "enable_path";
constexpr char kRateSettingPath[] = "rate_path";
constexpr base::TimeDelta interval = base::Milliseconds(10000);
class PeriodicCollectorTest : public ::testing::Test {
protected:
void SetUp() override {
settings_ = std::make_unique<test::FakeReportingSettings>();
sampler_ = std::make_unique<test::FakeSampler>();
metric_report_queue_ = std::make_unique<test::FakeMetricReportQueue>();
}
base::test::SingleThreadTaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::unique_ptr<test::FakeReportingSettings> settings_;
std::unique_ptr<test::FakeSampler> sampler_;
std::unique_ptr<test::FakeMetricReportQueue> metric_report_queue_;
base::HistogramTester histogram_tester_;
};
TEST_F(PeriodicCollectorTest, InitiallyEnabled) {
settings_->SetReportingEnabled(kEnableSettingPath, true);
settings_->SetInteger(kRateSettingPath, interval.InMilliseconds());
std::array<MetricData, 5> metric_data_list;
metric_data_list[0].mutable_telemetry_data();
metric_data_list[1].mutable_info_data();
metric_data_list[2].mutable_event_data();
metric_data_list[3].mutable_telemetry_data();
metric_data_list[3].mutable_event_data();
metric_data_list[4].mutable_info_data();
metric_data_list[4].mutable_event_data();
sampler_->SetMetricData(metric_data_list[0]);
PeriodicCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), kEnableSettingPath,
/*setting_enabled_default_value=*/false,
kRateSettingPath, interval / 2);
// One initial collection at startup.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(1));
// Expected calls count initialized to 1 to reflect the initial collection.
int expected_collect_calls = 1;
for (int i = 0; i < 2; ++i) {
sampler_->SetMetricData(metric_data_list[i + 1]);
// 5 secs elapsed, no new data collected.
task_environment_.FastForwardBy(interval / 2);
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(expected_collect_calls));
++expected_collect_calls;
// 10 secs elapsed, data should be collected.
task_environment_.FastForwardBy(interval / 2);
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(expected_collect_calls));
;
}
sampler_->SetMetricData(metric_data_list[3]);
settings_->SetReportingEnabled(kEnableSettingPath, false);
// Setting disabled, no data should be collected.
task_environment_.FastForwardBy(interval);
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(expected_collect_calls));
settings_->SetReportingEnabled(kEnableSettingPath, true);
// Initial collection at policy enablement.
++expected_collect_calls;
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(expected_collect_calls));
sampler_->SetMetricData(metric_data_list[4]);
// Setting enabled, data should be collected after interval.
task_environment_.FastForwardBy(interval / 2);
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(expected_collect_calls));
++expected_collect_calls;
task_environment_.FastForwardBy(interval / 2);
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(expected_collect_calls));
for (const auto& metric_data : metric_data_list) {
MetricData metric_data_reported =
metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_THAT(metric_data_reported.has_telemetry_data(),
Eq(metric_data.has_telemetry_data()));
EXPECT_THAT(metric_data_reported.has_info_data(),
Eq(metric_data.has_info_data()));
EXPECT_THAT(metric_data_reported.has_event_data(),
Eq(metric_data.has_event_data()));
}
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(metric_report_queue_->IsEmpty());
histogram_tester_.ExpectTotalCount(
PeriodicCollector::kNoMetricDataMetricsName, /*expected_count=*/0);
}
TEST_F(PeriodicCollectorTest, InitiallyEnabled_Delayed) {
constexpr base::TimeDelta init_delay = base::Minutes(1);
settings_->SetReportingEnabled(kEnableSettingPath, true);
settings_->SetInteger(kRateSettingPath, interval.InMilliseconds());
MetricData metric_data;
metric_data.mutable_telemetry_data();
sampler_->SetMetricData(metric_data);
PeriodicCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), kEnableSettingPath,
/*setting_enabled_default_value=*/false,
kRateSettingPath, interval / 2,
/*rate_unit_to_ms=*/1, init_delay);
// No collection since the init delay is not elapsed.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(0));
task_environment_.FastForwardBy(interval);
// Only interval is elapsed which is less than init delay so still no
// collection.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(0));
collector.Collect(/*is_event_driven=*/true);
// `init_delay` not elapsed but manual collection is triggered.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(1));
MetricData metric_data_reported =
metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_TRUE(metric_data_reported.has_telemetry_data());
EXPECT_TRUE(metric_data_reported.telemetry_data().is_event_driven());
EXPECT_TRUE(metric_report_queue_->IsEmpty());
task_environment_.FastForwardBy(init_delay - interval);
// One initial collection when the init delay is elapsed.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(2));
metric_data_reported = metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_TRUE(metric_data_reported.has_telemetry_data());
EXPECT_FALSE(metric_data_reported.telemetry_data().is_event_driven());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(metric_report_queue_->IsEmpty());
sampler_->SetMetricData(std::nullopt);
histogram_tester_.ExpectTotalCount(
PeriodicCollector::kNoMetricDataMetricsName, /*expected_count=*/0);
}
TEST_F(PeriodicCollectorTest, NoMetricData) {
settings_->SetReportingEnabled(kEnableSettingPath, true);
settings_->SetInteger(kRateSettingPath, interval.InMilliseconds());
sampler_->SetMetricData(std::nullopt);
PeriodicCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), kEnableSettingPath,
/*setting_enabled_default_value=*/false,
kRateSettingPath, interval / 2);
// One initial collection at startup.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(1));
base::RunLoop().RunUntilIdle();
ASSERT_TRUE(metric_report_queue_->IsEmpty());
histogram_tester_.ExpectBucketCount(
PeriodicCollector::kNoMetricDataMetricsName,
metric_report_queue_->GetDestination(), /*expected_count=*/1);
histogram_tester_.ExpectTotalCount(
PeriodicCollector::kNoMetricDataMetricsName, /*expected_count=*/1);
}
TEST_F(PeriodicCollectorTest, InitiallyDisabled) {
settings_->SetReportingEnabled(kEnableSettingPath, false);
settings_->SetInteger(kRateSettingPath, interval.InMilliseconds());
MetricData metric_data;
metric_data.mutable_telemetry_data();
sampler_->SetMetricData(std::move(metric_data));
PeriodicCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), kEnableSettingPath,
/*setting_enabled_default_value=*/false,
kRateSettingPath, interval / 2);
task_environment_.FastForwardBy(interval);
// Setting is disabled, no data collected.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(0));
collector.Collect(/*is_event_driven=*/true);
// Manual collection is triggered but reporting is disabled.
EXPECT_EQ(sampler_->GetNumCollectCalls(), 0);
settings_->SetReportingEnabled(kEnableSettingPath, true);
// One initial collection at policy enablement.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(1));
MetricData metric_data_reported =
metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_TRUE(metric_data_reported.has_telemetry_data());
EXPECT_FALSE(metric_data_reported.telemetry_data().has_is_event_driven());
task_environment_.FastForwardBy(interval / 2);
collector.Collect(/*is_event_driven=*/true);
// `interval` not elapsed but manual collection is triggered.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(2));
metric_data_reported = metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_TRUE(metric_data_reported.has_telemetry_data());
EXPECT_TRUE(metric_data_reported.telemetry_data().is_event_driven());
task_environment_.FastForwardBy(interval / 2);
// 1 collection at policy enablement + 1 manual collection + 1 collection
// after interval.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(3));
metric_data_reported = metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_TRUE(metric_data_reported.has_telemetry_data());
EXPECT_FALSE(metric_data_reported.telemetry_data().has_is_event_driven());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(metric_report_queue_->IsEmpty());
histogram_tester_.ExpectTotalCount(
PeriodicCollector::kNoMetricDataMetricsName, /*expected_count=*/0);
}
TEST_F(PeriodicCollectorTest, DefaultEnabled) {
settings_->SetInteger(kRateSettingPath, interval.InMilliseconds());
MetricData metric_data;
metric_data.mutable_telemetry_data();
sampler_->SetMetricData(std::move(metric_data));
PeriodicCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), "invalid/path",
/*setting_enabled_default_value=*/true,
kRateSettingPath, interval / 2);
// One initial collection at startup.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(1));
metric_data.Clear();
metric_data.mutable_event_data();
sampler_->SetMetricData(std::move(metric_data));
// 10 secs elapsed, data should be collected.
task_environment_.FastForwardBy(interval);
// 1 collection at startup + 1 collection after interval.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(2));
MetricData metric_data_reported =
metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_TRUE(metric_data_reported.has_telemetry_data());
metric_data_reported = metric_report_queue_->GetMetricDataReported();
EXPECT_TRUE(metric_data_reported.has_timestamp_ms());
EXPECT_FALSE(metric_data_reported.has_telemetry_data());
EXPECT_TRUE(metric_data_reported.has_event_data());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(metric_report_queue_->IsEmpty());
histogram_tester_.ExpectTotalCount(
PeriodicCollector::kNoMetricDataMetricsName, /*expected_count=*/0);
}
TEST_F(PeriodicCollectorTest, DefaultDisabled) {
settings_->SetInteger(kRateSettingPath, interval.InMilliseconds());
MetricData metric_data;
metric_data.mutable_telemetry_data();
PeriodicCollector collector(sampler_.get(), metric_report_queue_.get(),
settings_.get(), "invalid/path",
/*setting_enabled_default_value=*/false,
kRateSettingPath, interval / 2);
sampler_->SetMetricData(std::move(metric_data));
task_environment_.FastForwardBy(interval);
base::RunLoop().RunUntilIdle();
// Setting is disabled by default, no data collected.
EXPECT_THAT(sampler_->GetNumCollectCalls(), Eq(0));
EXPECT_TRUE(metric_report_queue_->IsEmpty());
histogram_tester_.ExpectTotalCount(
PeriodicCollector::kNoMetricDataMetricsName, /*expected_count=*/0);
}
} // namespace
} // namespace reporting