chromium/device/bluetooth/floss/bluetooth_floss_unittest.cc

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

#include "base/logging.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/floss/bluetooth_adapter_floss.h"
#include "device/bluetooth/floss/bluetooth_advertisement_floss.h"
#include "device/bluetooth/floss/bluetooth_device_floss.h"
#include "device/bluetooth/floss/fake_floss_adapter_client.h"
#include "device/bluetooth/floss/fake_floss_advertiser_client.h"
#include "device/bluetooth/floss/fake_floss_lescan_client.h"
#include "device/bluetooth/floss/fake_floss_manager_client.h"
#include "device/bluetooth/floss/floss_dbus_manager.h"
#include "device/bluetooth/test/mock_pairing_delegate.h"
#include "device/bluetooth/test/test_bluetooth_adapter_observer.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace {

BluetoothAdapter;
BluetoothDevice;
BluetoothDiscoverySession;
MockPairingDelegate;
TestBluetoothAdapterObserver;
_;
StrictMock;

const uint8_t kTestScannerId =;
#if BUILDFLAG(IS_CHROMEOS)
const uint8_t kTestScannerId2 = 11;
#endif
constexpr char kTestDeviceAddr[] =;
constexpr char kTestDeviceName[] =;

}  // namespace

namespace floss {

class FakeBluetoothLowEnergyScanSessionDelegate
    : public device::BluetoothLowEnergyScanSession::Delegate {};

// Unit tests exercising device/bluetooth/floss, with abstract Floss API
// implemented as a fake Floss*Client.
class BluetoothFlossTest : public testing::Test {};

TEST_F(BluetoothFlossTest, BondFailureTriggersCallbacks) {}

TEST_F(BluetoothFlossTest, PairJustWorks) {}

TEST_F(BluetoothFlossTest, PairingTwiceRejectsSecondRequest) {}

TEST_F(BluetoothFlossTest, PairConfirmPasskey) {}

TEST_F(BluetoothFlossTest, PairDisplayPasskeySucceeded) {}

TEST_F(BluetoothFlossTest, PairDisplayPasskeyFailed) {}

TEST_F(BluetoothFlossTest, PairPasskeyEntry) {}

TEST_F(BluetoothFlossTest, RemoveBonding) {}

TEST_F(BluetoothFlossTest, PairDisplayPinCodeSucceeded) {}

TEST_F(BluetoothFlossTest, PairRequestPinCodeSucceeded) {}

TEST_F(BluetoothFlossTest, Disconnect) {}

TEST_F(BluetoothFlossTest, UpdatesDeviceConnectionState) {}

TEST_F(BluetoothFlossTest, AdapterInitialDevices) {}

TEST_F(BluetoothFlossTest, TestIsConnectable) {}

TEST_F(BluetoothFlossTest, DisabledAdapterClearsDevices) {}

TEST_F(BluetoothFlossTest, RepeatsDiscoverySession) {}

TEST_F(BluetoothFlossTest, HandlesClearedDevices) {}

TEST_F(BluetoothFlossTest, UpdatesDeviceName) {}

TEST_F(BluetoothFlossTest, SetAdvertisingInterval) {}

#if BUILDFLAG(IS_CHROMEOS)
TEST_F(BluetoothFlossTest, StartLowEnergyScanSessions) {
  InitializeAndEnableAdapter();

  // Initial conditions
  EXPECT_EQ(0, GetFakeLEScanClient()->scanners_registered_);

  auto background_scan_session = adapter_->StartLowEnergyScanSession(
      /*filter=*/nullptr, /*delegate=*/nullptr);
  base::RunLoop().RunUntilIdle();

  // We should have registered a scanner
  EXPECT_EQ(1, GetFakeLEScanClient()->scanners_registered_);

  // Register another scanner
  auto another_background_scan_session = adapter_->StartLowEnergyScanSession(
      /*filter=*/nullptr, /*delegate=*/nullptr);
  base::RunLoop().RunUntilIdle();

  // Should register another scanner
  EXPECT_EQ(2, GetFakeLEScanClient()->scanners_registered_);

  // Destroy one of the sessions
  background_scan_session.reset();
  EXPECT_EQ(1, GetFakeLEScanClient()->scanners_registered_);
}

TEST_F(BluetoothFlossTest, StartLowEnergyScanSessionWithScanResult) {
  InitializeAndEnableAdapter();

  FakeBluetoothLowEnergyScanSessionDelegate delegate;
  GetFakeLEScanClient()->SetNextScannerUUID(
      device::BluetoothUUID(kTestUuidStr));
  auto background_scan_session = adapter_->StartLowEnergyScanSession(
      /*filter=*/nullptr, delegate.GetWeakPtr());
  base::RunLoop().RunUntilIdle();

  FakeBluetoothLowEnergyScanSessionDelegate delegate2;
  GetFakeLEScanClient()->SetNextScannerUUID(
      device::BluetoothUUID(kTestUuidStr2));
  auto background_scan_session2 = adapter_->StartLowEnergyScanSession(
      /*filter=*/nullptr, delegate2.GetWeakPtr());
  base::RunLoop().RunUntilIdle();

  // Initial conditions
  EXPECT_TRUE(GetFakeLEScanClient()->scanner_ids_.empty());

  EXPECT_EQ(0, delegate.sessions_started_);
  EXPECT_TRUE(delegate.devices_found_.empty());
  EXPECT_EQ(0, delegate.sessions_invalidated_);

  EXPECT_EQ(0, delegate2.sessions_started_);
  EXPECT_TRUE(delegate2.devices_found_.empty());
  EXPECT_EQ(0, delegate2.sessions_invalidated_);

  // Simulate OnScannerRegistered.
  RegisterScanner(device::BluetoothUUID(kTestUuidStr), kTestScannerId);
  EXPECT_TRUE(
      base::Contains(GetFakeLEScanClient()->scanner_ids_, kTestScannerId));
  EXPECT_EQ(1, delegate.sessions_started_);
  RegisterScanner(device::BluetoothUUID(kTestUuidStr2), kTestScannerId2);
  EXPECT_TRUE(
      base::Contains(GetFakeLEScanClient()->scanner_ids_, kTestScannerId2));
  EXPECT_EQ(1, delegate2.sessions_started_);

  // Simulate a scan result event
  GetScanResult();
  EXPECT_FALSE(base::Contains(delegate.devices_found_, kTestDeviceAddr));

  base::RunLoop run_loop;
  // Because of the workaround in BluetoothAdapterFloss::AdvertisementFound
  // we need to wait for a bit before checking if OnDeviceFound is called.
  // TODO(b/271165074): This is not needed when Floss daemon can consolidate
  // the OnAdvertisementFound callback together with the first advertisement
  // data.
  base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
      FROM_HERE, run_loop.QuitClosure(), base::Seconds(2));
  GetAdvFound();
  run_loop.Run();
  // The device found should only affect the scanner that causes it.
  EXPECT_TRUE(base::Contains(delegate.devices_found_, kTestDeviceAddr));
  EXPECT_FALSE(base::Contains(delegate2.devices_found_, kTestDeviceAddr));

  // Check that the scanned device is in the devices_ map so clients can
  // access the device.
  BluetoothDevice* device = adapter_->GetDevice(kTestDeviceAddr);
  EXPECT_NE(nullptr, device);

  adapter_->Shutdown();
  EXPECT_EQ(1, delegate.sessions_invalidated_);
}
#endif  // BUILDFLAG(IS_CHROMEOS)

}  // namespace floss