Commit db0faa44 authored by ortuno's avatar ortuno Committed by Commit bot

bluetooth: Implement simulatePreconnectedPeripheral.

simulatePreconnectedPeripherals allows clients to simulate peripherals
that already connected to the system but that the UA doesn't know about.

Adds a new helper method to create system-connected devices and uses
the method in a couple of tests.

BUG=569709

Review-Url: https://codereview.chromium.org/2858803003
Cr-Commit-Position: refs/heads/master@{#471190}
parent b26c3a43
......@@ -182,18 +182,12 @@ LayoutTestBluetoothAdapterProvider::GetBluetoothAdapter(
return GetFailStartDiscoveryAdapter();
if (fake_adapter_name == "GlucoseHeartRateAdapter")
return GetGlucoseHeartRateAdapter();
if (fake_adapter_name == "UnicodeDeviceAdapter")
return GetUnicodeDeviceAdapter();
if (fake_adapter_name == "DeviceNameLongerThan29BytesAdapter")
return GetDeviceNameLongerThan29BytesAdapter();
if (fake_adapter_name == "MissingServiceHeartRateAdapter")
return GetMissingServiceHeartRateAdapter();
if (fake_adapter_name == "MissingCharacteristicHeartRateAdapter")
return GetMissingCharacteristicHeartRateAdapter();
if (fake_adapter_name == "HeartRateAdapter")
return GetHeartRateAdapter();
if (fake_adapter_name == "EmptyNameDeviceAdapter")
return GetEmptyNameDeviceAdapter();
if (fake_adapter_name == "NoNameDeviceAdapter")
return GetNoNameDeviceAdapter();
if (fake_adapter_name == "EmptyNameHeartRateAdapter")
......@@ -380,27 +374,6 @@ LayoutTestBluetoothAdapterProvider::GetGlucoseHeartRateAdapter() {
return adapter;
}
// static
scoped_refptr<NiceMockBluetoothAdapter>
LayoutTestBluetoothAdapterProvider::GetUnicodeDeviceAdapter() {
scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
adapter->AddMockDevice(GetBaseDevice(adapter.get(), "❤❤❤❤❤❤❤❤❤"));
return adapter;
}
// static
scoped_refptr<NiceMockBluetoothAdapter>
LayoutTestBluetoothAdapterProvider::GetDeviceNameLongerThan29BytesAdapter() {
scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
adapter->AddMockDevice(GetBaseDevice(adapter.get(),
"a_device_name_that_is_longer_than_29_bytes_but_shorter_than_248_bytes"));
return adapter;
}
// Adds a device to |adapter| and notifies all observers about that new device.
// Mocks can call this asynchronously to cause changes in the middle of a test.
static void AddDevice(scoped_refptr<NiceMockBluetoothAdapter> adapter,
......@@ -766,16 +739,6 @@ LayoutTestBluetoothAdapterProvider::GetDisconnectingHealthThermometer(
return adapter;
}
// static
scoped_refptr<NiceMockBluetoothAdapter>
LayoutTestBluetoothAdapterProvider::GetEmptyNameDeviceAdapter() {
scoped_refptr<NiceMockBluetoothAdapter> adapter(GetEmptyAdapter());
auto device(GetConnectableDevice(adapter.get(), "" /* device_name */));
adapter->AddMockDevice(std::move(device));
return adapter;
}
// static
scoped_refptr<NiceMockBluetoothAdapter>
LayoutTestBluetoothAdapterProvider::GetNoNameDeviceAdapter() {
......
......@@ -107,24 +107,6 @@ class LayoutTestBluetoothAdapterProvider {
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetGlucoseHeartRateAdapter();
// |GetUnicodeDeviceAdapter|
// Inherits from |EmptyAdapter|
// Internal structure
// - UnicodeDevice
// - Mock Functions:
// - GetName(): Returns "❤❤❤❤❤❤❤❤❤"
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetUnicodeDeviceAdapter();
// |GetDeviceNameLongerThan29BytesAdapter|
// Inherits from |EmptyAdapter|
// Internal structure
// - DeviceNameLongerThan29Bytes
// - Mock Functions:
// - GetName(): Returns "a_device_name_that_is_longer_than_29_bytes_but_shorter_than_248_bytes"
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetDeviceNameLongerThan29BytesAdapter();
// |SecondDiscoveryFindsHeartRateAdapter|
// Inherits from |PoweredAdapter|
// Mock Functions:
......@@ -224,12 +206,6 @@ class LayoutTestBluetoothAdapterProvider {
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetHeartRateAdapter();
// |GetEmptyNameDeviceAdapter|
// Inherits from |EmptyAdapter|
// Contains a single device with an empty name and no UUIDs.
static scoped_refptr<testing::NiceMock<device::MockBluetoothAdapter>>
GetEmptyNameDeviceAdapter();
// |GetNoNameDeviceAdapter|
// Inherits from |EmptyAdapter|
// Contains a single device with no name and no UUIDs.
......
......@@ -47,6 +47,8 @@ source_set("fake_bluetooth") {
"test/fake_bluetooth.h",
"test/fake_central.cc",
"test/fake_central.h",
"test/fake_peripheral.cc",
"test/fake_peripheral.h",
]
deps = [
......
......@@ -38,4 +38,13 @@ interface FakeBluetooth {
// See Bluetooth 4.2 Vol 3 Part C 2.2.2 "Roles when Operating over an
// LE Physical Transport".
interface FakeCentral {
// Simulates a peripheral with |address| and |name| that has already
// been connected to the system. If the peripheral existed already it
// updates its name.
//
// Platforms offer methods to retrieve devices that have already been
// connected to the system or weren't connected through the UA e.g. a user
// connected a peripheral through the system's settings. This method is
// intended to simulate peripherals that those methods would return.
SimulatePreconnectedPeripheral(string address, string name) => ();
};
......@@ -10,6 +10,7 @@
#include "device/bluetooth/bluetooth_discovery_filter.h"
#include "device/bluetooth/public/interfaces/test/fake_bluetooth.mojom.h"
#include "device/bluetooth/test/fake_peripheral.h"
namespace bluetooth {
......@@ -17,7 +18,26 @@ FakeCentral::FakeCentral(mojom::CentralState state,
mojom::FakeCentralRequest request)
: state_(state), binding_(this, std::move(request)) {}
FakeCentral::~FakeCentral() {}
void FakeCentral::SimulatePreconnectedPeripheral(
const std::string& address,
const std::string& name,
SimulatePreconnectedPeripheralCallback callback) {
auto device_iter = devices_.find(address);
if (device_iter == devices_.end()) {
auto fake_peripheral = base::MakeUnique<FakePeripheral>(this, address);
auto insert_iter = devices_.emplace(address, std::move(fake_peripheral));
DCHECK(insert_iter.second);
device_iter = insert_iter.first;
}
FakePeripheral* fake_peripheral =
static_cast<FakePeripheral*>(device_iter->second.get());
fake_peripheral->SetName(name);
fake_peripheral->SetGattConnected(true);
std::move(callback).Run();
}
std::string FakeCentral::GetAddress() const {
NOTREACHED();
......@@ -158,4 +178,6 @@ void FakeCentral::RemovePairingDelegateInternal(
NOTREACHED();
}
FakeCentral::~FakeCentral() {}
} // namespace bluetooth
......@@ -23,6 +23,12 @@ class FakeCentral : NON_EXPORTED_BASE(public mojom::FakeCentral),
public:
FakeCentral(mojom::CentralState state, mojom::FakeCentralRequest request);
// FakeCentral overrides:
void SimulatePreconnectedPeripheral(
const std::string& address,
const std::string& name,
SimulatePreconnectedPeripheralCallback callback) override;
// BluetoothAdapter overrides:
std::string GetAddress() const override;
std::string GetName() const override;
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "device/bluetooth/test/fake_peripheral.h"
namespace bluetooth {
FakePeripheral::FakePeripheral(FakeCentral* fake_central,
const std::string& address)
: device::BluetoothDevice(fake_central),
address_(address),
gatt_connected_(false) {}
FakePeripheral::~FakePeripheral() {}
void FakePeripheral::SetName(base::Optional<std::string> name) {
name_ = name;
}
void FakePeripheral::SetGattConnected(bool connected) {
gatt_connected_ = connected;
}
uint32_t FakePeripheral::GetBluetoothClass() const {
NOTREACHED();
return 0;
}
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
device::BluetoothTransport FakePeripheral::GetType() const {
NOTREACHED();
return device::BLUETOOTH_TRANSPORT_INVALID;
}
#endif
std::string FakePeripheral::GetIdentifier() const {
NOTREACHED();
return std::string();
}
std::string FakePeripheral::GetAddress() const {
return address_;
}
device::BluetoothDevice::VendorIDSource FakePeripheral::GetVendorIDSource()
const {
NOTREACHED();
return VENDOR_ID_UNKNOWN;
}
uint16_t FakePeripheral::GetVendorID() const {
NOTREACHED();
return 0;
}
uint16_t FakePeripheral::GetProductID() const {
NOTREACHED();
return 0;
}
uint16_t FakePeripheral::GetDeviceID() const {
NOTREACHED();
return 0;
}
uint16_t FakePeripheral::GetAppearance() const {
NOTREACHED();
return 0;
}
base::Optional<std::string> FakePeripheral::GetName() const {
return name_;
}
base::string16 FakePeripheral::GetNameForDisplay() const {
return base::string16();
}
bool FakePeripheral::IsPaired() const {
NOTREACHED();
return false;
}
bool FakePeripheral::IsConnected() const {
NOTREACHED();
return false;
}
bool FakePeripheral::IsGattConnected() const {
return gatt_connected_;
}
bool FakePeripheral::IsConnectable() const {
NOTREACHED();
return false;
}
bool FakePeripheral::IsConnecting() const {
NOTREACHED();
return false;
}
device::BluetoothDevice::UUIDSet FakePeripheral::GetUUIDs() const {
return UUIDSet();
}
bool FakePeripheral::ExpectingPinCode() const {
NOTREACHED();
return false;
}
bool FakePeripheral::ExpectingPasskey() const {
NOTREACHED();
return false;
}
bool FakePeripheral::ExpectingConfirmation() const {
NOTREACHED();
return false;
}
void FakePeripheral::GetConnectionInfo(const ConnectionInfoCallback& callback) {
NOTREACHED();
}
void FakePeripheral::Connect(PairingDelegate* pairing_delegate,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::SetPinCode(const std::string& pincode) {
NOTREACHED();
}
void FakePeripheral::SetPasskey(uint32_t passkey) {
NOTREACHED();
}
void FakePeripheral::ConfirmPairing() {
NOTREACHED();
}
void FakePeripheral::RejectPairing() {
NOTREACHED();
}
void FakePeripheral::CancelPairing() {
NOTREACHED();
}
void FakePeripheral::Disconnect(const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::Forget(const base::Closure& callback,
const ErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::ConnectToService(
const device::BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::ConnectToServiceInsecurely(
const device::BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) {
NOTREACHED();
}
void FakePeripheral::CreateGattConnectionImpl() {
NOTREACHED();
}
void FakePeripheral::DisconnectGatt() {
NOTREACHED();
}
} // namespace bluetooth
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef DEVICE_BLUETOOTH_TEST_FAKE_PERIPHERAL_H_
#define DEVICE_BLUETOOTH_TEST_FAKE_PERIPHERAL_H_
#include <string>
#include "base/compiler_specific.h"
#include "base/macros.h"
#include "base/optional.h"
#include "device/bluetooth/bluetooth_device.h"
#include "device/bluetooth/test/fake_central.h"
namespace bluetooth {
// Implements device::BluetoothDevice. Meant to be used by FakeCentral
// to keep track of the peripheral's state and attributes.
class FakePeripheral : public device::BluetoothDevice {
public:
FakePeripheral(FakeCentral* fake_central, const std::string& address);
~FakePeripheral() override;
// Changes the name of the device.
void SetName(base::Optional<std::string> name);
// Set it to indicate if the Peripheral is connected or not.
void SetGattConnected(bool gatt_connected);
// BluetoothDevice overrides:
uint32_t GetBluetoothClass() const override;
#if defined(OS_CHROMEOS) || defined(OS_LINUX)
device::BluetoothTransport GetType() const override;
#endif
std::string GetIdentifier() const override;
std::string GetAddress() const override;
VendorIDSource GetVendorIDSource() const override;
uint16_t GetVendorID() const override;
uint16_t GetProductID() const override;
uint16_t GetDeviceID() const override;
uint16_t GetAppearance() const override;
base::Optional<std::string> GetName() const override;
base::string16 GetNameForDisplay() const override;
bool IsPaired() const override;
bool IsConnected() const override;
bool IsGattConnected() const override;
bool IsConnectable() const override;
bool IsConnecting() const override;
UUIDSet GetUUIDs() const override;
bool ExpectingPinCode() const override;
bool ExpectingPasskey() const override;
bool ExpectingConfirmation() const override;
void GetConnectionInfo(const ConnectionInfoCallback& callback) override;
void Connect(PairingDelegate* pairing_delegate,
const base::Closure& callback,
const ConnectErrorCallback& error_callback) override;
void SetPinCode(const std::string& pincode) override;
void SetPasskey(uint32_t passkey) override;
void ConfirmPairing() override;
void RejectPairing() override;
void CancelPairing() override;
void Disconnect(const base::Closure& callback,
const ErrorCallback& error_callback) override;
void Forget(const base::Closure& callback,
const ErrorCallback& error_callback) override;
void ConnectToService(
const device::BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) override;
void ConnectToServiceInsecurely(
const device::BluetoothUUID& uuid,
const ConnectToServiceCallback& callback,
const ConnectToServiceErrorCallback& error_callback) override;
protected:
void CreateGattConnectionImpl() override;
void DisconnectGatt() override;
private:
const std::string address_;
base::Optional<std::string> name_;
bool gatt_connected_;
DISALLOW_COPY_AND_ASSIGN(FakePeripheral);
};
} // namespace bluetooth
#endif // DEVICE_BLUETOOTH_TEST_FAKE_PERIPHERAL_H_
......@@ -2,10 +2,12 @@
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
<script src="../../../resources/mojo-helpers.js"></script>
<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
<script>
'use strict';
promise_test(() => {
return setBluetoothFakeAdapter('EmptyNameDeviceAdapter')
return setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithKeyDown({acceptAllDevices: true}))
.then(device => {
assert_equals(device.name, '');
......
......@@ -2,11 +2,12 @@
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
<script src="../../../resources/mojo-helpers.js"></script>
<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
<script>
promise_test(() => {
// The UnicodeDevice's name is '❤❤❤❤❤❤❤❤❤'. ❤ = \u2764
let device_name = generate_string(9, '\u2764');
return setBluetoothFakeAdapter('UnicodeDeviceAdapter')
let device_name = 'LE Device';
return setUpPreconnectedDevice({name: device_name})
.then(() => requestDeviceWithKeyDown({acceptAllDevices: true}))
.then(device => {
assert_equals(device.name, device_name);
......
......@@ -2,12 +2,14 @@
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
<script src="../../../resources/mojo-helpers.js"></script>
<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
<script>
'use strict';
promise_test(() => {
const DEVICE_NAME = 'a_device_name_that_is_longer_than_29_bytes_but_shorter_than_248_bytes';
return setBluetoothFakeAdapter('DeviceNameLongerThan29BytesAdapter')
return setUpPreconnectedDevice({name: DEVICE_NAME})
.then(() => requestDeviceWithKeyDown({ filters: [{name: DEVICE_NAME}]}))
.then(device => assert_equals(device.name, DEVICE_NAME));
}, 'A device name between 29 and 248 bytes is valid.');
......
......@@ -2,12 +2,14 @@
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
<script src="../../../resources/mojo-helpers.js"></script>
<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
<script>
promise_test(() => {
let valid_unicode_name = generate_string(
9, '\u2764'); // \u2764's UTF-8 representation is 3 bytes long.
// 9 chars * 3 bytes/char = 27 bytes
return setBluetoothFakeAdapter('UnicodeDeviceAdapter')
return setUpPreconnectedDevice({name: valid_unicode_name})
.then(() => requestDeviceWithKeyDown({
filters: [{name: valid_unicode_name}]}))
.then(device => {
......
......@@ -2,12 +2,14 @@
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/bluetooth/bluetooth-helpers.js"></script>
<script src="../../../resources/mojo-helpers.js"></script>
<script src="../../../resources/bluetooth/web-bluetooth-test.js"></script>
<script>
promise_test(() => {
let valid_unicode_name = generate_string(
9, '\u2764'); // \u2764's UTF-8 representation is 3 bytes long.
// 9 chars * 3 bytes/char = 27 bytes
return setBluetoothFakeAdapter('UnicodeDeviceAdapter')
return setUpPreconnectedDevice({name: valid_unicode_name})
.then(() => requestDeviceWithKeyDown({
filters: [{namePrefix: valid_unicode_name}]}))
.then(device => {
......
......@@ -2,16 +2,15 @@
<script src="../../resources/testharness.js"></script>
<script src="../../resources/testharnessreport.js"></script>
<script src="../../resources/bluetooth/bluetooth-helpers.js"></script>
<script src="../../resources/mojo-helpers.js"></script>
<script src="../../resources/bluetooth/web-bluetooth-test.js"></script>
<script>
'use strict';
promise_test(() => {
return setBluetoothFakeAdapter('EmptyNameHeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{name: ''}],
optionalServices: ['generic_access']}))
.then(device => {
assert_equals(device.name, '');
})
return setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithKeyDown({filters: [{name: ''}]}))
.then(device => {
assert_equals(device.name, '');
});
}, 'An empty name device can be obtained by empty name filter.');
</script>
......@@ -422,3 +422,11 @@ function generateRequestDeviceArgsWithServices(services = ['heart_rate']) {
optionalServices: ['heart_rate']
}];
}
function setUpPreconnectedDevice({address = '00:00:00:00:00:00', name}) {
return navigator.bluetooth.test.simulateCentral({state: 'powered-on'})
.then(fake_central => fake_central.simulatePreconnectedPeripheral({
address: address,
name: name
}));
}
......@@ -116,7 +116,36 @@
// performed by the device in the Central/Observer role.
class FakeCentral {
constructor(fake_central_ptr) {
this.fake_central_ptr = fake_central_ptr;
this.fake_central_ptr_ = fake_central_ptr;
this.peripherals_ = new Map();
}
// Simulates a peripheral with |address| and |name| that has already
// been connected to the system. If the peripheral existed already it
// updates its name.
//
// Platforms offer methods to retrieve devices that have already been
// connected to the system or weren't connected through the UA e.g. a
// user connected a peripheral through the system's settings. This method is
// intended to simulate peripherals that those methods would return.
async simulatePreconnectedPeripheral({address, name}) {
await this.fake_central_ptr_.simulatePreconnectedPeripheral(
address, name);
let peripheral = this.peripherals_.get(address);
if (peripheral === undefined) {
peripheral = new FakePeripheral(address, this);
this.peripherals_.set(address, peripheral);
}
return peripheral;
}
}
class FakePeripheral {
constructor(address, fake_central) {
this.address = address;
this.fake_central_ = fake_central;
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment