chromium/device/bluetooth/bluez/bluetooth_gatt_bluez_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 <stddef.h>
#include <stdint.h>

#include <memory>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "base/test/bind.h"
#include "base/test/task_environment.h"
#include "dbus/object_path.h"
#include "device/bluetooth/bluetooth_adapter.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/bluetooth_discovery_filter.h"
#include "device/bluetooth/bluetooth_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_gatt_connection.h"
#include "device/bluetooth/bluetooth_gatt_notify_session.h"
#include "device/bluetooth/bluetooth_remote_gatt_characteristic.h"
#include "device/bluetooth/bluetooth_remote_gatt_descriptor.h"
#include "device/bluetooth/bluetooth_remote_gatt_service.h"
#include "device/bluetooth/bluez/bluetooth_device_bluez.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/fake_bluetooth_adapter_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_agent_manager_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_device_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_characteristic_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_descriptor_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_gatt_service_client.h"
#include "device/bluetooth/dbus/fake_bluetooth_input_client.h"
#include "device/bluetooth/floss/floss_features.h"
#include "device/bluetooth/public/cpp/bluetooth_uuid.h"
#include "device/bluetooth/test/test_bluetooth_adapter_observer.h"
#include "testing/gtest/include/gtest/gtest.h"

BluetoothAdapter;
BluetoothDevice;
BluetoothDiscoveryFilter;
BluetoothGattConnection;
BluetoothGattNotifySession;
BluetoothGattService;
BluetoothRemoteGattCharacteristic;
BluetoothRemoteGattDescriptor;
BluetoothRemoteGattService;
BluetoothUUID;
TestBluetoothAdapterObserver;

UUIDSet;
WriteType;

DeviceToUUIDs;

namespace bluez {

namespace {

const BluetoothUUID kGenericAccessServiceUUID(
    bluez::FakeBluetoothGattServiceClient::kGenericAccessServiceUUID);
const BluetoothUUID kBatteryServiceUUID(
    bluez::FakeBluetoothGattServiceClient::kBatteryServiceUUID);
const BluetoothUUID kHeartRateServiceUUID(
    bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID);
const BluetoothUUID kHeartRateMeasurementUUID(
    bluez::FakeBluetoothGattCharacteristicClient::kHeartRateMeasurementUUID);
const BluetoothUUID kBodySensorLocationUUID(
    bluez::FakeBluetoothGattCharacteristicClient::kBodySensorLocationUUID);
const BluetoothUUID kHeartRateControlPointUUID(
    bluez::FakeBluetoothGattCharacteristicClient::kHeartRateControlPointUUID);

// Compares GATT characteristic/descriptor values. Returns true, if the values
// are equal.
bool ValuesEqual(const std::vector<uint8_t>& value0,
                 const std::vector<uint8_t>& value1) {}

void AddDeviceFilterWithUUID(BluetoothDiscoveryFilter* filter,
                             BluetoothUUID uuid) {}

}  // namespace

class BluetoothGattBlueZTest : public testing::Test {};

TEST_F(BluetoothGattBlueZTest,
       RetrieveGattConnectedDevicesWithDiscoveryFilter_NoFilter) {}

TEST_F(BluetoothGattBlueZTest,
       RetrieveGattConnectedDevicesWithDiscoveryFilter_NonMatchingFilter) {}

TEST_F(
    BluetoothGattBlueZTest,
    RetrieveGattConnectedDevicesWithDiscoveryFilter_OneMatchingServiceOneDevice) {}

TEST_F(
    BluetoothGattBlueZTest,
    RetrieveGattConnectedDevicesWithDiscoveryFilter_OneMatchingServiceTwoDevices) {}

TEST_F(BluetoothGattBlueZTest,
       RetrieveGattConnectedDevicesWithDiscoveryFilter_TwoServicesTwoDevices) {}

TEST_F(
    BluetoothGattBlueZTest,
    RetrieveGattConnectedDevicesWithDiscoveryFilter_OneMatchingServiceOneNonMatchingService) {}

TEST_F(BluetoothGattBlueZTest, GattConnection) {}

TEST_F(BluetoothGattBlueZTest, GattServiceAddedAndRemoved) {}

TEST_F(BluetoothGattBlueZTest, ServicesDiscoveredBeforeAdapterIsCreated) {}

TEST_F(BluetoothGattBlueZTest, ServicesDiscoveredAfterAdapterIsCreated) {}

TEST_F(BluetoothGattBlueZTest, DiscoverCachedServices) {}

TEST_F(BluetoothGattBlueZTest, DiscoverNewServices) {}

TEST_F(BluetoothGattBlueZTest, DiscoverCachedAndNewServices) {}

TEST_F(BluetoothGattBlueZTest, GattCharacteristicAddedAndRemoved) {}

TEST_F(BluetoothGattBlueZTest, GattDescriptorAddedAndRemoved) {}

TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue) {}

