910e62b5创建于 1月15日历史提交
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "device/bluetooth/floss/floss_dbus_manager.h"

#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/task_environment.h"
#include "base/test/test_future.h"
#include "device/bluetooth/floss/floss_dbus_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace floss {
namespace {
// This has to be different from FlossDBusManager::Get()->active_adapter_;
const int kMockAdapterIndex = 1;
}  // namespace

using testing::DoAll;

class FlossDBusManagerTest : public testing::Test {
 public:
  FlossDBusManagerTest() = default;

  void SetUp() override { FlossDBusManager::InitializeFake(); }

  void TearDown() override { FlossDBusManager::Shutdown(); }

  void SwitchAdapterOnTest() {
    base::test::TestFuture<void> ready;
    FlossDBusManager::Get()->SwitchAdapter(kMockAdapterIndex,
                                           ready.GetCallback());
    // Callback is not called since not all clients interface are present
    EXPECT_FALSE(ready.IsReady());
    PresentAllClients();
    // Callback is called since all clients interface are present
    EXPECT_TRUE(ready.Wait());
  }

  void SwitchAdapterOnTimeoutTest() {
    base::test::TestFuture<void> ready;
    FlossDBusManager::Get()->SwitchAdapter(kMockAdapterIndex,
                                           ready.GetCallback());
    // Callback is not called since not all clients interface are present
    EXPECT_FALSE(ready.IsReady());
    TriggerClientInitializerTimeout();
    // Callback is called because of timeout
    EXPECT_TRUE(ready.Wait());
  }

  void SwitchAdapterOnPartiallyPresentTimeoutTest() {
    base::test::TestFuture<void> ready;
    FlossDBusManager::Get()->SwitchAdapter(kMockAdapterIndex,
                                           ready.GetCallback());
    // Callback is not called since not all clients interface are present
    EXPECT_FALSE(ready.IsReady());
    PresentAllClientsExceptForGatt();
    // Callback is not called since not all clients interface are present
    EXPECT_FALSE(ready.IsReady());
    TriggerClientInitializerTimeout();
    // Callback is called because of timeout
    EXPECT_TRUE(ready.Wait());

    // If the client API is present later, we shouldn't crash.
    PresentGattClient();
    base::RunLoop().RunUntilIdle();
  }

  void SwitchAdapterOffTest() {
    base::test::TestFuture<void> ready;
    FlossDBusManager::Get()->SwitchAdapter(FlossDBusManager::kInvalidAdapter,
                                           ready.GetCallback());

    // Callback should be called immediately.
    EXPECT_TRUE(ready.Wait());
    UnpresentAllClients();
  }

 protected:
  void PresentAllClients() {
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateAdapterPath(kMockAdapterIndex),
        kAdapterInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateLoggingPath(kMockAdapterIndex),
        kAdapterLoggingInterface);
#if BUILDFLAG(IS_CHROMEOS)
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateAdminPath(kMockAdapterIndex), kAdminInterface);
#endif
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateBatteryManagerPath(kMockAdapterIndex),
        kBatteryManagerInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateBluetoothTelephonyPath(kMockAdapterIndex),
        kBluetoothTelephonyInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateGattPath(kMockAdapterIndex), kGattInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateAdapterPath(kMockAdapterIndex),
        kSocketManagerInterface);
  }

  void PresentAllClientsExceptForGatt() {
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateAdapterPath(kMockAdapterIndex),
        kAdapterInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateLoggingPath(kMockAdapterIndex),
        kAdapterLoggingInterface);
#if BUILDFLAG(IS_CHROMEOS)
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateAdminPath(kMockAdapterIndex), kAdminInterface);
#endif
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateBatteryManagerPath(kMockAdapterIndex),
        kBatteryManagerInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateBluetoothTelephonyPath(kMockAdapterIndex),
        kBluetoothTelephonyInterface);
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateAdapterPath(kMockAdapterIndex),
        kSocketManagerInterface);
  }

  void PresentGattClient() {
    FlossDBusManager::Get()->ObjectAdded(
        FlossDBusClient::GenerateGattPath(kMockAdapterIndex), kGattInterface);
  }

  void UnpresentAllClients() {
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateAdapterPath(kMockAdapterIndex),
        kAdapterInterface);
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateLoggingPath(kMockAdapterIndex),
        kAdapterLoggingInterface);
#if BUILDFLAG(IS_CHROMEOS)
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateAdminPath(kMockAdapterIndex), kAdminInterface);
#endif
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateBatteryManagerPath(kMockAdapterIndex),
        kBatteryManagerInterface);
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateBluetoothTelephonyPath(kMockAdapterIndex),
        kBluetoothTelephonyInterface);
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateGattPath(kMockAdapterIndex), kGattInterface);
    FlossDBusManager::Get()->ObjectRemoved(
        FlossDBusClient::GenerateAdapterPath(kMockAdapterIndex),
        kSocketManagerInterface);
  }

  void TriggerClientInitializerTimeout() {
    task_environment_.FastForwardBy(
        base::Milliseconds(FlossDBusManager::kClientReadyTimeoutMs));
  }

  base::test::SingleThreadTaskEnvironment task_environment_{
      base::test::TaskEnvironment::TimeSource::MOCK_TIME};
};

// Make sure callback is called after all clients API present
TEST_F(FlossDBusManagerTest, AllClientsReadyBeforeTimeout) {
  SwitchAdapterOnTest();
}

// Make sure callback is not called until timeout
TEST_F(FlossDBusManagerTest, NotAllClientsReadyBeforeTimeout) {
  SwitchAdapterOnPartiallyPresentTimeoutTest();
}

// Make sure callback is called immediately after switch adapter off.
TEST_F(FlossDBusManagerTest, AdapterOffCallImmediately) {
  SwitchAdapterOnTest();
  SwitchAdapterOffTest();
}

// Make sure callback is called correctly after an adapter power cycle.
TEST_F(FlossDBusManagerTest, RestartAdapterClientPresent) {
  SwitchAdapterOnTest();
  SwitchAdapterOffTest();
  SwitchAdapterOnTest();
}

// Make sure callback is called correctly after an adapter power cycle.
TEST_F(FlossDBusManagerTest, RestartAdapterTriggerTimeout) {
  SwitchAdapterOnTest();
  SwitchAdapterOffTest();
  SwitchAdapterOnTimeoutTest();
}

}  // namespace floss