| // 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 |