TEST_F(BluetoothGattBlueZTest, DeprecatedGattCharacteristicValue) {}

// Test a read request issued from the success callback of another read request.
TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Read_Read) {}

// Test a write request issued from the success callback of another write
// request.
TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Write_Write) {}

// Test a write request issued from the success callback of another write
// request.
TEST_F(BluetoothGattBlueZTest,
       GattCharacteristicValue_Nested_DeprecatedWrite_DeprecatedWrite) {}

// Test a write request issued from the success callback of a read request.
TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Read_Write) {}

// Test a write request issued from the success callback of a read request.
TEST_F(BluetoothGattBlueZTest,
       GattCharacteristicValue_Nested_Read_DeprecatedWrite) {}

// Test a read request issued from the success callback of a write request.
TEST_F(BluetoothGattBlueZTest, GattCharacteristicValue_Nested_Write_Read) {}

// Test a read request issued from the success callback of a write request.
TEST_F(BluetoothGattBlueZTest,
       GattCharacteristicValue_Nested_DeprecatedWrite_Read) {}

TEST_F(BluetoothGattBlueZTest, GattCharacteristicProperties) {}

TEST_F(BluetoothGattBlueZTest, GattDescriptorValue) {}

TEST_F(BluetoothGattBlueZTest, NotifySessions) {}

TEST_F(BluetoothGattBlueZTest, NotifySessionsMadeInactive) {}

#if BUILDFLAG(IS_CHROMEOS)
TEST_F(BluetoothGattBlueZTest, ReliableWrite) {
  fake_bluetooth_device_client_->CreateDevice(
      dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
      dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
  BluetoothDeviceBlueZ* device = static_cast<BluetoothDeviceBlueZ*>(
      adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress));
  ASSERT_TRUE(device);

  TestBluetoothAdapterObserver observer(adapter_);

  // Expose the fake Heart Rate service. This will asynchronously expose
  // characteristics.
  fake_bluetooth_gatt_service_client_->ExposeHeartRateService(
      dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
  ASSERT_EQ(1, observer.gatt_service_added_count());

  BluetoothRemoteGattService* service =
      device->GetGattService(observer.last_gatt_service_id());

  // Run the message loop so that the characteristics appear.
  {
    base::RunLoop loop;
    observer.set_quit_closure(loop.QuitWhenIdleClosure());
    loop.Run();
  }

  base::RunLoop loop;
  // Request to start notifications.
  service
      ->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_
                              ->GetHeartRateMeasurementPath()
                              .value())
      ->StartNotifySession(
          base::BindLambdaForTesting(
              [&loop,
               this](std::unique_ptr<BluetoothGattNotifySession> session) {
                NotifySessionCallback(std::move(session));
                loop.Quit();
              }),
          base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                         base::Unretained(this)));
  loop.Run();

  // Obtain writable Heart Rate Control Point characteristic.
  BluetoothRemoteGattCharacteristic* characteristic =
      service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_
                                     ->GetHeartRateControlPointPath()
                                     .value());
  std::vector<uint8_t> write_value = {0x01};

  // Prepare 1000 writes.
  success_callback_count_ = 0;
  error_callback_count_ = 0;
  observer.Reset();
  for (int i = 0; i < 1000; ++i) {
    characteristic->PrepareWriteRemoteCharacteristic(
        write_value,
        base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback,
                       base::Unretained(this)),
        base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                       base::Unretained(this)));
  }
  EXPECT_EQ(1000, success_callback_count_);
  EXPECT_EQ(0, error_callback_count_);
  EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count());

  // Abort.
  device->AbortWrite(
      base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback,
                     base::Unretained(this)),
      base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                     base::Unretained(this)));
  EXPECT_EQ(1001, success_callback_count_);
  EXPECT_EQ(0, error_callback_count_);
  EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count());

  // Prepare another 1000 writes.
  success_callback_count_ = 0;
  error_callback_count_ = 0;
  observer.Reset();
  for (int i = 0; i < 1000; ++i) {
    characteristic->PrepareWriteRemoteCharacteristic(
        write_value,
        base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback,
                       base::Unretained(this)),
        base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                       base::Unretained(this)));
  }
  EXPECT_EQ(1000, success_callback_count_);
  EXPECT_EQ(0, error_callback_count_);
  EXPECT_EQ(0, observer.gatt_characteristic_value_changed_count());

  // Execute.
  device->ExecuteWrite(
      base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback,
                     base::Unretained(this)),
      base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                     base::Unretained(this)));
  EXPECT_EQ(1001, success_callback_count_);
  EXPECT_EQ(0, error_callback_count_);
  EXPECT_EQ(1000, observer.gatt_characteristic_value_changed_count());
}

