blob: 62fa9e72ee7cb26b66705ae6643c0b93e6cda2a8 [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 <map>
#include <memory>
#include <utility>
#include <base/memory/scoped_refptr.h>
#include <base/time/time.h>
#include <brillo/errors/error.h>
#include <chromeos/dbus/service_constants.h>
#include <dbus/message.h>
#include <dbus/mock_bus.h>
#include <dbus/mock_object_proxy.h>
#include <dbus/object_path.h>
#include <dbus/power_manager/dbus-constants.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "debugd/dbus-proxy-mocks.h"
#include "diagnostics/cros_healthd/utils/battery_utils.h"
#include "power_manager/proto_bindings/power_supply_properties.pb.h"
namespace diagnostics {
using ::dbus::MockBus;
using ::dbus::MockObjectProxy;
using ::testing::_;
using ::testing::DoAll;
using ::testing::Invoke;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::WithArg;
namespace {
// Arbitrary test values for the various battery metrics.
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 kBatteryManufactureDateSmartChars[] = "87615";
constexpr int kBatteryManufactureDateSmart = 87615;
constexpr char kBatteryTemperatureSmartChars[] = "981329";
constexpr int kBatteryTemperatureSmart = 981329;
// Timeouts for the 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;
constexpr base::TimeDelta kPowerManagerDBusTimeout =
base::TimeDelta::FromSeconds(3);
} // namespace
class BatteryUtilsTest : public ::testing::Test {
protected:
BatteryUtilsTest() {
options_.bus_type = dbus::Bus::SYSTEM;
mock_bus_ = new dbus::MockBus(options_);
mock_power_manager_proxy_ = new dbus::MockObjectProxy(
mock_bus_.get(), power_manager::kPowerManagerServiceName,
dbus::ObjectPath(power_manager::kPowerManagerServicePath));
battery_fetcher_ = std::make_unique<BatteryFetcher>(
&mock_debugd_proxy_, mock_power_manager_proxy_.get());
}
BatteryFetcher* battery_fetcher() { return battery_fetcher_.get(); }
org::chromium::debugdProxyMock* mock_debugd_proxy() {
return &mock_debugd_proxy_;
}
dbus::MockObjectProxy* mock_power_manager_proxy() {
return mock_power_manager_proxy_.get();
}
private:
dbus::Bus::Options options_;
scoped_refptr<dbus::MockBus> mock_bus_;
StrictMock<org::chromium::debugdProxyMock> mock_debugd_proxy_;
scoped_refptr<dbus::MockObjectProxy> mock_power_manager_proxy_;
std::unique_ptr<BatteryFetcher> battery_fetcher_;
};
// Test that we can fetch all battery metrics correctly.
TEST_F(BatteryUtilsTest, FetchBatteryInfo) {
// Create PowerSupplyProperties response protobuf.
power_manager::PowerSupplyProperties power_supply_proto;
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);
// Set the mock power manager response.
EXPECT_CALL(*mock_power_manager_proxy(),
MIGRATE_MockCallMethodAndBlock(
_, kPowerManagerDBusTimeout.InMilliseconds()))
.WillOnce([&power_supply_proto](dbus::MethodCall*, int) {
std::unique_ptr<dbus::Response> power_manager_response =
dbus::Response::CreateEmpty();
dbus::MessageWriter power_manager_writer(power_manager_response.get());
power_manager_writer.AppendProtoAsArrayOfBytes(power_supply_proto);
return power_manager_response;
});
// 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 = kBatteryManufactureDateSmartChars;
})),
Return(true)));
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("temperature_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<1>(Invoke([](std::string* result) {
*result = kBatteryTemperatureSmartChars;
})),
Return(true)));
auto info = battery_fetcher()->FetchBatteryInfo();
ASSERT_EQ(info.size(), 1);
const auto& battery = info[0];
ASSERT_TRUE(battery);
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(kBatteryManufactureDateSmart, battery->manufacture_date_smart);
EXPECT_EQ(kBatteryTemperatureSmart, battery->temperature_smart);
}
// Test that we handle a malformed power_manager D-Bus response.
TEST_F(BatteryUtilsTest, MalformedPowerManagerDbusResponse) {
EXPECT_CALL(*mock_power_manager_proxy(),
MIGRATE_MockCallMethodAndBlock(
_, kPowerManagerDBusTimeout.InMilliseconds()))
.WillOnce(
[](dbus::MethodCall*, int) { return dbus::Response::CreateEmpty(); });
auto info = battery_fetcher()->FetchBatteryInfo();
ASSERT_EQ(info.size(), 0);
}
// Test that we handle an empty proto in a power_manager D-Bus response.
TEST_F(BatteryUtilsTest, EmptyProtoPowerManagerDbusResponse) {
power_manager::PowerSupplyProperties power_supply_proto;
// Set the mock power manager response.
EXPECT_CALL(*mock_power_manager_proxy(),
MIGRATE_MockCallMethodAndBlock(
_, kPowerManagerDBusTimeout.InMilliseconds()))
.WillOnce([&power_supply_proto](dbus::MethodCall*, int) {
std::unique_ptr<dbus::Response> power_manager_response =
dbus::Response::CreateEmpty();
dbus::MessageWriter power_manager_writer(power_manager_response.get());
power_manager_writer.AppendProtoAsArrayOfBytes(power_supply_proto);
return power_manager_response;
});
// 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 = kBatteryManufactureDateSmartChars;
})),
Return(true)));
EXPECT_CALL(
*mock_debugd_proxy(),
CollectSmartBatteryMetric("temperature_smart", _, _, kDebugdTimeOut))
.WillOnce(DoAll(WithArg<1>(Invoke([](std::string* result) {
*result = kBatteryTemperatureSmartChars;
})),
Return(true)));
auto info = battery_fetcher()->FetchBatteryInfo();
ASSERT_EQ(info.size(), 1);
const auto& battery = info[0];
ASSERT_TRUE(battery);
EXPECT_EQ(0, battery->cycle_count);
EXPECT_EQ("", battery->vendor);
EXPECT_EQ(0.0, battery->voltage_now);
EXPECT_EQ(0.0, battery->charge_full);
EXPECT_EQ(0.0, battery->charge_full_design);
EXPECT_EQ("", battery->serial_number);
EXPECT_EQ(0.0, battery->voltage_min_design);
EXPECT_EQ("", battery->model_name);
EXPECT_EQ(0, battery->charge_now);
EXPECT_EQ(kBatteryManufactureDateSmart, battery->manufacture_date_smart);
EXPECT_EQ(kBatteryTemperatureSmart, battery->temperature_smart);
}
// Test that we handle debugd failing to collect smart metrics.
TEST_F(BatteryUtilsTest, SmartMetricRetrievalFailure) {
power_manager::PowerSupplyProperties power_supply_proto;
// Set the mock power manager response.
EXPECT_CALL(*mock_power_manager_proxy(),
MIGRATE_MockCallMethodAndBlock(
_, kPowerManagerDBusTimeout.InMilliseconds()))
.WillOnce([&power_supply_proto](dbus::MethodCall*, int) {
std::unique_ptr<dbus::Response> power_manager_response =
dbus::Response::CreateEmpty();
dbus::MessageWriter power_manager_writer(power_manager_response.get());
power_manager_writer.AppendProtoAsArrayOfBytes(power_supply_proto);
return power_manager_response;
});
// 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)));
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 info = battery_fetcher()->FetchBatteryInfo();
ASSERT_EQ(info.size(), 1);
const auto& battery = info[0];
ASSERT_TRUE(battery);
EXPECT_EQ(0, battery->manufacture_date_smart);
EXPECT_EQ(0, battery->temperature_smart);
}
} // namespace diagnostics