chromium/chromeos/dbus/power/fake_power_manager_client_unittest.cc

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/dbus/power/fake_power_manager_client.h"

#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "chromeos/dbus/power_manager/backlight.pb.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace chromeos {
namespace {

const double kInitialBatteryPercent = 85;
const double kUpdatedBatteryPercent = 70;
const power_manager::PowerSupplyProperties_BatteryState kInitialBatteryState =
    power_manager::PowerSupplyProperties_BatteryState_DISCHARGING;
const power_manager::PowerSupplyProperties_ExternalPower kInitialExternalPower =
    power_manager::PowerSupplyProperties_ExternalPower_USB;

class TestObserver : public PowerManagerClient::Observer {
 public:
  TestObserver() : num_power_changed_(0) {}

  TestObserver(const TestObserver&) = delete;
  TestObserver& operator=(const TestObserver&) = delete;

  ~TestObserver() override = default;

  const power_manager::PowerSupplyProperties& props() const { return props_; }
  int num_power_changed() const { return num_power_changed_; }
  const power_manager::BatterySaverModeState& battery_saver_state() const {
    return battery_saver_state_;
  }
  const power_manager::AmbientLightSensorChange&
  last_ambient_light_sensor_change() const {
    return last_ambient_light_sensor_change_;
  }
  const power_manager::AmbientLightSensorChange&
  last_keyboard_ambient_light_sensor_change() const {
    return last_keyboard_ambient_light_sensor_change_;
  }

  void ClearProps() { props_.Clear(); }

  void PowerChanged(
      const power_manager::PowerSupplyProperties& proto) override {
    props_ = proto;
    ++num_power_changed_;
  }

  void BatterySaverModeStateChanged(
      const power_manager::BatterySaverModeState& proto) override {
    battery_saver_state_ = proto;
  }

  void AmbientLightSensorEnabledChanged(
      const power_manager::AmbientLightSensorChange& change) override {
    last_ambient_light_sensor_change_ = change;
  }

  void KeyboardAmbientLightSensorEnabledChanged(
      const power_manager::AmbientLightSensorChange& change) override {
    last_keyboard_ambient_light_sensor_change_ = change;
  }

 private:
  int num_power_changed_;
  power_manager::PowerSupplyProperties props_;
  power_manager::BatterySaverModeState battery_saver_state_;
  power_manager::AmbientLightSensorChange last_ambient_light_sensor_change_;
  power_manager::AmbientLightSensorChange
      last_keyboard_ambient_light_sensor_change_;
};

void SetTestProperties(power_manager::PowerSupplyProperties* props) {
  props->set_battery_percent(kInitialBatteryPercent);
  props->set_is_calculating_battery_time(true);
  props->set_battery_state(kInitialBatteryState);
  props->set_external_power(kInitialExternalPower);
}

}  // namespace

TEST(FakePowerManagerClientTest, UpdatePowerPropertiesTest) {
  // Checking to verify when UpdatePowerProperties is called,
  // |props_| values are updated.
  FakePowerManagerClient client;
  power_manager::PowerSupplyProperties props;

  SetTestProperties(&props);
  client.UpdatePowerProperties(props);

  EXPECT_EQ(kInitialBatteryPercent, client.GetLastStatus()->battery_percent());
  EXPECT_TRUE(client.GetLastStatus()->is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, client.GetLastStatus()->battery_state());
  EXPECT_EQ(kInitialExternalPower, client.GetLastStatus()->external_power());

  // Test if when the values are changed, the correct data is set in the
  // FakePowerManagerClient.
  props = *client.GetLastStatus();
  props.set_battery_percent(kUpdatedBatteryPercent);
  client.UpdatePowerProperties(props);

  EXPECT_EQ(kUpdatedBatteryPercent, client.GetLastStatus()->battery_percent());
  EXPECT_TRUE(client.GetLastStatus()->is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, client.GetLastStatus()->battery_state());
  EXPECT_EQ(kInitialExternalPower, client.GetLastStatus()->external_power());
}

