blob: 54f8f3b8920fd7d55a6939447092087b9fc46d04 [file] [log] [blame]
// Copyright 2022 The Chromium OS 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 "feature_usage/feature_usage_metrics.h"
#include <base/logging.h>
#include <base/power_monitor/power_monitor.h>
#include <base/power_monitor/power_monitor_device_source.h>
#include <base/run_loop.h>
#include <base/test/task_environment.h>
#include <base/time/clock.h>
#include <base/time/time.h>
#include <gtest/gtest.h>
#include <metrics/metrics_library_mock.h>
namespace feature_usage {
namespace {
const char kTestFeature[] = "TestFeature";
const char kTestMetric[] = "ChromeOS.FeatureUsage.TestFeature";
const char kTestUsetimeMetric[] = "ChromeOS.FeatureUsage.TestFeature.Usetime";
constexpr base::TimeDelta kDefaultUseTime = base::Minutes(10);
} // namespace
class FeatureUsageMetricsTest : public ::testing::Test,
public FeatureUsageMetrics::Delegate {
public:
FeatureUsageMetricsTest() {
if (!base::PowerMonitor::IsInitialized()) {
base::PowerMonitor::Initialize(
std::make_unique<base::PowerMonitorDeviceSource>());
}
feature_usage_metrics_ = std::make_unique<FeatureUsageMetrics>(
kTestFeature, this, env_.GetMockClock(), env_.GetMockTickClock());
feature_usage_metrics_->SetMetricsLibraryForTesting(
std::make_unique<MetricsLibraryMock>());
}
// FeatureUsageMetrics::Delegate:
bool IsEligible() const override { return is_eligible_; }
std::optional<bool> IsAccessible() const override { return is_accessible_; }
bool IsEnabled() const override { return is_enabled_; }
protected:
base::test::TaskEnvironment env_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
bool is_eligible_ = true;
std::optional<bool> is_accessible_;
bool is_enabled_ = true;
MetricsLibraryMock* GetMetricsLibraryMock() {
return static_cast<MetricsLibraryMock*>(
feature_usage_metrics_->metrics_library_for_testing());
}
std::unique_ptr<FeatureUsageMetrics> feature_usage_metrics_;
};
TEST_F(FeatureUsageMetricsTest, RecordUsageWithSuccess) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSuccess),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
feature_usage_metrics_->RecordUsage(/*success=*/true);
}
TEST_F(FeatureUsageMetricsTest, RecordUsageWithFailure) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithFailure),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
feature_usage_metrics_->RecordUsage(/*success=*/false);
}
TEST_F(FeatureUsageMetricsTest, RecordUsetime) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSuccess),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric, kDefaultUseTime.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
feature_usage_metrics_->RecordUsage(/*success=*/true);
feature_usage_metrics_->StartSuccessfulUsage();
env_.FastForwardBy(kDefaultUseTime);
feature_usage_metrics_->StopSuccessfulUsage();
}
TEST_F(FeatureUsageMetricsTest, RecordLongUsetime) {
size_t repeated_periods = 4;
const base::TimeDelta extra_small_use_time = base::Minutes(3);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(repeated_periods + 1);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(repeated_periods + 1);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSuccess),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric,
FeatureUsageMetrics::kRepeatedInterval.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100))
.Times(repeated_periods);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric, extra_small_use_time.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
const base::TimeDelta use_time =
FeatureUsageMetrics::kRepeatedInterval * repeated_periods +
extra_small_use_time;
feature_usage_metrics_->RecordUsage(/*success=*/true);
feature_usage_metrics_->StartSuccessfulUsage();
env_.FastForwardBy(use_time);
feature_usage_metrics_->StopSuccessfulUsage();
}
TEST_F(FeatureUsageMetricsTest, PeriodicMetricsTest) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(2);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
// Trigger initial periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kInitialInterval);
is_enabled_ = false;
// Trigger repeated periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kRepeatedInterval);
is_eligible_ = false;
// Trigger repeated periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kRepeatedInterval);
}
TEST_F(FeatureUsageMetricsTest, PeriodicWithAccessibleMetricsTest) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(3);
EXPECT_CALL(*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kAccessible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(2);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
is_accessible_ = true;
// Trigger initial periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kInitialInterval);
is_enabled_ = false;
// Trigger repeated periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kRepeatedInterval);
is_accessible_ = false;
// Trigger repeated periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kRepeatedInterval);
is_eligible_ = false;
// Trigger repeated periodic metrics report.
env_.FastForwardBy(FeatureUsageMetrics::kRepeatedInterval);
}
TEST_F(FeatureUsageMetricsTest, ReportUseTimeOnShutdown) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSuccess),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric, kDefaultUseTime.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
feature_usage_metrics_->RecordUsage(/*success=*/true);
feature_usage_metrics_->StartSuccessfulUsage();
env_.FastForwardBy(kDefaultUseTime);
feature_usage_metrics_.reset();
}
TEST_F(FeatureUsageMetricsTest, ReportPeriodicOnSuspend) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
base::PowerMonitorDeviceSource::HandleSystemSuspending();
base::RunLoop().RunUntilIdle();
// Undo global changes.
base::PowerMonitorDeviceSource::HandleSystemResumed();
}
TEST_F(FeatureUsageMetricsTest, ReportUseTimeOnSuspend) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(2);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(2);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSuccess),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric, kDefaultUseTime.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric, 0, base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
feature_usage_metrics_->RecordUsage(/*success=*/true);
feature_usage_metrics_->StartSuccessfulUsage();
env_.FastForwardBy(kDefaultUseTime);
base::PowerMonitorDeviceSource::HandleSystemSuspending();
base::RunLoop().RunUntilIdle();
// Undo global changes.
base::PowerMonitorDeviceSource::HandleSystemResumed();
}
TEST_F(FeatureUsageMetricsTest, SuspensionTimeNotReported) {
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEligible),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(3);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric, static_cast<int>(FeatureUsageMetrics::Event::kEnabled),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1))
.Times(3);
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendEnumToUMA(
kTestMetric,
static_cast<int>(FeatureUsageMetrics::Event::kUsedWithSuccess),
static_cast<int>(FeatureUsageMetrics::Event::kMaxValue) + 1));
EXPECT_CALL(*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric, kDefaultUseTime.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
EXPECT_CALL(*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric,
FeatureUsageMetrics::kInitialInterval.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
EXPECT_CALL(
*GetMetricsLibraryMock(),
SendToUMA(kTestUsetimeMetric,
kDefaultUseTime.InMilliseconds() -
FeatureUsageMetrics::kInitialInterval.InMilliseconds(),
base::Milliseconds(1).InMilliseconds(),
base::Hours(1).InMilliseconds(), 100));
feature_usage_metrics_->RecordUsage(/*success=*/true);
feature_usage_metrics_->StartSuccessfulUsage();
env_.FastForwardBy(kDefaultUseTime);
base::PowerMonitorDeviceSource::HandleSystemSuspending();
base::RunLoop().RunUntilIdle();
// Time during suspension must not be reported.
env_.AdvanceClock(FeatureUsageMetrics::kRepeatedInterval * 1.33);
base::PowerMonitorDeviceSource::HandleSystemResumed();
base::RunLoop().RunUntilIdle();
env_.FastForwardBy(kDefaultUseTime);
feature_usage_metrics_->StopSuccessfulUsage();
}
} // namespace feature_usage