Auto merge of #19801 - servo:wptup, r=jdm

Update web-platform-tests

<!-- 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/19801)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2018-01-20 13:06:43 -06:00 committed by GitHub
commit b62b51ab4b
832 changed files with 16026 additions and 2649 deletions

View file

@ -87,7 +87,7 @@ matrix:
apt:
packages:
- libnss3-tools
env: JOB=wpt_integration TOXENV=py27 SCRIPT=tools/ci/ci_wpt.sh
env: JOB=wpt_integration TOXENV=py27,py27-flake8 SCRIPT=tools/ci/ci_wpt.sh
exclude:
- env: # exclude empty env from the top-level above
allow_failures:

View file

@ -38,7 +38,8 @@ function makeVideo() {
video.oncanplaythrough = function() {
resolve(video);
};
video.src = "/images/pattern.ogv";
video.onerror = reject;
video.src = getVideoURI("/images/pattern");
});
}

View file

@ -4,6 +4,7 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/canvas-tests.js"></script>
<script src="/common/media.js"></script>
<script src="common.js"></script>
<link rel="stylesheet" href="/common/canvas-tests.css">
<body>

View file

@ -1,6 +1,7 @@
<!doctype html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/media.js"></script>
<script src="common.js"></script>
<script>

View file

@ -47,7 +47,7 @@ test_first_argument(["bits", new Blob(["bits"]), new Blob(), new Uint8Array([0x5
test_first_argument([12], 2, "Number in fileBits");
test_first_argument([[1,2,3]], 5, "Array in fileBits");
test_first_argument([{}], 15, "Object in fileBits"); // "[object Object]"
test_first_argument([document], 21, "HTMLDocument in fileBits"); // "[object HTMLDocument]"
test_first_argument([document.body], 24, "HTMLBodyElement in fileBits"); // "[object HTMLBodyElement]"
test_first_argument([to_string_obj], 8, "Object with toString in fileBits");
test_first_argument({[Symbol.iterator]() {
let i = 0;
@ -88,7 +88,7 @@ test_second_argument("dummy/foo", "dummy:foo", "Using special character in fileN
test_second_argument(null, "null", "Using null fileName");
test_second_argument(1, "1", "Using number fileName");
test_second_argument('', '', "Using empty string fileName");
test_second_argument(document, '[object HTMLDocument]', "Using object fileName");
test_second_argument(document.body, '[object HTMLBodyElement]', "Using object fileName");
// testing the third argument
[

View file

@ -9,7 +9,6 @@
<script>
const iframe_scripts = [
'/resources/testharness.js',
'resources/fetch-tests.js',
'url-format.any.js',
'url-with-xhr.any.js',
@ -18,6 +17,8 @@ const iframe_scripts = [
];
let html = '<!doctype html>\n<meta charset="utf-8">\n<body>\n';
html = html + '<script src="/resources/testharness.js"></' + 'script>\n';
html = html + '<script>setup({"explicit_timeout": true});</' + 'script>\n';
for (const script of iframe_scripts)
html = html + '<script src="' + script + '"></' + 'script>\n';
@ -27,4 +28,4 @@ frame.setAttribute('style', 'display:none;');
fetch_tests_from_window(frame.contentWindow);
</script>
</script>

View file

@ -2,7 +2,7 @@ const blob = new Blob(['test']);
const file = new File(['test'], 'name');
test(() => {
const url_count = 10000;
const url_count = 5000;
let list = [];
for (let i = 0; i < url_count; ++i)

View file

@ -1,40 +0,0 @@
<!doctype html>
<html>
<head>
<meta charset=utf-8>
<title>IDL check of WebCrypto</title>
<link rel="help" href="https://w3c.github.io/webcrypto/Overview.html#crypto-interface">
<script src=/resources/testharness.js></script>
<script src=/resources/testharnessreport.js></script>
<script src=/resources/WebIDLParser.js></script>
<script src=/resources/idlharness.js></script>
</head>
<body>
<h1 class="instructions">Description</h1>
<p class="instructions">This test verifies that the implementations of the WebCrypto API match with its WebIDL definition.</p>
<div id='log'></div>
<script>
var file_input;
setup(function() {
var idl_array = new IdlArray();
var request = new XMLHttpRequest();
request.open("GET", "WebCryptoAPI.idl");
request.send();
request.onload = function() {
var idls = request.responseText;
idl_array.add_idls(idls);
idl_array.add_objects({"Crypto":["crypto"], "SubtleCrypto":["crypto.subtle"]});
idl_array.test();
done();
};
}, {explicit_done: true});
</script>

View file

@ -24,7 +24,7 @@ setup(function() {
var idl_array = new IdlArray();
var request = new XMLHttpRequest();
request.open("GET", "WebCryptoAPI.idl");
request.open("GET", "../interfaces/WebCryptoAPI.idl");
request.send();
request.onload = function() {
var idls = request.responseText;

View file

@ -2,7 +2,7 @@ importScripts("/resources/testharness.js");
importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js");
var request = new XMLHttpRequest();
request.open("GET", "WebCryptoAPI.idl");
request.open("GET", "../interfaces/WebCryptoAPI.idl");
request.send();
request.onload = function() {
var idl_array = new IdlArray();

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>Accelerometer Feature Policy Test: Disabled</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>Accelerometer Feature Policy Test: Enabled by attribute redirect on load</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>Accelerometer Feature Policy Test: Enabled by attribute</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>Accelerometer Feature Policy Test: Enabled</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>Accelerometer Feature Policy Test: Enabled on self origin</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -11,5 +11,6 @@
runGenericSensorTests(Accelerometer);
runGenericSensorTests(GravitySensor);
runGenericSensorTests(LinearAccelerationSensor);
</script>

View file

@ -7,7 +7,7 @@
<script src="/resources/testharnessreport.js"></script>
<script src="/generic-sensor/generic-sensor-tests.js"></script>
<div id="log"></div>
<h2>Precondition</h2>
<h2>Note:</h2>
<ol>
<li>
Run test in an insecure context, e.g. http://example.com/.
@ -17,5 +17,6 @@
runGenericSensorInsecureContext("Accelerometer");
runGenericSensorInsecureContext("GravitySensor");
runGenericSensorInsecureContext("LinearAccelerationSensor");
</script>

View file

@ -17,5 +17,6 @@
runGenericSensorOnerror(Accelerometer);
runGenericSensorOnerror(GravitySensor);
runGenericSensorOnerror(LinearAccelerationSensor);
</script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>AmbientLightSensor Feature Policy Test: Enabled by attribute redirect on load</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>AmbientLightSensor Feature Policy Test: Enabled by attribute</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>AmbientLightSensor Feature Policy Test: Enabled</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -1,5 +1,6 @@
<!DOCTYPE html>
<body>
<title>AmbientLightSensor Feature Policy Test: Enabled on self origin</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/feature-policy/resources/featurepolicy.js"></script>

View file

@ -39,6 +39,10 @@ var emptyFormDataTest = { id: "EmptyFormData", data: CreateEmptyFormDataPayload(
var smallFormDataTest = { id: "SmallFormData", data: CreateFormDataFromPayload(smallPayload) };
var mediumFormDataTest = { id: "MediumFormData", data: CreateFormDataFromPayload(mediumPayload) };
var largeFormDataTest = { id: "LargeFormData", data: CreateFormDataFromPayload(largePayload) };
var smallSafeContentTypeEncodedTest = { id: "SmallSafeContentTypeEncoded", data: new Blob([smallPayload], { type: 'application/x-www-form-urlencoded' }) };
var smallSafeContentTypeFormTest = { id: "SmallSafeContentTypeForm", data: new FormData() };
var smallSafeContentTypeTextTest = { id: "SmallSafeContentTypeText", data: new Blob([smallPayload], { type: 'text/plain' }) };
var smallCORSContentTypeTextTest = { id: "SmallCORSContentTypeText", data: new Blob([smallPayload], { type: 'text/html' }) };
// We don't test maxFormData because the extra multipart separators make it difficult to
// calculate a maxPayload.
@ -57,7 +61,9 @@ var allTests = [].concat(stringTests, stringMaxTest, blobTests, blobMaxTest, buf
// This special cross section of test cases is meant to provide a slimmer but reasonably-
// representative set of tests for parameterization across variables (e.g. redirect codes,
// cors modes, etc.)
var sampleTests = [noDataTest, nullDataTest, undefinedDataTest, smallStringTest, smallBlobTest, smallBufferSourceTest, smallFormDataTest];
var sampleTests = [noDataTest, nullDataTest, undefinedDataTest, smallStringTest, smallBlobTest, smallBufferSourceTest, smallFormDataTest, smallSafeContentTypeEncodedTest, smallSafeContentTypeFormTest, smallSafeContentTypeTextTest];
var preflightTests = [smallCORSContentTypeTextTest];
// Build a test lookup table, which is useful when instructing a web worker or an iframe
// to run a test, so that we don't have to marshal the entire test case across a process boundary.

View file

@ -38,4 +38,30 @@
runTests(sampleTests);
});
// Now test a cross-origin request that doesn't use a safelisted Content-Type and ensure
// we are applying the proper restrictions. Since a non-safelisted Content-Type request
// header is used there should be a preflight/options request and we should only succeed
// send the payload if the proper CORS headers are used.
{
// Implement the self.buildId extension to identify the parameterized
// test in the report.
self.buildId = function (baseId) {
return `${baseId}-PREFLIGHT-ALLOW`;
};
// Implement the self.buildBaseUrl and self.buildTargetUrl extensions
// to change the target URL to use a cross-origin domain name.
self.buildBaseUrl = function (baseUrl) {
return "http://{{domains[www]}}:{{ports[http][0]}}";
};
// Implement the self.buildTargetUrl extension to append a directive
// to the handler, that it should return CORS headers for the preflight we expect.
self.buildTargetUrl = function (targetUrl) {
return `${targetUrl}&origin=http://{{host}}:{{ports[http][0]}}&credentials=true&preflightExpected=true`;
}
runTests(preflightTests);
}
done();

View file

@ -60,40 +60,52 @@ def main(request, response):
# with the unique session id, in order to retrieve a range of results
# later knowing the index range.
test_idx = request.GET.first("tidx")
test_data_key = build_stash_key(session_id, test_idx)
test_data = { "id": test_id, "error": None }
payload = ""
if "Content-Type" in request.headers and \
"form-data" in request.headers["Content-Type"]:
if "payload" in request.POST:
# The payload was sent as a FormData.
payload = request.POST.first("payload")
# Only store the actual POST requests, not any preflight/OPTIONS requests we may get.
if request.method == "POST":
test_data_key = build_stash_key(session_id, test_idx)
payload = ""
if "Content-Type" in request.headers and \
"form-data" in request.headers["Content-Type"]:
if "payload" in request.POST:
# The payload was sent as a FormData.
payload = request.POST.first("payload")
else:
# A FormData was sent with an empty payload.
pass
else:
# A FormData was sent with an empty payload.
pass
else:
# The payload was sent as either a string, Blob, or BufferSource.
payload = request.body
# The payload was sent as either a string, Blob, or BufferSource.
payload = request.body
payload_parts = filter(None, payload.split(":"))
if len(payload_parts) > 0:
payload_size = int(payload_parts[0])
payload_parts = filter(None, payload.split(":"))
if len(payload_parts) > 0:
payload_size = int(payload_parts[0])
# Confirm the payload size sent matches with the number of characters sent.
if payload_size != len(payload_parts[1]):
test_data["error"] = "expected %d characters but got %d" % (payload_size, len(payload_parts[1]))
# Confirm the payload size sent matches with the number of characters sent.
if payload_size != len(payload_parts[1]):
test_data["error"] = "expected %d characters but got %d" % (payload_size, len(payload_parts[1]))
else:
# Confirm the payload contains the correct characters.
for i in range(0, payload_size):
if payload_parts[1][i] != "*":
test_data["error"] = "expected '*' at index %d but got '%s''" % (i, payload_parts[1][i])
break
# Store the result in the stash so that it can be retrieved
# later with a 'stat' command.
request.server.stash.put(test_data_key, test_data)
elif request.method == "OPTIONS":
# If we expect a preflight, then add the cors headers we expect, otherwise log an error as we shouldn't
# send a preflight for all requests.
if "preflightExpected" in request.GET:
response.headers.set("Access-Control-Allow-Headers", "content-type")
response.headers.set("Access-Control-Allow-Methods", "POST")
else:
# Confirm the payload contains the correct characters.
for i in range(0, payload_size):
if payload_parts[1][i] != "*":
test_data["error"] = "expected '*' at index %d but got '%s''" % (i, payload_parts[1][i])
break
# Store the result in the stash so that it can be retrieved
# later with a 'stat' command.
request.server.stash.put(test_data_key, test_data)
test_data_key = build_stash_key(session_id, test_idx)
test_data["error"] = "Preflight not expected."
request.server.stash.put(test_data_key, test_data)
elif command == "stat":
test_idx_min = int(request.GET.first("tidx_min"))
test_idx_max = int(request.GET.first("tidx_max"))

View file

@ -10,3 +10,39 @@ The Chromium implementation is provided by
`../resources/chromium/web-bluetooth-test.js`.
[Web Bluetooth Testing API]: https://docs.google.com/document/d/1Nhv_oVDCodd1pEH_jj9k8gF4rPGb_84VYaZ9IG8M_WY/
# Generated gen-* files from generator.py
`generator.py` builds `gen-*.html` tests using templates in
`script-tests/*/*.js`.
The subdirectory structure in `bluetooth/script-test/*` is recreated into
`bluetooth/*`. The generator expands each CALL function from templates
into new leaf directories and files.
Example:
`script-tests/server/get-same-object.js` contains:
```
gattServer.CALLS([
getPrimaryService('heart_rate')|
getPrimaryServices()|
getPrimaryServices('heart_rate')[UUID]]),
```
Generating:
```
server/getPrimaryService/gen-get-same-object.html
server/getPrimaryServices/gen-get-same-object.html
server/getPrimaryServices/gen-get-same-object-with-uuid.html
```
Usage:
```
$ python generate.py
```
More details documented in `generate.py`.

View file

@ -0,0 +1,26 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'HeartRate device properties';
bluetooth_test(() => getHealthThermometerService()
.then(({service}) => Promise.all([
service.getCharacteristic('temperature_measurement'),
service.getCharacteristic('measurement_interval')]))
.then(([temperature_measurement, measurement_interval]) => {
let tm_expected_properties =
new TestCharacteristicProperties(['indicate']);
assert_properties_equal(temperature_measurement.properties,
tm_expected_properties);
let mi_expected_properties =
new TestCharacteristicProperties(['read', 'write', 'indicate']);
assert_properties_equal(measurement_interval.properties,
mi_expected_properties);
}), test_desc);
</script>

View file

@ -0,0 +1,25 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.getDescriptor(user_description.name), expected)),
test_desc);
</script>

View file

@ -0,0 +1,39 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Calls to getDescriptor should return the same object.';
let characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic} = _))
.then(() => Promise.all([
characteristic.getDescriptor(user_description.alias),
characteristic.getDescriptor(user_description.name),
characteristic.getDescriptor(user_description.uuid)
]))
.then(descriptors_arrays => {
assert_true(descriptors_arrays.length > 0)
// Convert to arrays if necessary.
for (let i = 0; i < descriptors_arrays.length; i++) {
descriptors_arrays[i] = [].concat(descriptors_arrays[i]);
}
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[0]);
for (let descriptors of descriptors_arrays) {
descriptors.forEach(descriptor => assert_true(base_set.has(descriptor)));
}
}), test_desc);
</script>

View file

@ -0,0 +1,25 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.getDescriptors(user_description.name), expected)),
test_desc);
</script>

View file

@ -0,0 +1,25 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.getDescriptors(), expected)),
test_desc);
</script>

View file

@ -0,0 +1,39 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Calls to getDescriptors should return the same object.';
let characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic} = _))
.then(() => Promise.all([
characteristic.getDescriptors(user_description.alias),
characteristic.getDescriptors(user_description.name),
characteristic.getDescriptors(user_description.uuid)
]))
.then(descriptors_arrays => {
assert_true(descriptors_arrays.length > 0)
// Convert to arrays if necessary.
for (let i = 0; i < descriptors_arrays.length; i++) {
descriptors_arrays[i] = [].concat(descriptors_arrays[i]);
}
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[0]);
for (let descriptors of descriptors_arrays) {
descriptors.forEach(descriptor => assert_true(base_set.has(descriptor)));
}
}), test_desc);
</script>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic is removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => fake_characteristic.remove())
.then(() => assert_promise_rejects_with_message(
characteristic.startNotifications(),
expected,
'Characteristic got removed.')),
test_desc);
</script>

