aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/atoms/static_atoms.txt1
-rw-r--r--components/bluetooth/lib.rs33
-rw-r--r--components/bluetooth/test.rs8
-rw-r--r--components/bluetooth_traits/lib.rs4
-rw-r--r--components/script/dom/bluetooth.rs4
-rw-r--r--components/script/dom/bluetoothdevice.rs69
-rw-r--r--components/script/dom/bluetoothremotegattserver.rs37
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json78
-rw-r--r--tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html.ini5
-rw-r--r--tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html.ini5
-rw-r--r--tests/wpt/mozilla/meta/mozilla/bluetooth/stopNotifications/disconnect-called-before.html.ini5
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/disconnect/event-is-fired.html33
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html36
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html29
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html39
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html35
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html32
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html31
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html35
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html37
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html31
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html27
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html34
-rw-r--r--tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html34
24 files changed, 649 insertions, 33 deletions
diff --git a/components/atoms/static_atoms.txt b/components/atoms/static_atoms.txt
index 1ddf07db553..e59c9cad809 100644
--- a/components/atoms/static_atoms.txt
+++ b/components/atoms/static_atoms.txt
@@ -65,3 +65,4 @@ fetch
characteristicvaluechanged
fullscreenchange
fullscreenerror
+gattserverdisconnected
diff --git a/components/bluetooth/lib.rs b/components/bluetooth/lib.rs
index 2d542868e02..8af1fab71da 100644
--- a/components/bluetooth/lib.rs
+++ b/components/bluetooth/lib.rs
@@ -247,6 +247,12 @@ impl BluetoothManager {
BluetoothRequest::Test(data_set_name, sender) => {
let _ = sender.send(self.test(data_set_name));
}
+ BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids) => {
+ self.remove_ids_from_caches(service_ids, characteristic_ids, descriptor_ids)
+ }
+ BluetoothRequest::IsRepresentedDeviceNull(id, sender) => {
+ let _ = sender.send(!self.device_is_cached(&id));
+ }
BluetoothRequest::Exit => {
break
},
@@ -273,6 +279,26 @@ impl BluetoothManager {
}
}
+ fn remove_ids_from_caches(&mut self,
+ service_ids: Vec<String>,
+ characteristic_ids: Vec<String>,
+ descriptor_ids: Vec<String>) {
+ for id in service_ids {
+ self.cached_services.remove(&id);
+ self.service_to_device.remove(&id);
+ }
+
+ for id in characteristic_ids {
+ self.cached_characteristics.remove(&id);
+ self.characteristic_to_service.remove(&id);
+ }
+
+ for id in descriptor_ids {
+ self.cached_descriptors.remove(&id);
+ self.descriptor_to_characteristic.remove(&id);
+ }
+ }
+
// Adapter
pub fn get_or_create_adapter(&mut self) -> Option<BluetoothAdapter> {
@@ -613,20 +639,19 @@ impl BluetoothManager {
}
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-disconnect
- fn gatt_server_disconnect(&mut self, device_id: String) -> BluetoothResult<bool> {
+ fn gatt_server_disconnect(&mut self, device_id: String) -> BluetoothResult<()> {
let mut adapter = try!(self.get_adapter());
-
match self.get_device(&mut adapter, &device_id) {
Some(d) => {
// Step 2.
if !d.is_connected().unwrap_or(true) {
- return Ok(false);
+ return Ok(());
}
let _ = d.disconnect();
for _ in 0..MAXIMUM_TRANSACTION_TIME {
match d.is_connected().unwrap_or(true) {
true => thread::sleep(Duration::from_millis(CONNECTION_TIMEOUT_MS)),
- false => return Ok(false),
+ false => return Ok(()),
}
}
return Err(BluetoothError::Network);
diff --git a/components/bluetooth/test.rs b/components/bluetooth/test.rs
index e2c6e639e82..b8f8a53750f 100644
--- a/components/bluetooth/test.rs
+++ b/components/bluetooth/test.rs
@@ -222,21 +222,23 @@ fn create_heart_rate_service(device: &BluetoothDevice,
try!(create_characteristic_with_value(&heart_rate_service,
HEART_RATE_MEASUREMENT_CHARACTERISTIC_UUID.to_owned(),
vec![0]));
- try!(heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string()]));
+ try!(heart_rate_measurement_characteristic.set_flags(vec![NOTIFY_FLAG.to_string(),
+ READ_FLAG.to_string(),
+ WRITE_FLAG.to_string()]));
// Body Sensor Location Characteristic 1
let body_sensor_location_characteristic_1 =
try!(create_characteristic_with_value(&heart_rate_service,
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
vec![49]));
- try!(body_sensor_location_characteristic_1.set_flags(vec![READ_FLAG.to_string()]));
+ try!(body_sensor_location_characteristic_1.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()]));
// Body Sensor Location Characteristic 2
let body_sensor_location_characteristic_2 =
try!(create_characteristic_with_value(&heart_rate_service,
BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.to_owned(),
vec![50]));
- try!(body_sensor_location_characteristic_2.set_flags(vec![READ_FLAG.to_string()]));
+ try!(body_sensor_location_characteristic_2.set_flags(vec![READ_FLAG.to_string(), WRITE_FLAG.to_string()]));
Ok(heart_rate_service)
}
diff --git a/components/bluetooth_traits/lib.rs b/components/bluetooth_traits/lib.rs
index ede1c8ecdba..345425cc1d5 100644
--- a/components/bluetooth_traits/lib.rs
+++ b/components/bluetooth_traits/lib.rs
@@ -85,12 +85,14 @@ pub type BluetoothResponseResult = Result<BluetoothResponse, BluetoothError>;
pub enum BluetoothRequest {
RequestDevice(RequestDeviceoptions, IpcSender<BluetoothResponseResult>),
GATTServerConnect(String, IpcSender<BluetoothResponseResult>),
- GATTServerDisconnect(String, IpcSender<BluetoothResult<bool>>),
+ GATTServerDisconnect(String, IpcSender<BluetoothResult<()>>),
GetGATTChildren(String, Option<String>, bool, GATTType, IpcSender<BluetoothResponseResult>),
ReadValue(String, IpcSender<BluetoothResponseResult>),
WriteValue(String, Vec<u8>, IpcSender<BluetoothResponseResult>),
EnableNotification(String, bool, IpcSender<BluetoothResponseResult>),
WatchAdvertisements(String, IpcSender<BluetoothResponseResult>),
+ SetRepresentedToNull(Vec<String>, Vec<String>, Vec<String>),
+ IsRepresentedDeviceNull(String, IpcSender<bool>),
Test(String, IpcSender<BluetoothResult<()>>),
Exit,
}
diff --git a/components/script/dom/bluetooth.rs b/components/script/dom/bluetooth.rs
index d2b3ced25fe..fdc248c360f 100644
--- a/components/script/dom/bluetooth.rs
+++ b/components/script/dom/bluetooth.rs
@@ -106,6 +106,10 @@ impl Bluetooth {
self.global().as_window().bluetooth_thread()
}
+ pub fn get_device_map(&self) -> &DOMRefCell<HashMap<String, MutJS<BluetoothDevice>>> {
+ &self.device_instance_map
+ }
+
// https://webbluetoothcg.github.io/web-bluetooth/#request-bluetooth-devices
fn request_bluetooth_devices(&self,
p: &Rc<Promise>,
diff --git a/components/script/dom/bluetoothdevice.rs b/components/script/dom/bluetoothdevice.rs
index d3d66b66440..d56970c0d98 100644
--- a/components/script/dom/bluetoothdevice.rs
+++ b/components/script/dom/bluetoothdevice.rs
@@ -10,6 +10,8 @@ use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMet
use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::error::Error;
+use dom::bindings::error::ErrorResult;
+use dom::bindings::inheritance::Castable;
use dom::bindings::js::{MutJS, MutNullableJS, Root};
use dom::bindings::reflector::{DomObject, reflect_dom_object};
use dom::bindings::str::DOMString;
@@ -22,7 +24,7 @@ use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
use dom::eventtarget::EventTarget;
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
-use ipc_channel::ipc::IpcSender;
+use ipc_channel::ipc::{self, IpcSender};
use js::jsapi::JSContext;
use std::cell::Cell;
use std::collections::HashMap;
@@ -72,6 +74,10 @@ impl BluetoothDevice {
BluetoothDeviceBinding::Wrap)
}
+ fn get_context(&self) -> Root<Bluetooth> {
+ self.context.get()
+ }
+
pub fn get_or_create_service(&self,
service: &BluetoothServiceMsg,
server: &BluetoothRemoteGATTServer)
@@ -119,6 +125,13 @@ impl BluetoothDevice {
return bt_characteristic;
}
+ pub fn is_represented_device_null(&self) -> bool {
+ let (sender, receiver) = ipc::channel().unwrap();
+ self.get_bluetooth_thread().send(
+ BluetoothRequest::IsRepresentedDeviceNull(self.Id().to_string(), sender)).unwrap();
+ receiver.recv().unwrap()
+ }
+
pub fn get_or_create_descriptor(&self,
descriptor: &BluetoothDescriptorMsg,
characteristic: &BluetoothRemoteGATTCharacteristic)
@@ -139,6 +152,60 @@ impl BluetoothDevice {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#clean-up-the-disconnected-device
+ #[allow(unrooted_must_root)]
+ pub fn clean_up_disconnected_device(&self) {
+ // Step 1.
+ self.Gatt().set_connected(false);
+
+ // TODO: Step 2: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+
+ // Step 3: We don't need `context`, we get the attributeInstanceMap from the device.
+ // https://github.com/WebBluetoothCG/web-bluetooth/issues/330
+
+ // Step 4.
+ let mut service_map = self.attribute_instance_map.0.borrow_mut();
+ let service_ids = service_map.drain().map(|(id, _)| id).collect();
+
+ let mut characteristic_map = self.attribute_instance_map.1.borrow_mut();
+ let characteristic_ids = characteristic_map.drain().map(|(id, _)| id).collect();
+
+ let mut descriptor_map = self.attribute_instance_map.2.borrow_mut();
+ let descriptor_ids = descriptor_map.drain().map(|(id, _)| id).collect();
+
+ // Step 5, 6.4, 7.
+ // TODO: Step 6: Implement `active notification context set` for BluetoothRemoteGATTCharacteristic.
+ let _ = self.get_bluetooth_thread().send(
+ BluetoothRequest::SetRepresentedToNull(service_ids, characteristic_ids, descriptor_ids));
+
+ // Step 8.
+ self.upcast::<EventTarget>().fire_bubbling_event(atom!("gattserverdisconnected"));
+ }
+
+ // https://webbluetoothcg.github.io/web-bluetooth/#garbage-collect-the-connection
+ #[allow(unrooted_must_root)]
+ pub fn garbage_collect_the_connection(&self) -> ErrorResult {
+ // Step 1: TODO: Check if other systems using this device.
+
+ // Step 2.
+ let context = self.get_context();
+ for (id, device) in context.get_device_map().borrow().iter() {
+ // Step 2.1 - 2.2.
+ if id == &self.Id().to_string() {
+ if device.get().Gatt().Connected() {
+ return Ok(());
+ }
+ // TODO: Step 2.3: Implement activeAlgorithms internal slot for BluetoothRemoteGATTServer.
+ }
+ }
+
+ // Step 3.
+ let (sender, receiver) = ipc::channel().unwrap();
+ self.get_bluetooth_thread().send(
+ BluetoothRequest::GATTServerDisconnect(String::from(self.Id()), sender)).unwrap();
+ receiver.recv().unwrap().map_err(Error::from)
+ }
}
impl BluetoothDeviceMethods for BluetoothDevice {
diff --git a/components/script/dom/bluetoothremotegattserver.rs b/components/script/dom/bluetoothremotegattserver.rs
index ad7833af908..e81aae08abe 100644
--- a/components/script/dom/bluetoothremotegattserver.rs
+++ b/components/script/dom/bluetoothremotegattserver.rs
@@ -15,7 +15,7 @@ use dom::bluetoothdevice::BluetoothDevice;
use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
use dom::globalscope::GlobalScope;
use dom::promise::Promise;
-use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::ipc::IpcSender;
use js::jsapi::JSContext;
use std::cell::Cell;
use std::rc::Rc;
@@ -46,6 +46,10 @@ impl BluetoothRemoteGATTServer {
fn get_bluetooth_thread(&self) -> IpcSender<BluetoothRequest> {
self.global().as_window().bluetooth_thread()
}
+
+ pub fn set_connected(&self, connected: bool) {
+ self.connected.set(connected);
+ }
}
impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
@@ -86,27 +90,14 @@ impl BluetoothRemoteGATTServerMethods for BluetoothRemoteGATTServer {
// Step 2.
if !self.Connected() {
- return Ok(());
+ return Ok(())
}
- let (sender, receiver) = ipc::channel().unwrap();
- self.get_bluetooth_thread().send(
- BluetoothRequest::GATTServerDisconnect(String::from(self.Device().Id()), sender)).unwrap();
- let server = receiver.recv().unwrap();
- // TODO: Step 3: Implement the `clean up the disconnected device` algorithm.
+ // Step 3.
+ self.Device().clean_up_disconnected_device();
- // TODO: Step 4: Implement representedDevice internal slot for BluetoothDevice.
-
- // TODO: Step 5: Implement the `garbage-collect the connection` algorithm.
- match server {
- Ok(connected) => {
- self.connected.set(connected);
- Ok(())
- },
- Err(error) => {
- Err(Error::from(error))
- },
- }
+ // Step 4 - 5:
+ self.Device().garbage_collect_the_connection()
}
#[allow(unrooted_must_root)]
@@ -134,6 +125,14 @@ impl AsyncBluetoothListener for BluetoothRemoteGATTServer {
match response {
// https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
BluetoothResponse::GATTServerConnect(connected) => {
+ // Step 5.2.3
+ if self.Device().is_represented_device_null() {
+ if let Err(e) = self.Device().garbage_collect_the_connection() {
+ return promise.reject_error(promise_cx, Error::from(e));
+ }
+ return promise.reject_error(promise_cx, Error::Network);
+ }
+
// Step 5.2.4.
self.connected.set(connected);
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index ca2f3db7589..25e032f876a 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -6794,6 +6794,12 @@
"url": "/_mozilla/mozilla/bluetooth/disconnect/disconnect-twice-in-a-row.html"
}
],
+ "mozilla/bluetooth/disconnect/event-is-fired.html": [
+ {
+ "path": "mozilla/bluetooth/disconnect/event-is-fired.html",
+ "url": "/_mozilla/mozilla/bluetooth/disconnect/event-is-fired.html"
+ }
+ ],
"mozilla/bluetooth/getCharacteristic/blocklisted-characteristic.html": [
{
"path": "mozilla/bluetooth/getCharacteristic/blocklisted-characteristic.html",
@@ -6830,6 +6836,18 @@
"url": "/_mozilla/mozilla/bluetooth/getCharacteristic/disconnect-called-during.html"
}
],
+ "mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html": [
+ {
+ "path": "mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html",
+ "url": "/_mozilla/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html"
+ }
+ ],
+ "mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html": [
+ {
+ "path": "mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html",
+ "url": "/_mozilla/mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html"
+ }
+ ],
"mozilla/bluetooth/getCharacteristic/get-same-characteristic.html": [
{
"path": "mozilla/bluetooth/getCharacteristic/get-same-characteristic.html",
@@ -6926,6 +6944,18 @@
"url": "/_mozilla/mozilla/bluetooth/getCharacteristics/disconnect-called-during.html"
}
],
+ "mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html": [
+ {
+ "path": "mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html",
+ "url": "/_mozilla/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html"
+ }
+ ],
+ "mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html": [
+ {
+ "path": "mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html",
+ "url": "/_mozilla/mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html"
+ }
+ ],
"mozilla/bluetooth/getCharacteristics/get-same-characteristics.html": [
{
"path": "mozilla/bluetooth/getCharacteristics/get-same-characteristics.html",
@@ -6992,6 +7022,18 @@
"url": "/_mozilla/mozilla/bluetooth/getDescriptor/disconnect-called-during.html"
}
],
+ "mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html": [
+ {
+ "path": "mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html",
+ "url": "/_mozilla/mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html"
+ }
+ ],
+ "mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html": [
+ {
+ "path": "mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html",
+ "url": "/_mozilla/mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html"
+ }
+ ],
"mozilla/bluetooth/getDescriptor/get-same-descriptor.html": [
{
"path": "mozilla/bluetooth/getDescriptor/get-same-descriptor.html",
@@ -7094,6 +7136,18 @@
"url": "/_mozilla/mozilla/bluetooth/getDescriptors/disconnect-called-during.html"
}
],
+ "mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html": [
+ {
+ "path": "mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html",
+ "url": "/_mozilla/mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html"
+ }
+ ],
+ "mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html": [
+ {
+ "path": "mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html",
+ "url": "/_mozilla/mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html"
+ }
+ ],
"mozilla/bluetooth/getDescriptors/get-same-descriptors.html": [
{
"path": "mozilla/bluetooth/getDescriptors/get-same-descriptors.html",
@@ -7124,12 +7178,24 @@
"url": "/_mozilla/mozilla/bluetooth/getPrimaryService/disconnect-called-during.html"
}
],
+ "mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html": [
+ {
+ "path": "mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html",
+ "url": "/_mozilla/mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html"
+ }
+ ],
"mozilla/bluetooth/getPrimaryService/disconnected-device.html": [
{
"path": "mozilla/bluetooth/getPrimaryService/disconnected-device.html",
"url": "/_mozilla/mozilla/bluetooth/getPrimaryService/disconnected-device.html"
}
],
+ "mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html": [
+ {
+ "path": "mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html",
+ "url": "/_mozilla/mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html"
+ }
+ ],
"mozilla/bluetooth/getPrimaryService/get-same-service.html": [
{
"path": "mozilla/bluetooth/getPrimaryService/get-same-service.html",
@@ -7220,6 +7286,12 @@
"url": "/_mozilla/mozilla/bluetooth/getPrimaryServices/disconnect-called-during.html"
}
],
+ "mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html": [
+ {
+ "path": "mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html",
+ "url": "/_mozilla/mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html"
+ }
+ ],
"mozilla/bluetooth/getPrimaryServices/disconnected-device-with-uuid.html": [
{
"path": "mozilla/bluetooth/getPrimaryServices/disconnected-device-with-uuid.html",
@@ -7232,6 +7304,12 @@
"url": "/_mozilla/mozilla/bluetooth/getPrimaryServices/disconnected-device.html"
}
],
+ "mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html": [
+ {
+ "path": "mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html",
+ "url": "/_mozilla/mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html"
+ }
+ ],
"mozilla/bluetooth/getPrimaryServices/get-same-service.html": [
{
"path": "mozilla/bluetooth/getPrimaryServices/get-same-service.html",
diff --git a/tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html.ini b/tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html.ini
new file mode 100644
index 00000000000..5e864acb72f
--- /dev/null
+++ b/tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html.ini
@@ -0,0 +1,5 @@
+[disconnect-invalidates-object.html]
+ type: testharness
+ [Calls on a characteristic after we disconnect and connect again. Should reject with InvalidStateError.]
+ expected: FAIL
+
diff --git a/tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html.ini b/tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html.ini
new file mode 100644
index 00000000000..03863760106
--- /dev/null
+++ b/tests/wpt/mozilla/meta/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html.ini
@@ -0,0 +1,5 @@
+[disconnect-invalidates-objects.html]
+ type: testharness
+ [Calls on characteristics after we disconnect and connect again. Should reject with InvalidStateError.]
+ expected: FAIL
+
diff --git a/tests/wpt/mozilla/meta/mozilla/bluetooth/stopNotifications/disconnect-called-before.html.ini b/tests/wpt/mozilla/meta/mozilla/bluetooth/stopNotifications/disconnect-called-before.html.ini
deleted file mode 100644
index af249ef0167..00000000000
--- a/tests/wpt/mozilla/meta/mozilla/bluetooth/stopNotifications/disconnect-called-before.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[disconnect-called-before.html]
- type: testharness
- [disconnect() called before stopNotifications. Reject with InvalidStateError.]
- expected: FAIL
-
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/disconnect/event-is-fired.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/disconnect/event-is-fired.html
new file mode 100644
index 00000000000..67e146fc956
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/disconnect/event-is-fired.html
@@ -0,0 +1,33 @@
+<!doctype html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(() => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [heart_rate.name]}],
+ optionalServices: [generic_access.name]
+ })
+ .then(device => {
+ return device.gatt.connect()
+ .then(gattServer => {
+ let event = 'gattserverdisconnected';
+ let disconnected = new Promise((resolve, reject) => {
+ let event_listener = (e) => {
+ device.removeEventListener(event, event_listener);
+ resolve(e);
+ };
+ device.addEventListener(event, event_listener);
+ });
+ gattServer.disconnect();
+ return disconnected
+ })
+ .then(disconnected => {
+ assert_equals(disconnected.target.name, mock_device_name.heart_rate);
+ assert_true(disconnected.bubbles);
+ });
+ });
+}, 'A device disconnecting while connected should fire the gattserverdisconnected event.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html
new file mode 100644
index 00000000000..c1e6a864b0c
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/disconnect-invalidates-object.html
@@ -0,0 +1,36 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(c => {
+ let characteristic = c;
+ gattServer.disconnect();
+ return gattServer.connect()
+ .then(() => characteristic);
+ });
+ })
+ .then(characteristic => {
+ let promises = [];
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.getDescriptor(number_of_digitals.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.getDescriptors(number_of_digitals.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.getDescriptors()));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.readValue()));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.writeValue(new Uint8Array(1))));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.startNotifications()));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.stopNotifications()));
+ return Promise.all(promises);
+ });
+}, 'Calls on a characteristic after we disconnect and connect again. Should reject with InvalidStateError.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html
new file mode 100644
index 00000000000..b65a9a27836
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristic/get-different-characteristic-after-reconnection.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ let characteristic1;
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic1 = characteristic)
+ .then(() => gattServer.disconnect())
+ .then(() => gattServer.connect())
+ .then(() => gattServer.getPrimaryService(generic_access.name))
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic2 => [characteristic1, characteristic2])
+ })
+ .then(characteristics_array => {
+ assert_not_equals(characteristics_array[0], characteristics_array[1]);
+ });
+}, 'Calls to getCharacteristic after a disconnection should return a different object.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html
new file mode 100644
index 00000000000..adf607a0954
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/disconnect-invalidates-objects.html
@@ -0,0 +1,39 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [heart_rate.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ return gattServer.getPrimaryService(heart_rate.name)
+ .then(service => service.getCharacteristics())
+ .then(c => {
+ let characteristics = c;
+ assert_greater_than(characteristics.length, 1);
+ gattServer.disconnect();
+ return gattServer.connect()
+ .then(() => characteristics);
+ });
+ })
+ .then(characteristics => {
+ let promises = [];
+ for (let characteristic of characteristics) {
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.getDescriptor(number_of_digitals.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.getDescriptors(number_of_digitals.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.getDescriptors()));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.readValue()));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.writeValue(new Uint8Array(1))));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.startNotifications()));
+ promises.push(promise_rejects(t, 'InvalidStateError', characteristic.stopNotifications()));
+ }
+ return Promise.all(promises);
+ });
+}, 'Calls on characteristics after we disconnect and connect again. Should reject with InvalidStateError.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html
new file mode 100644
index 00000000000..0e93083a1cb
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getCharacteristics/get-different-characteristics-after-reconnection.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [heart_rate.name]}],
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ let characteristics1;
+ return gattServer.getPrimaryService(heart_rate.name)
+ .then(service => service.getCharacteristics())
+ .then(characteristics => characteristics1 = characteristics)
+ .then(() => gattServer.disconnect())
+ .then(() => gattServer.connect())
+ .then(() => gattServer.getPrimaryService(heart_rate.name))
+ .then(service => service.getCharacteristics())
+ .then(characteristics2 => [characteristics1, characteristics2])
+ })
+ .then(characteristics_arrays => {
+ for (let i = 1; i < characteristics_arrays.length; i++) {
+ assert_equals(characteristics_arrays[0].length, characteristics_arrays[i].length);
+ }
+ let base_set = new Set(characteristics_arrays.shift());
+ for (let characteristics of characteristics_arrays) {
+ characteristics.forEach(characteristic => assert_false(base_set.has(characteristic)));
+ }
+ });
+}, 'Calls to getCharacteristics after a disconnection should return different objects.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html
new file mode 100644
index 00000000000..b99e877159b
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/disconnect-invalidates-object.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic.getDescriptor(number_of_digitals.name))
+ .then(d => {
+ let descriptor = d;
+ gattServer.disconnect();
+ return gattServer.connect()
+ .then(() => descriptor);
+ });
+ })
+ .then(descriptor => {
+ let promises = [];
+ promises.push(promise_rejects(t, 'InvalidStateError', descriptor.readValue()));
+ promises.push(promise_rejects(t, 'InvalidStateError', descriptor.writeValue(new Uint8Array(1))));
+ return Promise.all(promises);
+ });
+}, 'Calls on a descriptor after we disconnect and connect again. Should reject with InvalidStateError.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html
new file mode 100644
index 00000000000..ea7559415d4
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptor/get-different-descriptor-after-reconnection.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ let descriptor1;
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic.getDescriptor(number_of_digitals.name))
+ .then(descriptor => descriptor1 = descriptor)
+ .then(() => gattServer.disconnect())
+ .then(() => gattServer.connect())
+ .then(() => gattServer.getPrimaryService(generic_access.name))
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic.getDescriptor(number_of_digitals.name))
+ .then(descriptor2 => [descriptor1, descriptor2])
+ })
+ .then(descriptors_array => {
+ assert_not_equals(descriptors_array[0], descriptors_array[1]);
+ });
+}, 'Calls to getDescriptor after a disconnection should return a different object.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html
new file mode 100644
index 00000000000..8f912b06755
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/disconnect-invalidates-objects.html
@@ -0,0 +1,35 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic.getDescriptors())
+ .then(d => {
+ let descriptors = d;
+ gattServer.disconnect();
+ return gattServer.connect()
+ .then(() => descriptors);
+ });
+ })
+ .then(descriptors => {
+ let promises = [];
+ for (let descriptor of descriptors) {
+ promises.push(promise_rejects(t, 'InvalidStateError', descriptor.readValue()));
+ if (descriptor.uuid != client_characteristic_configuration.uuid)
+ promises.push(promise_rejects(t, 'InvalidStateError', descriptor.writeValue(new Uint8Array(1))));
+ }
+ return Promise.all(promises);
+ });
+}, 'Calls on descriptors after we disconnect and connect again. Should reject with InvalidStateError.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html
new file mode 100644
index 00000000000..4a5ea15f96c
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getDescriptors/get-different-descriptors-after-reconnection.html
@@ -0,0 +1,37 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ let descriptors1;
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic.getDescriptors(number_of_digitals.name))
+ .then(descriptors => descriptors1 = descriptors)
+ .then(() => gattServer.disconnect())
+ .then(() => gattServer.connect())
+ .then(() => gattServer.getPrimaryService(generic_access.name))
+ .then(service => service.getCharacteristic(device_name.name))
+ .then(characteristic => characteristic.getDescriptors(number_of_digitals.name))
+ .then(descriptors2 => [descriptors1, descriptors2])
+ })
+ .then(descriptors_arrays => {
+ for (let i = 1; i < descriptors_arrays.length; i++) {
+ assert_equals(descriptors_arrays[0].length, descriptors_arrays[i].length);
+ }
+ let base_set = new Set(descriptors_arrays.shift());
+ for (let descriptors of descriptors_arrays) {
+ descriptors.forEach(descriptor => assert_false(base_set.has(descriptor)));
+ }
+ });
+}, 'Calls to getDescriptors after a disconnection should return a different object.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html
new file mode 100644
index 00000000000..a0254ee32ce
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/disconnect-invalidates-object.html
@@ -0,0 +1,31 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [heart_rate.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ return gattServer.getPrimaryService(heart_rate.name)
+ .then(s => {
+ let service = s;
+ gattServer.disconnect();
+ return gattServer.connect()
+ .then(() => service);
+ });
+ })
+ .then(service => {
+ let promises = [];
+ promises.push(promise_rejects(t, 'InvalidStateError', service.getCharacteristic(body_sensor_location.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', service.getCharacteristics(body_sensor_location.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', service.getCharacteristics()));
+ return Promise.all(promises);
+ });
+}, 'Calls on a service after we disconnect and connect again. Should reject with InvalidStateError.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html
new file mode 100644
index 00000000000..4f6e2bbc92a
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryService/get-different-service-after-reconnection.html
@@ -0,0 +1,27 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [generic_access.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ let service1;
+ return gattServer.getPrimaryService(generic_access.name)
+ .then(service => service1 = service)
+ .then(() => gattServer.disconnect())
+ .then(() => gattServer.connect())
+ .then(() => gattServer.getPrimaryService(generic_access.name))
+ .then(service2 => [service1, service2])
+ })
+ .then(services_array => {
+ assert_not_equals(services_array[0], services_array[1]);
+ });
+}, 'Calls to getPrimaryService after a disconnection should return a different object.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html
new file mode 100644
index 00000000000..6f07ab81d99
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/disconnect-invalidates-objects.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [heart_rate.name]}]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ return gattServer.getPrimaryServices()
+ .then(s => {
+ let services = s;
+ assert_greater_than(services.length, 1);
+ gattServer.disconnect();
+ return gattServer.connect()
+ .then(() => services);
+ });
+ })
+ .then(services => {
+ let promises = [];
+ for (let service of services) {
+ promises.push(promise_rejects(t, 'InvalidStateError', service.getCharacteristic(body_sensor_location.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', service.getCharacteristics(body_sensor_location.name)));
+ promises.push(promise_rejects(t, 'InvalidStateError', service.getCharacteristics()));
+ }
+ return Promise.all(promises);
+ });
+}, 'Calls on services after we disconnect and connect again. Should reject with InvalidStateError.');
+</script>
diff --git a/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html
new file mode 100644
index 00000000000..2ef3da7730d
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/bluetooth/getPrimaryServices/get-different-services-after-reconnection.html
@@ -0,0 +1,34 @@
+<!doctype html>
+<meta charset="utf-8">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/_mozilla/mozilla/bluetooth/bluetooth-helpers.js"></script>
+<script>
+'use strict';
+promise_test(t => {
+ window.testRunner.setBluetoothMockDataSet(adapter_type.two_heart_rate);
+ return window.navigator.bluetooth.requestDevice({
+ filters: [{services: [heart_rate.name]}],
+ optionalServices: [generic_access.name]
+ })
+ .then(device => device.gatt.connect())
+ .then(gattServer => {
+ let services1;
+ return gattServer.getPrimaryServices()
+ .then(services => services1 = services)
+ .then(() => gattServer.disconnect())
+ .then(() => gattServer.connect())
+ .then(() => gattServer.getPrimaryServices())
+ .then(services2 => [services1, services2])
+ })
+ .then(services_arrays => {
+ for (let i = 1; i < services_arrays.length; i++) {
+ assert_equals(services_arrays[0].length, services_arrays[i].length);
+ }
+ let base_set = new Set(services_arrays.shift());
+ for (let services of services_arrays) {
+ services.forEach(service => assert_false(base_set.has(service)));
+ }
+ });
+}, 'Calls to getPrimaryServices after a disconnection should return different objects.');
+</script>