chromium/chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_periodic_collector_unittest.cc

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ash/policy/reporting/metrics_reporting/apps/app_usage_telemetry_periodic_collector.h"

#include <memory>
#include <optional>

#include "base/test/task_environment.h"
#include "chrome/browser/ash/policy/reporting/metrics_reporting/metric_reporting_prefs.h"
#include "chrome/browser/chromeos/reporting/metric_default_utils.h"
#include "chromeos/ash/components/dbus/session_manager/session_manager_client.h"
#include "chromeos/ash/components/login/session/session_termination_manager.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 "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::Eq;

namespace reporting {
namespace {

class AppUsageTelemetryPeriodicCollectorTest : public ::testing::Test {
 protected:
  void SetUp() override {
    ::ash::SessionManagerClient::InitializeFakeInMemory();
  }

  base::test::SingleThreadTaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};

  ::ash::SessionTerminationManager session_termination_manager_;
  test::FakeReportingSettings reporting_settings_;
  test::FakeSampler sampler_;
  test::FakeMetricReportQueue metric_report_queue_;
};

TEST_F(AppUsageTelemetryPeriodicCollectorTest,
       CollectMetricDataWhenRateNotSet) {
  // Set up test sampler to report telemetry data.
  MetricData metric_data;
  metric_data.mutable_telemetry_data();
  sampler_.SetMetricData(std::move(metric_data));

  // Fast forward timer to trigger telemetry collection and verify data being
  // reported.
  const AppUsageTelemetryPeriodicCollector collector(
      &sampler_, &metric_report_queue_, &reporting_settings_);
  task_environment_.FastForwardBy(
      metrics::kDefaultAppUsageTelemetryCollectionRate);
  ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(1));
  ASSERT_FALSE(metric_report_queue_.IsEmpty());
  const auto& enqueued_metric_data =
      metric_report_queue_.GetMetricDataReported();
  EXPECT_TRUE(enqueued_metric_data.has_timestamp_ms());
  EXPECT_TRUE(enqueued_metric_data.has_telemetry_data());
}

TEST_F(AppUsageTelemetryPeriodicCollectorTest, CollectMetricDataWhenRateSet) {
  // Set collection rate via policy setting.
  static constexpr base::TimeDelta kCollectionRate = base::Minutes(5);
  reporting_settings_.SetInteger(
      ::ash::reporting::kReportAppUsageCollectionRateMs,
      kCollectionRate.InMilliseconds());

  // Set up sampler to report telemetry data.
  MetricData metric_data;
  metric_data.mutable_telemetry_data();
  sampler_.SetMetricData(std::move(metric_data));

  // Fast forward timer to trigger telemetry collection and verify data being
  // reported.
  const AppUsageTelemetryPeriodicCollector collector(
      &sampler_, &metric_report_queue_, &reporting_settings_);
  task_environment_.FastForwardBy(kCollectionRate);
  ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(1));
  const auto& enqueued_metric_data =
      metric_report_queue_.GetMetricDataReported();
  EXPECT_TRUE(enqueued_metric_data.has_timestamp_ms());
  EXPECT_TRUE(enqueued_metric_data.has_telemetry_data());
}

TEST_F(AppUsageTelemetryPeriodicCollectorTest,
       CollectMetricDataWhenRateUpdated) {
  // Set initial collection rate via policy setting.
  static constexpr base::TimeDelta kCollectionRate = base::Minutes(5);
  reporting_settings_.SetInteger(
      ::ash::reporting::kReportAppUsageCollectionRateMs,
      kCollectionRate.InMilliseconds());

  // Set up sampler to report telemetry data.
  MetricData metric_data;
  metric_data.mutable_telemetry_data();
  sampler_.SetMetricData(std::move(metric_data));
  const AppUsageTelemetryPeriodicCollector collector(
      &sampler_, &metric_report_queue_, &reporting_settings_);

  // Update collection rate setting before triggering collection. This is
  // so the rate controller can pick up updated setting value on collection and
  // configure subsequent ones accordingly.
  static constexpr base::TimeDelta kNewCollectionRate =
      kCollectionRate + kCollectionRate;
  reporting_settings_.SetInteger(
      ::ash::reporting::kReportAppUsageCollectionRateMs,
      kNewCollectionRate.InMilliseconds());

  // Fast forward timer to trigger telemetry collection and verify data being
  // reported.
  {
    task_environment_.FastForwardBy(kCollectionRate);
    ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(1));
    const auto& enqueued_metric_data =
        metric_report_queue_.GetMetricDataReported();
    ASSERT_TRUE(enqueued_metric_data.has_timestamp_ms());
    ASSERT_TRUE(enqueued_metric_data.has_telemetry_data());
  }

  // Advance timer by old collection rate and verify no data is being reported.
  task_environment_.FastForwardBy(kCollectionRate);
  ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(1));
  ASSERT_TRUE(metric_report_queue_.IsEmpty());

  // Advance timer by the new collection rate and verify data being reported.
  {
    task_environment_.FastForwardBy(kNewCollectionRate);
    ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(2));
    const auto& enqueued_metric_data =
        metric_report_queue_.GetMetricDataReported();
    EXPECT_TRUE(enqueued_metric_data.has_timestamp_ms());
    EXPECT_TRUE(enqueued_metric_data.has_telemetry_data());
  }
}

TEST_F(AppUsageTelemetryPeriodicCollectorTest, CollectEmptyMetricData) {
  // Set up sampler to report empty metric data.
  sampler_.SetMetricData(std::nullopt);

  // Fast forward timer to trigger telemetry collection and verify no data is
  // being reported.
  const AppUsageTelemetryPeriodicCollector collector(
      &sampler_, &metric_report_queue_, &reporting_settings_);
  task_environment_.FastForwardBy(
      metrics::kDefaultAppUsageTelemetryCollectionRate);
  ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(1));
  ASSERT_TRUE(metric_report_queue_.IsEmpty());
}

TEST_F(AppUsageTelemetryPeriodicCollectorTest, OnCollectorDestruction) {
  // Set up test sampler to report data.
  MetricData metric_data;
  metric_data.mutable_telemetry_data();
  sampler_.SetMetricData(std::move(metric_data));

  // Set up periodic collector and destroy collector before triggering
  // collection.
  auto collector = std::make_unique<AppUsageTelemetryPeriodicCollector>(
      &sampler_, &metric_report_queue_, &reporting_settings_);
  collector.reset();

  // Fast forward timer and verify no data is being reported.
  task_environment_.FastForwardBy(
      metrics::kDefaultAppUsageTelemetryCollectionRate);
  ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(0));
  ASSERT_TRUE(metric_report_queue_.IsEmpty());
}

TEST_F(AppUsageTelemetryPeriodicCollectorTest, OnSessionTermination) {
  // Set up test sampler to report data.
  MetricData metric_data;
  metric_data.mutable_telemetry_data();
  sampler_.SetMetricData(std::move(metric_data));

  // Set up periodic collector and terminate session.
  const AppUsageTelemetryPeriodicCollector collector(
      &sampler_, &metric_report_queue_, &reporting_settings_);
  session_termination_manager_.StopSession(
      ::login_manager::SessionStopReason::USER_REQUESTS_SIGNOUT);

  // Verify data being reported.
  ASSERT_THAT(sampler_.GetNumCollectCalls(), Eq(1));
  const auto& enqueued_metric_data =
      metric_report_queue_.GetMetricDataReported();
  ASSERT_TRUE(enqueued_metric_data.has_timestamp_ms());
  ASSERT_TRUE(enqueued_metric_data.has_telemetry_data());
}

}  // namespace
}  // namespace reporting