TEST_F(BluetoothGattBlueZTest, NotificationType) {
  fake_bluetooth_device_client_->CreateDevice(
      dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
      dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
  BluetoothDeviceBlueZ* device = static_cast<BluetoothDeviceBlueZ*>(
      adapter_->GetDevice(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress));
  ASSERT_TRUE(device);

  TestBluetoothAdapterObserver observer(adapter_);

  // Expose the fake Heart Rate service. This will asynchronously expose
  // characteristics.
  fake_bluetooth_gatt_service_client_->ExposeHeartRateService(
      dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
  ASSERT_EQ(1, observer.gatt_service_added_count());

  BluetoothRemoteGattService* service =
      device->GetGattService(observer.last_gatt_service_id());

  // Run the message loop so that the characteristics appear.
  {
    base::RunLoop loop;
    observer.set_quit_closure(loop.QuitWhenIdleClosure());
    loop.Run();
  }

  BluetoothRemoteGattCharacteristic* characteristic =
      service->GetCharacteristic(fake_bluetooth_gatt_characteristic_client_
                                     ->GetHeartRateMeasurementPath()
                                     .value());

  // Request to start notifications.
  {
    base::RunLoop loop;
    characteristic->StartNotifySession(
        device::BluetoothGattCharacteristic::NotificationType::kNotification,
        base::BindLambdaForTesting(
            [&loop, this](std::unique_ptr<BluetoothGattNotifySession> session) {
              NotifySessionCallback(std::move(session));
              loop.Quit();
            }),
        base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                       base::Unretained(this)));
    loop.Run();
  }
  EXPECT_EQ(1, observer.gatt_characteristic_value_changed_count());

  // Request to start indications.
  fake_bluetooth_gatt_characteristic_client_->StopNotify(
      fake_bluetooth_gatt_characteristic_client_->GetHeartRateMeasurementPath(),
      base::BindOnce(&BluetoothGattBlueZTest::SuccessCallback,
                     base::Unretained(this)),
      base::BindOnce(&BluetoothGattBlueZTest::DBusErrorCallback,
                     base::Unretained(this)));
  {
    base::RunLoop loop;
    characteristic->StartNotifySession(
        device::BluetoothGattCharacteristic::NotificationType::kIndication,
        base::BindLambdaForTesting(
            [&loop, this](std::unique_ptr<BluetoothGattNotifySession> session) {
              NotifySessionCallback(std::move(session));
              loop.Quit();
            }),
        base::BindOnce(&BluetoothGattBlueZTest::ServiceErrorCallback,
                       base::Unretained(this)));
    loop.Run();
  }
  EXPECT_EQ(2, observer.gatt_characteristic_value_changed_count());
}
#endif  // BUILDFLAG(IS_CHROMEOS)

TEST_F(BluetoothGattBlueZTest, MultipleDevices) {}
}  // namespace bluez