chromium/chrome/browser/ash/policy/handlers/bluetooth_policy_handler_unittest.cc

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

#include "chrome/browser/ash/policy/handlers/bluetooth_policy_handler.h"

#include <utility>

#include "base/test/task_environment.h"
#include "chrome/browser/ash/settings/scoped_testing_cros_settings.h"
#include "chrome/browser/ash/settings/stub_cros_settings_provider.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/test/mock_bluetooth_adapter.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace policy {

class BluetoothPolicyHandlerTest : public testing::Test {
 protected:
  class TestingBluetoothAdapter : public device::MockBluetoothAdapter {
   public:
    TestingBluetoothAdapter() = default;

    void Shutdown() override {
      is_shutdown_ = true;
      for (auto observer : GetObservers()) {
        observer.AdapterPresentChanged(this, false);
      }
    }
    void Initialize(base::OnceClosure callback) override {
      is_shutdown_ = false;

      adapter_observer_->AdapterPresentChanged(this, true);
      std::move(callback).Run();
    }
    void SetPowered(bool powered,
                    base::OnceClosure callback,
                    ErrorCallback error_callback) override {
      is_powered_ = powered;

      adapter_observer_->AdapterPoweredChanged(this, powered);
      std::move(callback).Run();
    }
    void SetServiceAllowList(const UUIDList& uuids,
                             base::OnceClosure callback,
                             ErrorCallback error_callback) override {
      uuids_ = uuids;
    }
    bool IsPresent() const override { return !is_shutdown_; }
    bool IsPowered() const override { return is_powered_; }
    const UUIDList& GetAllowList() const { return uuids_; }

    void AddObserver(device::BluetoothAdapter::Observer* observer) override {
      DCHECK(!adapter_observer_);
      adapter_observer_ = observer;
    }

   protected:
    ~TestingBluetoothAdapter() override = default;

    bool is_shutdown_ = false;
    bool is_powered_ = true;
    UUIDList uuids_;
    raw_ptr<device::BluetoothAdapter::Observer, DanglingUntriaged>
        adapter_observer_ = nullptr;
  };

  BluetoothPolicyHandlerTest()
      : adapter_(base::MakeRefCounted<TestingBluetoothAdapter>()) {}
  ~BluetoothPolicyHandlerTest() override = default;

  // testing::Test
  void SetUp() override {
    testing::Test::SetUp();
    device::BluetoothAdapterFactory::SetAdapterForTesting(adapter_);
  }

 protected:
  void SetAllowBluetooth(bool allow_bluetooth) {
    scoped_testing_cros_settings_.device_settings()->SetBoolean(
        ash::kAllowBluetooth, allow_bluetooth);
  }

  void SetDeviceAllowedBluetoothServices(base::Value::List allowlist) {
    scoped_testing_cros_settings_.device_settings()->Set(
        ash::kDeviceAllowedBluetoothServices,
        base::Value(std::move(allowlist)));
  }

  base::test::TaskEnvironment task_environment_;
  scoped_refptr<TestingBluetoothAdapter> adapter_;
  ash::ScopedTestingCrosSettings scoped_testing_cros_settings_;
};

TEST_F(BluetoothPolicyHandlerTest, TestZeroOnOffOn) {
  BluetoothPolicyHandler shutdown_policy_handler(ash::CrosSettings::Get());
  EXPECT_TRUE(adapter_->IsPresent());

  SetAllowBluetooth(true);
  EXPECT_TRUE(adapter_->IsPresent());

  SetAllowBluetooth(false);
  EXPECT_FALSE(adapter_->IsPresent());
  EXPECT_FALSE(adapter_->IsPowered());

  // Once the Bluetooth stack goes down, it needs a reboot to come back up.
  SetAllowBluetooth(true);
  EXPECT_FALSE(adapter_->IsPresent());
}