View file

@ -0,0 +1,28 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Add multiple event listeners then readValue().';
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => fake_characteristic.setNextReadResponse(GATT_SUCCESS, [0,1,2]))
.then(() => assert_promise_resolves_after_event(
characteristic,
'readValue',
'characteristicvaluechanged',
3 /* attach 3 listeners */))
.then(results => {
let read_value = new Uint8Array(results[0].buffer);
let event_values = results.slice(1).map(v => new Uint8Array(v.buffer));
for (let event_value of event_values) {
assert_equals(event_value.buffer, read_value.buffer);
assert_array_equals(event_value, read_value);
}
}), test_desc);
</script>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => fake_characteristic.remove())
.then(() => assert_promise_rejects_with_message(
characteristic.readValue(),
expected,
'Characteristic got removed.')),
test_desc);
</script>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Reading a characteristic should fire an event.';
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => fake_characteristic.setNextReadResponse(
GATT_SUCCESS, [0, 1, 2]))
.then(() => assert_promise_resolves_after_event(
characteristic,
'readValue',
'characteristicvaluechanged'))
.then(results => new Promise(resolve => {
let read_value = new Uint8Array(results[0].buffer);
let event_value = new Uint8Array(results[1].buffer);
assert_equals(event_value.buffer, read_value.buffer);
assert_array_equals(event_value, read_value);
resolve();
})), test_desc);
</script>

