blob: 985f6c87e54c9e8cddb24753a88f980d2561da58 [file] [log] [blame]
// Copyright 2020 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 "chromeos/components/diagnostics_ui/backend/system_data_provider.h"
#include <cstdint>
#include <vector>
#include "base/bind.h"
#include "base/run_loop.h"
#include "base/strings/string16.h"
#include "base/system/sys_info.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "base/timer/mock_timer.h"
#include "chromeos/components/diagnostics_ui/backend/cpu_usage_data.h"
#include "chromeos/components/diagnostics_ui/backend/power_manager_client_conversions.h"
#include "chromeos/dbus/cros_healthd/cros_healthd_client.h"
#include "chromeos/dbus/cros_healthd/fake_cros_healthd_client.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "chromeos/dbus/power_manager/power_supply_properties.pb.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd.mojom.h"
#include "chromeos/services/cros_healthd/public/mojom/cros_healthd_probe.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace chromeos {
namespace diagnostics {
namespace {
void SetProbeTelemetryInfoResponse(
cros_healthd::mojom::BatteryInfoPtr battery_info,
cros_healthd::mojom::CpuInfoPtr cpu_info,
cros_healthd::mojom::MemoryInfoPtr memory_info,
cros_healthd::mojom::SystemInfoPtr system_info) {
auto info = cros_healthd::mojom::TelemetryInfo::New();
if (system_info) {
info->system_result = cros_healthd::mojom::SystemResult::NewSystemInfo(
std::move(system_info));
}
if (battery_info) {
info->battery_result = cros_healthd::mojom::BatteryResult::NewBatteryInfo(
std::move(battery_info));
}
if (memory_info) {
info->memory_result = cros_healthd::mojom::MemoryResult::NewMemoryInfo(
std::move(memory_info));
}
if (cpu_info) {
info->cpu_result =
cros_healthd::mojom::CpuResult::NewCpuInfo(std::move(cpu_info));
}
cros_healthd::FakeCrosHealthdClient::Get()
->SetProbeTelemetryInfoResponseForTesting(info);
}
void SetCrosHealthdSystemInfoResponse(const std::string& board_name,
const std::string& marketing_name,
const std::string& cpu_model,
uint32_t total_memory_kib,
uint16_t cpu_threads_count,
uint32_t cpu_max_clock_speed_khz,
bool has_battery,
const std::string& milestone_version) {
// System info
auto system_info = cros_healthd::mojom::SystemInfo::New();
system_info->product_name = base::Optional<std::string>(board_name);
auto os_version_info = cros_healthd::mojom::OsVersion::New();
os_version_info->release_milestone = milestone_version;
system_info->os_version = std::move(os_version_info);
system_info->marketing_name = marketing_name;
// Battery info
auto battery_info =
has_battery ? cros_healthd::mojom::BatteryInfo::New() : nullptr;
// Memory info
auto memory_info = cros_healthd::mojom::MemoryInfo::New();
memory_info->total_memory_kib = total_memory_kib;
// CPU info
auto cpu_info = cros_healthd::mojom::CpuInfo::New();
auto physical_cpu_info = cros_healthd::mojom::PhysicalCpuInfo::New();
auto logical_cpu_info = cros_healthd::mojom::LogicalCpuInfo::New();
logical_cpu_info->max_clock_speed_khz = cpu_max_clock_speed_khz;
physical_cpu_info->logical_cpus.push_back(std::move(logical_cpu_info));
physical_cpu_info->model_name = cpu_model;
cpu_info->num_total_threads = cpu_threads_count;
cpu_info->physical_cpus.emplace_back(std::move(physical_cpu_info));
SetProbeTelemetryInfoResponse(std::move(battery_info), std::move(cpu_info),
std::move(memory_info), std::move(system_info));
}
// Constructs a BatteryInfoPtr. If |temperature| = 0, it will be omitted from
// the response to simulate an empty temperature field.
cros_healthd::mojom::BatteryInfoPtr CreateCrosHealthdBatteryInfoResponse(
int64_t cycle_count,
double voltage_now,
const std::string& vendor,
const std::string& serial_number,
double charge_full_design,
double charge_full,
double voltage_min_design,
const std::string& model_name,
double charge_now,
double current_now,
const std::string& technology,
const std::string& status,
const base::Optional<std::string>& manufacture_date,
uint64_t temperature) {
cros_healthd::mojom::NullableUint64Ptr temp_value_ptr(
cros_healthd::mojom::NullableUint64::New());
if (temperature != 0) {
temp_value_ptr->value = temperature;
}
auto battery_info = cros_healthd::mojom::BatteryInfo::New(
cycle_count, voltage_now, vendor, serial_number, charge_full_design,
charge_full, voltage_min_design, model_name, charge_now, current_now,
technology, status, manufacture_date, std::move(temp_value_ptr));
return battery_info;
}
cros_healthd::mojom::BatteryInfoPtr CreateCrosHealthdBatteryInfoResponse(
const std::string& vendor,
double charge_full_design) {
return CreateCrosHealthdBatteryInfoResponse(
/*cycle_count=*/0,
/*voltage_now=*/0,
/*vendor=*/vendor,
/*serial_number=*/"",
/*charge_full_design=*/charge_full_design,
/*charge_full=*/0,
/*voltage_min_design=*/0,
/*model_name=*/"",
/*charge_now=*/0,
/*current_now=*/0,
/*technology=*/"",
/*status=*/"",
/*manufacture_date=*/base::nullopt,
/*temperature=*/0);
}
cros_healthd::mojom::BatteryInfoPtr
CreateCrosHealthdBatteryChargeStatusResponse(double charge_now,
double current_now) {
return CreateCrosHealthdBatteryInfoResponse(
/*cycle_count=*/0,
/*voltage_now=*/0,
/*vendor=*/"",
/*serial_number=*/"",
/*charge_full_design=*/0,
/*charge_full=*/0,
/*voltage_min_design=*/0,
/*model_name=*/"",
/*charge_now=*/charge_now,
/*current_now=*/current_now,
/*technology=*/"",
/*status=*/"",
/*manufacture_date=*/base::nullopt,
/*temperature=*/0);
}
cros_healthd::mojom::BatteryInfoPtr CreateCrosHealthdBatteryHealthResponse(
double charge_full_now,
double charge_full_design,
int32_t cycle_count) {
return CreateCrosHealthdBatteryInfoResponse(
/*cycle_count=*/cycle_count,
/*voltage_now=*/0,
/*vendor=*/"",
/*serial_number=*/"",
/*charge_full_design=*/charge_full_design,
/*charge_full=*/charge_full_now,
/*voltage_min_design=*/0,
/*model_name=*/"",
/*charge_now=*/0,
/*current_now=*/0,
/*technology=*/"",
/*status=*/"",
/*manufacture_date=*/base::nullopt,
/*temperature=*/0);
}
void SetCrosHealthdBatteryInfoResponse(const std::string& vendor,
double charge_full_design) {
cros_healthd::mojom::BatteryInfoPtr battery_info =
CreateCrosHealthdBatteryInfoResponse(vendor, charge_full_design);
SetProbeTelemetryInfoResponse(std::move(battery_info), /*cpu_info=*/nullptr,
/*memory_info=*/nullptr,
/*system_info=*/nullptr);
}
void SetCrosHealthdBatteryChargeStatusResponse(double charge_now,
double current_now) {
cros_healthd::mojom::BatteryInfoPtr battery_info =
CreateCrosHealthdBatteryChargeStatusResponse(charge_now, current_now);
SetProbeTelemetryInfoResponse(std::move(battery_info), /*cpu_info=*/nullptr,
/*memory_info=*/nullptr,
/*system_info=*/nullptr);
}
void SetCrosHealthdBatteryHealthResponse(double charge_full_now,
double charge_full_design,
int32_t cycle_count) {
cros_healthd::mojom::BatteryInfoPtr battery_info =
CreateCrosHealthdBatteryHealthResponse(charge_full_now,
charge_full_design, cycle_count);
SetProbeTelemetryInfoResponse(std::move(battery_info), /*cpu_info=*/nullptr,
/*memory_info=*/nullptr,
/*system_info=*/nullptr);
}
void SetCrosHealthdMemoryUsageResponse(uint32_t total_memory_kib,
uint32_t free_memory_kib,
uint32_t available_memory_kib) {
cros_healthd::mojom::MemoryInfoPtr memory_info =
cros_healthd::mojom::MemoryInfo::New(total_memory_kib, free_memory_kib,
available_memory_kib,
/*page_faults_since_last_boot=*/0);
SetProbeTelemetryInfoResponse(/*battery_info=*/nullptr, /*cpu_info=*/nullptr,
/*memory_info=*/std::move(memory_info),
/*system_info=*/nullptr);
}
void SetCrosHealthdCpuResponse(
const std::vector<CpuUsageData>& usage_data,
const std::vector<int32_t>& cpu_temps,
const std::vector<uint32_t>& scaled_cpu_clock_speed) {
auto cpu_info_ptr = cros_healthd::mojom::CpuInfo::New();
auto physical_cpu_info_ptr = cros_healthd::mojom::PhysicalCpuInfo::New();
DCHECK_EQ(usage_data.size(), scaled_cpu_clock_speed.size());
for (size_t i = 0; i < usage_data.size(); ++i) {
const auto& data = usage_data[i];
auto logical_cpu_info_ptr = cros_healthd::mojom::LogicalCpuInfo::New();
logical_cpu_info_ptr->user_time_user_hz = data.GetUserTime();
logical_cpu_info_ptr->system_time_user_hz = data.GetSystemTime();
logical_cpu_info_ptr->idle_time_user_hz = data.GetIdleTime();
logical_cpu_info_ptr->scaling_current_frequency_khz =
scaled_cpu_clock_speed[i];
physical_cpu_info_ptr->logical_cpus.emplace_back(
std::move(logical_cpu_info_ptr));
}
cpu_info_ptr->physical_cpus.push_back(std::move(physical_cpu_info_ptr));
for (const auto& cpu_temp : cpu_temps) {
auto cpu_temp_channel_ptr =
cros_healthd::mojom::CpuTemperatureChannel::New();
cpu_temp_channel_ptr->temperature_celsius = cpu_temp;
cpu_info_ptr->temperature_channels.emplace_back(
std::move(cpu_temp_channel_ptr));
}
SetProbeTelemetryInfoResponse(/*battery_info=*/nullptr,
std::move(cpu_info_ptr),
/*memory_info=*/nullptr,
/*system_info=*/nullptr);
}
// Sets the CpuUsage response on cros_healthd. |usage_data| should contain one
// entry for each logical cpu.
void SetCrosHealthdCpuUsageResponse(
const std::vector<CpuUsageData>& usage_data) {
// Use fake temp and scaled clock speed data since none was supplied.
const std::vector<uint32_t> scaled_clock_speeds(usage_data.size(), 10000);
SetCrosHealthdCpuResponse(usage_data, {50}, scaled_clock_speeds);
}
void SetCrosHealthdCpuTemperatureResponse(
const std::vector<int32_t>& cpu_temps) {
// Use fake usage_data and scaled clock speed data since none was supplied.
SetCrosHealthdCpuResponse({CpuUsageData(1000, 1000, 1000)}, cpu_temps,
{10000});
}
void SetCrosHealthdCpuScalingResponse(const std::vector<uint32_t>& cpu_speeds) {
// Use fake temp and usage_data data since none was supplied.
const std::vector<CpuUsageData> usage_data(cpu_speeds.size(),
CpuUsageData(1000, 1000, 1000));
SetCrosHealthdCpuResponse(usage_data, {50}, cpu_speeds);
}
bool AreValidPowerTimes(int64_t time_to_full, int64_t time_to_empty) {
// Exactly one of |time_to_full| or |time_to_empty| must be zero. The other
// can be a positive integer to represent the time to charge/discharge or -1
// to represent that the time is being calculated.
return (time_to_empty == 0 && (time_to_full > 0 || time_to_full == -1)) ||
(time_to_full == 0 && (time_to_empty > 0 || time_to_empty == -1));
}
power_manager::PowerSupplyProperties ConstructPowerSupplyProperties(
power_manager::PowerSupplyProperties::ExternalPower power_source,
power_manager::PowerSupplyProperties::BatteryState battery_state,
bool is_calculating_battery_time,
int64_t time_to_full,
int64_t time_to_empty) {
power_manager::PowerSupplyProperties props;
props.set_external_power(power_source);
props.set_battery_state(battery_state);
if (battery_state ==
power_manager::PowerSupplyProperties_BatteryState_NOT_PRESENT) {
// Leave |time_to_full| and |time_to_empty| unset.
return props;
}
DCHECK(AreValidPowerTimes(time_to_full, time_to_empty));
props.set_is_calculating_battery_time(is_calculating_battery_time);
props.set_battery_time_to_full_sec(time_to_full);
props.set_battery_time_to_empty_sec(time_to_empty);
return props;
}
// Sets the PowerSupplyProperties on FakePowerManagerClient. Calling this
// method immediately notifies PowerManagerClient observers. One of
// |time_to_full| or |time_to_empty| must be either -1 or a positive number.
// The other must be 0. If |battery_state| is NOT_PRESENT, both |time_to_full|
// and |time_to_empty| will be left unset.
void SetPowerManagerProperties(
power_manager::PowerSupplyProperties::ExternalPower power_source,
power_manager::PowerSupplyProperties::BatteryState battery_state,
bool is_calculating_battery_time,
int64_t time_to_full,
int64_t time_to_empty) {
power_manager::PowerSupplyProperties props = ConstructPowerSupplyProperties(
power_source, battery_state, is_calculating_battery_time, time_to_full,
time_to_empty);
FakePowerManagerClient::Get()->UpdatePowerProperties(props);
}
void VerifyChargeStatusResult(
const mojom::BatteryChargeStatusPtr& update,
double charge_now,
double current_now,
power_manager::PowerSupplyProperties::ExternalPower power_source,
power_manager::PowerSupplyProperties::BatteryState battery_state,
bool is_calculating_battery_time,
int64_t time_to_full,
int64_t time_to_empty) {
const uint32_t expected_charge_now_milliamp_hours = charge_now * 1000;
const int32_t expected_current_now_milliamps = current_now * 1000;
mojom::ExternalPowerSource expected_power_source =
ConvertPowerSourceFromProto(power_source);
mojom::BatteryState expected_battery_state =
ConvertBatteryStateFromProto(battery_state);
EXPECT_EQ(expected_charge_now_milliamp_hours,
update->charge_now_milliamp_hours);
EXPECT_EQ(expected_current_now_milliamps, update->current_now_milliamps);
EXPECT_EQ(expected_power_source, update->power_adapter_status);
EXPECT_EQ(expected_battery_state, update->battery_state);
if (expected_battery_state == mojom::BatteryState::kFull) {
EXPECT_EQ(base::string16(), update->power_time);
return;
}
DCHECK(AreValidPowerTimes(time_to_full, time_to_empty));
const power_manager::PowerSupplyProperties props =
ConstructPowerSupplyProperties(power_source, battery_state,
is_calculating_battery_time, time_to_full,
time_to_empty);
base::string16 expected_power_time =
ConstructPowerTime(expected_battery_state, props);
EXPECT_EQ(expected_power_time, update->power_time);
}
void VerifyHealthResult(const mojom::BatteryHealthPtr& update,
double charge_full_now,
double charge_full_design,
int32_t expected_cycle_count) {
const int32_t expected_charge_full_now_milliamp_hours =
charge_full_now * 1000;
const int32_t expected_charge_full_design_milliamp_hours =
charge_full_design * 1000;
const int8_t expected_battery_wear_percentage =
expected_charge_full_now_milliamp_hours /
expected_charge_full_design_milliamp_hours;
EXPECT_EQ(expected_charge_full_now_milliamp_hours,
update->charge_full_now_milliamp_hours);
EXPECT_EQ(expected_charge_full_design_milliamp_hours,
update->charge_full_design_milliamp_hours);
EXPECT_EQ(expected_cycle_count, update->cycle_count);
EXPECT_EQ(expected_battery_wear_percentage, update->battery_wear_percentage);
}
void VerifyMemoryUsageResult(const mojom::MemoryUsagePtr& update,
uint32_t expected_total_memory_kib,
uint32_t expected_free_memory_kib,
uint32_t expected_available_memory_kib) {
EXPECT_EQ(expected_total_memory_kib, update->total_memory_kib);
EXPECT_EQ(expected_free_memory_kib, update->free_memory_kib);
EXPECT_EQ(expected_available_memory_kib, update->available_memory_kib);
}
void VerifyCpuUsageResult(const mojom::CpuUsagePtr& update,
uint8_t expected_percent_user,
uint8_t expected_percent_system,
uint8_t expected_percent_free) {
EXPECT_EQ(expected_percent_user, update->percent_usage_user);
EXPECT_EQ(expected_percent_system, update->percent_usage_system);
EXPECT_EQ(expected_percent_free, update->percent_usage_free);
}
void VerifyCpuTempResult(const mojom::CpuUsagePtr& update,
uint32_t expected_average_temp) {
EXPECT_EQ(expected_average_temp, update->average_cpu_temp_celsius);
}
void VerifyCpuScalingResult(const mojom::CpuUsagePtr& update,
uint32_t expected_scaled_speed) {
EXPECT_EQ(expected_scaled_speed, update->scaling_current_frequency_khz);
}
} // namespace
struct FakeBatteryChargeStatusObserver
: public mojom::BatteryChargeStatusObserver {
// mojom::BatteryChargeStatusObserver
void OnBatteryChargeStatusUpdated(
mojom::BatteryChargeStatusPtr status_ptr) override {
updates.push_back(std::move(status_ptr));
}
// Tracks calls to OnBatteryChargeStatusUpdated. Each call adds an element to
// the vector.
std::vector<mojom::BatteryChargeStatusPtr> updates;
mojo::Receiver<mojom::BatteryChargeStatusObserver> receiver{this};
};
struct FakeBatteryHealthObserver : public mojom::BatteryHealthObserver {
// mojom::BatteryHealthObserver
void OnBatteryHealthUpdated(mojom::BatteryHealthPtr status_ptr) override {
updates.push_back(std::move(status_ptr));
}
// Tracks calls to OnBatteryHealthUpdated. Each call adds an element to
// the vector.
std::vector<mojom::BatteryHealthPtr> updates;
mojo::Receiver<mojom::BatteryHealthObserver> receiver{this};
};
struct FakeMemoryUsageObserver : public mojom::MemoryUsageObserver {
// mojom::MemoryUsageObserver
void OnMemoryUsageUpdated(mojom::MemoryUsagePtr status_ptr) override {
updates.push_back(std::move(status_ptr));
}
// Tracks calls to OnMemoryUsageUpdated. Each call adds an element to
// the vector.
std::vector<mojom::MemoryUsagePtr> updates;
mojo::Receiver<mojom::MemoryUsageObserver> receiver{this};
};
struct FakeCpuUsageObserver : public mojom::CpuUsageObserver {
// mojom::CpuUsageObserver
void OnCpuUsageUpdated(mojom::CpuUsagePtr status_ptr) override {
updates.push_back(std::move(status_ptr));
}
// Tracks calls to OnCpuUsageUpdated. Each call adds an element to
// the vector.
std::vector<mojom::CpuUsagePtr> updates;
mojo::Receiver<mojom::CpuUsageObserver> receiver{this};
};
class SystemDataProviderTest : public testing::Test {
public:
SystemDataProviderTest() {
chromeos::PowerManagerClient::InitializeFake();
chromeos::CrosHealthdClient::InitializeFake();
system_data_provider_ = std::make_unique<SystemDataProvider>();
}
~SystemDataProviderTest() override {
system_data_provider_.reset();
chromeos::CrosHealthdClient::Shutdown();
chromeos::PowerManagerClient::Shutdown();
base::RunLoop().RunUntilIdle();
}
protected:
std::unique_ptr<SystemDataProvider> system_data_provider_;
private:
base::test::TaskEnvironment task_environment_;
};
TEST_F(SystemDataProviderTest, GetSystemInfo) {
const std::string expected_board_name = "board_name";
const std::string expected_marketing_name = "marketing_name";
const std::string expected_cpu_model = "cpu_model";
const uint32_t expected_total_memory_kib = 1234;
const uint16_t expected_cpu_threads_count = 5678;
const uint32_t expected_cpu_max_clock_speed_khz = 91011;
const bool expected_has_battery = true;
const std::string expected_milestone_version = "M99";
SetCrosHealthdSystemInfoResponse(
expected_board_name, expected_marketing_name, expected_cpu_model,
expected_total_memory_kib, expected_cpu_threads_count,
expected_cpu_max_clock_speed_khz, expected_has_battery,
expected_milestone_version);
base::RunLoop run_loop;
system_data_provider_->GetSystemInfo(
base::BindLambdaForTesting([&](mojom::SystemInfoPtr ptr) {
ASSERT_TRUE(ptr);
EXPECT_EQ(expected_board_name, ptr->board_name);
EXPECT_EQ(expected_marketing_name, ptr->marketing_name);
EXPECT_EQ(expected_cpu_model, ptr->cpu_model_name);
EXPECT_EQ(expected_total_memory_kib, ptr->total_memory_kib);
EXPECT_EQ(expected_cpu_threads_count, ptr->cpu_threads_count);
EXPECT_EQ(expected_cpu_max_clock_speed_khz,
ptr->cpu_max_clock_speed_khz);
EXPECT_EQ(expected_milestone_version,
ptr->version_info->milestone_version);
EXPECT_EQ(expected_has_battery, ptr->device_capabilities->has_battery);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(SystemDataProviderTest, NoBattery) {
const std::string expected_board_name = "board_name";
const std::string expected_marketing_name = "marketing_name";
const std::string expected_cpu_model = "cpu_model";
const uint32_t expected_total_memory_kib = 1234;
const uint16_t expected_cpu_threads_count = 5678;
const uint32_t expected_cpu_max_clock_speed_khz = 91011;
const bool expected_has_battery = false;
const std::string expected_milestone_version = "M99";
SetCrosHealthdSystemInfoResponse(
expected_board_name, expected_marketing_name, expected_cpu_model,
expected_total_memory_kib, expected_cpu_threads_count,
expected_cpu_max_clock_speed_khz, expected_has_battery,
expected_milestone_version);
base::RunLoop run_loop;
system_data_provider_->GetSystemInfo(
base::BindLambdaForTesting([&](mojom::SystemInfoPtr ptr) {
ASSERT_TRUE(ptr);
EXPECT_EQ(expected_board_name, ptr->board_name);
EXPECT_EQ(expected_marketing_name, ptr->marketing_name);
EXPECT_EQ(expected_cpu_model, ptr->cpu_model_name);
EXPECT_EQ(expected_total_memory_kib, ptr->total_memory_kib);
EXPECT_EQ(expected_cpu_threads_count, ptr->cpu_threads_count);
EXPECT_EQ(expected_cpu_max_clock_speed_khz,
ptr->cpu_max_clock_speed_khz);
EXPECT_EQ(expected_milestone_version,
ptr->version_info->milestone_version);
EXPECT_EQ(expected_has_battery, ptr->device_capabilities->has_battery);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(SystemDataProviderTest, BatteryInfo) {
const std::string expected_manufacturer = "manufacturer";
const double charge_full_amp_hours = 25;
SetCrosHealthdBatteryInfoResponse(expected_manufacturer,
charge_full_amp_hours);
const uint32_t expected_charge_full_design_milliamp_hours =
charge_full_amp_hours * 1000;
base::RunLoop run_loop;
system_data_provider_->GetBatteryInfo(
base::BindLambdaForTesting([&](mojom::BatteryInfoPtr ptr) {
ASSERT_TRUE(ptr);
EXPECT_EQ(expected_manufacturer, ptr->manufacturer);
EXPECT_EQ(expected_charge_full_design_milliamp_hours,
ptr->charge_full_design_milliamp_hours);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(SystemDataProviderTest, BatteryChargeStatusObserver) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetBatteryChargeStatusTimerForTesting(
std::move(timer));
// Setup initial data
const double charge_now_amp_hours = 20;
const double current_now_amps = 2;
const auto power_source =
power_manager::PowerSupplyProperties_ExternalPower_AC;
const auto battery_state =
power_manager::PowerSupplyProperties_BatteryState_CHARGING;
const bool is_calculating_battery_time = false;
const int64_t time_to_full_secs = 1000;
const int64_t time_to_empty_secs = 0;
SetCrosHealthdBatteryChargeStatusResponse(charge_now_amp_hours,
current_now_amps);
SetPowerManagerProperties(power_source, battery_state,
is_calculating_battery_time, time_to_full_secs,
time_to_empty_secs);
// Registering as an observer should trigger one update.
FakeBatteryChargeStatusObserver charge_status_observer;
system_data_provider_->ObserveBatteryChargeStatus(
charge_status_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, charge_status_observer.updates.size());
VerifyChargeStatusResult(charge_status_observer.updates[0],
charge_now_amp_hours, current_now_amps, power_source,
battery_state, is_calculating_battery_time,
time_to_full_secs, time_to_empty_secs);
// Firing the timer should trigger another.
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, charge_status_observer.updates.size());
VerifyChargeStatusResult(charge_status_observer.updates[0],
charge_now_amp_hours, current_now_amps, power_source,
battery_state, is_calculating_battery_time,
time_to_full_secs, time_to_empty_secs);
// Updating the PowerManagerClient Properties should trigger yet another.
const int64_t new_time_to_full_secs = time_to_full_secs - 10;
SetPowerManagerProperties(
power_manager::PowerSupplyProperties_ExternalPower_AC,
power_manager::PowerSupplyProperties_BatteryState_CHARGING,
is_calculating_battery_time, new_time_to_full_secs, time_to_empty_secs);
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, charge_status_observer.updates.size());
VerifyChargeStatusResult(charge_status_observer.updates[0],
charge_now_amp_hours, current_now_amps, power_source,
battery_state, is_calculating_battery_time,
new_time_to_full_secs, time_to_empty_secs);
}
TEST_F(SystemDataProviderTest, BatteryHealthObserver) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetBatteryHealthTimerForTesting(std::move(timer));
// Setup initial data
const double charge_full_now = 20;
const double charge_full_design = 26;
const int32_t cycle_count = 500;
SetCrosHealthdBatteryHealthResponse(charge_full_now, charge_full_design,
cycle_count);
// Registering as an observer should trigger one update.
FakeBatteryHealthObserver health_observer;
system_data_provider_->ObserveBatteryHealth(
health_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, health_observer.updates.size());
VerifyHealthResult(health_observer.updates[0], charge_full_now,
charge_full_design, cycle_count);
// Firing the timer should trigger another.
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, health_observer.updates.size());
VerifyHealthResult(health_observer.updates[1], charge_full_now,
charge_full_design, cycle_count);
// Updating the information in Croshealthd does not trigger an update until
// the timer fires
const int32_t new_cycle_count = cycle_count + 1;
SetCrosHealthdBatteryHealthResponse(charge_full_now, charge_full_design,
new_cycle_count);
EXPECT_EQ(2u, health_observer.updates.size());
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, health_observer.updates.size());
VerifyHealthResult(health_observer.updates[2], charge_full_now,
charge_full_design, new_cycle_count);
}
TEST_F(SystemDataProviderTest, MemoryUsageObserver) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetMemoryUsageTimerForTesting(std::move(timer));
// Setup initial data
const uint32_t total_memory_kib = 10000;
const uint32_t free_memory_kib = 2000;
const uint32_t available_memory_kib = 4000;
SetCrosHealthdMemoryUsageResponse(total_memory_kib, free_memory_kib,
available_memory_kib);
// Registering as an observer should trigger one update.
FakeMemoryUsageObserver memory_usage_observer;
system_data_provider_->ObserveMemoryUsage(
memory_usage_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, memory_usage_observer.updates.size());
VerifyMemoryUsageResult(memory_usage_observer.updates[0], total_memory_kib,
free_memory_kib, available_memory_kib);
// Firing the timer should trigger another.
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, memory_usage_observer.updates.size());
VerifyMemoryUsageResult(memory_usage_observer.updates[1], total_memory_kib,
free_memory_kib, available_memory_kib);
// Updating the information in Croshealthd does not trigger an update until
// the timer fires
const uint32_t new_available_memory_kib = available_memory_kib + 1000;
SetCrosHealthdMemoryUsageResponse(total_memory_kib, free_memory_kib,
new_available_memory_kib);
EXPECT_EQ(2u, memory_usage_observer.updates.size());
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, memory_usage_observer.updates.size());
VerifyMemoryUsageResult(memory_usage_observer.updates[2], total_memory_kib,
free_memory_kib, new_available_memory_kib);
}
TEST_F(SystemDataProviderTest, CpuUsageObserverOneProcessor) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetCpuUsageTimerForTesting(std::move(timer));
// Setup initial data
CpuUsageData core_1(1000, 1000, 1000);
SetCrosHealthdCpuUsageResponse({core_1});
// Registering as an observer should trigger one update.
FakeCpuUsageObserver cpu_usage_observer;
system_data_provider_->ObserveCpuUsage(
cpu_usage_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
// There should be one update with no percentages since we could not calculate
// a delta yet.
EXPECT_EQ(1u, cpu_usage_observer.updates.size());
VerifyCpuUsageResult(cpu_usage_observer.updates[0],
/*expected_percent_user=*/0,
/*expected_percent_system=*/0,
/*expected_percent_free=*/0);
CpuUsageData delta(3000, 2500, 4500);
SetCrosHealthdCpuUsageResponse({core_1 + delta});
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, cpu_usage_observer.updates.size());
VerifyCpuUsageResult(cpu_usage_observer.updates[1],
delta.GetUserTime() * 100 / delta.GetTotalTime(),
delta.GetSystemTime() * 100 / delta.GetTotalTime(),
delta.GetIdleTime() * 100 / delta.GetTotalTime());
}
TEST_F(SystemDataProviderTest, CpuUsageObserverTwoProcessor) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetCpuUsageTimerForTesting(std::move(timer));
// Setup initial data
CpuUsageData core_1(1000, 1000, 1000);
CpuUsageData core_2(2000, 2000, 2000);
SetCrosHealthdCpuUsageResponse({core_1, core_2});
// Registering as an observer should trigger one update.
FakeCpuUsageObserver cpu_usage_observer;
system_data_provider_->ObserveCpuUsage(
cpu_usage_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
// There should be one update with no percentages since we could not calculate
// a delta yet.
EXPECT_EQ(1u, cpu_usage_observer.updates.size());
VerifyCpuUsageResult(cpu_usage_observer.updates[0],
/*expected_percent_user=*/0,
/*expected_percent_system=*/0,
/*expected_percent_free=*/0);
CpuUsageData core_1_delta(3000, 2500, 4500);
CpuUsageData core_2_delta(1000, 5500, 3500);
SetCrosHealthdCpuUsageResponse(
{core_1 + core_1_delta, core_2 + core_2_delta});
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
// The result should be the averages of the times from the two cores.
const int64_t expected_percent_user = 20;
const int64_t expected_percent_system = 40;
const int64_t expected_percent_free = 40;
EXPECT_EQ(2u, cpu_usage_observer.updates.size());
VerifyCpuUsageResult(cpu_usage_observer.updates[1], expected_percent_user,
expected_percent_system, expected_percent_free);
}
TEST_F(SystemDataProviderTest, CpuUsageObserverTemp) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetCpuUsageTimerForTesting(std::move(timer));
// Setup initial data
uint32_t temp_1 = 40;
uint32_t temp_2 = 50;
uint32_t temp_3 = 15;
SetCrosHealthdCpuTemperatureResponse({temp_1, temp_2, temp_3});
// Registering as an observer should trigger one update.
FakeCpuUsageObserver cpu_usage_observer;
system_data_provider_->ObserveCpuUsage(
cpu_usage_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, cpu_usage_observer.updates.size());
VerifyCpuTempResult(cpu_usage_observer.updates[0],
/*expected_average_temp=*/35);
temp_1 = 20;
temp_2 = 25;
temp_3 = 45;
SetCrosHealthdCpuTemperatureResponse({temp_1, temp_2, temp_3});
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, cpu_usage_observer.updates.size());
VerifyCpuTempResult(cpu_usage_observer.updates[1],
/*expected_average_temp=*/30);
temp_1 = 20;
temp_2 = 26;
temp_3 = 46;
SetCrosHealthdCpuTemperatureResponse({temp_1, temp_2, temp_3});
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, cpu_usage_observer.updates.size());
// Integer division so `expected_average_temp` should still be 30.
VerifyCpuTempResult(cpu_usage_observer.updates[2],
/*expected_average_temp=*/30);
}
TEST_F(SystemDataProviderTest, CpuUsageScaledClock) {
// Setup Timer
auto timer = std::make_unique<base::MockRepeatingTimer>();
auto* timer_ptr = timer.get();
system_data_provider_->SetCpuUsageTimerForTesting(std::move(timer));
// Setup initial data
uint32_t core_1_speed = 4000;
uint32_t core_2_speed = 5000;
SetCrosHealthdCpuScalingResponse({core_1_speed, core_2_speed});
// Registering as an observer should trigger one update.
FakeCpuUsageObserver cpu_usage_observer;
system_data_provider_->ObserveCpuUsage(
cpu_usage_observer.receiver.BindNewPipeAndPassRemote());
base::RunLoop().RunUntilIdle();
EXPECT_EQ(1u, cpu_usage_observer.updates.size());
VerifyCpuScalingResult(cpu_usage_observer.updates[0],
/*expected_scaled_speed=*/4500);
core_1_speed = 2000;
core_2_speed = 2000;
SetCrosHealthdCpuScalingResponse({core_1_speed, core_2_speed});
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(2u, cpu_usage_observer.updates.size());
VerifyCpuScalingResult(cpu_usage_observer.updates[1],
/*expected_scaled_speed=*/2000);
core_1_speed = 2000;
core_2_speed = 2001;
SetCrosHealthdCpuScalingResponse({core_1_speed, core_2_speed});
timer_ptr->Fire();
base::RunLoop().RunUntilIdle();
EXPECT_EQ(3u, cpu_usage_observer.updates.size());
// Integer division so `expected_scaled_speed` should still be 2000.
VerifyCpuScalingResult(cpu_usage_observer.updates[2],
/*expected_scaled_speed=*/2000);
}
} // namespace diagnostics
} // namespace chromeos