#include "chrome/browser/ash/arc/bluetooth/arc_bluetooth_bridge.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/system/sys_info.h"
#include "base/test/bind.h"
#include "base/test/scoped_chromeos_version_info.h"
#include "base/test/task_environment.h"
#include "chrome/browser/ash/arc/bluetooth/arc_bluez_bridge.h"
#include "chromeos/ash/experiences/arc/bluetooth/bluetooth_type_converters.h"
#include "chromeos/ash/experiences/arc/mojom/bluetooth.mojom.h"
#include "chromeos/ash/experiences/arc/session/arc_bridge_service.h"
#include "chromeos/ash/experiences/arc/test/connection_holder_util.h"
#include "chromeos/ash/experiences/arc/test/fake_bluetooth_instance.h"
#include "device/bluetooth/bluetooth_discovery_session.h"
#include "device/bluetooth/dbus/bluez_dbus_manager.h"
#include "device/bluetooth/dbus/fake_bluetooth_adapter_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_le_advertising_manager_client.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
constexpr int16_t kTestRssi = -50;
constexpr int16_t kTestRssi2 = -70;
constexpr char kTestServiceUUID[] = "00001357-0000-1000-8000-00805f9b34fb";
const std::vector<uint8_t> kEIR = {0x00, 0x01, 0x02};
}
namespace arc {
constexpr int kFailureAdvHandle = -1;
class ArcBluetoothBridgeTest : public testing::Test {
protected:
void StartDiscovery() {
base::RunLoop run_loop;
adapter_->StartDiscoverySession(
std::string(),
base::BindLambdaForTesting(
[this, &run_loop](std::unique_ptr<device::BluetoothDiscoverySession>
discovery_session) {
arc_bluetooth_bridge_->discovery_session_ =
std::move(discovery_session);
run_loop.Quit();
}),
base::DoNothing());
run_loop.Run();
}
void AddTestDevice() {
bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
auto* fake_bluetooth_device_client =
static_cast<bluez::FakeBluetoothDeviceClient*>(
dbus_manager->GetBluetoothDeviceClient());
auto* fake_bluetooth_gatt_service_client =
static_cast<bluez::FakeBluetoothGattServiceClient*>(
dbus_manager->GetBluetoothGattServiceClient());
auto* fake_bluetooth_gatt_characteristic_client =
static_cast<bluez::FakeBluetoothGattCharacteristicClient*>(
dbus_manager->GetBluetoothGattCharacteristicClient());
fake_bluetooth_device_client->CreateDevice(
dbus::ObjectPath(bluez::FakeBluetoothAdapterClient::kAdapterPath),
dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
fake_bluetooth_device_client->UpdateServiceAndManufacturerData(
dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath),
{kTestServiceUUID}, {},
{});
fake_bluetooth_device_client->UpdateEIR(
dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath),
kEIR);
fake_bluetooth_gatt_service_client->ExposeHeartRateService(
dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
fake_bluetooth_gatt_characteristic_client->ExposeHeartRateCharacteristics(
fake_bluetooth_gatt_service_client->GetHeartRateServicePath());
ChangeTestDeviceRssi(kTestRssi);
}
void ChangeTestDeviceRssi(uint16_t rssi) {
bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
auto* fake_bluetooth_device_client =
static_cast<bluez::FakeBluetoothDeviceClient*>(
dbus_manager->GetBluetoothDeviceClient());
fake_bluetooth_device_client->UpdateDeviceRSSI(
dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath),
rssi);
}
void ChangeTestDeviceConnected(bool connected) {
bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
auto* fake_bluetooth_device_client =
static_cast<bluez::FakeBluetoothDeviceClient*>(
dbus_manager->GetBluetoothDeviceClient());
bluez::FakeBluetoothDeviceClient::Properties* properties =
fake_bluetooth_device_client->GetProperties(
dbus::ObjectPath(bluez::FakeBluetoothDeviceClient::kLowEnergyPath));
properties->connected.ReplaceValue(connected);
}
void OnAdapterInitialized(scoped_refptr<device::BluetoothAdapter> adapter) {
adapter_ = adapter;
get_adapter_run_loop_.Quit();
}
void SetUp() override {
std::unique_ptr<bluez::BluezDBusManagerSetter> dbus_setter =
bluez::BluezDBusManager::GetSetterForTesting();
auto fake_bluetooth_device_client =
std::make_unique<bluez::FakeBluetoothDeviceClient>();
fake_bluetooth_device_client->RemoveAllDevices();
dbus_setter->SetBluetoothDeviceClient(
std::move(fake_bluetooth_device_client));
auto fake_bluetooth_adapter_client =
std::make_unique<bluez::FakeBluetoothAdapterClient>();
fake_bluetooth_adapter_client->SetDiscoverySimulation(false);
fake_bluetooth_adapter_client->SetSimulationIntervalMs(0);
dbus_setter->SetBluetoothAdapterClient(
std::move(fake_bluetooth_adapter_client));
dbus_setter->SetBluetoothGattServiceClient(
std::make_unique<bluez::FakeBluetoothGattServiceClient>());
dbus_setter->SetBluetoothGattCharacteristicClient(
std::make_unique<bluez::FakeBluetoothGattCharacteristicClient>());
dbus_setter->SetBluetoothGattDescriptorClient(
std::make_unique<bluez::FakeBluetoothGattDescriptorClient>());
arc_bridge_service_ = std::make_unique<ArcBridgeService>();
arc_bluetooth_bridge_ =
std::make_unique<ArcBluezBridge>(nullptr, arc_bridge_service_.get());
fake_bluetooth_instance_ = std::make_unique<FakeBluetoothInstance>();
arc_bridge_service_->bluetooth()->SetInstance(
fake_bluetooth_instance_.get(), 20);
WaitForInstanceReady(arc_bridge_service_->bluetooth());
device::BluetoothAdapterFactory::Get()->GetAdapter(base::BindOnce(
&ArcBluetoothBridgeTest::OnAdapterInitialized, base::Unretained(this)));
get_adapter_run_loop_.Run();
}
void TearDown() override {
arc_bridge_service_->bluetooth()->CloseInstance(
fake_bluetooth_instance_.get());
fake_bluetooth_instance_.reset();
arc_bluetooth_bridge_.reset();
arc_bridge_service_.reset();
}
int32_t ReserveAdvertisementHandle() {
constexpr int kSentinelHandle = -2;
last_adv_handle_ = kSentinelHandle;
arc_bluetooth_bridge_->ReserveAdvertisementHandle(base::BindOnce(
&ArcBluetoothBridgeTest::ReserveAdvertisementHandleCallback,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
EXPECT_NE(kSentinelHandle, last_adv_handle_);
return last_adv_handle_;
}
mojom::BluetoothGattStatus EnableAdvertisement(
int adv_handle,
std::unique_ptr<device::BluetoothAdvertisement::Data> data) {
last_status_ = mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED;
arc_bluetooth_bridge_->EnableAdvertisement(
adv_handle, std::move(data),
base::BindOnce(&ArcBluetoothBridgeTest::StatusSetterCallback,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
EXPECT_NE(mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED,
last_status_);
return last_status_;
}
mojom::BluetoothGattStatus DisableAdvertisement(int adv_handle) {
last_status_ = mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED;
arc_bluetooth_bridge_->DisableAdvertisement(
adv_handle,
base::BindOnce(&ArcBluetoothBridgeTest::StatusSetterCallback,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
EXPECT_NE(mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED,
last_status_);
return last_status_;
}
mojom::BluetoothGattStatus ReleaseAdvertisementHandle(int adv_handle) {
last_status_ = mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED;
arc_bluetooth_bridge_->ReleaseAdvertisementHandle(
adv_handle,
base::BindOnce(&ArcBluetoothBridgeTest::StatusSetterCallback,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
EXPECT_NE(mojom::BluetoothGattStatus::GATT_REQUEST_NOT_SUPPORTED,
last_status_);
return last_status_;
}
void ReserveAdvertisementHandleCallback(mojom::BluetoothGattStatus status,
int32_t adv_handle) {
if (status == mojom::BluetoothGattStatus::GATT_FAILURE)
last_adv_handle_ = kFailureAdvHandle;
else
last_adv_handle_ = adv_handle;
}
void StatusSetterCallback(mojom::BluetoothGattStatus status) {
last_status_ = status;
}
int NumActiveAdvertisements() {
bluez::FakeBluetoothLEAdvertisingManagerClient* adv_client =
static_cast<bluez::FakeBluetoothLEAdvertisingManagerClient*>(
bluez::BluezDBusManager::Get()
->GetBluetoothLEAdvertisingManagerClient());
return adv_client->currently_registered();
}
int last_adv_handle_;
mojom::BluetoothGattStatus last_status_;
std::unique_ptr<ArcBridgeService> arc_bridge_service_;
std::unique_ptr<FakeBluetoothInstance> fake_bluetooth_instance_;
std::unique_ptr<ArcBluetoothBridge> arc_bluetooth_bridge_;
scoped_refptr<device::BluetoothAdapter> adapter_;
base::test::SingleThreadTaskEnvironment task_environment_;
base::RunLoop get_adapter_run_loop_;
};
TEST_F(ArcBluetoothBridgeTest, DeviceFound) {
EXPECT_EQ(0u, fake_bluetooth_instance_->device_found_data().size());
EXPECT_EQ(0u,
fake_bluetooth_instance_->device_properties_changed_data().size());
StartDiscovery();
AddTestDevice();
EXPECT_EQ(1u, fake_bluetooth_instance_->device_found_data().size());
EXPECT_EQ(4u,
fake_bluetooth_instance_->device_properties_changed_data().size());
const std::vector<mojom::BluetoothPropertyPtr>& prop =
fake_bluetooth_instance_->device_properties_changed_data().back();
EXPECT_EQ(7u, prop.size());
EXPECT_TRUE(prop[0]->is_bdname());
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
prop[0]->get_bdname());
EXPECT_TRUE(prop[1]->is_bdaddr());
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
prop[1]->get_bdaddr()->To<std::string>());
EXPECT_TRUE(prop[2]->is_uuids());
EXPECT_THAT(
prop[2]->get_uuids(),
testing::UnorderedElementsAre(
device::BluetoothUUID(
bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID),
device::BluetoothUUID(kTestServiceUUID)));
EXPECT_TRUE(prop[3]->is_device_class());
EXPECT_EQ(bluez::FakeBluetoothDeviceClient::kLowEnergyClass,
prop[3]->get_device_class());
EXPECT_TRUE(prop[4]->is_device_type());
EXPECT_TRUE(prop[5]->is_remote_friendly_name());
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyName),
prop[5]->get_remote_friendly_name());
EXPECT_TRUE(prop[6]->is_remote_rssi());
EXPECT_EQ(kTestRssi, prop[6]->get_remote_rssi());
ChangeTestDeviceRssi(kTestRssi2);
EXPECT_EQ(1u, fake_bluetooth_instance_->device_found_data().size());
EXPECT_EQ(5u,
fake_bluetooth_instance_->device_properties_changed_data().size());
const std::vector<mojom::BluetoothPropertyPtr>& prop2 =
fake_bluetooth_instance_->device_properties_changed_data().back();
EXPECT_EQ(7u, prop2.size());
EXPECT_TRUE(prop2[6]->is_remote_rssi());
EXPECT_EQ(kTestRssi2, prop2[6]->get_remote_rssi());
}
TEST_F(ArcBluetoothBridgeTest, LEDeviceFound) {
base::test::ScopedChromeOSVersionInfo version(
"CHROMEOS_ARC_ANDROID_SDK_VERSION=28", base::Time::Now());
EXPECT_EQ(0u, fake_bluetooth_instance_->le_device_found_data().size());
StartDiscovery();
AddTestDevice();
EXPECT_EQ(3u, fake_bluetooth_instance_->le_device_found_data().size());
const auto& le_device_found_data =
fake_bluetooth_instance_->le_device_found_data().back();
const mojom::BluetoothAddressPtr& addr = le_device_found_data->addr();
const std::vector<uint8_t>& eir = le_device_found_data->eir();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
addr->To<std::string>());
EXPECT_EQ(kEIR, eir);
EXPECT_EQ(kTestRssi, le_device_found_data->rssi());
ChangeTestDeviceRssi(kTestRssi2);
EXPECT_EQ(4u, fake_bluetooth_instance_->le_device_found_data().size());
EXPECT_EQ(kTestRssi2,
fake_bluetooth_instance_->le_device_found_data().back()->rssi());
}
TEST_F(ArcBluetoothBridgeTest, DeviceConnectStateChangedAfterLEConnectReuqest) {
StartDiscovery();
AddTestDevice();
arc_bluetooth_bridge_->ConnectLEDevice(mojom::BluetoothAddress::From(
std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress)));
ASSERT_EQ(1u,
fake_bluetooth_instance_->connection_state_changed_data().size());
const auto& connected_data =
fake_bluetooth_instance_->connection_state_changed_data().back();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
connected_data->addr()->To<std::string>());
EXPECT_EQ(device::BLUETOOTH_TRANSPORT_LE, connected_data->device_type());
EXPECT_EQ(true, connected_data->connected());
ASSERT_EQ(1u,
fake_bluetooth_instance_->le_connection_state_change_data().size());
const auto& le_connected_data =
fake_bluetooth_instance_->le_connection_state_change_data().back();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
le_connected_data->addr()->To<std::string>());
EXPECT_EQ(true, le_connected_data->connected());
ChangeTestDeviceConnected(false);
ASSERT_EQ(2u,
fake_bluetooth_instance_->connection_state_changed_data().size());
const auto& disconnected_data =
fake_bluetooth_instance_->connection_state_changed_data().back();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
disconnected_data->addr()->To<std::string>());
EXPECT_EQ(device::BLUETOOTH_TRANSPORT_LE, disconnected_data->device_type());
EXPECT_EQ(false, disconnected_data->connected());
ASSERT_EQ(2u,
fake_bluetooth_instance_->le_connection_state_change_data().size());
const auto& le_disconnected_data =
fake_bluetooth_instance_->le_connection_state_change_data().back();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
le_disconnected_data->addr()->To<std::string>());
EXPECT_EQ(false, le_disconnected_data->connected());
}
TEST_F(ArcBluetoothBridgeTest,
DeviceConnectStateChangedWithoutLEConnectRequest) {
StartDiscovery();
AddTestDevice();
ChangeTestDeviceConnected(true);
ASSERT_EQ(1u,
fake_bluetooth_instance_->connection_state_changed_data().size());
const auto& connected_data =
fake_bluetooth_instance_->connection_state_changed_data().back();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
connected_data->addr()->To<std::string>());
EXPECT_EQ(device::BLUETOOTH_TRANSPORT_LE, connected_data->device_type());
EXPECT_EQ(true, connected_data->connected());
ASSERT_EQ(0u,
fake_bluetooth_instance_->le_connection_state_change_data().size());
ChangeTestDeviceConnected(false);
ASSERT_EQ(2u,
fake_bluetooth_instance_->connection_state_changed_data().size());
const auto& disconnected_data =
fake_bluetooth_instance_->connection_state_changed_data().back();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
disconnected_data->addr()->To<std::string>());
EXPECT_EQ(device::BLUETOOTH_TRANSPORT_LE, disconnected_data->device_type());
EXPECT_EQ(false, disconnected_data->connected());
ASSERT_EQ(0u,
fake_bluetooth_instance_->le_connection_state_change_data().size());
}
TEST_F(ArcBluetoothBridgeTest, GetGattDB) {
StartDiscovery();
AddTestDevice();
arc_bluetooth_bridge_->GetGattDB(mojom::BluetoothAddress::From(
std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress)));
EXPECT_EQ(1u, fake_bluetooth_instance_->gatt_db_result().size());
const mojom::BluetoothAddressPtr& addr =
fake_bluetooth_instance_->gatt_db_result().back()->remote_addr();
EXPECT_EQ(std::string(bluez::FakeBluetoothDeviceClient::kLowEnergyAddress),
addr->To<std::string>());
const std::vector<mojom::BluetoothGattDBElementPtr>& db =
fake_bluetooth_instance_->gatt_db_result().back()->db();
EXPECT_EQ(5u, db.size());
EXPECT_EQ(device::BluetoothUUID(
bluez::FakeBluetoothGattServiceClient::kHeartRateServiceUUID),
db[0]->uuid);
EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_PRIMARY_SERVICE,
db[0]->type);
EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
kHeartRateMeasurementUUID),
db[1]->uuid);
EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
db[1]->type);
EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_NOTIFY |
device::BluetoothGattCharacteristic::PROPERTY_INDICATE,
db[1]->properties);
EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattDescriptorClient::
kClientCharacteristicConfigurationUUID),
db[2]->uuid);
EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_DESCRIPTOR,
db[2]->type);
EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
kBodySensorLocationUUID),
db[3]->uuid);
EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
db[3]->type);
EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_READ,
db[3]->properties);
EXPECT_EQ(device::BluetoothUUID(bluez::FakeBluetoothGattCharacteristicClient::
kHeartRateControlPointUUID),
db[4]->uuid);
EXPECT_EQ(mojom::BluetoothGattDBAttributeType::BTGATT_DB_CHARACTERISTIC,
db[4]->type);
EXPECT_EQ(device::BluetoothGattCharacteristic::PROPERTY_WRITE,
db[4]->properties);
}
TEST_F(ArcBluetoothBridgeTest, SingleAdvertisement) {
int32_t handle = ReserveAdvertisementHandle();
EXPECT_NE(kFailureAdvHandle, handle);
EXPECT_EQ(0, NumActiveAdvertisements());
auto adv_data = std::make_unique<device::BluetoothAdvertisement::Data>(
device::BluetoothAdvertisement::ADVERTISEMENT_TYPE_BROADCAST);
mojom::BluetoothGattStatus status =
EnableAdvertisement(handle, std::move(adv_data));
EXPECT_EQ(mojom::BluetoothGattStatus::GATT_SUCCESS, status);
EXPECT_EQ(1, NumActiveAdvertisements());
status = DisableAdvertisement(handle);
EXPECT_EQ(mojom::BluetoothGattStatus::GATT_SUCCESS, status);
EXPECT_EQ(0, NumActiveAdvertisements());
status = ReleaseAdvertisementHandle(handle);
EXPECT_EQ(mojom::BluetoothGattStatus::GATT_SUCCESS, status);
EXPECT_EQ(0, NumActiveAdvertisements());
}
TEST_F(ArcBluetoothBridgeTest, ServiceChanged) {
StartDiscovery();
AddTestDevice();
bluez::BluezDBusManager* dbus_manager = bluez::BluezDBusManager::Get();
auto* fake_bluetooth_gatt_service_client =
static_cast<bluez::FakeBluetoothGattServiceClient*>(
dbus_manager->GetBluetoothGattServiceClient());
device::BluetoothDevice* device = adapter_->GetDevices()[0];
device::BluetoothRemoteGattService* service =
device->GetGattService(fake_bluetooth_gatt_service_client->GetHeartRateServicePath().value());
fake_bluetooth_instance_->reset_service_changed_flag();
EXPECT_FALSE(fake_bluetooth_instance_->get_service_changed_flag());
arc_bluetooth_bridge_->GattServiceAdded(adapter_.get(), device, service);
EXPECT_TRUE(fake_bluetooth_instance_->get_service_changed_flag());
fake_bluetooth_instance_->reset_service_changed_flag();
EXPECT_FALSE(fake_bluetooth_instance_->get_service_changed_flag());
arc_bluetooth_bridge_->GattServiceRemoved(adapter_.get(), device, service);
EXPECT_TRUE(fake_bluetooth_instance_->get_service_changed_flag());
fake_bluetooth_instance_->reset_service_changed_flag();
EXPECT_FALSE(fake_bluetooth_instance_->get_service_changed_flag());
arc_bluetooth_bridge_->GattServiceChanged(adapter_.get(), service);
EXPECT_TRUE(fake_bluetooth_instance_->get_service_changed_flag());
}
TEST_F(ArcBluetoothBridgeTest, ReadMissingDescriptorFailsGracefully) {
base::RunLoop run_loop;
arc_bluetooth_bridge_->ReadGattDescriptor(
mojom::BluetoothAddress::New(),
mojom::BluetoothGattServiceID::New(),
mojom::BluetoothGattID::New(),
mojom::BluetoothGattID::New(),
base::BindOnce(
[](base::RepeatingClosure quit_closure,
mojom::BluetoothGattValuePtr value) {
ASSERT_TRUE(value);
EXPECT_TRUE(value->value.empty());
EXPECT_EQ(value->status, mojom::BluetoothGattStatus::GATT_FAILURE);
quit_closure.Run();
},
run_loop.QuitClosure()));
run_loop.Run();
}
TEST_F(ArcBluetoothBridgeTest, WritingMissingDescriptorFailsGracefully) {
base::RunLoop run_loop;
arc_bluetooth_bridge_->WriteGattDescriptor(
mojom::BluetoothAddress::New(),
mojom::BluetoothGattServiceID::New(),
mojom::BluetoothGattID::New(),
mojom::BluetoothGattID::New(),
mojom::BluetoothGattValue::New(),
base::BindOnce(
[](base::RepeatingClosure quit_closure,
mojom::BluetoothGattStatus status) {
EXPECT_EQ(status, mojom::BluetoothGattStatus::GATT_FAILURE);
quit_closure.Run();
},
run_loop.QuitClosure()));
run_loop.Run();
}
TEST_F(ArcBluetoothBridgeTest, ReadMissingCharacteristicFailsGracefully) {
base::RunLoop run_loop;
arc_bluetooth_bridge_->ReadGattCharacteristic(
mojom::BluetoothAddress::New(),
mojom::BluetoothGattServiceID::New(),
mojom::BluetoothGattID::New(),
base::BindOnce(
[](base::RepeatingClosure quit_closure,
mojom::BluetoothGattValuePtr value) {
ASSERT_TRUE(value);
EXPECT_TRUE(value->value.empty());
EXPECT_EQ(value->status, mojom::BluetoothGattStatus::GATT_FAILURE);
quit_closure.Run();
},
run_loop.QuitClosure()));
run_loop.Run();
}
TEST_F(ArcBluetoothBridgeTest, WriteMissingCharacteristicFailsGracefully) {
base::RunLoop run_loop;
arc_bluetooth_bridge_->WriteGattCharacteristic(
mojom::BluetoothAddress::New(),
mojom::BluetoothGattServiceID::New(),
mojom::BluetoothGattID::New(),
mojom::BluetoothGattValue::New(),
false,
base::BindOnce(
[](base::RepeatingClosure quit_closure,
mojom::BluetoothGattStatus status) {
EXPECT_EQ(status, mojom::BluetoothGattStatus::GATT_FAILURE);
quit_closure.Run();
},
run_loop.QuitClosure()));
run_loop.Run();
}
TEST_F(ArcBluetoothBridgeTest, SetDiscoverabilityAndTimeout) {
arc_bluetooth_bridge_->SetAdapterProperty(
mojom::BluetoothProperty::NewAdapterScanMode(
mojom::BluetoothScanMode::CONNECTABLE_DISCOVERABLE));
ASSERT_FALSE(adapter_->IsDiscoverable());
arc_bluetooth_bridge_->SetAdapterProperty(
mojom::BluetoothProperty::NewDiscoveryTimeout(0));
arc_bluetooth_bridge_->SetAdapterProperty(
mojom::BluetoothProperty::NewAdapterScanMode(
mojom::BluetoothScanMode::CONNECTABLE_DISCOVERABLE));
ASSERT_TRUE(adapter_->IsDiscoverable());
}
TEST_F(ArcBluetoothBridgeTest, NoLEDeviceFoundIfNotScanning) {
EXPECT_EQ(0u, fake_bluetooth_instance_->le_device_found_data().size());
AddTestDevice();
EXPECT_EQ(0u, fake_bluetooth_instance_->le_device_found_data().size());
}
}