Auto merge of #14277 - szeged:service-and-manufacturer-data, r=jdm

serviceData and manufacturerData support

<!-- Please describe your changes on the following line: -->
Allow requesting for BluetoothDevices with service and manufacturer specific data.

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors

<!-- Either: -->
- [x] There are tests for these changes

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14277)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2016-11-23 01:25:39 -08:00 committed by GitHub
commit 5946f756d7
19 changed files with 830 additions and 83 deletions

View file

@ -7370,6 +7370,12 @@
"url": "/_mozilla/mozilla/bluetooth/requestDevice/blocklisted-service-in-optionalServices.html"
}
],
"mozilla/bluetooth/requestDevice/canonicalizeFilter/blocklisted-service-data-key.html": [
{
"path": "mozilla/bluetooth/requestDevice/canonicalizeFilter/blocklisted-service-data-key.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/canonicalizeFilter/blocklisted-service-data-key.html"
}
],
"mozilla/bluetooth/requestDevice/canonicalizeFilter/empty-filter.html": [
{
"path": "mozilla/bluetooth/requestDevice/canonicalizeFilter/empty-filter.html",
@ -7466,6 +7472,24 @@
"url": "/_mozilla/mozilla/bluetooth/requestDevice/canonicalizeFilter/unicode-valid-length-name-namePrefix.html"
}
],
"mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-manufacturer-data-key.html": [
{
"path": "mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-manufacturer-data-key.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-manufacturer-data-key.html"
}
],
"mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-mask-length.html": [
{
"path": "mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-mask-length.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-mask-length.html"
}
],
"mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-service-data-key.html": [
{
"path": "mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-service-data-key.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-service-data-key.html"
}
],
"mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.html": [
{
"path": "mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-optionalServices-member.html",
@ -7478,6 +7502,42 @@
"url": "/_mozilla/mozilla/bluetooth/requestDevice/canonicalizeFilter/wrong-service-in-services-member.html"
}
],
"mozilla/bluetooth/requestDevice/device-found-using-mask.html": [
{
"path": "mozilla/bluetooth/requestDevice/device-found-using-mask.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/device-found-using-mask.html"
}
],
"mozilla/bluetooth/requestDevice/device-found-with-key-and-value.html": [
{
"path": "mozilla/bluetooth/requestDevice/device-found-with-key-and-value.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/device-found-with-key-and-value.html"
}
],
"mozilla/bluetooth/requestDevice/device-found-with-key-only.html": [
{
"path": "mozilla/bluetooth/requestDevice/device-found-with-key-only.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/device-found-with-key-only.html"
}
],
"mozilla/bluetooth/requestDevice/device-found-with-service-and-manufacturer-data.html": [
{
"path": "mozilla/bluetooth/requestDevice/device-found-with-service-and-manufacturer-data.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/device-found-with-service-and-manufacturer-data.html"
}
],
"mozilla/bluetooth/requestDevice/device-not-found-with-extra-data.html": [
{
"path": "mozilla/bluetooth/requestDevice/device-not-found-with-extra-data.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/device-not-found-with-extra-data.html"
}
],
"mozilla/bluetooth/requestDevice/device-not-found-with-service-and-manufacturer-data.html": [
{
"path": "mozilla/bluetooth/requestDevice/device-not-found-with-service-and-manufacturer-data.html",
"url": "/_mozilla/mozilla/bluetooth/requestDevice/device-not-found-with-service-and-manufacturer-data.html"
}
],
"mozilla/bluetooth/requestDevice/discovery-succeeds.html": [
{
"path": "mozilla/bluetooth/requestDevice/discovery-succeeds.html",

View file

@ -0,0 +1,53 @@
<!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';
let blocklisted_keys = [{
filters: [{
serviceData: {
'heart_rate': {},
'00001812-0000-1000-8000-00805f9b34fb': {}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {},
'00001530-1212-efde-1523-785feabcd123': {}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {},
'f000ffc0-0451-4000-b000-000000000000': {}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {},
'human_interface_device': {}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {},
0x1812: {}
}
}]
}];
promise_test(t => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
let promises = [];
blocklisted_keys.forEach(args => {
promises.push(promise_rejects(t, 'SecurityError', window.navigator.bluetooth.requestDevice(args)));
});
return Promise.all(promises);
}, 'Rejects with SecurityError, if a serviceData key is blocklisted.');
</script>

View file

@ -0,0 +1,74 @@
<!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';
let wrong_manufacturer_data_keys = [{
filters: [{
manufacturerData: {
17: {},
'A': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
undefined: {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
null: {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
'': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
'-0': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
'-17': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
65536: {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
'65536': {}
}
}]
}];
promise_test(t => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
let promises = [];
wrong_manufacturer_data_keys.forEach(args => {
promises.push(promise_rejects(t, new TypeError(), window.navigator.bluetooth.requestDevice(args)));
});
return Promise.all(promises);
}, 'Rejects with TypeError, if a manufacturerData key is not an unsigned short.');
</script>

View file

@ -0,0 +1,70 @@
<!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';
let length_error_cases = [{
filters: [{
manufacturerData: {
17: {
dataPrefix: new Uint8Array([0x91, 0xAA, 0x78]),
mask: new Uint8Array([0x0F, 0x57])
}
}
}]
}, {
filters: [{
manufacturerData: {
17: {
dataPrefix: new Uint8Array([0x91]),
mask: new Uint8Array([0x0F, 0x57])
}
}
}]
}, {
filters: [{
manufacturerData: {
17: {
mask: new Uint8Array([0x0F, 0x57])
}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {
dataPrefix: new Uint8Array([0x91, 0xAA, 0x78]),
mask: new Uint8Array([0x0F, 0x57])
}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {
dataPrefix: new Uint8Array([0x91]),
mask: new Uint8Array([0x0F, 0x57])
}
}
}]
}, {
filters: [{
serviceData: {
'heart_rate': {
mask: new Uint8Array([0x0F, 0x57])
}
}
}]
}];
promise_test(t => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
let promises = [];
length_error_cases.forEach(args => {
promises.push(promise_rejects(t, new TypeError(), window.navigator.bluetooth.requestDevice(args)));
});
return Promise.all(promises);
}, 'Rejects with TypeError, if mask present, and does not have the same length as dataPrefix.');
</script>

View file

@ -0,0 +1,88 @@
<!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';
let wrong_service_data_keys = [{
filters: [{
serviceData: {
'glucose': {},
'wrong_service': {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
'-240': {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
'': {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
'-0': {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
null: {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
undefined: {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
'4294967296': {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
4294967296: {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
'123456789-0000-1000-8000-00805f9b34fb': {}
}
}]
}, {
filters: [{
serviceData: {
'glucose': {},
'0x180d': {}
}
}]
}];
promise_test(t => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
let promises = [];
wrong_service_data_keys.forEach(args => {
promises.push(promise_rejects(t, 'SyntaxError', window.navigator.bluetooth.requestDevice(args)));
});
return Promise.all(promises);
}, 'Rejects with SyntaxError, if a serviceData key does not convert to a valid uuid.');
</script>

View file

@ -0,0 +1,52 @@
<!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(() => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
return Promise.all([
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {
dataPrefix: new Uint8Array([0x91, 0xAA, 0x03]),
mask: new Uint8Array([0x0F, 0x57, 0x0F])
}
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
0x1808: {
dataPrefix: new Uint8Array([0x91, 0xAA, 0x03]),
mask: new Uint8Array([0x0F, 0x57, 0x0F])
}
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {
dataPrefix: new Uint8Array([0x91, 0xAA, 0x03]),
mask: new Uint8Array([0x0F, 0x57, 0x0F])
}
},
serviceData: {
0x1808: {
dataPrefix: new Uint8Array([0x91, 0xAA, 0x03]),
mask: new Uint8Array([0x0F, 0x57, 0x0F])
}
}
}]
}),
])
.then(devices => {
devices.forEach(device => assert_equals(device.name, mock_device_name.glucose));
});
}, 'A device can be found by requesting service/manufacturerData with a dataPrefix and an appropriate mask');
</script>

View file

@ -0,0 +1,68 @@
<!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(() => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
return Promise.all([
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {dataPrefix: new Uint8Array([1, 2, 3])},
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {dataPrefix: new Uint8Array([1, 2])},
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {dataPrefix: new Uint8Array([1])},
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
'glucose': {dataPrefix: new Uint8Array([1, 2, 3])},
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
'00001808-0000-1000-8000-00805f9b34fb': {dataPrefix: new Uint8Array([1, 2])},
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
0x1808: {dataPrefix: new Uint8Array([1])},
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {dataPrefix: new Uint8Array([1])},
},
serviceData: {
0x1808: {dataPrefix: new Uint8Array([1])},
}
}]
})
])
.then(devices => {
devices.forEach(device => assert_equals(device.name, mock_device_name.glucose));
});
}, 'A device can be found by requesting with a service/manufacturerData.dataPrefix, which contains the starting or all bytes of device\'s advertised service/manufacturer specific data bytes.');
</script>