View file

@ -0,0 +1,25 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.readValue(), expected)),
test_desc);
</script>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'A read request succeeds and returns the characteristic\'s ' +
'value.';
const EXPECTED_VALUE = [0, 1, 2];
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => fake_characteristic.setNextReadResponse(
GATT_SUCCESS,
EXPECTED_VALUE))
.then(() => characteristic.readValue())
.then(value => assert_array_equals(
new Uint8Array(value.buffer),
EXPECTED_VALUE)),
test_desc);
</script>

View file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Succesful read should update characteristic.value';
const EXPECTED_VALUE = [0, 1, 2];
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => assert_equals(characteristic.value, null))
.then(() => fake_characteristic.setNextReadResponse(
GATT_SUCCESS, EXPECTED_VALUE))
.then(() => characteristic.readValue())
.then(() => assert_array_equals(
new Uint8Array(characteristic.value.buffer),
EXPECTED_VALUE)),
test_desc);
</script>

View file

@ -0,0 +1,25 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.startNotifications(), expected)),
test_desc);
</script>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => fake_characteristic.remove())
.then(() => assert_promise_rejects_with_message(
characteristic.writeValue(new ArrayBuffer(1 /* length */)),
expected,
'Characteristic got removed.')),
test_desc);
</script>

View file

@ -0,0 +1,25 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.writeValue(new Uint8Array(1)), expected)),
test_desc);
</script>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'A regular write request to a writable characteristic ' +
'should succeed.';
let typed_array = Uint8Array.of(1, 2);
let array_buffer = Uint8Array.of(3, 4).buffer;
let data_view = new DataView(new ArrayBuffer(2));
let characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic, fake_characteristic} = _))
.then(() => new Promise(resolve => {
data_view.setUint8(0, 5);
data_view.setUint8(1, 6);
resolve();
}))
.then(() => fake_characteristic.getLastWrittenValue())
.then(last_value => assert_true(last_value === null))
.then(() => fake_characteristic.setNextWriteResponse(GATT_SUCCESS))
.then(() => characteristic.writeValue(typed_array))
.then(() => fake_characteristic.getLastWrittenValue())
.then(last_value => assert_array_equals(last_value, [1, 2]))
.then(() => fake_characteristic.setNextWriteResponse(GATT_SUCCESS))
.then(() => characteristic.writeValue(array_buffer))
.then(() => fake_characteristic.getLastWrittenValue())
.then(last_value => assert_array_equals(last_value, [3, 4]))
.then(() => fake_characteristic.setNextWriteResponse(GATT_SUCCESS))
.then(() => characteristic.writeValue(data_view))
.then(() => fake_characteristic.getLastWrittenValue())
.then(last_value => assert_array_equals(last_value, [5, 6])),
test_desc);
</script>

