blob: e95484850c9a91ef51749e6fb8c793e98acb1b33 [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 <cstdint>
#include <map>
#include <memory>
#include <utility>
#include <base/memory/scoped_refptr.h>
#include <brillo/errors/error.h>
#include <chromeos/dbus/service_constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "debugd/dbus-proxy-mocks.h"
#include "diagnostics/cros_healthd/fetchers/battery_fetcher.h"
#include "diagnostics/cros_healthd/system/mock_context.h"
#include "power_manager/proto_bindings/power_supply_properties.pb.h"
namespace diagnostics {
using ::chromeos::cros_healthd::mojom::ErrorType;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::WithArg;
namespace {
// Arbitrary test values for the various battery metrics.
constexpr power_manager::PowerSupplyProperties_BatteryState kBatteryStateFull =
power_manager::PowerSupplyProperties_BatteryState_FULL;
constexpr char kBatteryVendor[] = "TEST_MFR";
constexpr double kBatteryVoltage = 127.45;
constexpr int kBatteryCycleCount = 2;
constexpr char kBatterySerialNumber[] = "1000";
constexpr double kBatteryVoltageMinDesign = 114.00;
constexpr double kBatteryChargeFull = 4.3;
constexpr double kBatteryChargeFullDesign = 3.92;
constexpr char kBatteryModelName[] = "TEST_MODEL_NAME";
constexpr double kBatteryChargeNow = 5.17;
constexpr char kSmartBatteryManufactureDateResponse[] =
"Read from I2C port 2 at 0xb offset 0x1b = 0x4d06";
constexpr char kSmartBatteryManufactureDate[] = "2018-08-06";
constexpr char kSmartBatteryTemperatureResponse[] =
"Read from I2C port 2 at 0xb offset 0x8 = 0xbae";
constexpr uint64_t kSmartBatteryTemperature = 2990;
constexpr char kInvalidRegexSmartMetricResponse[] =
"this does not match the regex";
constexpr double kBatteryCurrentNow = 6.45;
constexpr char kBatteryTechnology[] = "Battery technology.";
constexpr char kBatteryStatus[] = "Discharging";
// Timeouts for the Debugd D-Bus calls. Note that D-Bus is mocked out in the
// test, but the timeouts are still part of the mock calls.
constexpr int kDebugdTimeOut = 10 * 1000;
} // namespace
class BatteryFetcherTest : public ::testing::Test {
protected:
BatteryFetcherTest() = default;
void SetUp() override {
ASSERT_TRUE(mock_context_.Initialize());
SetHasSmartBatteryInfo(true);
}
BatteryFetcher* battery_fetcher() { return &battery_fetcher_; }
org::chromium::debugdProxyMock* mock_debugd_proxy() {
return mock_context_.mock_debugd_proxy();
}
FakePowerdAdapter* fake_powerd_adapter() {
return mock_context_.fake_powerd_adapter();
}
void SetHasBattery(const bool value) {
mock_context_.fake_system_config()->SetHasBattery(value);
}
void SetHasSmartBatteryInfo(const bool value) {
mock_context_.fake_system_config()->SetHasSmartBattery(value);
}
private:
MockContext mock_context_;
BatteryFetcher battery_fetcher_{&mock_context_};
};
// Test that we can fetch all battery metrics correctly.
TEST_F(BatteryFetcherTest, FetchBatteryInfo) {
// Create PowerSupplyProperties response protobuf.
power_manager::PowerSupplyProperties power_supply_proto;
power_supply_proto.set_battery_state(kBatteryStateFull);
power_supply_proto.set_battery_vendor(kBatteryVendor);
power_supply_proto.set_battery_voltage(kBatteryVoltage);
power_supply_proto.set_battery_cycle_count(kBatteryCycleCount);
power_supply_proto.set_battery_charge_full(kBatteryChargeFull);
power_supply_proto.set_battery_charge_full_design(kBatteryChargeFullDesign);
power_supply_proto.set_battery_serial_number(kBatterySerialNumber);
power_supply_proto.set_battery_voltage_min_design(kBatteryVoltageMinDesign);
power_supply_proto.set_battery_model_name(kBatteryModelName);
power_supply_proto.set_battery_charge(kBatteryChargeNow);
power_supply_proto.set_battery_current(kBatteryCurrentNow);
power_supply_proto.set_battery_technology(kBatteryTechnology);
power_supply_proto.set_battery_status(kBatteryStatus);
fake_powerd_adapter()->SetPowerSupplyProperties(power_supply_proto);
// Set the mock Debugd Adapter responses.
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("manufacture_date_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<1>(Invoke([](std::string* result) {
*result = kSmartBatteryManufactureDateResponse;
})),
Return(true)));
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("temperature_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<1>(Invoke([](std::string* result) {
*result = kSmartBatteryTemperatureResponse;
})),
Return(true)));
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->is_battery_info());
const auto& battery = battery_result->get_battery_info();
EXPECT_EQ(kBatteryCycleCount, battery->cycle_count);
EXPECT_EQ(kBatteryVendor, battery->vendor);
EXPECT_EQ(kBatteryVoltage, battery->voltage_now);
EXPECT_EQ(kBatteryChargeFull, battery->charge_full);
EXPECT_EQ(kBatteryChargeFullDesign, battery->charge_full_design);
EXPECT_EQ(kBatterySerialNumber, battery->serial_number);
EXPECT_EQ(kBatteryVoltageMinDesign, battery->voltage_min_design);
EXPECT_EQ(kBatteryModelName, battery->model_name);
EXPECT_EQ(kBatteryChargeNow, battery->charge_now);
EXPECT_EQ(kBatteryCurrentNow, battery->current_now);
EXPECT_EQ(kBatteryTechnology, battery->technology);
EXPECT_EQ(kBatteryStatus, battery->status);
// Test that optional smart battery metrics are populated.
ASSERT_TRUE(battery->manufacture_date.has_value());
ASSERT_TRUE(battery->temperature);
EXPECT_EQ(kSmartBatteryManufactureDate, battery->manufacture_date.value());
EXPECT_EQ(kSmartBatteryTemperature, battery->temperature->value);
}
// Test that an empty proto in a power_manager D-Bus response returns an error.
TEST_F(BatteryFetcherTest, EmptyProtoPowerManagerDbusResponse) {
power_manager::PowerSupplyProperties power_supply_proto;
fake_powerd_adapter()->SetPowerSupplyProperties(power_supply_proto);
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->is_error());
EXPECT_EQ(battery_result->get_error()->type, ErrorType::kSystemUtilityError);
}
// Test that debugd failing to collect battery manufacture date returns an
// error.
TEST_F(BatteryFetcherTest, ManufactureDateRetrievalFailure) {
power_manager::PowerSupplyProperties power_supply_proto;
power_supply_proto.set_battery_state(kBatteryStateFull);
fake_powerd_adapter()->SetPowerSupplyProperties(power_supply_proto);
// Set the mock Debugd Adapter responses.
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("manufacture_date_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<2>(Invoke([](brillo::ErrorPtr* error) {
*error = brillo::Error::Create(FROM_HERE, "", "", "");
})),
Return(false)));
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->is_error());
EXPECT_EQ(battery_result->get_error()->type, ErrorType::kSystemUtilityError);
}
// Test that debugd failing to collect battery temperature returns an error.
TEST_F(BatteryFetcherTest, TemperatureRetrievalFailure) {
power_manager::PowerSupplyProperties power_supply_proto;
power_supply_proto.set_battery_state(kBatteryStateFull);
fake_powerd_adapter()->SetPowerSupplyProperties(power_supply_proto);
// Set the mock Debugd Adapter responses.
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("manufacture_date_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<1>(Invoke([](std::string* result) {
*result = kSmartBatteryManufactureDateResponse;
})),
Return(true)));
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("temperature_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<2>(Invoke([](brillo::ErrorPtr* error) {
*error = brillo::Error::Create(FROM_HERE, "", "", "");
})),
Return(false)));
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->is_error());
EXPECT_EQ(battery_result->get_error()->type, ErrorType::kSystemUtilityError);
}
// Test that failing to match the regex to the debugd responses returns an
// error.
TEST_F(BatteryFetcherTest, SmartMetricRegexFailure) {
power_manager::PowerSupplyProperties power_supply_proto;
power_supply_proto.set_battery_state(kBatteryStateFull);
fake_powerd_adapter()->SetPowerSupplyProperties(power_supply_proto);
// Set the mock Debugd Adapter responses.
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("manufacture_date_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<1>(Invoke([](std::string* result) {
*result = kInvalidRegexSmartMetricResponse;
})),
Return(true)));
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->is_error());
EXPECT_EQ(battery_result->get_error()->type, ErrorType::kParseError);
}
// Test that Smart Battery metrics are not fetched when a device does not have a
// Smart Battery.
TEST_F(BatteryFetcherTest, NoSmartBattery) {
SetHasSmartBatteryInfo(false);
// Set the mock power manager response.
power_manager::PowerSupplyProperties power_supply_proto;
power_supply_proto.set_battery_state(kBatteryStateFull);
fake_powerd_adapter()->SetPowerSupplyProperties(power_supply_proto);
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->is_battery_info());
const auto& battery = battery_result->get_battery_info();
EXPECT_FALSE(battery->manufacture_date.has_value());
EXPECT_FALSE(battery->temperature);
}
// Test that no battery info is returned when a device does not have a battery.
TEST_F(BatteryFetcherTest, NoBattery) {
SetHasBattery(false);
auto battery_result = battery_fetcher()->FetchBatteryInfo();
ASSERT_TRUE(battery_result->get_battery_info().is_null());
}
} // namespace diagnostics