blob: 0356d5371a92523994b8fac374b0b2ebc6905341 [file] [log] [blame]
// Copyright 2019 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 "power_manager/powerd/policy/charge_controller.h"
#include <cmath>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include <base/strings/string_split.h>
#include <base/strings/string_number_conversions.h>
#include <base/strings/stringprintf.h>
#include <gtest/gtest.h>
#include "power_manager/common/battery_percentage_converter.h"
#include "power_manager/common/power_constants.h"
#include "power_manager/powerd/system/charge_controller_helper_stub.h"
#include "power_manager/proto_bindings/policy.pb.h"
namespace power_manager {
namespace policy {
namespace {
// Holds hours and minutes.
using TestDayConfig = std::vector<std::pair<int, int>>;
constexpr double kLowBatteryShutdownPercent = 4.0;
constexpr double kFullFactor = 0.97;
// |configs| must contain three hour/minute pairs: the start time, the end time
// and the charge start time.
void MakePeakShiftDayConfig(
PowerManagementPolicy::WeekDay week_day,
const TestDayConfig& configs,
PowerManagementPolicy::PeakShiftDayConfig* config_proto) {
DCHECK(config_proto);
ASSERT_EQ(configs.size(), 3);
config_proto->set_day(week_day);
config_proto->mutable_start_time()->set_hour(configs[0].first);
config_proto->mutable_start_time()->set_minute(configs[0].second);
config_proto->mutable_end_time()->set_hour(configs[1].first);
config_proto->mutable_end_time()->set_minute(configs[1].second);
config_proto->mutable_charge_start_time()->set_hour(configs[2].first);
config_proto->mutable_charge_start_time()->set_minute(configs[2].second);
}
// |configs| must contain two hour/minute pairs: the charge start time and the
// charge end time.
void MakeAdvancedBatteryChargeModeDayConfig(
PowerManagementPolicy::WeekDay week_day,
const TestDayConfig& configs,
PowerManagementPolicy::AdvancedBatteryChargeModeDayConfig* config_proto) {
DCHECK(config_proto);
ASSERT_EQ(configs.size(), 2);
config_proto->set_day(week_day);
config_proto->mutable_charge_start_time()->set_hour(configs[0].first);
config_proto->mutable_charge_start_time()->set_minute(configs[0].second);
config_proto->mutable_charge_end_time()->set_hour(configs[1].first);
config_proto->mutable_charge_end_time()->set_minute(configs[1].second);
}
class ChargeControllerTest : public ::testing::Test {
public:
ChargeControllerTest() {
controller_.Init(&helper_, &battery_percentage_converter_);
}
const BatteryPercentageConverter& battery_percentage_converter() const {
return battery_percentage_converter_;
}
protected:
// Sets PeakShift policy in PowerManagementPolicy proto.
void SetPeakShift(int threshold,
const std::map<PowerManagementPolicy::WeekDay,
TestDayConfig>& day_configs) {
policy_.set_peak_shift_battery_percent_threshold(threshold);
policy_.mutable_peak_shift_day_configs()->Clear();
for (const auto& item : day_configs) {
MakePeakShiftDayConfig(item.first, item.second,
policy_.add_peak_shift_day_configs());
}
}
// Checks that PeakShift policy was applied as expected.
bool CheckPeakShift(bool enable,
int threshold,
const std::map<PowerManagementPolicy::WeekDay,
std::string>& day_configs) {
for (const auto& item : day_configs) {
EXPECT_EQ(helper_.peak_shift_day_config(item.first), item.second);
if (helper_.peak_shift_day_config(item.first) != item.second) {
return false;
}
}
EXPECT_EQ(helper_.peak_shift_enabled(), enable);
EXPECT_EQ(helper_.peak_shift_threshold(), threshold);
return helper_.peak_shift_enabled() == enable &&
helper_.peak_shift_threshold() == threshold;
}
// Sets AdvancedBatteryChargeMode policy in PowerManagementPolicy proto.
void SetAdvancedBatteryChargeMode(
const std::map<PowerManagementPolicy::WeekDay, TestDayConfig>&
day_configs) {
policy_.mutable_advanced_battery_charge_mode_day_configs()->Clear();
for (const auto& item : day_configs) {
MakeAdvancedBatteryChargeModeDayConfig(
item.first, item.second,
policy_.add_advanced_battery_charge_mode_day_configs());
}
}
// Checks that AdvancedBatteryChargeMode policy was applied as expected.
bool CheckAdvancedBatteryChargeMode(
bool enable,
const std::map<PowerManagementPolicy::WeekDay, std::string>&
day_configs) {
for (const auto& item : day_configs) {
EXPECT_EQ(helper_.advanced_battery_charge_mode_day_config(item.first),
item.second);
if (helper_.advanced_battery_charge_mode_day_config(item.first) !=
item.second) {
return false;
}
}
EXPECT_EQ(helper_.advanced_battery_charge_mode_enabled(), enable);
return helper_.advanced_battery_charge_mode_enabled() == enable;
}
// Sets BatteryChargeMode policy in PowerManagementPolicy proto.
void SetBatteryChargeMode(PowerManagementPolicy::BatteryChargeMode::Mode mode,
int custom_charge_start,
int custom_charge_stop) {
policy_.mutable_battery_charge_mode()->set_mode(mode);
policy_.mutable_battery_charge_mode()->set_custom_charge_start(
custom_charge_start);
policy_.mutable_battery_charge_mode()->set_custom_charge_stop(
custom_charge_stop);
}
// Checks that BatteryChargeMode policy was applied as expected.
bool CheckBatteryChargeMode(
PowerManagementPolicy::BatteryChargeMode::Mode mode,
int custom_charge_start =
system::ChargeControllerHelperStub::kCustomChargeThresholdUnset,
int custom_charge_stop =
system::ChargeControllerHelperStub::kCustomChargeThresholdUnset) {
EXPECT_EQ(helper_.battery_charge_mode(), mode);
EXPECT_EQ(helper_.custom_charge_start(), custom_charge_start);
EXPECT_EQ(helper_.custom_charge_stop(), custom_charge_stop);
return helper_.battery_charge_mode() == mode &&
helper_.custom_charge_start() == custom_charge_start &&
helper_.custom_charge_stop() == custom_charge_stop;
}
system::ChargeControllerHelperStub helper_;
ChargeController controller_;
PowerManagementPolicy policy_;
private:
BatteryPercentageConverter battery_percentage_converter_{
kLowBatteryShutdownPercent, kFullFactor};
};
} // namespace
TEST_F(ChargeControllerTest, PeakShiftNoPolicies) {
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.peak_shift_enabled());
}
TEST_F(ChargeControllerTest, PeakShiftThresholdOnly) {
constexpr int kThreshold = 50;
policy_.set_peak_shift_battery_percent_threshold(kThreshold);
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.peak_shift_enabled());
}
TEST_F(ChargeControllerTest, PeakShiftDayConfigsOnly) {
constexpr PowerManagementPolicy::WeekDay kDay = PowerManagementPolicy::MONDAY;
const TestDayConfig kDayConfig{{0, 30}, {9, 45}, {20, 0}};
MakePeakShiftDayConfig(kDay, kDayConfig,
policy_.add_peak_shift_day_configs());
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.peak_shift_enabled());
}
TEST_F(ChargeControllerTest, PeakShift) {
constexpr int kThreshold1 = 50;
constexpr int kThreshold2 = 45;
const int actual_threshold1 = std::round(
battery_percentage_converter().ConvertDisplayToActual(kThreshold1));
const int actual_threshold2 = std::round(
battery_percentage_converter().ConvertDisplayToActual(kThreshold2));
constexpr PowerManagementPolicy::WeekDay kDay1 =
PowerManagementPolicy::MONDAY;
constexpr PowerManagementPolicy::WeekDay kDay2 =
PowerManagementPolicy::FRIDAY;
const TestDayConfig kDayConfig1{{0, 30}, {9, 45}, {20, 0}};
constexpr char kExpectedDayConfig1[] = "00:30 09:45 20:00";
const TestDayConfig kDayConfig2{{9, 15}, {10, 0}, {23, 15}};
constexpr char kExpectedDayConfig2[] = "09:15 10:00 23:15";
SetPeakShift(kThreshold1, {{kDay1, kDayConfig1}, {kDay2, kDayConfig2}});
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckPeakShift(
true, actual_threshold1,
{{kDay1, kExpectedDayConfig1}, {kDay2, kExpectedDayConfig2}}));
SetPeakShift(kThreshold2, {{kDay1, kDayConfig2}, {kDay2, kDayConfig1}});
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckPeakShift(
true, actual_threshold2,
{{kDay1, kExpectedDayConfig2}, {kDay2, kExpectedDayConfig1}}));
helper_.Reset();
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckPeakShift(
false, system::ChargeControllerHelperStub::kPeakShiftThresholdUnset,
{{kDay1, ""}, {kDay2, ""}}));
}
TEST_F(ChargeControllerTest, BootOnAc) {
policy_.set_boot_on_ac(false);
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.boot_on_ac_enabled());
policy_.set_boot_on_ac(true);
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(helper_.boot_on_ac_enabled());
helper_.Reset();
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.boot_on_ac_enabled());
}
TEST_F(ChargeControllerTest, UsbPowerShare) {
policy_.set_usb_power_share(false);
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.usb_power_share_enabled());
policy_.set_usb_power_share(true);
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(helper_.usb_power_share_enabled());
helper_.Reset();
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.usb_power_share_enabled());
}
TEST_F(ChargeControllerTest, AdvancedBatteryChargeModeEnabledNoPolicies) {
controller_.HandlePolicyChange(policy_);
EXPECT_FALSE(helper_.advanced_battery_charge_mode_enabled());
}
TEST_F(ChargeControllerTest, AdvancedBatteryChargeMode) {
constexpr PowerManagementPolicy::WeekDay kDay1 =
PowerManagementPolicy::TUESDAY;
constexpr PowerManagementPolicy::WeekDay kDay2 =
PowerManagementPolicy::SUNDAY;
const TestDayConfig kDayConfigStartEnd1{{2, 45}, {8, 30}};
constexpr char kExpectedDayConfigStartDuration1[] = "02:45 05:45";
const TestDayConfig kDayConfigStartEnd2{{3, 30}, {16, 0}};
constexpr char kExpectedDayConfigStartDuration2[] = "03:30 12:30";
SetAdvancedBatteryChargeMode(
{{kDay1, kDayConfigStartEnd1}, {kDay2, kDayConfigStartEnd2}});
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckAdvancedBatteryChargeMode(
true, {{kDay1, kExpectedDayConfigStartDuration1},
{kDay2, kExpectedDayConfigStartDuration2}}));
SetAdvancedBatteryChargeMode(
{{kDay1, kDayConfigStartEnd2}, {kDay2, kDayConfigStartEnd1}});
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckAdvancedBatteryChargeMode(
true, {{kDay1, kExpectedDayConfigStartDuration2},
{kDay2, kExpectedDayConfigStartDuration1}}));
helper_.Reset();
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(
CheckAdvancedBatteryChargeMode(false, {{kDay1, ""}, {kDay2, ""}}));
}
TEST_F(ChargeControllerTest, BatteryChargeModeNoPolicies) {
EXPECT_TRUE(CheckBatteryChargeMode(
system::ChargeControllerHelperStub::kBatteryChargeModeUnset));
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckBatteryChargeMode(
PowerManagementPolicy::BatteryChargeMode::STANDARD));
}
TEST_F(ChargeControllerTest, BatteryChargeMode) {
constexpr PowerManagementPolicy::BatteryChargeMode::Mode kMode1 =
PowerManagementPolicy::BatteryChargeMode::PRIMARILY_AC_USE;
constexpr PowerManagementPolicy::BatteryChargeMode::Mode kMode2 =
PowerManagementPolicy::BatteryChargeMode::CUSTOM;
constexpr int kCustomStartCharge = 60;
constexpr int kCustomEndCharge = 90;
const int actual_custom_start_charge =
std::round(battery_percentage_converter().ConvertDisplayToActual(
kCustomStartCharge));
const int actual_custom_end_charge = std::round(
battery_percentage_converter().ConvertDisplayToActual(kCustomEndCharge));
policy_.mutable_battery_charge_mode()->set_mode(kMode1);
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckBatteryChargeMode(kMode1));
SetBatteryChargeMode(kMode2, kCustomStartCharge, kCustomEndCharge);
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckBatteryChargeMode(kMode2, actual_custom_start_charge,
actual_custom_end_charge));
helper_.Reset();
controller_.HandlePolicyChange(policy_);
EXPECT_TRUE(CheckBatteryChargeMode(
system::ChargeControllerHelperStub::kBatteryChargeModeUnset));
}
// If AdvancedBatteryChargeMode is specified, it overrides BatteryChargeMode.
TEST_F(ChargeControllerTest,
AdvancedBatteryChargeModeOverridesBatteryChargeMode) {
constexpr PowerManagementPolicy::BatteryChargeMode::Mode kMode =
PowerManagementPolicy::BatteryChargeMode::EXPRESS_CHARGE;
constexpr PowerManagementPolicy::WeekDay kDay1 =
PowerManagementPolicy::FRIDAY;
constexpr PowerManagementPolicy::WeekDay kDay2 =
PowerManagementPolicy::SUNDAY;
const TestDayConfig kDayConfigStartEnd1{{8, 15}, {10, 45}};
constexpr char kExpectedDayConfigStartDuration1[] = "08:15 02:30";
const TestDayConfig kDayConfigStartEnd2{{4, 0}, {6, 15}};
constexpr char kExpectedDayConfigStartDuration2[] = "04:00 02:15";
policy_.mutable_battery_charge_mode()->set_mode(kMode);
SetAdvancedBatteryChargeMode(
{{kDay1, kDayConfigStartEnd1}, {kDay2, kDayConfigStartEnd2}});
controller_.HandlePolicyChange(policy_);
EXPECT_EQ(helper_.battery_charge_mode(),
system::ChargeControllerHelperStub::kBatteryChargeModeUnset);
EXPECT_TRUE(CheckAdvancedBatteryChargeMode(
true, {{kDay1, kExpectedDayConfigStartDuration1},
{kDay2, kExpectedDayConfigStartDuration2}}));
}
} // namespace policy
} // namespace power_manager