View file

@ -0,0 +1,189 @@
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# TODO(509038): Delete the file in LayoutTests/bluetooth after all the script
# tests have been migrated to this directory.
"""Generator script for Web Bluetooth LayoutTests.
For each script-tests/X.js creates the following test files depending on the
contents of X.js
- getPrimaryService/X.html
- getPrimaryServices/X.html
- getPrimaryServices/X-with-uuid.html
script-tests/X.js files should contain "CALLS([variation1 | variation2 | ...])"
tokens that indicate what files to generate. Each variation in CALLS([...])
should corresponds to a js function call and its arguments. Additionally a
variation can end in [UUID] to indicate that the generated file's name should
have the -with-uuid suffix.
The PREVIOUS_CALL token will be replaced with the function that replaced CALLS.
The FUNCTION_NAME token will be replaced with the name of the function that
replaced CALLS.
For example, for the following template file:
// script-tests/example.js
promise_test(() => {
return navigator.bluetooth.requestDevice(...)
.then(device => device.gatt.CALLS([
getPrimaryService('heart_rate')|
getPrimaryServices('heart_rate')[UUID]]))
.then(device => device.gatt.PREVIOUS_CALL);
}, 'example test for FUNCTION_NAME');
this script will generate:
// getPrimaryService/example.html
promise_test(() => {
return navigator.bluetooth.requestDevice(...)
.then(device => device.gatt.getPrimaryService('heart_rate'))
.then(device => device.gatt.getPrimaryService('heart_rate'));
}, 'example test for getPrimaryService');
// getPrimaryServices/example-with-uuid.html
promise_test(() => {
return navigator.bluetooth.requestDevice(...)
.then(device => device.gatt.getPrimaryServices('heart_rate'))
.then(device => device.gatt.getPrimaryServices('heart_rate'));
}, 'example test for getPrimaryServices');
Run
$ python //third_party/WebKit/LayoutTests/bluetooth/generate.py
and commit the generated files.
"""
import fnmatch
import os
import re
import sys
import logging
TEMPLATES_DIR = 'script-tests'
class GeneratedTest:
def __init__(self, data, path, template):
self.data = data
self.path = path
self.template = template
def GetGeneratedTests():
"""Yields a GeneratedTest for each call in templates in script-tests."""
bluetooth_tests_dir = os.path.dirname(os.path.realpath(__file__))
# Read Base Test Template.
base_template_file_handle = open(
os.path.join(
bluetooth_tests_dir,
TEMPLATES_DIR,
'base_test_html.template'
), 'r')
base_template_file_data = base_template_file_handle.read().decode('utf-8')
base_template_file_handle.close()
# Get Templates.
template_path = os.path.join(bluetooth_tests_dir, TEMPLATES_DIR)
available_templates = []
for root, _, files in os.walk(template_path):
for template in files:
if template.endswith('.js'):
available_templates.append(os.path.join(root, template))
# Generate Test Files
for template in available_templates:
# Read template
template_file_handle = open(template, 'r')
template_file_data = template_file_handle.read().decode('utf-8')
template_file_handle.close()
template_name = os.path.splitext(os.path.basename(template))[0]
# Find function names in multiline pattern: CALLS( [ function_name,function_name2[UUID] ])
result = re.search(
r'CALLS\(' + # CALLS(
r'[^\[]*' + # Any characters not [, allowing for new lines.
r'\[' + # [
r'(.*?)' + # group matching: function_name(), function_name2[UUID]
r'\]\)', # adjacent closing characters: ])
template_file_data, re.MULTILINE | re.DOTALL)
if result is None:
raise Exception('Template must contain \'CALLS\' tokens')
new_test_file_data = base_template_file_data.replace('TEST',
template_file_data)
# Replace CALLS([...]) with CALLS so that we don't have to replace the
# CALLS([...]) for every new test file.
new_test_file_data = new_test_file_data.replace(result.group(), 'CALLS')
# Replace 'PREVIOUS_CALL' with 'CALLS' so that we can replace it while
# replacing CALLS.
new_test_file_data = new_test_file_data.replace('PREVIOUS_CALL', 'CALLS')
for call in result.group(1).split('|'):
# Parse call
call = call.strip()
function_name, args, uuid_suffix = re.search(r'(.*?)\((.*)\)(\[UUID\])?', call).groups()
# Replace template tokens
call_test_file_data = new_test_file_data
call_test_file_data = call_test_file_data.replace('CALLS', '{}({})'.format(function_name, args))
call_test_file_data = call_test_file_data.replace('FUNCTION_NAME', function_name)
# Get test file name
group_dir = os.path.basename(os.path.abspath(os.path.join(template, os.pardir)))
call_test_file_name = 'gen-{}{}.https.html'.format(template_name, '-with-uuid' if uuid_suffix else '')
call_test_file_path = os.path.join(bluetooth_tests_dir, group_dir, function_name, call_test_file_name)
yield GeneratedTest(call_test_file_data, call_test_file_path, template)
def main():
logging.basicConfig(level=logging.INFO)
previous_generated_files = set()
current_path = os.path.dirname(os.path.realpath(__file__))
for root, _, filenames in os.walk(current_path):
for filename in fnmatch.filter(filenames, 'gen-*.https.html'):
previous_generated_files.add(os.path.join(root, filename))
generated_files = set()
for generated_test in GetGeneratedTests():
prev_len = len(generated_files)
generated_files.add(generated_test.path)
if prev_len == len(generated_files):
logging.info('Generated the same test twice for template:\n%s',
generated_test.template)
# Create or open test file
directory = os.path.dirname(generated_test.path)
if not os.path.exists(directory):
os.makedirs(directory)
test_file_handle = open(generated_test.path, 'wb')
# Write contents
test_file_handle.write(generated_test.data.encode('utf-8'))
test_file_handle.close()
new_generated_files = generated_files - previous_generated_files
if len(new_generated_files) != 0:
logging.info('Newly generated tests:')
for generated_file in new_generated_files:
logging.info(generated_file)
obsolete_files = previous_generated_files - generated_files
if len(obsolete_files) != 0:
logging.warning('The following files might be obsolete:')
for generated_file in obsolete_files:
logging.warning(generated_file)
if __name__ == '__main__':
sys.exit(main())

View file

