Commit ab253b0f authored by Conley Owens's avatar Conley Owens Committed by Commit Bot

Add RemoveFakeCharacteristic to BT test interface

We need to be able to simulate the removal of a characteristic.  This
addition to the interface seems to be the most straightforward way of
accomplishing this goal.

BUG=569709

Change-Id: If700ea99a6df9badc98fc81ef5f7461e574b7985
Reviewed-on: https://chromium-review.googlesource.com/583640Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarVincent Scheib <scheib@chromium.org>
Commit-Queue: Conley Owens <cco3@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491097}
parent 091a3283
......@@ -105,6 +105,12 @@ interface FakeCentral {
// have completed or if there was an error during any of them.
SetNextGATTDiscoveryResponse(string address, uint16 code) => (bool success);
// Signals a state change in a BluetoothRemoteGATTService. This involves any
// characteristics and/or descriptors that get added or removed from the
// service, as well as Service Changed indications from the remote device.
// https://webbluetoothcg.github.io/web-bluetooth/#event-types
SimulateGATTServicesChanged(string address) => (bool success);
// Adds a fake GATT Service with |service_uuid| to |peripheral_address|
// peripheral. The service will be found found when discovering the
// peripheral's GATT Attributes. Runs its callback with the fake service's Id.
......@@ -123,6 +129,13 @@ interface FakeCentral {
string service_id,
string peripheral_address) => (string? characteristic_id);
// Removes a fake GATT Characteristic with |identifier| to the fake service
// with |service_id| in |peripheral_address| peripheral.
RemoveFakeCharacteristic(
string identifier,
string service_id,
string peripheral_address) => (bool success);
// Adds a fake GATT Descriptor with |descriptor_uuid| to the fake service with
// |service_id| in |peripheral_address| peripheral. The descriptor will be
// found when discovering the peripheral's GATT Attributes. Runs its callback
......
......@@ -78,6 +78,12 @@ void FakeCentral::SetNextGATTDiscoveryResponse(
std::move(callback).Run(true);
}
void FakeCentral::SimulateGATTServicesChanged(
const std::string& address,
SimulateGATTServicesChangedCallback callback) {
std::move(callback).Run(true);
}
void FakeCentral::AddFakeService(const std::string& peripheral_address,
const device::BluetoothUUID& service_uuid,
AddFakeServiceCallback callback) {
......@@ -113,6 +119,29 @@ void FakeCentral::AddFakeCharacteristic(
characteristic_uuid, std::move(properties)));
}
void FakeCentral::RemoveFakeCharacteristic(
const std::string& identifier,
const std::string& service_id,
const std::string& peripheral_address,
RemoveFakeCharacteristicCallback callback) {
auto device_iter = devices_.find(peripheral_address);
if (device_iter == devices_.end()) {
std::move(callback).Run(false);
return;
}
FakeRemoteGattService* fake_remote_gatt_service =
static_cast<FakeRemoteGattService*>(
device_iter->second.get()->GetGattService(service_id));
if (fake_remote_gatt_service == nullptr) {
std::move(callback).Run(false);
return;
}
std::move(callback).Run(
fake_remote_gatt_service->RemoveFakeCharacteristic(identifier));
}
void FakeCentral::AddFakeDescriptor(
const device::BluetoothUUID& descriptor_uuid,
const std::string& characteristic_id,
......
......@@ -41,6 +41,9 @@ class FakeCentral : NON_EXPORTED_BASE(public mojom::FakeCentral),
const std::string& address,
uint16_t code,
SetNextGATTDiscoveryResponseCallback callback) override;
void SimulateGATTServicesChanged(
const std::string& address,
SimulateGATTServicesChangedCallback callback) override;
void AddFakeService(const std::string& peripheral_address,
const device::BluetoothUUID& service_uuid,
AddFakeServiceCallback callback) override;
......@@ -49,6 +52,11 @@ class FakeCentral : NON_EXPORTED_BASE(public mojom::FakeCentral),
const std::string& service_id,
const std::string& peripheral_address,
AddFakeCharacteristicCallback callback) override;
void RemoveFakeCharacteristic(
const std::string& identifier,
const std::string& service_id,
const std::string& peripheral_address,
RemoveFakeCharacteristicCallback callback) override;
void AddFakeDescriptor(const device::BluetoothUUID& characteristic_uuid,
const std::string& characteristic_id,
const std::string& service_id,
......
......@@ -50,6 +50,18 @@ std::string FakeRemoteGattService::AddFakeCharacteristic(
return it->second->GetIdentifier();
}
bool FakeRemoteGattService::RemoveFakeCharacteristic(
const std::string& identifier) {
GetCharacteristic(identifier);
const auto& it = fake_characteristics_.find(identifier);
if (it == fake_characteristics_.end()) {
return false;
}
fake_characteristics_.erase(it);
return true;
}
std::string FakeRemoteGattService::GetIdentifier() const {
return service_id_;
}
......
......@@ -38,6 +38,9 @@ class FakeRemoteGattService : public device::BluetoothRemoteGattService {
const device::BluetoothUUID& characteristic_uuid,
mojom::CharacteristicPropertiesPtr properties);
// Removes a fake characteristic with |identifier| from this service.
bool RemoveFakeCharacteristic(const std::string& identifier);
// device::BluetoothGattService overrides:
std::string GetIdentifier() const override;
device::BluetoothUUID GetUUID() const override;
......
......@@ -8,24 +8,15 @@
<script>
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.getDescriptor(user_description.name),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.getDescriptor(user_description.name), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
</script>
......@@ -8,24 +8,15 @@
<script>
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.getDescriptors(user_description.name),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.getDescriptors(user_description.name), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
</script>
......@@ -8,24 +8,15 @@
<script>
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.getDescriptors(),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.getDescriptors(), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
</script>
......@@ -8,24 +8,15 @@
<script>
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.readValue(),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.readValue(), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
</script>
......@@ -8,24 +8,15 @@
<script>
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.startNotifications(),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.startNotifications(), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
</script>
......@@ -8,24 +8,15 @@
<script>
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.writeValue(val),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.writeValue(new Uint8Array(1)), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
</script>
......@@ -119,13 +119,10 @@ def GetGeneratedTests():
# replacing CALLS.
new_test_file_data = new_test_file_data.replace('PREVIOUS_CALL', 'CALLS')
calls = result.group(1)
calls = ''.join(calls.split()) # Removes whitespace.
calls = calls.split('|')
for call in calls:
for call in result.group(1).split('|'):
# Parse call
function_name, args, uuid_suffix = re.search(r'(.*?)\((.*?)\)(\[UUID\])?', call).groups()
call = call.strip()
function_name, args, uuid_suffix = re.search(r'(.*?)\((.*)\)(\[UUID\])?', call).groups()
# Replace template tokens
call_test_file_data = new_test_file_data
......
'use strict';
promise_test(() => {
let val = new Uint8Array([1]);
return setBluetoothFakeAdapter('HeartRateAdapter')
.then(() => requestDeviceWithKeyDown({
filters: [{services: ['heart_rate']}],
optionalServices: ['generic_access']}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryService('generic_access'))
.then(service => service.getCharacteristic('gap.device_name'))
.then(characteristic => {
return setBluetoothFakeAdapter('MissingCharacteristicHeartRateAdapter')
.then(() => assert_promise_rejects_with_message(
characteristic.CALLS([
getDescriptor(user_description.name)|
getDescriptors(user_description.name)[UUID]|
getDescriptors()|
readValue()|
writeValue(val)|
startNotifications()]),
new DOMException(
'GATT Characteristic no longer exists.',
'InvalidStateError'),
'Characteristic got removed.'));
});
let fake_peripheral, characteristic, fake_characteristic;
return getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(characteristic.CALLS([
getDescriptor(user_description.name)|
getDescriptors(user_description.name)[UUID]|
getDescriptors()|
readValue()|
writeValue(new Uint8Array(1))|
startNotifications()
]), new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError')));
}, 'Characteristic gets removed. Reject with InvalidStateError.');
......@@ -235,6 +235,23 @@
if (success !== true) throw 'setNextGATTDiscoveryResponse failed.';
}
// Simulates an Indication from the peripheral's GATT `Service Changed`
// Characteristic from BT 4.2 Vol 3 Part G 7.1. This Indication is signaled
// when services, characteristics, or descriptors are changed, added, or
// removed.
//
// The value for `Service Changed` is a range of attribute handles that have
// changed. However, this testing specification works at an abstracted
// level and does not expose setting attribute handles when adding
// attributes. Consequently, this simulate method should include the full
// range of all the peripheral's attribute handle values.
async simulateGATTServicesChanged() {
let {success} =
await this.fake_central_ptr_.simulateGATTServicesChanged(this.address);
if (success !== true) throw 'simulateGATTServicesChanged failed.';
}
}
class FakeRemoteGATTService {
......@@ -336,6 +353,13 @@
return value;
}
// Removes the fake GATT Characteristic from its fake service.
async remove() {
let {success} =
await this.fake_central_ptr_.removeFakeCharacteristic(...this.ids_);
if (!success) throw 'remove failed';
}
}
class FakeRemoteGATTDescriptor {
......
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