View file

@ -0,0 +1,51 @@
<!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(() => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
return Promise.all([
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {}
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
'17': {}
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
'glucose': {}
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
'00001808-0000-1000-8000-00805f9b34fb': {}
}
}]
}),
window.navigator.bluetooth.requestDevice({
filters: [{
serviceData: {
0x1808: {}
}
}]
})
])
.then(devices => {
devices.forEach(device => assert_equals(device.name, mock_device_name.glucose));
});
}, 'Only using the correct service/manufacturerData key, a device can be found.');
</script>

View file

@ -0,0 +1,22 @@
<!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(() => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
return window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {dataPrefix: new Uint8Array([1, 2, 3])},
},
serviceData: {
'glucose': {dataPrefix: new Uint8Array([1, 2, 3])}
}
}]
})
.then(device => assert_equals(device.name, mock_device_name.glucose));
}, 'Requesting with manufacturerData and serviceData in the same filter, will find the device which advertises both.');
</script>

View file

@ -0,0 +1,63 @@
<!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';
let extra_data_filters = [{
filters: [{
manufacturerData: {
17: {},
18: {}
}
}]
}, {
filters: [{
serviceData: {
'battery_service': {},
'glucose': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
18: {}
},
serviceData: {
'battery_service': {},
'glucose': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {}
},
serviceData: {
'battery_service': {},
'glucose': {}
}
}]
}, {
filters: [{
manufacturerData: {
17: {},
18: {}
},
serviceData: {
'glucose': {}
}
}]
}];
promise_test(t => {
window.testRunner.setBluetoothMockDataSet(adapter_type.glucose_heart_rate);
let promises = [];
extra_data_filters.forEach(args => {
promises.push(promise_rejects(t, 'NotFoundError', window.navigator.bluetooth.requestDevice(args)));
});
return Promise.all(promises);
}, 'Requesting with an extra service/manufacturerData, which is not advertised, rejects with NotFoundError.');
</script>

View file

@ -0,0 +1,22 @@
<!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.glucose_heart_rate);
return promise_rejects(
t, 'NotFoundError',
window.navigator.bluetooth.requestDevice({
filters: [{
manufacturerData: {
17: {dataPrefix: new Uint8Array([1, 2, 3])},
},
serviceData: {
'heart_rate': {dataPrefix: new Uint8Array([1, 2, 3])}
}
}]}));
}, 'Requesting with manufacturerData and serviceData in the same filter, will not find a device which does not advertise both.');
</script>

View file

@ -11,6 +11,8 @@ let matching_namePrefix = 'Heart';
let non_matching_services = [battery_service.name];
let non_matching_name = 'Some Device';
let non_matching_namePrefix = 'Some';
let non_matching_manufacturer_data = {18: {}};
let non_matching_service_data = {'battery_service': {}};
let test_specs = [{
filters: [{
@ -81,6 +83,16 @@ let test_specs = [{
filters: [{
namePrefix: non_matching_namePrefix
}]
}, {
filters: [{
name: matching_name,
manufacturerData: non_matching_manufacturer_data
}]
}, {
filters: [{
namePrefix: matching_namePrefix,
serviceData: non_matching_service_data
}]
}];
promise_test(t => {