@ -0,0 +1,56 @@
#!/usr/bin/python
# Copyright 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# TODO(50903): Delete the file in LayoutTests/bluetooth after all the tests have
# been migrated to this directory.
"""Test that the set of gen-* files is the same as the generated files."""
import fnmatch
import os
import sys
import generate
import logging
UPDATE_TIP = 'To update the generated tests, run:\n' \
'$ python third_party/WebKit/LayoutTests/bluetooth/generate.py'
def main():
logging.basicConfig(level=logging.INFO)
logging.info(UPDATE_TIP)
generated_files = set()
# Tests data in gen-* files is the same as the data generated.
for generated_test in generate.GetGeneratedTests():
generated_files.add(generated_test.path)
try:
with open(generated_test.path, 'r') as f:
data = f.read().decode('utf-8')
if data != generated_test.data:
logging.error('%s does not match template', generated_test.path)
return -1
except IOError, e:
if e.errno == 2:
logging.error('Missing generated test:\n%s\nFor template:\n%s',
generated_test.path,
generated_test.template)
return -1
# Tests that there are no obsolete generated files.
previous_generated_files = set()
current_path = os.path.dirname(os.path.realpath(__file__))
for root, _, filenames in os.walk(current_path):
for filename in fnmatch.filter(filenames, 'gen-*.https.html'):
previous_generated_files.add(os.path.join(root, filename))
if previous_generated_files != generated_files:
logging.error('There are extra generated tests. Please remove them.')
for test_path in previous_generated_files - generated_files:
logging.error('%s', test_path)
return -1
if __name__ == '__main__':
sys.exit(main())

View file

@ -4,6 +4,7 @@
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
const test_desc = 'Bluetooth IDL test';
test(() => {
assert_throws(new TypeError(), () => new Bluetooth(),
@ -14,6 +15,5 @@ test(() => {
// Bluetooth implements BluetoothDiscovery;
assert_true('requestDevice' in navigator.bluetooth);
assert_equals(navigator.bluetooth.requestDevice.length, 0);
}, 'Bluetooth IDL test');
}, test_desc);
</script>

View file

@ -3,6 +3,7 @@
<script src="/resources/testharnessreport.js"></script>
<script>
'use strict';
const test_desc = '[SameObject] test for navigator.bluetooth';
test(() => {
assert_true('bluetooth' in navigator,
@ -11,5 +12,5 @@ test(() => {
test(() => {
assert_equals(navigator.bluetooth, navigator.bluetooth);
}, '[SameObject] test for navigator.bluetooth');
}, test_desc);
</script>

View file

@ -6,12 +6,11 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
bluetooth_test(() => {
return setUpPreconnectedDevice({name: ''})
const test_desc = 'Device with empty name and no UUIDs nearby. Should be ' +
'found if acceptAllDevices is true.';
bluetooth_test(() => setUpPreconnectedDevice({name: ''})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => {
assert_equals(device.name, '');
});
}, 'Device with empty name and no UUIDs nearby. Should be found if ' +
'acceptAllDevices is true.');
.then(device => assert_equals(device.name, '')),
test_desc);
</script>

View file

@ -5,13 +5,12 @@
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
bluetooth_test(() => {
let device_name = 'LE Device';
return setUpPreconnectedDevice({name: device_name})
const test_desc = 'A device with name and no UUIDs nearby. Should be found if ' +
'acceptAllDevices is true.';
const name = 'LE Device';
bluetooth_test(() => setUpPreconnectedDevice({name: name})
.then(() => requestDeviceWithTrustedClick({acceptAllDevices: true}))
.then(device => {
assert_equals(device.name, device_name);
});
}, 'A device with name and no UUIDs nearby. Should be found if ' +
'acceptAllDevices is true.');
.then(device => assert_equals(device.name, name)),
test_desc);
</script>

View file

@ -6,15 +6,17 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
bluetooth_test(() => {
return getHealthThermometerDevice({acceptAllDevices: true})
const test_desc = 'requestDevice called with acceptAllDevices: true and ' +
'with no optionalServices. Should not get access to any services.';
const expected = new DOMException(
'Origin is not allowed to access any service. ' +
'Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError');
bluetooth_test(() => getHealthThermometerDevice({acceptAllDevices: true})
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.getPrimaryServices(),
new DOMException(
'Origin is not allowed to access any service. ' +
'Tip: Add the service UUID to \'optionalServices\' in ' +
'requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError')));
}, 'requestDevice called with acceptAllDevices: true and with no ' +
'optionalServices. Should not get access to any services.');
expected)),
test_desc);
</script>

View file

@ -9,19 +9,18 @@
const test_desc = 'requestDevice called with acceptAllDevices: true and with ' +
'optionalServices. Should get access to services.';
bluetooth_test(() =>
getTwoHealthThermometerServicesDevice()
.then(() => requestDeviceWithTrustedClick({
acceptAllDevices: true,
optionalServices: ['health_thermometer']
}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryServices())
.then(services => {
assert_equals(services.length, 2);
services.forEach(service => {
assert_equals(service.uuid,
BluetoothUUID.getService('health_thermometer'));
});
}), test_desc);
bluetooth_test(() => getTwoHealthThermometerServicesDevice()
.then(() => requestDeviceWithTrustedClick({
acceptAllDevices: true,
optionalServices: ['health_thermometer']
}))
.then(device => device.gatt.connect())
.then(gattServer => gattServer.getPrimaryServices())
.then(services => {
assert_equals(services.length, 2);
services.forEach(service => {
assert_equals(service.uuid,
BluetoothUUID.getService('health_thermometer'));
});
}), test_desc);
</script>

View file

@ -4,27 +4,27 @@ let device;
function requestDeviceWithOptionsAndConnect(options) {
return navigator.bluetooth.requestDevice(options)
.then(device => device.gatt.connect());
.then(device => device.gatt.connect());
}
window.onmessage = messageEvent => {
switch (messageEvent.data.type) {
case 'RequestAndConnect':
requestDeviceWithOptionsAndConnect(messageEvent.data.options)
.then(gatt => {
device = gatt.device;
parent.postMessage('Connected', '*');
}).catch(err => {
parent.postMessage(`FAIL: ${err}`, '*');
});
.then(gatt => {
device = gatt.device;
parent.postMessage('Connected', '*');
}).catch(err => {
parent.postMessage(`FAIL: ${err}`, '*');
});
break;
case 'DiscoverServices':
requestDeviceWithOptionsAndConnect(messageEvent.data.options)
.then(gatt => gatt.getPrimaryServices())
.then(() => parent.postMessage('DiscoveryComplete', '*'))
.catch(err => {
parent.postMessage(`FAIL: ${err}`, '*');
});
.then(gatt => gatt.getPrimaryServices())
.then(() => parent.postMessage('DiscoveryComplete', '*'))
.catch(err => {
parent.postMessage(`FAIL: ${err}`, '*');
});
break;
default:
parent.postMessage(`FAIL: Bad message type: ${messageEvent.data.type}`,

View file

@ -0,0 +1,10 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
TEST
</script>

View file

@ -0,0 +1,22 @@
'use strict';
const test_desc = 'Characteristic gets removed. Reject with InvalidStateError.';
const expected = new DOMException('GATT Characteristic no longer exists.',
'InvalidStateError');
let fake_peripheral, characteristic, fake_characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({fake_peripheral, characteristic, fake_characteristic} = _))
.then(() => characteristic.getDescriptor(user_description.name))
.then(() => null, (e) => assert_unreached('Caught error unexpectedly.', e))
.then(() => fake_characteristic.remove())
.then(() => fake_peripheral.simulateGATTServicesChanged())
.then(() => assert_promise_rejects_with_message(
characteristic.CALLS([
getDescriptor(user_description.name)|
getDescriptors(user_description.name)[UUID]|
getDescriptors()|
readValue()|
writeValue(new Uint8Array(1))|
startNotifications()
]), expected)),
test_desc);

View file

@ -0,0 +1,32 @@
'use strict';
const test_desc = 'Calls to FUNCTION_NAME should return the same object.';
let characteristic;
bluetooth_test(() => getMeasurementIntervalCharacteristic()
.then(_ => ({characteristic} = _))
.then(() => Promise.all([
characteristic.CALLS([
getDescriptor(user_description.alias)|
getDescriptors(user_description.alias)
]),
characteristic.FUNCTION_NAME(user_description.name),
characteristic.FUNCTION_NAME(user_description.uuid)
]))
.then(descriptors_arrays => {
assert_true(descriptors_arrays.length > 0)
// Convert to arrays if necessary.
for (let i = 0; i < descriptors_arrays.length; i++) {
descriptors_arrays[i] = [].concat(descriptors_arrays[i]);
}
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[0]);
for (let descriptors of descriptors_arrays) {
descriptors.forEach(descriptor => assert_true(base_set.has(descriptor)));
}
}), test_desc);

View file

@ -0,0 +1,22 @@
'use strict';
const test_desc = 'disconnect() called before FUNCTION_NAME. ' +
'Reject with NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.',
'NetworkError');
let device;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']
})
.then(_ => ({device} = _))
.then(() => device.gatt.disconnect())
.then(() => assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]]),
expected)),
test_desc);

