chromium/ash/components/arc/wake_lock/arc_wake_lock_bridge_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 "ash/components/arc/wake_lock/arc_wake_lock_bridge.h"

#include <memory>
#include <utility>

#include "ash/components/arc/mojom/power.mojom.h"
#include "ash/components/arc/session/arc_bridge_service.h"
#include "ash/components/arc/test/connection_holder_util.h"
#include "ash/components/arc/test/fake_power_instance.h"
#include "ash/components/arc/test/fake_wake_lock_instance.h"
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "services/device/public/cpp/test/test_wake_lock_provider.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace arc {

using device::mojom::WakeLockType;

class ArcWakeLockBridgeTest : public testing::Test {
 public:
  ArcWakeLockBridgeTest()
      : task_environment_(base::test::TaskEnvironment::TimeSource::MOCK_TIME) {
    bridge_service_ = std::make_unique<ArcBridgeService>();
    wake_lock_bridge_ =
        std::make_unique<ArcWakeLockBridge>(nullptr, bridge_service_.get());

    mojo::Remote<device::mojom::WakeLockProvider> remote_provider;
    wake_lock_provider_.BindReceiver(
        remote_provider.BindNewPipeAndPassReceiver());
    wake_lock_bridge_->SetWakeLockProviderForTesting(
        std::move(remote_provider));
    CreateWakeLockInstance();
  }

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

  ~ArcWakeLockBridgeTest() override { DestroyWakeLockInstance(); }

 protected:
  // Returns true iff there is no failure acquiring a system wake lock.
  bool AcquirePartialWakeLock() {
    base::RunLoop loop;
    bool result = false;
    wake_lock_bridge_->AcquirePartialWakeLock(base::BindOnce(
        [](bool* result_out, bool result) { *result_out = result; }, &result));
    loop.RunUntilIdle();
    wake_lock_bridge_->FlushWakeLocksForTesting();
    return result;
  }

  // Returns true iff there is no failure releasing a system wake lock.
  bool ReleasePartialWakeLock() {
    base::RunLoop loop;
    bool result = false;
    wake_lock_bridge_->ReleasePartialWakeLock(base::BindOnce(
        [](bool* result_out, bool result) { *result_out = result; }, &result));
    loop.RunUntilIdle();
    wake_lock_bridge_->FlushWakeLocksForTesting();
    return result;
  }

  // Creates a FakeWakeLockInstance for |bridge_service_|. This results in
  // ArcWakeLockBridge::OnInstanceReady() being called.
  void CreateWakeLockInstance() {
    instance_ = std::make_unique<FakeWakeLockInstance>();
    bridge_service_->wake_lock()->SetInstance(instance_.get());
    WaitForInstanceReady(bridge_service_->wake_lock());
  }

  // Destroys the FakeWakeLockInstance. This results in
  // ArcWakeLockBridge::OnInstanceClosed() being called.
  void DestroyWakeLockInstance() {
    if (!instance_)
      return;
    bridge_service_->wake_lock()->CloseInstance(instance_.get());
    instance_.reset();
  }

  // Returns the number of active wake locks of type |type|.
  int GetActiveWakeLocks(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;
  }

 private:
  base::test::TaskEnvironment task_environment_;

  device::TestWakeLockProvider wake_lock_provider_;

  std::unique_ptr<ArcBridgeService> bridge_service_;
  std::unique_ptr<FakeWakeLockInstance> instance_;
  std::unique_ptr<ArcWakeLockBridge> wake_lock_bridge_;
};

TEST_F(ArcWakeLockBridgeTest, AcquireAndReleaseSinglePartialWakeLock) {
  EXPECT_TRUE(AcquirePartialWakeLock());
  EXPECT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));

  EXPECT_TRUE(ReleasePartialWakeLock());
  EXPECT_EQ(0, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));
}

TEST_F(ArcWakeLockBridgeTest, AcquireAndReleaseMultiplePartialWakeLocks) {
  // Taking multiple wake locks should result in only one active wake lock.
  EXPECT_TRUE(AcquirePartialWakeLock());
  EXPECT_TRUE(AcquirePartialWakeLock());
  EXPECT_TRUE(AcquirePartialWakeLock());
  EXPECT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));

  // Releasing two wake locks after acquiring three should not result in
  // releasing a wake lock.
  EXPECT_TRUE(ReleasePartialWakeLock());
  EXPECT_TRUE(ReleasePartialWakeLock());
  EXPECT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));

  // Releasing the remaining wake lock should result in the release of the wake
  // lock.
  EXPECT_TRUE(ReleasePartialWakeLock());
  EXPECT_EQ(0, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));
}

TEST_F(ArcWakeLockBridgeTest, ReleaseWakeLockOnInstanceClosed) {
  EXPECT_TRUE(AcquirePartialWakeLock());
  ASSERT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));

  // If the instance is closed, all wake locks should be released.
  base::RunLoop run_loop;
  DestroyWakeLockInstance();
  run_loop.RunUntilIdle();
  EXPECT_EQ(0, GetActiveWakeLocks(WakeLockType::kPreventDisplaySleep));

  // Check that wake locks can be requested after the instance becomes ready
  // again.
  CreateWakeLockInstance();
  EXPECT_TRUE(AcquirePartialWakeLock());
  EXPECT_EQ(1, GetActiveWakeLocks(WakeLockType::kPreventAppSuspension));
}

}  // namespace arc