chromium/chromeos/ash/services/libassistant/power_manager_provider_impl_unittest.cc

// Copyright 2018 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/ash/services/libassistant/power_manager_provider_impl.h"

#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "chromeos/ash/services/libassistant/test_support/fake_platform_delegate.h"
#include "chromeos/dbus/power/fake_power_manager_client.h"
#include "services/device/public/cpp/test/test_wake_lock_provider.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::libassistant {

namespace {

// Constants to be used with the |AddWakeAlarm| API.
const uint64_t kAlarmRelativeTimeMs = 1000;
const uint64_t kAlarmMaxDelayMs = 0;

class FakePlatformDelegateImpl : public assistant::FakePlatformDelegate {
 public:
  explicit FakePlatformDelegateImpl(
      device::TestWakeLockProvider* wake_lock_provider)
      : wake_lock_provider_(wake_lock_provider) {}

  // FakePlatformDelegate implementation:
  void BindWakeLockProvider(
      mojo::PendingReceiver<::device::mojom::WakeLockProvider> receiver)
      override {
    wake_lock_provider_->BindReceiver(std::move(receiver));
  }

 private:
  const raw_ptr<device::TestWakeLockProvider> wake_lock_provider_;
};

}  // namespace

class AssistantPowerManagerProviderImplTest : public testing::Test {
 public:
  AssistantPowerManagerProviderImplTest()
      : task_environment_(base::test::TaskEnvironment::MainThreadType::IO,
                          base::test::TaskEnvironment::TimeSource::MOCK_TIME) {}

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

  ~AssistantPowerManagerProviderImplTest() override = default;

  void SetUp() override {
    chromeos::PowerManagerClient::InitializeFake();
    chromeos::FakePowerManagerClient::Get()->set_tick_clock(
        task_environment_.GetMockTickClock());
    power_manager_provider_impl_ = std::make_unique<PowerManagerProviderImpl>();
    power_manager_provider_impl_->set_tick_clock_for_testing(
        task_environment_.GetMockTickClock());

    power_manager_provider_impl_->Initialize(&platform_delegate_);
  }

  void TearDown() override {
    power_manager_provider_impl_.reset();
    chromeos::PowerManagerClient::Shutdown();
  }

 protected:
  PowerManagerProviderImpl* GetPowerManagerProviderImpl() {
    return power_manager_provider_impl_.get();
  }

  // Calls the acquire wake lock API and ensures that the request has reached
  // the wake lock provider.
  void AcquireWakeLock() {
    power_manager_provider_impl_->AcquireWakeLock();
    base::RunLoop run_loop;
    run_loop.RunUntilIdle();
  }

  // Calls the release wake lock API and ensures that the request has reached
  // the wake lock provider.
  void ReleaseWakeLock() {
    power_manager_provider_impl_->ReleaseWakeLock();
    base::RunLoop run_loop;
    run_loop.RunUntilIdle();
  }

  // Returns the number of active wake locks of type |type|.
  int GetActiveWakeLocks(device::mojom::WakeLockType type) {
    base::RunLoop run_loop;
    int result_count = 0;
    wake_lock_provider_.GetActiveWakeLocksForTests(
        type,
        base::BindOnce(
            [](base::RunLoop* run_loop, int* result_count, int32_t count) {
              *result_count = count;
              run_loop->Quit();
            },
            &run_loop, &result_count));
    run_loop.Run();
    return result_count;
  }

  // Returns true iff adding a wake alarm via |AddWakeAlarm| returns a > 0
  // result and the alarm expiration callback fires.
  bool CheckAddWakeAlarmAndExpiration(uint64_t relative_time_ms,
                                      uint64_t max_delay_ms) {
    // Schedule wake alarm and check if valid id is returned and timer callback
    // is fired.
    bool result = false;
    assistant_client::Callback0 wake_alarm_expiration_cb(
        [&result]() { result = true; });
    assistant_client::PowerManagerProvider::AlarmId id =
        power_manager_provider_impl_->AddWakeAlarm(
            relative_time_ms, max_delay_ms,
            std::move(wake_alarm_expiration_cb));
    task_environment_.FastForwardBy(base::Milliseconds(relative_time_ms));

    if (id <= 0UL)
      return false;
    return result;
  }

 private:
  // Needs to be of type |MainThreadType::IO| to use |NativeTimer|.
  base::test::TaskEnvironment task_environment_;

  device::TestWakeLockProvider wake_lock_provider_;
  FakePlatformDelegateImpl platform_delegate_{&wake_lock_provider_};

  std::unique_ptr<PowerManagerProviderImpl> power_manager_provider_impl_;
};

TEST_F(AssistantPowerManagerProviderImplTest, CheckAcquireAndReleaseWakeLock) {
  // Acquire wake lock and check wake lock count.
  AcquireWakeLock();
  EXPECT_EQ(1, GetActiveWakeLocks(
                   device::mojom::WakeLockType::kPreventAppSuspension));
  // Acquire another wake lock, this shouldn't change the overall count.
  AcquireWakeLock();
  EXPECT_EQ(1, GetActiveWakeLocks(
                   device::mojom::WakeLockType::kPreventAppSuspension));
  // Release wake lock, this shouldn't change the overall count.
  ReleaseWakeLock();
  EXPECT_EQ(1, GetActiveWakeLocks(
                   device::mojom::WakeLockType::kPreventAppSuspension));
  // Release wake lock, this should finally release the wake lock.
  ReleaseWakeLock();
  EXPECT_EQ(0, GetActiveWakeLocks(
                   device::mojom::WakeLockType::kPreventAppSuspension));
  // An unbalanced release call shouldn't do anything.
  ReleaseWakeLock();
  EXPECT_EQ(0, GetActiveWakeLocks(
                   device::mojom::WakeLockType::kPreventAppSuspension));
}

TEST_F(AssistantPowerManagerProviderImplTest, CheckWakeAlarms) {
  // Check consecutive wake alarms addition and expiration.
  EXPECT_TRUE(
      CheckAddWakeAlarmAndExpiration(kAlarmRelativeTimeMs, kAlarmMaxDelayMs));
  EXPECT_TRUE(
      CheckAddWakeAlarmAndExpiration(kAlarmRelativeTimeMs, kAlarmMaxDelayMs));
}

}  // namespace ash::libassistant