View file

@ -0,0 +1,22 @@
'use strict';
const test_desc = 'disconnect() called during a FUNCTION_NAME ' +
'call that fails. Reject with NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.', 'NetworkError');
let device;
bluetooth_test(() => getEmptyHealthThermometerDevice()
.then(_ => ({device} = _))
.then(() => {
let promise = assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]
]),
expected)
device.gatt.disconnect();
return promise;
}),
test_desc);

View file

@ -0,0 +1,23 @@
'use strict';
const test_desc = 'disconnect() called during a FUNCTION_NAME call that ' +
'succeeds. Reject with NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.',
'NetworkError');
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']
})
.then(({device}) => {
let promise = assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]
]),
expected);
device.gatt.disconnect();
return promise;
}), test_desc);

View file

@ -0,0 +1,39 @@
'use strict';
const test_desc = 'Calls on services after we disconnect and connect again. '+
'Should reject with InvalidStateError.';
let device, services;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}]
})
.then(_ => ({device} = _))
.then(() => device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]]))
// Convert to array if necessary.
.then(s => services = [].concat(s))
.then(() => device.gatt.disconnect())
.then(() => device.gatt.connect())
.then(() => {
let promises = Promise.resolve();
for (let service of services) {
let error = new DOMException(
`Service with UUID ${service.uuid} is no longer valid. Remember ` +
`to retrieve the service again after reconnecting.`,
'InvalidStateError');
promises = promises.then(() =>
assert_promise_rejects_with_message(
service.getCharacteristic('measurement_interval'),
error));
promises = promises.then(() =>
assert_promise_rejects_with_message(
service.getCharacteristics(),
error));
promises = promises.then(() =>
assert_promise_rejects_with_message(
service.getCharacteristics('measurement_interval'),
error));
}
return promises;
}), test_desc);

View file

@ -0,0 +1,20 @@
'use strict';
const test_desc = 'FUNCTION_NAME called before connecting. Reject with ' +
'NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.',
'NetworkError');
bluetooth_test(() => getDiscoveredHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']
})
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]
]),
expected)),
test_desc);

View file

@ -0,0 +1,25 @@
'use strict';
const test_desc = 'Request for absent service without permission. Should ' +
'Reject with SecurityError even if services have been discovered already.';
const expected = new DOMException(
'Origin is not allowed to access the service. Tip: Add the service ' +
'UUID to \'optionalServices\' in requestDevice() options. ' +
'https://goo.gl/HxfxSQ',
'SecurityError');
let device;
bluetooth_test(() => getHealthThermometerDeviceWithServicesDiscovered({
filters: [{services: ['health_thermometer']}]
})
.then(_ => ({device} = _))
.then(() => Promise.all([
assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService(glucose.alias)|
getPrimaryServices(glucose.alias)[UUID]
]), expected),
assert_promise_rejects_with_message(
device.gatt.FUNCTION_NAME(glucose.name), expected),
assert_promise_rejects_with_message(
device.gatt.FUNCTION_NAME(glucose.uuid), expected)])),
test_desc);

View file

@ -0,0 +1,16 @@
'use strict';
const test_desc = 'Request for absent service. Must reject with ' +
'NotFoundError even when the services have previously been discovered.';
bluetooth_test(() => getHealthThermometerDeviceWithServicesDiscovered({
filters: [{services: ['health_thermometer']}],
optionalServices: ['glucose']})
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('glucose')|
getPrimaryServices('glucose')[UUID]
]),
new DOMException(
`No Services matching UUID ${glucose.uuid} found in Device.`,
'NotFoundError'))),
test_desc);

View file

@ -0,0 +1,25 @@
'use strict';
const test_desc = 'Garbage Collection ran during a FUNCTION_NAME ' +
'call that failed. Should not crash.'
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect first ' +
'with `device.gatt.connect`.',
'NetworkError');
let promise;
bluetooth_test(() => getEmptyHealthThermometerDevice()
.then(({device}) => {
promise = assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]
]),
expected);
// Disconnect called to clear attributeInstanceMap and allow the
// object to get garbage collected.
device.gatt.disconnect();
return runGarbageCollection();
})
.then(() => promise),
test_desc);

View file

@ -0,0 +1,24 @@
'use strict';
const test_desc = 'Garbage Collection ran during a FUNCTION_NAME call that ' +
'succeeds. Should not crash.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. ' +
'(Re)connect first with `device.gatt.connect`.',
'NetworkError');
let promise;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}]
})
.then(({device}) => {
promise = assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('health_thermometer') |
getPrimaryServices() |
getPrimaryServices('health_thermometer')[UUID]]),
expected);
device.gatt.disconnect();
return runGarbageCollection();
})
.then(() => promise),
test_desc);

View file

@ -0,0 +1,35 @@
'use strict';
const test_desc = 'Calls to FUNCTION_NAME after a disconnection should return ' +
'a different object.';
let device, services_first_connection, services_second_connection;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']
})
.then(_ => ({device} = _))
.then(() => device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]]))
.then(services => services_first_connection = services)
.then(() => device.gatt.disconnect())
.then(() => device.gatt.connect())
.then(() => device.gatt.PREVIOUS_CALL)
.then(services => services_second_connection = services)
.then(() => {
// Convert to arrays if necessary.
services_first_connection = [].concat(services_first_connection);
services_second_connection = [].concat(services_second_connection);
assert_equals(services_first_connection.length,
services_second_connection.length);
let first_connection_set = new Set(services_first_connection);
let second_connection_set = new Set(services_second_connection);
// The two sets should be disjoint.
let common_services = services_first_connection.filter(
val => second_connection_set.has(val));
assert_equals(common_services.length, 0);
}), test_desc);

