blob: deea6f5fdec469d675fd396ada143cccbeec9d37 [file] [log] [blame]
// Copyright 2019 The Chromium 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 <utility>
#include "base/bind.h"
#include "base/macros.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/threading/thread_task_runner_handle.h"
#include "build/build_config.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/subprocess_metrics_provider.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "content/public/common/service_manager_connection.h"
#include "content/public/test/browser_test_utils.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/device/public/mojom/battery_monitor.mojom.h"
#include "services/device/public/mojom/battery_status.mojom.h"
#include "services/device/public/mojom/constants.mojom.h"
#include "services/service_manager/public/cpp/service_binding.h"
namespace {
// Retries fetching |histogram_name| until it contains at least |count| samples.
void RetryForHistogramBucketUntilCountReached(
base::HistogramTester* histogram_tester,
const std::string& histogram_name,
base::HistogramBase::Sample target_bucket,
size_t count) {
base::RunLoop().RunUntilIdle();
for (size_t attempt = 0; attempt < 50; ++attempt) {
const std::vector<base::Bucket> buckets =
histogram_tester->GetAllSamples(histogram_name);
size_t total_count = 0;
for (const auto& bucket : buckets) {
if (bucket.min == target_bucket)
total_count += bucket.count;
}
if (total_count >= count)
return;
content::FetchHistogramsFromChildProcesses();
SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
base::RunLoop().RunUntilIdle();
}
}
// Replaces the platform specific implementation of BatteryMonitor.
class MockBatteryMonitor : public device::mojom::BatteryMonitor {
public:
MockBatteryMonitor() : binding_(this) {}
~MockBatteryMonitor() override = default;
void Bind(device::mojom::BatteryMonitorRequest request) {
DCHECK(!binding_.is_bound());
binding_.Bind(std::move(request));
}
void DidChange(const device::mojom::BatteryStatus& battery_status) {
status_ = battery_status;
status_to_report_ = true;
if (!callback_.is_null())
ReportStatus();
}
void CloseBinding() { binding_.Close(); }
private:
// mojom::BatteryMonitor methods:
void QueryNextStatus(QueryNextStatusCallback callback) override {
if (!callback_.is_null()) {
binding_.Close();
return;
}
callback_ = std::move(callback);
if (status_to_report_)
ReportStatus();
}
void ReportStatus() {
std::move(callback_).Run(status_.Clone());
status_to_report_ = false;
}
QueryNextStatusCallback callback_;
device::mojom::BatteryStatus status_;
bool status_to_report_ = false;
mojo::Binding<device::mojom::BatteryMonitor> binding_;
DISALLOW_COPY_AND_ASSIGN(MockBatteryMonitor);
};
// Test that the metricss around battery usage are recorded correctly.
class BatteryMetricsBrowserTest : public InProcessBrowserTest {
public:
BatteryMetricsBrowserTest() = default;
~BatteryMetricsBrowserTest() override = default;
protected:
MockBatteryMonitor* mock_battery_monitor() {
return mock_battery_monitor_.get();
}
private:
void SetUpOnMainThread() override {
mock_battery_monitor_ = std::make_unique<MockBatteryMonitor>();
service_manager::ServiceBinding::OverrideInterfaceBinderForTesting(
device::mojom::kServiceName,
base::BindRepeating(&MockBatteryMonitor::Bind,
base::Unretained(mock_battery_monitor_.get())));
}
void TearDownOnMainThread() override {
service_manager::ServiceBinding::ClearInterfaceBinderOverrideForTesting<
device::mojom::BatteryMonitor>(device::mojom::kServiceName);
InProcessBrowserTest::TearDownOnMainThread();
}
std::unique_ptr<MockBatteryMonitor> mock_battery_monitor_;
DISALLOW_COPY_AND_ASSIGN(BatteryMetricsBrowserTest);
};
#if defined(OS_WIN)
#define DISABLED_ON_WIN(name) DISABLED##name
#else
#define DISABLED_ON_WIN(name) name
#endif
IN_PROC_BROWSER_TEST_F(BatteryMetricsBrowserTest,
DISABLED_ON_WIN(BatteryDropUMA)) {
// Verify that drops in battery level are recorded, and drops by less than 1%
// are aggregated together until there is a full percentage drop.
device::mojom::BatteryStatus status;
status.charging = false;
status.charging_time = std::numeric_limits<double>::infinity();
status.discharging_time = 100;
status.level = 0.6;
mock_battery_monitor()->DidChange(status);
base::HistogramTester histogram_tester;
// A drop of 10.9% should record in the 10 bucket.
status.level = 0.491;
mock_battery_monitor()->DidChange(status);
RetryForHistogramBucketUntilCountReached(&histogram_tester,
"Power.BatteryPercentDrop", 10, 1);
// .9% should be stored from the previous drop, so an additional drop to 1%
// should be recorded in the 1% bucket.
status.level = 0.49;
mock_battery_monitor()->DidChange(status);
RetryForHistogramBucketUntilCountReached(&histogram_tester,
"Power.BatteryPercentDrop", 1, 1);
}
} // namespace