TEST_F(BluetoothPolicyHandlerTest, OffDuringStartup) {
  SetAllowBluetooth(false);
  BluetoothPolicyHandler shutdown_policy_handler(ash::CrosSettings::Get());
  EXPECT_FALSE(adapter_->IsPresent());
  EXPECT_FALSE(adapter_->IsPowered());
}

TEST_F(BluetoothPolicyHandlerTest, OnDuringStartup) {
  SetAllowBluetooth(true);
  BluetoothPolicyHandler shutdown_policy_handler(ash::CrosSettings::Get());
  EXPECT_TRUE(adapter_->IsPresent());
}

TEST_F(BluetoothPolicyHandlerTest, TestSetServiceAllowList) {
  base::Value::List allowlist;
  const char kTestUuid1[] = "0x1124";
  const char kTestUuid2[] = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee";
  allowlist.Append(kTestUuid1);
  allowlist.Append(kTestUuid2);
  SetDeviceAllowedBluetoothServices(std::move(allowlist));
  BluetoothPolicyHandler bluetooth_policy_handler(ash::CrosSettings::Get());
  const device::BluetoothUUID test_uuid1(kTestUuid1);
  const device::BluetoothUUID test_uuid2(kTestUuid2);
  const std::vector<device::BluetoothUUID>& allowlist_result =
      adapter_->GetAllowList();
  ASSERT_EQ(2u, allowlist_result.size());
  EXPECT_EQ(test_uuid1, allowlist_result[0]);
  EXPECT_EQ(test_uuid2, allowlist_result[1]);
}

TEST_F(BluetoothPolicyHandlerTest, TestPolicySettingsWhileBTNotReady) {
  base::Value::List allowlist;
  const char kTestUuid1[] = "0x1124";
  const char kTestUuid2[] = "0x1108";
  std::vector<device::BluetoothUUID> allowlist_result;
  const device::BluetoothUUID test_uuid1(kTestUuid1);
  const device::BluetoothUUID test_uuid2(kTestUuid2);

  BluetoothPolicyHandler bluetooth_policy_handler(ash::CrosSettings::Get());

  allowlist.Append(kTestUuid1);

  adapter_->Shutdown();
  ASSERT_TRUE(!adapter_->IsPresent());
  ASSERT_TRUE(adapter_->IsPowered());

  SetDeviceAllowedBluetoothServices(allowlist.Clone());

  // policy is not propagated to adapter since it's not yet ready.
  allowlist_result = adapter_->GetAllowList();
  EXPECT_EQ(0u, allowlist_result.size());

  adapter_->Initialize(base::DoNothing());
  ASSERT_TRUE(adapter_->IsPresent());
  ASSERT_TRUE(adapter_->IsPowered());
  ASSERT_TRUE(adapter_->IsInitialized());

  allowlist_result = adapter_->GetAllowList();
  // policy should be set to adapter after adapter is ready.
  ASSERT_EQ(1u, allowlist_result.size());
  EXPECT_EQ(test_uuid1, allowlist_result[0]);

  adapter_->SetPowered(false, base::DoNothing(), base::DoNothing());

  allowlist.Append(kTestUuid2);
  SetDeviceAllowedBluetoothServices(allowlist.Clone());

  // policy is not propagated to adapter since it's not powered.
  allowlist_result = adapter_->GetAllowList();
  ASSERT_EQ(1u, allowlist_result.size());
  EXPECT_EQ(test_uuid1, allowlist_result[0]);

  adapter_->SetPowered(true, base::DoNothing(), base::DoNothing());
  ASSERT_TRUE(adapter_->IsPresent());
  ASSERT_TRUE(adapter_->IsPowered());
  ASSERT_TRUE(adapter_->IsInitialized());

  // policy should be set to adapter after adapter is ready.
  allowlist_result = adapter_->GetAllowList();
  ASSERT_EQ(2u, allowlist_result.size());
  EXPECT_EQ(test_uuid1, allowlist_result[0]);
  EXPECT_EQ(test_uuid2, allowlist_result[1]);
}
}  // namespace policy