View file

@ -0,0 +1,33 @@
'use strict';
const test_desc = 'Calls to FUNCTION_NAME should return the same object.';
let device;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']})
.then(({device}) => Promise.all([
device.gatt.CALLS([
getPrimaryService('health_thermometer')|
getPrimaryServices()|
getPrimaryServices('health_thermometer')[UUID]]),
device.gatt.PREVIOUS_CALL]))
.then(([services_first_call, services_second_call]) => {
// Convert to arrays if necessary.
services_first_call = [].concat(services_first_call);
services_second_call = [].concat(services_second_call);
assert_equals(services_first_call.length, services_second_call.length);
let first_call_set = new Set(services_first_call);
assert_equals(services_first_call.length, first_call_set.size);
let second_call_set = new Set(services_second_call);
assert_equals(services_second_call.length, second_call_set.size);
services_first_call.forEach(service => {
assert_true(second_call_set.has(service))
});
services_second_call.forEach(service => {
assert_true(first_call_set.has(service));
});
}), test_desc);

View file

@ -0,0 +1,22 @@
'use strict';
const test_desc = 'Wrong Service name. Reject with TypeError.';
const expected = new DOMException(
"Failed to execute 'FUNCTION_NAME' on " +
"'BluetoothRemoteGATTServer': Invalid Service 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/services" +
" e.g. 'alert_notification'.",
'TypeError');
bluetooth_test(() => getHealthThermometerDevice()
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('wrong_name')|
getPrimaryServices('wrong_name')
]),
expected,
'Wrong Service name passed.')),
test_desc);

View file

@ -0,0 +1,23 @@
'use strict';
const test_desc = 'Request for absent service without permission. ' +
'Reject with SecurityError.';
const expected = new DOMException(
'Origin is not allowed to access the service. Tip: Add the service UUID ' +
'to \'optionalServices\' in requestDevice() options. ' +
'https://goo.gl/HxfxSQ',
'SecurityError');
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}]
})
.then(({device}) => Promise.all([
assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService(glucose.alias)|
getPrimaryServices(glucose.alias)[UUID]
]), expected),
assert_promise_rejects_with_message(
device.gatt.FUNCTION_NAME(glucose.name), expected),
assert_promise_rejects_with_message(
device.gatt.FUNCTION_NAME(glucose.uuid), expected)])),
test_desc);

View file

@ -0,0 +1,17 @@
'use strict';
const test_desc = 'Request for present service without permission to access ' +
'any service. Reject with SecurityError.';
const expected = new DOMException(
'Origin is not allowed to access any service. Tip: Add the service ' +
'UUID to \'optionalServices\' in requestDevice() options. ' +
'https://goo.gl/HxfxSQ',
'SecurityError');
bluetooth_test(() => getHealthThermometerDevice({acceptAllDevices: true})
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('heart_rate')|
getPrimaryServices()|
getPrimaryServices('heart_rate')[UUID]]),
expected)),
test_desc);

View file

@ -0,0 +1,22 @@
'use strict';
const test_desc = 'Request for present service without permission. ' +
'Reject with SecurityError.';
const expected = new DOMException(
'Origin is not allowed to access the service. Tip: Add the service UUID ' +
'to \'optionalServices\' in requestDevice() options. https://goo.gl/HxfxSQ',
'SecurityError');
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}]
})
.then(({device}) => Promise.all([
assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService(generic_access.alias)|
getPrimaryServices(generic_access.alias)[UUID]
]), expected),
assert_promise_rejects_with_message(
device.gatt.FUNCTION_NAME(generic_access.name), expected),
assert_promise_rejects_with_message(
device.gatt.FUNCTION_NAME(generic_access.uuid), expected)])),
test_desc);

View file

@ -0,0 +1,16 @@
'use strict';
const test_desc = 'Request for absent service. Reject with NotFoundError.';
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['glucose']
})
.then(({device}) => assert_promise_rejects_with_message(
device.gatt.CALLS([
getPrimaryService('glucose')|
getPrimaryServices('glucose')[UUID]
]),
new DOMException(
`No Services matching UUID ${glucose.uuid} found in Device.`,
'NotFoundError'))),
test_desc);

View file

@ -6,12 +6,14 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
bluetooth_test(() => {
return getDiscoveredHealthThermometerDevice()
.then(({device, fake_peripheral}) => {
return fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})
.then(() => device.gatt.connect())
.then(gatt => assert_true(gatt.connected));
});
}, 'Device will connect');
const test_desc = 'Device will connect';
let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() =>
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(gatt => assert_true(gatt.connected)),
test_desc);
</script>

View file

@ -6,17 +6,17 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
bluetooth_test(() => {
return getDiscoveredHealthThermometerDevice()
.then(({device, fake_peripheral}) => {
return fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})
.then(() => {
// Don't return the promise and let |device| go out of scope
// so that it gets garbage collected.
device.gatt.connect();
});
})
.then(runGarbageCollection)
}, 'Garbage Collection ran during a connect call that succeeds. ' +
'Should not crash.');
const test_desc = 'Garbage Collection ran during a connect call that ' +
'succeeds. Should not crash.';
let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() =>
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
// Don't return the promise and let |device| go out of scope
// so that it gets garbage collected.
.then(() => device.gatt.connect())
.then(runGarbageCollection),
test_desc);
</script>

View file

@ -6,20 +6,20 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
bluetooth_test(() => {
return getDiscoveredHealthThermometerDevice()
.then(({device, fake_peripheral}) => {
return fake_peripheral
.setNextGATTConnectionResponse({code: HCI_SUCCESS})
.then(() => device.gatt.connect())
.then(gatt1 => {
// No second response is necessary because an ATT Bearer
// already exists from the first connection.
// See https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
// step 5.1.
return device.gatt.connect().then(gatt2 => [gatt1, gatt2]);
});
})
.then(([gatt1, gatt2]) => assert_equals(gatt1, gatt2));
}, 'Multiple connects should return the same gatt object.');
const test_desc = 'Multiple connects should return the same gatt object.';
let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() =>
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
// No second response is necessary because an ATT Bearer
// already exists from the first connection.
// See https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-connect
// step 5.1.
.then(gatt1 => device.gatt.connect()
.then(gatt2 => [gatt1, gatt2]))
.then(([gatt1, gatt2]) => assert_equals(gatt1, gatt2)),
test_desc);
</script>

View file

@ -6,14 +6,14 @@
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
bluetooth_test(() => {
return getDiscoveredHealthThermometerDevice()
.then(({device, fake_peripheral}) => {
return fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS})
.then(() => device.gatt.connect());
})
.then(gatt => {
assert_equals(gatt.device, gatt.device);
});
}, "[SameObject] test for BluetoothRemoteGATTServer's device.");
const test_desc = '[SameObject] test for BluetoothRemoteGATTServer\'s device.';
let device, fake_peripheral;
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() =>
fake_peripheral.setNextGATTConnectionResponse({code: HCI_SUCCESS}))
.then(() => device.gatt.connect())
.then(gatt => assert_equals(gatt.device, gatt.device)),
test_desc);
</script>

