summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/bluetooth/service
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/bluetooth/service')
-rw-r--r--testing/web-platform/tests/bluetooth/service/detachedIframe.https.window.js26
-rw-r--r--testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.window.js14
-rw-r--r--testing/web-platform/tests/bluetooth/service/device-same-object.https.window.js13
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.window.js25
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/detachedIframe.https.window.js31
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js23
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js19
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js28
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js39
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js23
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.window.js17
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.window.js39
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.window.js41
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.window.js15
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js23
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js19
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js28
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js28
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js27
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js39
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js39
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js23
-rw-r--r--testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js23
27 files changed, 710 insertions, 0 deletions
diff --git a/testing/web-platform/tests/bluetooth/service/detachedIframe.https.window.js b/testing/web-platform/tests/bluetooth/service/detachedIframe.https.window.js
new file mode 100644
index 0000000000..f75fc225a7
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/detachedIframe.https.window.js
@@ -0,0 +1,26 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+
+bluetooth_test(async () => {
+ let iframe = document.createElement('iframe');
+ const {device} = await getHealthThermometerDeviceFromIframe(iframe);
+ let error;
+
+ iframe.remove();
+ // Set iframe to null to ensure that the GC cleans up as much as possible.
+ iframe = null;
+ await garbageCollect();
+
+ try {
+ await device.gatt.getPrimaryService(health_thermometer.name);
+ } catch (e) {
+ // Cannot use promise_rejects_dom() because |e| is thrown from a different
+ // global.
+ error = e;
+ }
+ assert_not_equals(error, undefined);
+ assert_equals(error.name, 'NetworkError');
+}, 'getPrimaryService() rejects in a detached context');
diff --git a/testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.window.js b/testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.window.js
new file mode 100644
index 0000000000..5b2ba310d3
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/device-same-from-2-services.https.window.js
@@ -0,0 +1,14 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'Same parent device returned from multiple services.';
+
+bluetooth_test(async () => {
+ let {device} = await getTwoHealthThermometerServicesDevice(
+ {filters: [{services: ['health_thermometer']}]});
+ let [service1, service2] =
+ await device.gatt.getPrimaryServices('health_thermometer');
+ assert_equals(service1.device, service2.device);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/device-same-object.https.window.js b/testing/web-platform/tests/bluetooth/service/device-same-object.https.window.js
new file mode 100644
index 0000000000..97da769a9e
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/device-same-object.https.window.js
@@ -0,0 +1,13 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = '[SameObject] test for BluetoothRemoteGATTService device.';
+
+bluetooth_test(async () => {
+ let {device} = await getHealthThermometerDevice(
+ {filters: [{services: ['health_thermometer']}]});
+ let service = await device.gatt.getPrimaryService('health_thermometer');
+ assert_equals(service.device, device);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.window.js
new file mode 100644
index 0000000000..807852ae13
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/characteristic-found.https.window.js
@@ -0,0 +1,25 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'Request for characteristic. Should return right ' +
+ 'characteristic.';
+
+bluetooth_test(async () => {
+ let {device} = await getHealthThermometerDevice();
+ let service = await device.gatt.getPrimaryService('health_thermometer');
+ let characteristics = await Promise.all([
+ service.getCharacteristic(measurement_interval.alias),
+ service.getCharacteristic(measurement_interval.name),
+ service.getCharacteristic(measurement_interval.uuid)
+ ]);
+ characteristics.forEach(characteristic => {
+ assert_equals(
+ characteristic.uuid, measurement_interval.uuid,
+ 'Characteristic UUID should be the same as requested UUID.');
+ assert_equals(
+ characteristic.service, service,
+ 'Characteristic service should be the same as service.');
+ });
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/detachedIframe.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/detachedIframe.https.window.js
new file mode 100644
index 0000000000..ea8c96160f
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/detachedIframe.https.window.js
@@ -0,0 +1,31 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+
+bluetooth_test(async () => {
+ let iframe = document.createElement('iframe');
+ let error;
+
+ const {device, fakes} = await getHealthThermometerDeviceFromIframe(iframe);
+ await fakes.fake_peripheral.setNextGATTDiscoveryResponse({
+ code: HCI_SUCCESS,
+ });
+ let service = await device.gatt.getPrimaryService(health_thermometer.name);
+
+ iframe.remove();
+ // Set iframe to null to ensure that the GC cleans up as much as possible.
+ iframe = null;
+ await garbageCollect();
+
+ try {
+ await service.getCharacteristic(measurement_interval.alias);
+ } catch (e) {
+ // Cannot use promise_rejects_dom() because |e| is thrown from a different
+ // global.
+ error = e;
+ }
+ assert_not_equals(error, undefined);
+ assert_equals(error.name, 'NetworkError');
+}, 'getCharacteristic() rejects in a detached context');
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js
new file mode 100644
index 0000000000..cce302d650
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-blocklisted-characteristic.https.window.js
@@ -0,0 +1,23 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Serial Number String characteristic is blocklisted. ' +
+ 'Should reject with SecurityError.';
+const expected = new DOMException(
+ 'getCharacteristic(s) called with blocklisted UUID. https://goo.gl/4NeimX',
+ 'SecurityError');
+
+bluetooth_test(() => getHIDDevice({
+ filters: [{services: ['device_information']}]
+})
+ .then(({device}) => device.gatt.getPrimaryService('device_information'))
+ .then(service => assert_promise_rejects_with_message(
+ service.getCharacteristic('serial_number_string'),
+ expected,
+ 'Serial Number String characteristic is blocklisted.')),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js
new file mode 100644
index 0000000000..2ed48eb5c6
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-characteristic-not-found.https.window.js
@@ -0,0 +1,19 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Request for absent characteristics with UUID. ' +
+ 'Reject with NotFoundError.';
+
+bluetooth_test(() => getEmptyHealthThermometerService()
+ .then(({service}) => assert_promise_rejects_with_message(
+ service.getCharacteristic('battery_level'),
+ new DOMException(
+ `No Characteristics matching UUID ${battery_level.uuid} found ` +
+ `in Service with UUID ${health_thermometer.uuid}.`,
+ 'NotFoundError'))),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js
new file mode 100644
index 0000000000..1fd70c8fad
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-garbage-collection-ran-during-error.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Garbage Collection ran during getCharacteristic ' +
+ 'call that fails. Should not crash';
+const expected = new DOMException(
+ 'GATT Server is disconnected. Cannot retrieve characteristics. ' +
+ '(Re)connect first with `device.gatt.connect`.',
+ 'NetworkError');
+let promise;
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => {
+ promise = assert_promise_rejects_with_message(
+ service.getCharacteristic('measurement_interval'), expected);
+ // Disconnect called to clear attributeInstanceMap and allow the object to
+ // get garbage collected.
+ service.device.gatt.disconnect();
+ })
+ .then(garbageCollect)
+ .then(() => promise),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js
new file mode 100644
index 0000000000..c5176cdc5e
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-get-same-object.https.window.js
@@ -0,0 +1,28 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Calls to getCharacteristic should return the same object.';
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => Promise.all([
+ service.getCharacteristic('measurement_interval'),
+ service.getCharacteristic('measurement_interval')]))
+ .then(([characteristics_first_call, characteristics_second_call]) => {
+ // Convert to arrays if necessary.
+ characteristics_first_call = [].concat(characteristics_first_call);
+ characteristics_second_call = [].concat(characteristics_second_call);
+
+ let first_call_set = new Set(characteristics_first_call);
+ assert_equals(characteristics_first_call.length, first_call_set.size);
+ let second_call_set = new Set(characteristics_second_call);
+ assert_equals(characteristics_second_call.length, second_call_set.size);
+
+ characteristics_first_call.forEach(characteristic => {
+ assert_true(second_call_set.has(characteristic));
+ });
+ }), test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js
new file mode 100644
index 0000000000..da0f5bda28
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-invalid-characteristic-name.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Wrong Characteristic name. Reject with TypeError.';
+const expected = new DOMException(
+ "Failed to execute 'getCharacteristic' on " +
+ "'BluetoothRemoteGATTService': Invalid Characteristic name: " +
+ "'wrong_name'. " +
+ "It must be a valid UUID alias (e.g. 0x1234), " +
+ "UUID (lowercase hex characters e.g. " +
+ "'00001234-0000-1000-8000-00805f9b34fb'), " +
+ "or recognized standard name from " +
+ "https://www.bluetooth.com/specifications/gatt/characteristics" +
+ " e.g. 'aerobic_heart_rate_lower_limit'.",
+ 'TypeError');
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => assert_promise_rejects_with_message(
+ service.getCharacteristic('wrong_name'),
+ expected,
+ 'Wrong Characteristic name passed.')),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js
new file mode 100644
index 0000000000..8801c152e9
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-reconnect-during.https.window.js
@@ -0,0 +1,39 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'disconnect() and connect() called during ' +
+ 'getCharacteristic. Reject with NetworkError.';
+const expected = new DOMException(
+ 'GATT Server is disconnected. Cannot retrieve characteristics. ' +
+ '(Re)connect first with `device.gatt.connect`.',
+ 'NetworkError');
+let device;
+
+bluetooth_test(() => getHealthThermometerDeviceWithServicesDiscovered({
+ filters: [{services: [health_thermometer.name]}],
+})
+ .then(_ => ({device} = _))
+ .then(() => device.gatt.getPrimaryService(health_thermometer.name))
+ .then(service => Promise.all([
+ // 1. Make a call to service.getCharacteristic, while the service is still
+ // valid.
+ assert_promise_rejects_with_message(service.getCharacteristic(measurement_interval.name), expected),
+
+ // 2. disconnect() and connect before the initial call completes.
+ // This is accomplished by making the calls without waiting for the
+ // earlier promises to resolve.
+ // connect() guarantees on OS-level connection, but disconnect()
+ // only disconnects the current instance.
+ // getHealthThermometerDeviceWithServicesDiscovered holds another
+ // connection in an iframe, so disconnect() and connect() are certain to
+ // reconnect. However, disconnect() will invalidate the service object so
+ // the subsequent calls made to it will fail, even after reconnecting.
+ device.gatt.disconnect(),
+ device.gatt.connect()
+ ])),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js
new file mode 100644
index 0000000000..bfeb318c46
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristic/gen-service-is-removed.https.window.js
@@ -0,0 +1,23 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Service is removed before getCharacteristic call. ' +
+ 'Reject with InvalidStateError.';
+const expected = new DOMException('GATT Service no longer exists.',
+ 'InvalidStateError');
+let service, fake_service, fake_peripheral;
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(_ => ({service, fake_service, fake_peripheral} = _))
+ .then(() => fake_service.remove())
+ .then(() => fake_peripheral.simulateGATTServicesChanged())
+ .then(() => assert_promise_rejects_with_message(
+ service.getCharacteristic('measurement_interval'),
+ expected,
+ 'Service got removed.')),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.window.js
new file mode 100644
index 0000000000..408943585a
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/blocklisted-characteristics.https.window.js
@@ -0,0 +1,17 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'The Device Information service is composed of blocklisted ' +
+ 'characteristics so we shouldn\'t find any.';
+const expected =
+ new DOMException('No Characteristics found in service.', 'NotFoundError');
+
+bluetooth_test(async () => {
+ let {device} =
+ await getHIDDevice({filters: [{services: ['device_information']}]});
+ let service = await device.gatt.getPrimaryService('device_information');
+ return assert_promise_rejects_with_message(
+ service.getCharacteristics(), expected);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.window.js
new file mode 100644
index 0000000000..f11c69c92e
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found-with-uuid.https.window.js
@@ -0,0 +1,39 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'Find characteristics with UUID in service.';
+
+bluetooth_test(async () => {
+ let {device, fake_peripheral, fake_services} = await getDiscoveredHealthThermometerDevice();
+ // Setup a device with two measurement intervals.
+ await fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS});
+ await device.gatt.connect();
+ let fake_health_thermometer = fake_services.get('health_thermometer');
+ await Promise.all([
+ fake_health_thermometer.addFakeCharacteristic({
+ uuid: 'measurement_interval',
+ properties: ['read', 'write', 'indicate']
+ }),
+ fake_health_thermometer.addFakeCharacteristic({
+ uuid: 'measurement_interval',
+ properties: ['read', 'write', 'indicate']
+ }),
+ fake_health_thermometer.addFakeCharacteristic(
+ {uuid: 'temperature_measurement', properties: ['indicate']})
+ ]);
+ await fake_peripheral.setNextGATTDiscoveryResponse({code: HCI_SUCCESS});
+ let service = await device.gatt.getPrimaryService('health_thermometer');
+ // Actual test starts.
+ let characteristics_arrays = await Promise.all([
+ service.getCharacteristics(measurement_interval.alias),
+ service.getCharacteristics(measurement_interval.name),
+ service.getCharacteristics(measurement_interval.uuid)
+ ]);
+ characteristics_arrays.forEach(characteristics => {
+ assert_equals(characteristics.length, 2);
+ assert_equals(characteristics[0].uuid, measurement_interval.uuid);
+ assert_equals(characteristics[1].uuid, measurement_interval.uuid);
+ });
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.window.js
new file mode 100644
index 0000000000..3244dd3e17
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-found.https.window.js
@@ -0,0 +1,41 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'Find all characteristics in a service.';
+
+bluetooth_test(async () => {
+ let {device, fake_peripheral, fake_services} = await getDiscoveredHealthThermometerDevice();
+ // Setup a device with two measurement intervals.
+ await fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS});
+ await device.gatt.connect();
+ let fake_health_thermometer = fake_services.get('health_thermometer');
+ await Promise.all([
+ fake_health_thermometer.addFakeCharacteristic({
+ uuid: 'measurement_interval',
+ properties: ['read', 'write', 'indicate']
+ }),
+ fake_health_thermometer.addFakeCharacteristic({
+ uuid: 'measurement_interval',
+ properties: ['read', 'write', 'indicate']
+ }),
+ fake_health_thermometer.addFakeCharacteristic(
+ {uuid: 'temperature_measurement', properties: ['indicate']})
+ ]);
+ await fake_peripheral.setNextGATTDiscoveryResponse({code: HCI_SUCCESS});
+ let service = await device.gatt.getPrimaryService('health_thermometer');
+ // Actual test starts.
+ let characteristics = await service.getCharacteristics();
+ // Expect three characteristic instances.
+ assert_equals(characteristics.length, 3);
+
+ let uuid_set = new Set(characteristics.map(c => c.uuid));
+ // Two of the expected characteristics are
+ // 'measurement_interval', so only 2 unique UUID.
+ assert_equals(uuid_set.size, 2);
+ assert_true(
+ uuid_set.has(BluetoothUUID.getCharacteristic('measurement_interval')));
+ assert_true(
+ uuid_set.has(BluetoothUUID.getCharacteristic('temperature_measurement')));
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.window.js
new file mode 100644
index 0000000000..5b0c1896d6
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/characteristics-not-found.https.window.js
@@ -0,0 +1,15 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+'use strict';
+const test_desc = 'Request for absent characteristics. Reject with ' +
+ 'NotFoundError.';
+const expected =
+ new DOMException('No Characteristics found in service.', 'NotFoundError');
+
+bluetooth_test(async () => {
+ let {service} = await getEmptyHealthThermometerService();
+ return assert_promise_rejects_with_message(
+ service.getCharacteristics(), expected);
+}, test_desc);
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js
new file mode 100644
index 0000000000..79cd01032b
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-blocklisted-characteristic-with-uuid.https.window.js
@@ -0,0 +1,23 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Serial Number String characteristic is blocklisted. ' +
+ 'Should reject with SecurityError.';
+const expected = new DOMException(
+ 'getCharacteristic(s) called with blocklisted UUID. https://goo.gl/4NeimX',
+ 'SecurityError');
+
+bluetooth_test(() => getHIDDevice({
+ filters: [{services: ['device_information']}]
+})
+ .then(({device}) => device.gatt.getPrimaryService('device_information'))
+ .then(service => assert_promise_rejects_with_message(
+ service.getCharacteristics('serial_number_string'),
+ expected,
+ 'Serial Number String characteristic is blocklisted.')),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js
new file mode 100644
index 0000000000..8a5e2ab4e4
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-characteristic-not-found-with-uuid.https.window.js
@@ -0,0 +1,19 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Request for absent characteristics with UUID. ' +
+ 'Reject with NotFoundError.';
+
+bluetooth_test(() => getEmptyHealthThermometerService()
+ .then(({service}) => assert_promise_rejects_with_message(
+ service.getCharacteristics('battery_level'),
+ new DOMException(
+ `No Characteristics matching UUID ${battery_level.uuid} found ` +
+ `in Service with UUID ${health_thermometer.uuid}.`,
+ 'NotFoundError'))),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
new file mode 100644
index 0000000000..683b93e352
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error-with-uuid.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Garbage Collection ran during getCharacteristics ' +
+ 'call that fails. Should not crash';
+const expected = new DOMException(
+ 'GATT Server is disconnected. Cannot retrieve characteristics. ' +
+ '(Re)connect first with `device.gatt.connect`.',
+ 'NetworkError');
+let promise;
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => {
+ promise = assert_promise_rejects_with_message(
+ service.getCharacteristics('measurement_interval'), expected);
+ // Disconnect called to clear attributeInstanceMap and allow the object to
+ // get garbage collected.
+ service.device.gatt.disconnect();
+ })
+ .then(garbageCollect)
+ .then(() => promise),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js
new file mode 100644
index 0000000000..c964781ab4
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-garbage-collection-ran-during-error.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Garbage Collection ran during getCharacteristics ' +
+ 'call that fails. Should not crash';
+const expected = new DOMException(
+ 'GATT Server is disconnected. Cannot retrieve characteristics. ' +
+ '(Re)connect first with `device.gatt.connect`.',
+ 'NetworkError');
+let promise;
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => {
+ promise = assert_promise_rejects_with_message(
+ service.getCharacteristics(), expected);
+ // Disconnect called to clear attributeInstanceMap and allow the object to
+ // get garbage collected.
+ service.device.gatt.disconnect();
+ })
+ .then(garbageCollect)
+ .then(() => promise),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js
new file mode 100644
index 0000000000..64b53f4eb3
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object-with-uuid.https.window.js
@@ -0,0 +1,28 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Calls to getCharacteristics should return the same object.';
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => Promise.all([
+ service.getCharacteristics('measurement_interval'),
+ service.getCharacteristics('measurement_interval')]))
+ .then(([characteristics_first_call, characteristics_second_call]) => {
+ // Convert to arrays if necessary.
+ characteristics_first_call = [].concat(characteristics_first_call);
+ characteristics_second_call = [].concat(characteristics_second_call);
+
+ let first_call_set = new Set(characteristics_first_call);
+ assert_equals(characteristics_first_call.length, first_call_set.size);
+ let second_call_set = new Set(characteristics_second_call);
+ assert_equals(characteristics_second_call.length, second_call_set.size);
+
+ characteristics_first_call.forEach(characteristic => {
+ assert_true(second_call_set.has(characteristic));
+ });
+ }), test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js
new file mode 100644
index 0000000000..6aad17c1e6
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-get-same-object.https.window.js
@@ -0,0 +1,28 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Calls to getCharacteristics should return the same object.';
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => Promise.all([
+ service.getCharacteristics(),
+ service.getCharacteristics()]))
+ .then(([characteristics_first_call, characteristics_second_call]) => {
+ // Convert to arrays if necessary.
+ characteristics_first_call = [].concat(characteristics_first_call);
+ characteristics_second_call = [].concat(characteristics_second_call);
+
+ let first_call_set = new Set(characteristics_first_call);
+ assert_equals(characteristics_first_call.length, first_call_set.size);
+ let second_call_set = new Set(characteristics_second_call);
+ assert_equals(characteristics_second_call.length, second_call_set.size);
+
+ characteristics_first_call.forEach(characteristic => {
+ assert_true(second_call_set.has(characteristic));
+ });
+ }), test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js
new file mode 100644
index 0000000000..c7d439e13a
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-invalid-characteristic-name.https.window.js
@@ -0,0 +1,27 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Wrong Characteristic name. Reject with TypeError.';
+const expected = new DOMException(
+ "Failed to execute 'getCharacteristics' on " +
+ "'BluetoothRemoteGATTService': Invalid Characteristic name: " +
+ "'wrong_name'. " +
+ "It must be a valid UUID alias (e.g. 0x1234), " +
+ "UUID (lowercase hex characters e.g. " +
+ "'00001234-0000-1000-8000-00805f9b34fb'), " +
+ "or recognized standard name from " +
+ "https://www.bluetooth.com/specifications/gatt/characteristics" +
+ " e.g. 'aerobic_heart_rate_lower_limit'.",
+ 'TypeError');
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(({service}) => assert_promise_rejects_with_message(
+ service.getCharacteristics('wrong_name'),
+ expected,
+ 'Wrong Characteristic name passed.')),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js
new file mode 100644
index 0000000000..db373fbca1
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during-with-uuid.https.window.js
@@ -0,0 +1,39 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'disconnect() and connect() called during ' +
+ 'getCharacteristics. Reject with NetworkError.';
+const expected = new DOMException(
+ 'GATT Server is disconnected. Cannot retrieve characteristics. ' +
+ '(Re)connect first with `device.gatt.connect`.',
+ 'NetworkError');
+let device;
+
+bluetooth_test(() => getHealthThermometerDeviceWithServicesDiscovered({
+ filters: [{services: [health_thermometer.name]}],
+})
+ .then(_ => ({device} = _))
+ .then(() => device.gatt.getPrimaryService(health_thermometer.name))
+ .then(service => Promise.all([
+ // 1. Make a call to service.getCharacteristics, while the service is still
+ // valid.
+ assert_promise_rejects_with_message(service.getCharacteristics(measurement_interval.name), expected),
+
+ // 2. disconnect() and connect before the initial call completes.
+ // This is accomplished by making the calls without waiting for the
+ // earlier promises to resolve.
+ // connect() guarantees on OS-level connection, but disconnect()
+ // only disconnects the current instance.
+ // getHealthThermometerDeviceWithServicesDiscovered holds another
+ // connection in an iframe, so disconnect() and connect() are certain to
+ // reconnect. However, disconnect() will invalidate the service object so
+ // the subsequent calls made to it will fail, even after reconnecting.
+ device.gatt.disconnect(),
+ device.gatt.connect()
+ ])),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js
new file mode 100644
index 0000000000..8b3ba7cc6b
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-reconnect-during.https.window.js
@@ -0,0 +1,39 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'disconnect() and connect() called during ' +
+ 'getCharacteristics. Reject with NetworkError.';
+const expected = new DOMException(
+ 'GATT Server is disconnected. Cannot retrieve characteristics. ' +
+ '(Re)connect first with `device.gatt.connect`.',
+ 'NetworkError');
+let device;
+
+bluetooth_test(() => getHealthThermometerDeviceWithServicesDiscovered({
+ filters: [{services: [health_thermometer.name]}],
+})
+ .then(_ => ({device} = _))
+ .then(() => device.gatt.getPrimaryService(health_thermometer.name))
+ .then(service => Promise.all([
+ // 1. Make a call to service.getCharacteristics, while the service is still
+ // valid.
+ assert_promise_rejects_with_message(service.getCharacteristics(), expected),
+
+ // 2. disconnect() and connect before the initial call completes.
+ // This is accomplished by making the calls without waiting for the
+ // earlier promises to resolve.
+ // connect() guarantees on OS-level connection, but disconnect()
+ // only disconnects the current instance.
+ // getHealthThermometerDeviceWithServicesDiscovered holds another
+ // connection in an iframe, so disconnect() and connect() are certain to
+ // reconnect. However, disconnect() will invalidate the service object so
+ // the subsequent calls made to it will fail, even after reconnecting.
+ device.gatt.disconnect(),
+ device.gatt.connect()
+ ])),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js
new file mode 100644
index 0000000000..2d4db52822
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed-with-uuid.https.window.js
@@ -0,0 +1,23 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Service is removed before getCharacteristics call. ' +
+ 'Reject with InvalidStateError.';
+const expected = new DOMException('GATT Service no longer exists.',
+ 'InvalidStateError');
+let service, fake_service, fake_peripheral;
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(_ => ({service, fake_service, fake_peripheral} = _))
+ .then(() => fake_service.remove())
+ .then(() => fake_peripheral.simulateGATTServicesChanged())
+ .then(() => assert_promise_rejects_with_message(
+ service.getCharacteristics('measurement_interval'),
+ expected,
+ 'Service got removed.')),
+ test_desc);
+
diff --git a/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js
new file mode 100644
index 0000000000..f922b45cdc
--- /dev/null
+++ b/testing/web-platform/tests/bluetooth/service/getCharacteristics/gen-service-is-removed.https.window.js
@@ -0,0 +1,23 @@
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+// META: script=/common/gc.js
+// META: script=/bluetooth/resources/bluetooth-test.js
+// META: script=/bluetooth/resources/bluetooth-fake-devices.js
+// Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py
+'use strict';
+const test_desc = 'Service is removed before getCharacteristics call. ' +
+ 'Reject with InvalidStateError.';
+const expected = new DOMException('GATT Service no longer exists.',
+ 'InvalidStateError');
+let service, fake_service, fake_peripheral;
+
+bluetooth_test(() => getHealthThermometerService()
+ .then(_ => ({service, fake_service, fake_peripheral} = _))
+ .then(() => fake_service.remove())
+ .then(() => fake_peripheral.simulateGATTServicesChanged())
+ .then(() => assert_promise_rejects_with_message(
+ service.getCharacteristics(),
+ expected,
+ 'Service got removed.')),
+ test_desc);
+