blob: 7db5bdf4c14912ef63374f82236851658c1a4538 [file] [log] [blame]
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/android/battery_metrics.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
using Delta = AndroidBatteryMetrics::EnergyConsumedTracker::Delta;
bool operator==(const Delta& lhs, const Delta& rhs) {
return lhs.subsystem == rhs.subsystem &&
lhs.energy_consumed_mwh == rhs.energy_consumed_mwh;
}
namespace {
using LoadingScenario = performance_scenarios::LoadingScenario;
using InputScenario = performance_scenarios::InputScenario;
using Subsystem = AndroidBatteryMetrics::EnergyConsumedTracker::Subsystem;
using ::testing::IsEmpty;
using ::testing::UnorderedElementsAre;
TEST(PerformanceScenarioTracker, UnknownScenarioByDefault) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
EXPECT_EQ(tracker.GetMetricSuffix(),
"UnknownLoadingScenario_UnknownInputScenario");
}
TEST(PerformanceScenarioTracker, UpdateSetsNewScenario) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
tracker.UpdateInputScenario(InputScenario::kNoInput);
EXPECT_EQ(tracker.GetMetricSuffix(), "NoPageLoading_NoInput");
}
TEST(PerformanceScenarioTracker, InputTypingTakesPrecedenceOverNoInput) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateInputScenario(InputScenario::kNoInput);
tracker.UpdateInputScenario(InputScenario::kTyping);
tracker.UpdateInputScenario(InputScenario::kNoInput);
EXPECT_EQ(tracker.GetMetricSuffix(), "UnknownLoadingScenario_Typing");
}
TEST(PerformanceScenarioTracker, InputTapTakesPrecedenceOverTyping) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateInputScenario(InputScenario::kNoInput);
tracker.UpdateInputScenario(InputScenario::kTyping);
tracker.UpdateInputScenario(InputScenario::kTap);
tracker.UpdateInputScenario(InputScenario::kTyping);
tracker.UpdateInputScenario(InputScenario::kNoInput);
EXPECT_EQ(tracker.GetMetricSuffix(), "UnknownLoadingScenario_Tap");
}
TEST(PerformanceScenarioTracker, InputScrollTakesPrecedence) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateInputScenario(InputScenario::kNoInput);
tracker.UpdateInputScenario(InputScenario::kTyping);
tracker.UpdateInputScenario(InputScenario::kTap);
tracker.UpdateInputScenario(InputScenario::kScroll);
tracker.UpdateInputScenario(InputScenario::kTap);
tracker.UpdateInputScenario(InputScenario::kTyping);
tracker.UpdateInputScenario(InputScenario::kNoInput);
EXPECT_EQ(tracker.GetMetricSuffix(), "UnknownLoadingScenario_Scroll");
}
TEST(PerformanceScenarioTracker, FocusedLoadingTakesPrecedence) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kBackgroundPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kVisiblePageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kFocusedPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kVisiblePageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kBackgroundPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
// No loading -> background loading -> visible loading -> focused loading ->
// visible loading -> background loading -> no loading. The overall scenario
// is "FocusedPageLoading".
EXPECT_EQ(tracker.GetMetricSuffix(),
"FocusedPageLoading_UnknownInputScenario");
}
TEST(PerformanceScenarioTracker,
VisibleLoadingTakesPrecedenceOverBackgroundLoading) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kBackgroundPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kVisiblePageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kBackgroundPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
// No loading -> background loading -> visible loading ->
// background loading -> no loading. The overall scenario is
// "VisiblePageLoading".
EXPECT_EQ(tracker.GetMetricSuffix(),
"VisiblePageLoading_UnknownInputScenario");
}
TEST(PerformanceScenarioTracker,
BackgroundLoadingTakesPrecedenceOverNoLoading) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kBackgroundPageLoading);
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
// No loading -> background loading -> no loading. The overall scenario is
// "BackgroundPageLoading".
EXPECT_EQ(tracker.GetMetricSuffix(),
"BackgroundPageLoading_UnknownInputScenario");
}
TEST(PerformanceScenarioTracker, ResetSetsLatestScenario) {
AndroidBatteryMetrics::PerformanceScenarioTracker tracker;
// Visible loading + typing first.
tracker.UpdateLoadingScenario(LoadingScenario::kVisiblePageLoading);
tracker.UpdateInputScenario(InputScenario::kTyping);
// No loading and no input after it.
tracker.UpdateLoadingScenario(LoadingScenario::kNoPageLoading);
tracker.UpdateInputScenario(InputScenario::kNoInput);
// Visible loading and typing take precedence (see Precedence tests above).
ASSERT_EQ(tracker.GetMetricSuffix(), "VisiblePageLoading_Typing");
tracker.UseLatestScenarios();
// Visible loading + typing is no longer in the tracked window.
EXPECT_EQ(tracker.GetMetricSuffix(), "NoPageLoading_NoInput");
}
TEST(EnergyConsumedTracker, InitiallyEmptyDeltas) {
AndroidBatteryMetrics::EnergyConsumedTracker tracker;
// No previous values in the tracker, so no deltas to report.
EXPECT_THAT(tracker.GetDeltas({{"CPU", 10000}}), IsEmpty());
}
TEST(EnergyConsumedTracker, AllKnownSubsystems) {
AndroidBatteryMetrics::EnergyConsumedTracker tracker;
tracker.UpdatePowerMonitorReadings(
{{"CPU", 3600}, {"GPU", 10 * 3600}, {"DISPLAY", 100 * 3600}});
EXPECT_THAT(
tracker.GetDeltas(
{{"CPU", 2 * 3600}, {"GPU", 20 * 3600}, {"DISPLAY", 200 * 3600}}),
UnorderedElementsAre(Delta{Subsystem::kCpu, 1},
Delta{Subsystem::kGpu, 10},
Delta{Subsystem::kDisplay, 100}));
}
TEST(EnergyConsumedTracker, UnknownSubsystemsReportedAsOther) {
AndroidBatteryMetrics::EnergyConsumedTracker tracker;
tracker.UpdatePowerMonitorReadings(
{{"Unknown1", 3600}, {"Unknown2", 10 * 3600}});
// All deltas from unknown subsystems reported together as "Other".
EXPECT_THAT(
tracker.GetDeltas({{"Unknown1", 2 * 3600}, {"Unknown2", 20 * 3600}}),
UnorderedElementsAre(Delta{Subsystem::kOther, 11}));
}
TEST(EnergyConsumedTracker, SumsUpDifferentCpus) {
AndroidBatteryMetrics::EnergyConsumedTracker tracker;
tracker.UpdatePowerMonitorReadings(
{{"CPU/0", 3600}, {"CPU/1", 10 * 3600}, {"CPU/2", 100 * 3600}});
EXPECT_THAT(
tracker.GetDeltas(
{{"CPU/0", 2 * 3600}, {"CPU/1", 20 * 3600}, {"CPU/2", 200 * 3600}}),
UnorderedElementsAre(Delta{Subsystem::kCpu, 111}));
}
TEST(EnergyConsumedTracker, DoesNotReportNegativeValues) {
AndroidBatteryMetrics::EnergyConsumedTracker tracker;
tracker.UpdatePowerMonitorReadings({{"CPU", 10 * 3600}});
// The new value is lower than the previous one. The tracker should report 0,
// not a negative value.
EXPECT_THAT(tracker.GetDeltas({{"CPU", 3600}}),
UnorderedElementsAre(Delta{Subsystem::kCpu, 0}));
}
TEST(EnergyConsumedTracker, TreatsZerosAsErrors) {
AndroidBatteryMetrics::EnergyConsumedTracker tracker;
tracker.UpdatePowerMonitorReadings({{"CPU", 3600}});
// 0 value for total energy is an error. The tracker should not report any
// deltas.
EXPECT_THAT(tracker.GetDeltas({{"CPU", 0}}), IsEmpty());
}
} // namespace
} // namespace content