View file

@ -12,18 +12,18 @@ let device, fake_peripheral;
// TODO(569716): Test that the disconnect signal was sent to the device.
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS,
}))
.then(() => device.gatt.connect()
.then(gattServer => {
gattServer.disconnect();
assert_false(gattServer.connected);
})
.then(() => device.gatt.connect())
.then(gattServer => {
gattServer.disconnect();
assert_false(gattServer.connected);
})), test_desc);
.then(_ => ({device, fake_peripheral} = _))
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS,
}))
.then(() => device.gatt.connect()
.then(gattServer => {
gattServer.disconnect();
assert_false(gattServer.connected);
})
.then(() => device.gatt.connect())
.then(gattServer => {
gattServer.disconnect();
assert_false(gattServer.connected);
})), test_desc);
</script>

View file

@ -11,26 +11,26 @@ const test_desc = 'Detach frame then garbage collect. We shouldn\'t crash.';
let iframe = document.createElement('iframe');
bluetooth_test(() => setUpConnectableHealthThermometerDevice()
// 1. Load the iframe.
.then(() => new Promise(resolve => {
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Connect device, detach the iframe, and run garbage collection.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'RequestAndConnect',
options: {filters: [{services: ['health_thermometer']}]}
}, '*');
});
// 1. Load the iframe.
.then(() => new Promise(resolve => {
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Connect device, detach the iframe, and run garbage collection.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'RequestAndConnect',
options: {filters: [{services: ['health_thermometer']}]}
}, '*');
});
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'Connected');
iframe.remove();
runGarbageCollection().then(resolve);
}
})), test_desc)
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'Connected');
iframe.remove();
runGarbageCollection().then(resolve);
}
})), test_desc)
</script>
</body>

View file

@ -12,15 +12,15 @@ let device, fake_peripheral;
// TODO(569716): Test that the disconnect signal was sent to the device.
bluetooth_test(() => getDiscoveredHealthThermometerDevice()
.then(_ => ({device, fake_peripheral} = _))
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS,
}))
.then(() => device.gatt.connect())
.then(gattServer => {
gattServer.disconnect();
assert_false(gattServer.connected);
gattServer.disconnect();
assert_false(gattServer.connected);
}), test_desc);
.then(_ => ({device, fake_peripheral} = _))
.then(() => fake_peripheral.setNextGATTConnectionResponse({
code: HCI_SUCCESS,
}))
.then(() => device.gatt.connect())
.then(gattServer => {
gattServer.disconnect();
assert_false(gattServer.connected);
gattServer.disconnect();
assert_false(gattServer.connected);
}), test_desc);
</script>

View file

@ -11,28 +11,28 @@ const test_desc = 'Garbage collect then detach frame. We shouldn\'t crash.';
let iframe = document.createElement('iframe');
bluetooth_test(() => setUpConnectableHealthThermometerDevice()
// 1. Load the iframe.
.then((f) => new Promise(resolve => {
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Connect device, run garbage collection, and detach iframe.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'RequestAndConnect',
options: {filters: [{services: ['health_thermometer']}]}
}, '*');
});
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'Connected');
runGarbageCollection().then(() => {
iframe.remove();
resolve();
// 1. Load the iframe.
.then((f) => new Promise(resolve => {
iframe.src = '/bluetooth/resources/health-thermometer-iframe.html';
document.body.appendChild(iframe);
iframe.addEventListener('load', resolve);
}))
// 2. Connect device, run garbage collection, and detach iframe.
.then(() => new Promise(resolve => {
callWithTrustedClick(() => {
iframe.contentWindow.postMessage({
type: 'RequestAndConnect',
options: {filters: [{services: ['health_thermometer']}]}
}, '*');
});
}
})), test_desc)
window.onmessage = messageEvent => {
assert_equals(messageEvent.data, 'Connected');
runGarbageCollection().then(() => {
iframe.remove();
resolve();
});
}
})), test_desc)
</script>
</body>

View file

@ -0,0 +1,29 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'disconnect() called before getPrimaryService. ' +
'Reject with NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.',
'NetworkError');
let device;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']
})
.then(_ => ({device} = _))
.then(() => device.gatt.disconnect())
.then(() => assert_promise_rejects_with_message(
device.gatt.getPrimaryService('health_thermometer'),
expected)),
test_desc);
</script>

View file

@ -0,0 +1,28 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'disconnect() called during a getPrimaryService ' +
'call that fails. Reject with NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.', 'NetworkError');
let device;
bluetooth_test(() => getEmptyHealthThermometerDevice()
.then(_ => ({device} = _))
.then(() => {
let promise = assert_promise_rejects_with_message(
device.gatt.getPrimaryService('health_thermometer'),
expected)
device.gatt.disconnect();
return promise;
}),
test_desc);
</script>

View file

@ -0,0 +1,29 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'disconnect() called during a getPrimaryService call that ' +
'succeeds. Reject with NetworkError.';
const expected = new DOMException(
'GATT Server is disconnected. Cannot retrieve services. (Re)connect ' +
'first with `device.gatt.connect`.',
'NetworkError');
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}],
optionalServices: ['generic_access']
})
.then(({device}) => {
let promise = assert_promise_rejects_with_message(
device.gatt.getPrimaryService('health_thermometer'),
expected);
device.gatt.disconnect();
return promise;
}), test_desc);
</script>

View file

@ -0,0 +1,46 @@
<!-- Generated by //third_party/WebKit/LayoutTests/bluetooth/generate.py -->
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/resources/testdriver.js"></script>
<script src="/resources/testdriver-vendor.js"></script>
<script src="/bluetooth/resources/bluetooth-helpers.js"></script>
<script>
'use strict';
const test_desc = 'Calls on services after we disconnect and connect again. '+
'Should reject with InvalidStateError.';
let device, services;
bluetooth_test(() => getHealthThermometerDevice({
filters: [{services: ['health_thermometer']}]
})
.then(_ => ({device} = _))
.then(() => device.gatt.getPrimaryService('health_thermometer'))
// Convert to array if necessary.
.then(s => services = [].concat(s))
.then(() => device.gatt.disconnect())
.then(() => device.gatt.connect())
.then(() => {
let promises = Promise.resolve();
for (let service of services) {
let error = new DOMException(
`Service with UUID ${service.uuid} is no longer valid. Remember ` +
`to retrieve the service again after reconnecting.`,
'InvalidStateError');
promises = promises.then(() =>
assert_promise_rejects_with_message(
service.getCharacteristic('measurement_interval'),
error));
promises = promises.then(() =>
assert_promise_rejects_with_message(
service.getCharacteristics(),
error));
promises = promises.then(() =>
assert_promise_rejects_with_message(
service.getCharacteristics('measurement_interval'),
error));
}
return promises;
}), test_desc);
</script>

Some files were not shown because too many files have changed in this diff Show more