TEST(FakePowerManagerClientTest, NotifyObserversTest) {
  FakePowerManagerClient client;
  TestObserver test_observer;

  // Test adding observer.
  client.AddObserver(&test_observer);
  EXPECT_TRUE(client.HasObserver(&test_observer));

  // Test if NotifyObservers() sends the correct values to |observer|.
  // Check number of times NotifyObservers() is called.
  power_manager::PowerSupplyProperties props;
  SetTestProperties(&props);
  client.UpdatePowerProperties(props);

  EXPECT_EQ(kInitialBatteryPercent, test_observer.props().battery_percent());
  EXPECT_TRUE(test_observer.props().is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, test_observer.props().battery_state());
  EXPECT_EQ(kInitialExternalPower, test_observer.props().external_power());
  EXPECT_EQ(1, test_observer.num_power_changed());

  // Test if RequestStatusUpdate() will propagate the data to the observer.
  // Check number of times NotifyObservers is called.
  // RequestStatusUpdate posts to the current message loop. This is
  // necessary because we want to make sure that NotifyObservers() is
  // called as a result of RequestStatusUpdate().
  base::test::SingleThreadTaskEnvironment task_environment(
      base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
  test_observer.ClearProps();
  client.RequestStatusUpdate();
  base::RunLoop().RunUntilIdle();

  EXPECT_EQ(kInitialBatteryPercent, test_observer.props().battery_percent());
  EXPECT_TRUE(test_observer.props().is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, test_observer.props().battery_state());
  EXPECT_EQ(kInitialExternalPower, test_observer.props().external_power());
  EXPECT_EQ(2, test_observer.num_power_changed());

  // Check when values are changed, the correct values are propagated to the
  // observer
  props = *client.GetLastStatus();
  props.set_battery_percent(kUpdatedBatteryPercent);
  props.set_external_power(
      power_manager::PowerSupplyProperties_ExternalPower_AC);
  client.UpdatePowerProperties(props);

  EXPECT_EQ(kUpdatedBatteryPercent, test_observer.props().battery_percent());
  EXPECT_TRUE(test_observer.props().is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, test_observer.props().battery_state());
  EXPECT_EQ(power_manager::PowerSupplyProperties_ExternalPower_AC,
            test_observer.props().external_power());
  EXPECT_EQ(3, test_observer.num_power_changed());

  // Test removing observer.
  client.RemoveObserver(&test_observer);
  EXPECT_FALSE(client.HasObserver(&test_observer));
}

TEST(FakePowerManagerClientTest, UpdatePowerPropertiesWithNullTest) {
  // Checking to verify when UpdatePowerProperties is called,
  // |props_| values are updated.
  FakePowerManagerClient client;
  power_manager::PowerSupplyProperties props;

  SetTestProperties(&props);
  client.UpdatePowerProperties(props);

  ASSERT_TRUE(client.GetLastStatus().has_value());
  EXPECT_EQ(kInitialBatteryPercent, client.GetLastStatus()->battery_percent());
  EXPECT_TRUE(client.GetLastStatus()->is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, client.GetLastStatus()->battery_state());
  EXPECT_EQ(kInitialExternalPower, client.GetLastStatus()->external_power());

  client.UpdatePowerProperties(std::nullopt);

  EXPECT_FALSE(client.GetLastStatus().has_value());
}

TEST(FakePowerManagerClientTest,
     UpdatePowerPropertiesWithNullWillNotNotifyObserversTest) {
  FakePowerManagerClient client;
  TestObserver test_observer;

  // Test adding observer.
  client.AddObserver(&test_observer);
  EXPECT_TRUE(client.HasObserver(&test_observer));

  // Test if NotifyObservers() sends the correct values to |observer|.
  // Check number of times NotifyObservers() is called.
  power_manager::PowerSupplyProperties props;
  SetTestProperties(&props);
  client.UpdatePowerProperties(props);

  EXPECT_EQ(1, test_observer.num_power_changed());
  EXPECT_EQ(kInitialBatteryPercent, test_observer.props().battery_percent());
  EXPECT_TRUE(test_observer.props().is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, test_observer.props().battery_state());
  EXPECT_EQ(kInitialExternalPower, test_observer.props().external_power());

  // Check when update power properties with null,
  // the observer isn't notified and the props from observer doesn't change.
  client.UpdatePowerProperties(std::nullopt);

  EXPECT_EQ(1, test_observer.num_power_changed());
  EXPECT_EQ(kInitialBatteryPercent, test_observer.props().battery_percent());
  EXPECT_TRUE(test_observer.props().is_calculating_battery_time());
  EXPECT_EQ(kInitialBatteryState, test_observer.props().battery_state());
  EXPECT_EQ(kInitialExternalPower, test_observer.props().external_power());
}

// Test that observers are notified asynchronously of battery saver state
// updates.
TEST(FakePowerManagerClientTest, BatterySaverState) {
  base::test::SingleThreadTaskEnvironment task_environment(
      base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
  FakePowerManagerClient client;
  TestObserver test_observer;

  client.AddObserver(&test_observer);
  EXPECT_FALSE(test_observer.battery_saver_state().has_enabled());

  // Turn battery saver on, and check that observers are notified
  // asynchronously.
  {
    power_manager::SetBatterySaverModeStateRequest request;
    request.set_enabled(true);
    client.SetBatterySaverModeState(request);

    // Battery saver should not be enabled synchronously, since the real client
    // waits for a response from Power Manager.
    EXPECT_FALSE(test_observer.battery_saver_state().has_enabled());
    base::RunLoop().RunUntilIdle();

    // Should be on now.
    EXPECT_TRUE(test_observer.battery_saver_state().has_enabled());
    EXPECT_TRUE(test_observer.battery_saver_state().enabled());
  }

  // Verify GetBatterySaverModeState is on and asynchronous.
  {
    bool called = false;
    client.GetBatterySaverModeState(base::BindOnce(
        [](std::reference_wrapper<bool> called_ref,
           std::optional<power_manager::BatterySaverModeState> state) {
          EXPECT_TRUE(state.has_value());
          EXPECT_TRUE(state->has_enabled());
          EXPECT_TRUE(state->enabled());
          called_ref.get() = true;
        },
        std::ref(called)));

    // Result should be asynchronous.
    EXPECT_FALSE(called);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(called);
  }

  // Turn battery saver off, and check that observers are notified
  // asynchronously.
  {
    power_manager::SetBatterySaverModeStateRequest request;
    request.set_enabled(false);
    client.SetBatterySaverModeState(request);

    // Again, make sure response is async by checking for stale values.
    EXPECT_TRUE(test_observer.battery_saver_state().has_enabled());
    EXPECT_TRUE(test_observer.battery_saver_state().enabled());

    base::RunLoop().RunUntilIdle();

    // Should be off now.
    EXPECT_TRUE(test_observer.battery_saver_state().has_enabled());
    EXPECT_FALSE(test_observer.battery_saver_state().enabled());
  }

  // Verify GetBatterySaverModeState is off and asynchronous.
  {
    bool called = false;
    client.GetBatterySaverModeState(base::BindOnce(
        [](std::reference_wrapper<bool> called_ref,
           std::optional<power_manager::BatterySaverModeState> state) {
          EXPECT_TRUE(state.has_value());
          EXPECT_TRUE(state->has_enabled());
          EXPECT_FALSE(state->enabled());
          called_ref.get() = true;
        },
        std::ref(called)));

    // Result should be asynchronous.
    EXPECT_FALSE(called);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(called);
  }
}

// Test that observers are notified asynchronously when the Ambient Light Sensor
// status changes.
TEST(FakePowerManagerClientTest, AmbientLightSensorEnabled) {
  base::test::SingleThreadTaskEnvironment task_environment(
      base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
  FakePowerManagerClient client;
  TestObserver test_observer;

  client.AddObserver(&test_observer);

  // The Ambient Light Sensor is enabled by default.
  EXPECT_FALSE(
      test_observer.last_ambient_light_sensor_change().has_sensor_enabled());
  EXPECT_FALSE(test_observer.last_ambient_light_sensor_change().has_cause());

  // Turn the Ambient Light Sensor off, and check that observers are notified
  // asynchronously.
  power_manager::SetAmbientLightSensorEnabledRequest set_als_request;
  set_als_request.set_sensor_enabled(false);
  client.SetAmbientLightSensorEnabled(set_als_request);

  // The Ambient Light Sensor should not be disabled synchronously, since the
  // real client waits for a response from Power Manager.
  EXPECT_FALSE(
      test_observer.last_ambient_light_sensor_change().has_sensor_enabled());
  EXPECT_FALSE(test_observer.last_ambient_light_sensor_change().has_cause());
  base::RunLoop().RunUntilIdle();

  // The Ambient Light Sensor should be disabled now.
  EXPECT_TRUE(
      test_observer.last_ambient_light_sensor_change().has_sensor_enabled());
  EXPECT_FALSE(
      test_observer.last_ambient_light_sensor_change().sensor_enabled());
  // The change cause should be USER_REQUEST_SETTINGS_APP because the change was
  // triggered via the PowerManagerClient function.
  EXPECT_TRUE(test_observer.last_ambient_light_sensor_change().has_cause());
  EXPECT_EQ(
      test_observer.last_ambient_light_sensor_change().cause(),
      power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP);

  // Turn the Ambient Light Sensor on, and check that observers are notified
  // asynchronously.
  set_als_request.set_sensor_enabled(true);
  client.SetAmbientLightSensorEnabled(set_als_request);

  // The Ambient Light Sensor should not be enabled synchronously, since the
  // real client waits for a response from Power Manager.
  EXPECT_TRUE(
      test_observer.last_ambient_light_sensor_change().has_sensor_enabled());
  EXPECT_FALSE(
      test_observer.last_ambient_light_sensor_change().sensor_enabled());
  base::RunLoop().RunUntilIdle();

  // The Ambient Light Sensor should be enabled now.
  EXPECT_TRUE(
      test_observer.last_ambient_light_sensor_change().sensor_enabled());
  // The cause should be the same as before.
  EXPECT_TRUE(test_observer.last_ambient_light_sensor_change().has_cause());
  EXPECT_EQ(
      test_observer.last_ambient_light_sensor_change().cause(),
      power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP);
}

// Test that observers are notified asynchronously when the Keyboard Ambient
// Light Sensor status changes.
TEST(FakePowerManagerClientTest, KeyboardAmbientLightSensorEnabled) {
  base::test::SingleThreadTaskEnvironment task_environment(
      base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
  FakePowerManagerClient client;
  TestObserver test_observer;

  client.AddObserver(&test_observer);

  // The Keyboard Ambient Light Sensor is enabled by default.
  EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change()
                   .has_sensor_enabled());
  EXPECT_FALSE(
      test_observer.last_keyboard_ambient_light_sensor_change().has_cause());

  // Turn the Keyboard Ambient Light Sensor off, and check that observers are
  // notified asynchronously.
  power_manager::SetAmbientLightSensorEnabledRequest set_als_request;
  set_als_request.set_sensor_enabled(false);
  client.SetKeyboardAmbientLightSensorEnabled(set_als_request);

  // The Keyboard Ambient Light Sensor should not be disabled synchronously,
  // since the real client waits for a response from Power Manager.
  EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change()
                   .has_sensor_enabled());
  EXPECT_FALSE(
      test_observer.last_keyboard_ambient_light_sensor_change().has_cause());
  base::RunLoop().RunUntilIdle();

  // The Keyboard Ambient Light Sensor should be disabled now.
  EXPECT_TRUE(test_observer.last_keyboard_ambient_light_sensor_change()
                  .has_sensor_enabled());
  EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change()
                   .sensor_enabled());
  // The change cause should be USER_REQUEST_SETTINGS_APP because the change was
  // triggered via the PowerManagerClient function.
  EXPECT_TRUE(
      test_observer.last_keyboard_ambient_light_sensor_change().has_cause());
  EXPECT_EQ(
      test_observer.last_keyboard_ambient_light_sensor_change().cause(),
      power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP);

  // Turn the Keyboard Ambient Light Sensor on, and check that observers are
  // notified asynchronously.
  set_als_request.set_sensor_enabled(true);
  client.SetKeyboardAmbientLightSensorEnabled(set_als_request);

  // The Keyboard Ambient Light Sensor should not be enabled synchronously,
  // since the real client waits for a response from Power Manager.
  EXPECT_TRUE(test_observer.last_keyboard_ambient_light_sensor_change()
                  .has_sensor_enabled());
  EXPECT_FALSE(test_observer.last_keyboard_ambient_light_sensor_change()
                   .sensor_enabled());
  base::RunLoop().RunUntilIdle();

  // The Keyboard Ambient Light Sensor should be enabled now.
  EXPECT_TRUE(test_observer.last_keyboard_ambient_light_sensor_change()
                  .sensor_enabled());
  // The cause should be the same as before.
  EXPECT_TRUE(
      test_observer.last_keyboard_ambient_light_sensor_change().has_cause());
  EXPECT_EQ(
      test_observer.last_keyboard_ambient_light_sensor_change().cause(),
      power_manager::AmbientLightSensorChange_Cause_USER_REQUEST_SETTINGS_APP);
}

// Test that GetAmbientLightSensorEnabled works correctly.
TEST(FakePowerManagerClientTest, GetAmbientLightSensorEnabled) {
  base::test::SingleThreadTaskEnvironment task_environment(
      base::test::SingleThreadTaskEnvironment::MainThreadType::UI);
  FakePowerManagerClient client;

  {
    power_manager::SetAmbientLightSensorEnabledRequest set_als_request;
    set_als_request.set_sensor_enabled(true);
    client.SetAmbientLightSensorEnabled(set_als_request);

    bool called = false;
    client.GetAmbientLightSensorEnabled(base::BindOnce(
        [](std::reference_wrapper<bool> called_ref,
           std::optional<bool> is_ambient_light_sensor_enabled) {
          // The callback should be called with a value indicating that the
          // ambient light sensor is enabled.
          EXPECT_TRUE(is_ambient_light_sensor_enabled.value());

          // Indicate that this function was called.
          called_ref.get() = true;
        },
        std::ref(called)));

    // Result should be asynchronous.
    EXPECT_FALSE(called);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(called);
  }

  {
    power_manager::SetAmbientLightSensorEnabledRequest set_als_request;
    set_als_request.set_sensor_enabled(false);
    client.SetAmbientLightSensorEnabled(set_als_request);

    bool called = false;
    client.GetAmbientLightSensorEnabled(base::BindOnce(
        [](std::reference_wrapper<bool> called_ref,
           std::optional<bool> is_ambient_light_sensor_enabled) {
          // The callback should be called with a value indicating that the
          // ambient light sensor is not enabled.
          EXPECT_FALSE(is_ambient_light_sensor_enabled.value());

          // Indicate that this function was called.
          called_ref.get() = true;
        },
        std::ref(called)));

    // Result should be asynchronous.
    EXPECT_FALSE(called);
    base::RunLoop().RunUntilIdle();
    EXPECT_TRUE(called);
  }
}

}  // namespace chromeos