summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/compute-pressure
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/compute-pressure')
-rw-r--r--testing/web-platform/tests/compute-pressure/README.md2
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.window.js9
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_basic_async.tentative.https.window.js88
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_detached_iframe.tentative.https.html97
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.window.js40
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js33
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js63
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.window.js61
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_factors.tentative.https.window.js18
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.window.js30
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js40
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js16
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js17
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.window.js23
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js130
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.window.js19
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.window.js29
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.window.js77
-rw-r--r--testing/web-platform/tests/compute-pressure/idlharness.https.window.js14
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html39
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html37
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html55
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.headers1
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html44
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.headers1
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html34
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html62
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html.headers1
-rw-r--r--testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html11
-rw-r--r--testing/web-platform/tests/compute-pressure/resources/pressure-helpers.js35
-rw-r--r--testing/web-platform/tests/compute-pressure/resources/support-iframe.html30
31 files changed, 1156 insertions, 0 deletions
diff --git a/testing/web-platform/tests/compute-pressure/README.md b/testing/web-platform/tests/compute-pressure/README.md
new file mode 100644
index 0000000000..05bacb7f16
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/README.md
@@ -0,0 +1,2 @@
+This directory contains (tentative) tests for the
+[Compute Pressure](https://wicg.github.io/compute-pressure/) specification.
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.window.js
new file mode 100644
index 0000000000..2f463e502b
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.window.js
@@ -0,0 +1,9 @@
+'use strict';
+
+promise_test(async t => {
+ await new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+}, 'An active PressureObserver calls its callback at least once');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_basic_async.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_basic_async.tentative.https.window.js
new file mode 100644
index 0000000000..3a9a32dedc
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_basic_async.tentative.https.window.js
@@ -0,0 +1,88 @@
+// META: timeout=long
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+
+'use strict';
+
+pressure_test((t, mockPressureService) => {
+ const observer = new PressureObserver(() => {
+ assert_unreached('The observer callback should not be called');
+ });
+
+ mockPressureService.setExpectedFailure(
+ new DOMException('', 'NotSupportedError'));
+ return promise_rejects_dom(t, 'NotSupportedError', observer.observe('cpu'));
+}, 'Return NotSupportedError when calling observer()');
+
+pressure_test(async (t, mockPressureService) => {
+ const changes = await new Promise(resolve => {
+ const observer = new PressureObserver(resolve);
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 1.0);
+ });
+ assert_true(changes.length === 1);
+ assert_equals(changes[0].state, 'critical');
+ assert_equals(changes[0].source, 'cpu');
+ assert_equals(typeof changes[0].time, 'number');
+}, 'Basic functionality test');
+
+pressure_test((t, mockPressureService) => {
+ const observer = new PressureObserver(() => {
+ assert_unreached('The observer callback should not be called');
+ });
+
+ const promise = observer.observe('cpu');
+ observer.unobserve('cpu');
+ mockPressureService.setPressureUpdate('critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 1.0);
+
+ return promise_rejects_dom(t, 'NotSupportedError', promise);
+}, 'Removing observer before observe() resolves works');
+
+pressure_test(async (t, mockPressureService) => {
+ const callbackPromises = [];
+ const observePromises = [];
+
+ for (let i = 0; i < 2; i++) {
+ callbackPromises.push(new Promise(resolve => {
+ const observer = new PressureObserver(resolve);
+ observePromises.push(observer.observe('cpu'));
+ }));
+ }
+
+ await Promise.all(observePromises);
+
+ mockPressureService.setPressureUpdate('critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 1.0);
+
+ return Promise.all(callbackPromises);
+}, 'Calling observe() multiple times works');
+
+pressure_test(async (t, mockPressureService) => {
+ const observer1_changes = [];
+ await new Promise(resolve => {
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ resolve();
+ });
+ t.add_cleanup(() => observer1.disconnect());
+ observer1.observe('cpu');
+ mockPressureService.setPressureUpdate('critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 1.0);
+ });
+ assert_true(observer1_changes.length === 1);
+ assert_equals(observer1_changes[0][0].state, 'critical');
+
+ const observer2_changes = [];
+ await new Promise(resolve => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ });
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu');
+ });
+ assert_true(observer2_changes.length === 1);
+ assert_equals(observer2_changes[0][0].state, 'critical');
+}, 'Starting a new observer after an observer has started works');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_detached_iframe.tentative.https.html b/testing/web-platform/tests/compute-pressure/compute_pressure_detached_iframe.tentative.https.html
new file mode 100644
index 0000000000..3b0a5504e5
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_detached_iframe.tentative.https.html
@@ -0,0 +1,97 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>PressureObserver on DOMWindow of detached iframe</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+'use strict';
+
+test(() => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const frame_window = iframe.contentWindow;
+
+ iframe.remove();
+ assert_equals(undefined, frame_window.PressureObserver);
+}, 'PressureObserver constructor does not exist in detached iframes');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const frame_window = iframe.contentWindow;
+
+ const observer = new frame_window.PressureObserver(
+ () => {},
+ {sampleRate: 1});
+ const iframe_DOMException = frame_window.DOMException;
+
+ iframe.remove();
+
+ // Calling observe() from a detached iframe should fail but not crash.
+ await promise_rejects_dom(t, 'NotSupportedError', iframe_DOMException,
+ observer.observe('cpu'));
+}, 'PressureObserver.observe() on detached frame rejects');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const frame_window = iframe.contentWindow;
+
+ const observer = new frame_window.PressureObserver(
+ () => {},
+ {sampleRate: 1});
+
+ await observer.observe('cpu');
+
+ iframe.remove();
+
+ // Calling disconnect() from a detached iframe should not crash.
+ observer.disconnect();
+}, 'PressureObserver.disconnect() on detached frame returns');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const frame_window = iframe.contentWindow;
+
+ const observer = new frame_window.PressureObserver(
+ () => {},
+ {sampleRate: 1});
+ const iframe_DOMException = frame_window.DOMException;
+
+ // await is intentionally not used here. We want to remove the iframe while
+ // the returned Promise settles.
+ const observe_promise = observer.observe('cpu');
+ iframe.remove();
+
+ // Establish an observer and wait for changes in the main frame. This should
+ // keep the test running long enough to catch any crash from the observe()
+ // call in the removed iframe's PressureObserver.
+ const changes = await new Promise((resolve, reject) => {
+ const observer = new PressureObserver(
+ resolve, {sampleRate: 1});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+ assert_in_array(changes[0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+}, 'Detaching frame while PressureObserver.observe() settles');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const frame_window = iframe.contentWindow;
+ const observer = new frame_window.PressureObserver(() => {
+ assert_unreached('The observer callback should not be called');
+ }, {sampleRate: 1});
+
+ await observer.observe('cpu');
+
+ iframe.remove();
+
+ return new Promise(resolve => t.step_timeout(resolve, 1000));
+}, 'PressureObserver on detached frame returns with no callback');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.window.js
new file mode 100644
index 0000000000..c9950f2dc8
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.window.js
@@ -0,0 +1,40 @@
+'use strict';
+
+test(t => {
+ const observer = new PressureObserver(() => {
+ assert_unreached('The observer callback should not be called');
+ });
+ t.add_cleanup(() => observer.disconnect());
+ observer.disconnect();
+}, 'Call disconnect() directly should not crash');
+
+promise_test(async t => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(change => {
+ observer1_changes.push(change);
+ }, {sampleRate: 1.0});
+ t.add_cleanup(() => observer1.disconnect());
+ // Ensure that observer1's schema gets registered before observer2 starts.
+ await observer1.observe('cpu');
+ observer1.disconnect();
+
+ const observer2_changes = [];
+ await new Promise((resolve, reject) => {
+ const observer2 = new PressureObserver(change => {
+ observer2_changes.push(change);
+ resolve();
+ }, {sampleRate: 1.0});
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu').catch(reject);
+ });
+
+ assert_equals(
+ observer1_changes.length, 0,
+ 'disconnected observers should not receive callbacks');
+
+ assert_equals(observer2_changes.length, 1);
+ assert_equals(observer2_changes[0].length, 1);
+ assert_in_array(
+ observer2_changes[0][0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+}, 'Stopped PressureObserver do not receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js
new file mode 100644
index 0000000000..72021fd270
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.window.js
@@ -0,0 +1,33 @@
+'use strict';
+
+promise_test(async t => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ }, {sampleRate: 1});
+ t.add_cleanup(() => observer1.disconnect());
+ // Ensure that observer1's schema gets registered before observer2 starts.
+ const promise = observer1.observe('cpu');
+ observer1.disconnect();
+ observer1.disconnect();
+ await promise_rejects_dom(t, 'NotSupportedError', promise);
+
+ const observer2_changes = [];
+ await new Promise((resolve, reject) => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ }, {sampleRate: 1});
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu').catch(reject);
+ });
+
+ assert_equals(
+ observer1_changes.length, 0,
+ 'stopped observers should not receive callbacks');
+
+ assert_equals(observer2_changes.length, 1);
+ assert_in_array(
+ observer2_changes[0][0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+}, 'Stopped PressureObserver do not receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js
new file mode 100644
index 0000000000..1abe84d572
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.window.js
@@ -0,0 +1,63 @@
+'use strict';
+
+promise_test(async t => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ }, {sampleRate: 1.0});
+ t.add_cleanup(() => observer1.disconnect());
+ // Ensure that observer1's schema gets registered before observer2 starts.
+ const promise = observer1.observe('cpu');
+ observer1.disconnect();
+ await promise_rejects_dom(t, 'NotSupportedError', promise);
+
+ const observer2_changes = [];
+ await new Promise((resolve, reject) => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ }, {sampleRate: 1.0});
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu').catch(reject);
+ });
+
+ assert_equals(
+ observer1_changes.length, 0,
+ 'stopped observers should not receive callbacks');
+
+ assert_equals(observer2_changes.length, 1);
+ assert_equals(observer2_changes[0].length, 1);
+ assert_in_array(
+ observer2_changes[0][0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+}, 'Stopped PressureObserver do not receive changes');
+
+promise_test(async t => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ }, {sampleRate: 1});
+ t.add_cleanup(() => observer1.disconnect());
+
+ const observer2_changes = [];
+ await new Promise(async resolve => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ }, {sampleRate: 1});
+ t.add_cleanup(() => observer2.disconnect());
+ const promise = observer1.observe('cpu');
+ observer2.observe('cpu');
+ observer1.disconnect();
+ await promise_rejects_dom(t, 'NotSupportedError', promise);
+ });
+
+ assert_equals(
+ observer1_changes.length, 0,
+ 'stopped observers should not receive callbacks');
+
+ assert_equals(observer2_changes.length, 1);
+ assert_in_array(
+ observer2_changes[0][0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+}, 'Removing observer before observe() resolves does not affect other observers');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.window.js
new file mode 100644
index 0000000000..3c312ca5b1
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.window.js
@@ -0,0 +1,61 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const pressureChanges = await new Promise(async resolve => {
+ const observer_changes = [];
+ let n = 0;
+ const observer = new PressureObserver(changes => {
+ observer_changes.push(changes);
+ if (++n === 2)
+ resolve(observer_changes);
+ }, {sampleRate: 5.0});
+ observer.observe('cpu');
+ const updatesDelivered = mockPressureService.updatesDelivered();
+ mockPressureService.setPressureUpdate('critical');
+ mockPressureService.startPlatformCollector(/*sampleRate*/ 5.0);
+ // Deliver 2 updates.
+ await t.step_wait(
+ () => mockPressureService.updatesDelivered() >= (updatesDelivered + 2),
+ 'Wait for more than one update to be delivered to the observer');
+ mockPressureService.setPressureUpdate('nominal');
+ // Deliver more updates, |resolve()| will be called when the new pressure
+ // state reaches PressureObserver and its callback is invoked
+ // for the second time.
+ });
+ assert_equals(pressureChanges.length, 2);
+ assert_equals(pressureChanges[0][0].state, 'critical');
+ assert_equals(pressureChanges[1][0].state, 'nominal');
+}, 'Changes that fail the "has change in data" test are discarded.');
+
+pressure_test(async (t, mockPressureService) => {
+ const pressureChanges = await new Promise(async resolve => {
+ const observer_changes = [];
+ let n = 0;
+ const observer = new PressureObserver(changes => {
+ observer_changes.push(changes);
+ if (++n === 2)
+ resolve(observer_changes);
+ }, {sampleRate: 5.0});
+ observer.observe('cpu');
+ const updatesDelivered = mockPressureService.updatesDelivered();
+ mockPressureService.setPressureUpdate('critical', ['thermal']);
+ mockPressureService.startPlatformCollector(/*sampleRate*/ 5.0);
+
+ // Deliver 2 updates.
+ await t.step_wait(
+ () => mockPressureService.updatesDelivered() >= (updatesDelivered + 2),
+ 'Wait for more than one update to be delivered to the observer');
+ mockPressureService.setPressureUpdate('critical', ['power-supply']);
+ // Deliver more updates, |resolve()| will be called when the new pressure
+ // state reaches PressureObserver and its callback is invoked
+ // for the second time.
+ });
+ assert_equals(pressureChanges.length, 2);
+ assert_equals(pressureChanges[0][0].state, 'critical');
+ assert_equals(pressureChanges[0][0].factors[0], 'thermal');
+ assert_equals(pressureChanges[1][0].state, 'critical');
+ assert_equals(pressureChanges[1][0].factors[0], 'power-supply');
+}, 'Factors that fail the "has change in data" test are discarded.');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_factors.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_factors.tentative.https.window.js
new file mode 100644
index 0000000000..6d8d220888
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_factors.tentative.https.window.js
@@ -0,0 +1,18 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const changes = await new Promise(resolve => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('critical', ['thermal']);
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 1.0);
+ });
+ assert_true(changes.length === 1);
+ assert_equals(changes[0].state, 'critical');
+ assert_equals(changes[0].source, 'cpu');
+ assert_equals(typeof changes[0].time, 'number');
+ assert_equals(changes[0].factors[0], 'thermal');
+}, 'Basic factors functionality test');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.window.js
new file mode 100644
index 0000000000..6015ae1f81
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.window.js
@@ -0,0 +1,30 @@
+'use strict';
+
+promise_test(async t => {
+ const changes1_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const changes2_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const changes3_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const [changes1, changes2, changes3] =
+ await Promise.all([changes1_promise, changes2_promise, changes3_promise]);
+
+ for (const changes of [changes1, changes2, changes3]) {
+ assert_in_array(
+ changes[0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+ }
+}, 'Three PressureObserver instances receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js
new file mode 100644
index 0000000000..838b9a17a0
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_multiple_across_iframes.tentative.https.window.js
@@ -0,0 +1,40 @@
+'use strict';
+
+promise_test(async t => {
+ const changes1_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ // iframe numbers are aligned with observer numbers. The first observer is
+ // in the main frame, so there is no iframe1.
+ const iframe2 = document.createElement('iframe');
+ document.body.appendChild(iframe2);
+
+ const changes2_promise = new Promise((resolve, reject) => {
+ const observer =
+ new iframe2.contentWindow.PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const iframe3 = document.createElement('iframe');
+ document.body.appendChild(iframe3);
+
+ const changes3_promise = new Promise((resolve, reject) => {
+ const observer =
+ new iframe3.contentWindow.PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const [changes1, changes2, changes3] =
+ await Promise.all([changes1_promise, changes2_promise, changes3_promise]);
+
+ for (const changes of [changes1, changes2, changes3]) {
+ assert_in_array(
+ changes[0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+ }
+}, 'Three PressureObserver instances, in different iframes, receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js
new file mode 100644
index 0000000000..e60115fee8
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.window.js
@@ -0,0 +1,16 @@
+'use strict';
+
+promise_test(async t => {
+ const update = await new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ observer.observe('cpu').catch(reject);
+ observer.observe('cpu').catch(reject);
+ });
+
+ assert_equals(typeof update[0].state, 'string');
+ assert_in_array(
+ update[0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu pressure state');
+}, 'PressureObserver.observe() is idempotent');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js
new file mode 100644
index 0000000000..c32649da5c
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.window.js
@@ -0,0 +1,17 @@
+'use strict';
+
+promise_test(async t => {
+ const observer = new PressureObserver(
+ t.unreached_func('oops should not end up here'), {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ await promise_rejects_js(t, TypeError, observer.observe('random'));
+}, 'PressureObserver.observe() requires a valid source');
+
+test(t => {
+ const observer = new PressureObserver(
+ t.unreached_func('oops should not end up here'), {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+ assert_throws_js(TypeError, () => {
+ observer.unobserve('random');
+ });
+}, 'PressureObserver.unobserve() requires a valid source');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.window.js
new file mode 100644
index 0000000000..d142ecc088
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.window.js
@@ -0,0 +1,23 @@
+'use strict';
+
+test(t => {
+ assert_throws_js(RangeError, () => {
+ new PressureObserver(() => {}, {sampleRate: 0});
+ });
+}, 'PressureObserver constructor requires a non-zero sampleRate');
+
+test(t => {
+ assert_throws_js(RangeError, () => {
+ new PressureObserver(() => {}, {sampleRate: -2});
+ });
+}, 'PressureObserver constructor requires a positive sampleRate');
+
+test(t => {
+ const observer = new PressureObserver(() => {}, {sampleRate: 0.5});
+ assert_equals(typeof observer, 'object');
+}, 'PressureObserver constructor doesnt throw error on positive sampleRate');
+
+test(t => {
+ const observer = new PressureObserver(() => {}, {});
+ assert_equals(typeof observer, 'object');
+}, 'PressureObserver constructor succeeds on empty sampleRate');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js
new file mode 100644
index 0000000000..3a4198f547
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_privacy_test.tentative.https.window.js
@@ -0,0 +1,130 @@
+// META: timeout=long
+// META: script=/common/get-host-info.sub.js
+// META: script=/common/media.js
+// META: script=/mediacapture-streams/permission-helper.js
+// META: script=/picture-in-picture/resources/picture-in-picture-helpers.js
+// META: script=/resources/testdriver.js
+// META: script=/resources/testdriver-vendor.js
+
+'use strict';
+
+promise_test(async t => {
+ const video = await loadVideo();
+ document.body.appendChild(video);
+ const pipWindow = await requestPictureInPictureWithTrustedClick(video);
+ assert_not_equals(pipWindow.width, 0);
+ assert_not_equals(pipWindow.height, 0);
+
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ // Focus on the iframe to make the main frame lose focus, so that
+ // PressureObserver in the main frame can't receive PressureRecord
+ // by default. However, if the main frame is the initiator of active
+ // Picture-in-Picture session, PressureObserver in the main frame can
+ // receive PressureRecord.
+ iframe.contentWindow.focus();
+
+ await new Promise(resolve => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(async () => {
+ observer.disconnect();
+ iframe.remove();
+ if (document.pictureInPictureElement) {
+ await document.exitPictureInPicture();
+ }
+ video.remove();
+ });
+ observer.observe('cpu');
+ });
+}, 'Observer should receive PressureRecord if associated document is the initiator of active Picture-in-Picture session');
+
+promise_test(async t => {
+ await setMediaPermission();
+ const stream =
+ await navigator.mediaDevices.getUserMedia({video: true, audio: true});
+ assert_true(stream.active);
+
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ // Focus on the iframe to make the main frame lose focus, so that
+ // PressureObserver in the main frame can't receive PressureRecord
+ // by default. However, if the main frame's browsing context is capturing,
+ // PressureObserver in the main frame can receive PressureRecord.
+ iframe.contentWindow.focus();
+
+ await new Promise(resolve => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(async () => {
+ observer.disconnect();
+ iframe.remove();
+ stream.getTracks().forEach(track => track.stop());
+ });
+ observer.observe('cpu');
+ });
+}, 'Observer should receive PressureRecord if browsing context is capturing');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ // Focus on the iframe to make the main frame lose focus, so that
+ // PressureObserver in the main frame can't receive PressureRecord
+ // by default.
+ iframe.contentWindow.focus();
+
+ const observer = new PressureObserver(() => {
+ assert_unreached('The observer callback should not be called');
+ });
+ t.add_cleanup(() => {
+ observer.disconnect();
+ iframe.remove();
+ });
+
+ return new Promise(resolve => t.step_timeout(resolve, 2000));
+}, 'Observer should not receive PressureRecord when top-level browsing context does not have system focus');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ // Focus on the main frame to make the iframe lose focus, so that
+ // PressureObserver in the iframe can't receive PressureRecord by default.
+ // However, if the iframe is same-origin with the main frame and the main
+ // frame has focus, PressureObserver in iframe can receive PressureRecord.
+ window.focus();
+
+ await new Promise(resolve => {
+ const observer = new iframe.contentWindow.PressureObserver(resolve);
+ t.add_cleanup(() => {
+ observer.disconnect();
+ iframe.remove();
+ });
+ observer.observe('cpu');
+ });
+}, 'Observer in iframe should receive PressureRecord when focused on same-origin main frame');
+
+promise_test(async t => {
+ const iframe = document.createElement('iframe');
+ iframe.src = get_host_info().HTTPS_REMOTE_ORIGIN +
+ '/compute-pressure/resources/support-iframe.html';
+ iframe.allow = 'compute-pressure';
+ const iframeLoadWatcher = new EventWatcher(t, iframe, 'load');
+ document.body.appendChild(iframe);
+ await iframeLoadWatcher.wait_for('load');
+ // Focus on the main frame to make the iframe lose focus, so that
+ // PressureObserver in the iframe can't receive PressureRecord by default.
+ // If the main frame has focus, but the iframe is cross-origin with the main
+ // frame, PressureObserver in the iframe still can't receive PressureRecord.
+ window.focus();
+
+ return new Promise((resolve, reject) => {
+ window.addEventListener('message', (e) => {
+ if (e.data.result === 'timeout') {
+ resolve();
+ } else if (e.data.result === 'success') {
+ reject('Observer should not receive PressureRecord');
+ } else {
+ reject('Got unexpected reply');
+ }
+ }, {once: true});
+ iframe.contentWindow.postMessage({command: 'start'}, '*');
+ });
+}, 'Observer in iframe should not receive PressureRecord when focused on cross-origin main frame');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.window.js
new file mode 100644
index 0000000000..2a69e731e7
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.window.js
@@ -0,0 +1,19 @@
+'use strict';
+
+test(() => {
+ // Compute Pressure should support at least "cpu"
+ const sources = PressureObserver.supportedSources;
+ assert_in_array('cpu', sources);
+}, 'PressureObserver should support at least "cpu"');
+
+test(() => {
+ // Compute Pressure should be frozen array
+ const sources = PressureObserver.supportedSources;
+ assert_equals(sources, PressureObserver.supportedSources);
+}, 'PressureObserver must return always the same array');
+
+test(() => {
+ // Compute Pressure should be frozen array
+ let sources = PressureObserver.supportedSources;
+ assert_equals(Object.isFrozen(), true);
+}, 'PressureObserver must return a frozen array');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.window.js
new file mode 100644
index 0000000000..d294a7e80f
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.window.js
@@ -0,0 +1,29 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+
+'use strict';
+
+test(t => {
+ const observer = new PressureObserver(
+ t.unreached_func('This callback should not have been called.'),
+ {sampleRate: 1.0});
+
+ const records = observer.takeRecords();
+ assert_equals(records.length, 0, 'No record before observe');
+}, 'Calling takeRecords() before observe()');
+
+promise_test(async t => {
+ let observer;
+ const changes = await new Promise(resolve => {
+ observer = new PressureObserver(resolve, {sampleRate: 1.0});
+ t.add_cleanup(() => observer.disconnect());
+
+ observer.observe('cpu');
+ });
+ assert_in_array(
+ changes[0].state, ['nominal', 'fair', 'serious', 'critical'],
+ 'cpu presure state');
+
+ const records = observer.takeRecords();
+ assert_equals(records.length, 0, 'No record available');
+}, 'takeRecords() returns empty record after callback invoke');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.window.js
new file mode 100644
index 0000000000..b9b932e64f
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.window.js
@@ -0,0 +1,77 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const readings = ['nominal', 'fair', 'serious', 'critical'];
+
+ const sampleRate = 4.0;
+ const pressureChanges = await new Promise(async resolve => {
+ const observerChanges = [];
+ const observer = new PressureObserver(changes => {
+ observerChanges.push(changes);
+ }, {sampleRate});
+ observer.observe('cpu');
+
+ mockPressureService.startPlatformCollector(sampleRate * 2);
+ let i = 0;
+ // mockPressureService.updatesDelivered() does not necessarily match
+ // pressureChanges.length, as system load and browser optimizations can
+ // cause the actual timer used by mockPressureService to deliver readings
+ // to be a bit slower or faster than requested.
+ while (observerChanges.length < 4) {
+ mockPressureService.setPressureUpdate(readings[i++ % readings.length]);
+ await t.step_wait(
+ () => mockPressureService.updatesDelivered() >= i,
+ `At least ${i} readings have been delivered`);
+ }
+ observer.disconnect();
+ resolve(observerChanges);
+ });
+
+ assert_equals(pressureChanges.length, 4);
+ assert_greater_than_equal(
+ pressureChanges[1][0].time - pressureChanges[0][0].time,
+ (1 / sampleRate * 1000));
+ assert_greater_than_equal(
+ pressureChanges[2][0].time - pressureChanges[1][0].time,
+ (1 / sampleRate * 1000));
+ assert_greater_than_equal(
+ pressureChanges[3][0].time - pressureChanges[2][0].time,
+ (1 / sampleRate * 1000));
+}, 'Faster collector: Timestamp difference between two changes should be higher or equal to the observer sample rate');
+
+pressure_test(async (t, mockPressureService) => {
+ const pressureChanges = [];
+ const sampleRate = 1.0;
+ const observer = new PressureObserver(changes => {
+ pressureChanges.push(changes);
+ }, {sampleRate});
+
+ await new Promise(async resolve => {
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('critical');
+ mockPressureService.startPlatformCollector(sampleRate);
+ await t.step_wait(() => pressureChanges.length == 1);
+ observer.disconnect();
+ resolve();
+ });
+
+ await new Promise(async resolve => {
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('serious');
+ mockPressureService.startPlatformCollector(sampleRate * 4);
+ await t.step_wait(() => pressureChanges.length == 2);
+ observer.disconnect();
+ resolve();
+ });
+
+ assert_equals(pressureChanges.length, 2);
+ // When disconnect() is called, PressureRecord in [[LastRecordMap]] for cpu
+ // should be deleted. So the second PressureRecord is not discarded even
+ // though the time interval does not meet the requirement.
+ assert_less_than(
+ pressureChanges[1][0].time - pressureChanges[0][0].time,
+ (1 / sampleRate * 1000));
+}, 'disconnect() should update [[LastRecordMap]]');
diff --git a/testing/web-platform/tests/compute-pressure/idlharness.https.window.js b/testing/web-platform/tests/compute-pressure/idlharness.https.window.js
new file mode 100644
index 0000000000..1cdfb59be0
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/idlharness.https.window.js
@@ -0,0 +1,14 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+// https://wicg.github.io/compute-pressure/
+
+'use strict';
+
+idl_test(['compute-pressure'], ['dom', 'html'], async idl_array => {
+ idl_array.add_objects({
+ PressureObserver: ['observer'],
+ });
+
+ self.observer = new PressureObserver(() => {}, {sampleRate: 1.0});
+});
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html
new file mode 100644
index 0000000000..ec5b464461
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute-redirect-on-load.https.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/permissions-policy/resources/permissions-policy.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+"use strict";
+
+const relative_path =
+ '/permissions-policy/resources/permissions-policy-compute-pressure.html';
+const base_src = '/permissions-policy/resources/redirect-on-load.html#';
+const same_origin_src = base_src + relative_path;
+const cross_origin_src =
+ base_src + get_host_info().HTTPS_REMOTE_ORIGIN + relative_path;
+const header = 'permissions policy allow="compute-pressure"';
+
+async_test(t => {
+ test_feature_availability(
+ 'PressureObserver.observe()',
+ t,
+ same_origin_src,
+ expect_feature_available_default,
+ 'compute-pressure'
+ );
+}, `${header} allows same-origin navigation in an iframe.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'PressureObserver.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_unavailable_default,
+ 'compute-pressure'
+ );
+}, `${header} disallows cross-origin navigation in an iframe.`);
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html
new file mode 100644
index 0000000000..d6dfcfc191
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy-attribute.https.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/permissions-policy/resources/permissions-policy.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+"use strict";
+
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-compute-pressure.html';
+const cross_origin_src = get_host_info().HTTPS_REMOTE_ORIGIN + same_origin_src;
+const feature_name = 'permissions policy "compute-pressure"';
+const attribute = 'allow="compute-pressure" attribute';
+
+async_test(t => {
+ test_feature_availability(
+ 'PressureObserver.observe()',
+ t,
+ same_origin_src,
+ expect_feature_available_default,
+ 'compute-pressure'
+ );
+}, `${feature_name} can be enabled in same-origin iframe using ${attribute}`);
+
+async_test(t => {
+ test_feature_availability(
+ 'PressureObserver.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_available_default,
+ 'compute-pressure'
+ );
+}, `${feature_name} can be enabled in cross-origin iframe using ${attribute}`);
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html
new file mode 100644
index 0000000000..1651f72612
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html
@@ -0,0 +1,55 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/permissions-policy/resources/permissions-policy.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+"use strict";
+
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-compute-pressure.html';
+const cross_origin_src = get_host_info().HTTPS_REMOTE_ORIGIN + same_origin_src;
+const header = 'permissions policy header "compute-pressure=*"';
+const attribute = 'allow="compute-pressure" attribute';
+
+promise_test(async () => {
+ try {
+ const observer = new PressureObserver(() => {});
+ await observer.observe("cpu");
+ observer.disconnect();
+ } catch (e) {
+ assert_unreached("expected promise to resolve.");
+ }
+}, `${header} allows the top-level document.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ same_origin_src,
+ expect_feature_available_default
+ );
+}, `${header} allows same-origin iframes.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_unavailable_default
+ );
+}, `${header} disallows cross-origin iframes.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_available_default,
+ 'compute-pressure'
+ );
+}, `${header} allows cross-origin iframes with ${attribute}.`);
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.headers b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.headers
new file mode 100644
index 0000000000..76185cbb2d
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: compute-pressure=*
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html
new file mode 100644
index 0000000000..98450b91a7
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/permissions-policy/resources/permissions-policy.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+"use strict";
+
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-compute-pressure.html';
+const cross_origin_src = get_host_info().HTTPS_REMOTE_ORIGIN + same_origin_src;
+const header = 'permissions policy header "compute-pressure=self"';
+
+promise_test(async () => {
+ try {
+ const observer = new PressureObserver(() => {});
+ await observer.observe("cpu");
+ observer.disconnect();
+ } catch (e) {
+ assert_unreached('expected promise to resolve.');
+ }
+}, `${header} allows the top-level document.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ same_origin_src,
+ expect_feature_available_default
+ );
+}, `${header} allows same-origin iframes.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_unavailable_default
+ );
+}, `${header} disallows cross-origin iframes.`);
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.headers b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.headers
new file mode 100644
index 0000000000..6852f871bb
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-on-self-origin-by-permissions-policy.https.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: compute-pressure=self
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html
new file mode 100644
index 0000000000..5a7c77264e
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-default-permissions-policy.https.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/permissions-policy/resources/permissions-policy.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+"use strict";
+
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-compute-pressure.html';
+const cross_origin_src = get_host_info().HTTPS_REMOTE_ORIGIN + same_origin_src;
+const header = 'Default "compute-pressure" permissions policy';
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ same_origin_src,
+ expect_feature_available_default
+ );
+}, `${header} allows same-origin iframes.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_unavailable_default
+ );
+}, `${header} disallows cross-origin iframes.`);
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html
new file mode 100644
index 0000000000..58b044247c
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/permissions-policy/resources/permissions-policy.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script>
+"use strict";
+
+const same_origin_src =
+ '/permissions-policy/resources/permissions-policy-compute-pressure.html';
+const cross_origin_src = get_host_info().HTTPS_REMOTE_ORIGIN + same_origin_src;
+const header = 'permissions policy header "compute-pressure=()"';
+const attribute = 'allow="compute-pressure" attribute';
+
+promise_test(async t => {
+ const observer = new PressureObserver(
+ t.unreached_func('oops should not end up here')
+ );
+ await promise_rejects_dom(t, 'NotAllowedError', observer.observe("cpu"));
+}, `${header} disallows the top-level document.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ same_origin_src,
+ expect_feature_unavailable_default
+ );
+}, `${header} disallows same-origin iframes.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_unavailable_default
+ );
+}, `${header} disallows cross-origin iframes.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ same_origin_src,
+ expect_feature_unavailable_default,
+ 'compute-pressure'
+ );
+}, `${header} disallows same-origin iframes despite the ${attribute}.`);
+
+async_test(t => {
+ test_feature_availability(
+ 'ComputePressure.observe()',
+ t,
+ cross_origin_src,
+ expect_feature_unavailable_default,
+ 'compute-pressure'
+ );
+}, `${header} disallows cross-origin iframes despite the ${attribute}.`);
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html.headers b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html.headers
new file mode 100644
index 0000000000..2e9f2ecce0
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html.headers
@@ -0,0 +1 @@
+Permissions-Policy: compute-pressure=()
diff --git a/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html
new file mode 100644
index 0000000000..931fcb66b4
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-supported-by-permissions-policy.html
@@ -0,0 +1,11 @@
+<!DOCTYPE html>
+<title>Test that compute-pressure is advertised in the feature list</title>
+<link rel="help" href="https://w3c.github.io/webappsec-permissions-policy/#dom-permissions-policy-features">
+<link rel="help" href="https://wicg.github.io/compute-pressure/#policy-control">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+test(() => {
+ assert_in_array('compute-pressure', document.featurePolicy.features());
+}, 'document.featurePolicy.features should advertise compute-pressure.');
+</script>
diff --git a/testing/web-platform/tests/compute-pressure/resources/pressure-helpers.js b/testing/web-platform/tests/compute-pressure/resources/pressure-helpers.js
new file mode 100644
index 0000000000..5234cf2d78
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/resources/pressure-helpers.js
@@ -0,0 +1,35 @@
+'use strict';
+
+// These tests rely on the User Agent providing an implementation of
+// platform compute pressure backends.
+//
+// In Chromium-based browsers this implementation is provided by a polyfill
+// in order to reduce the amount of test-only code shipped to users. To enable
+// these tests the browser must be run with these options:
+//
+// --enable-blink-features=MojoJS,MojoJSTest
+
+let mockPressureService = undefined;
+
+function pressure_test(func, name, properties) {
+ promise_test(async t => {
+ if (mockPressureService === undefined) {
+ if (isChromiumBased) {
+ const mocks =
+ await import('/resources/chromium/mock-pressure-service.js');
+ mockPressureService = mocks.mockPressureService;
+ }
+ }
+ assert_implements(
+ mockPressureService,
+ 'missing mockPressureService after initialization');
+
+ mockPressureService.start();
+
+ t.add_cleanup(() => {
+ mockPressureService.reset();
+ return mockPressureService.stop();
+ });
+ return func(t, mockPressureService);
+ }, name, properties);
+}
diff --git a/testing/web-platform/tests/compute-pressure/resources/support-iframe.html b/testing/web-platform/tests/compute-pressure/resources/support-iframe.html
new file mode 100644
index 0000000000..57e18b77f6
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/resources/support-iframe.html
@@ -0,0 +1,30 @@
+<!DOCTYPE HTML>
+<meta charset="utf-8">
+<title>compute pressure iframe tester</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+async function messageHandler(e) {
+ if (e.data.command === 'start') {
+ return new Promise((resolve, reject) => {
+ const observer = new PressureObserver(()=> {
+ resolve('success');
+ });
+ observer.observe('cpu');
+ window.setTimeout(() => { reject('timeout'); }, 2000);
+ });
+ } else {
+ return Promise.reject(`unknown command "${e.data.command}"`);
+ }
+}
+
+window.onmessage = async (e) => {
+ let reply;
+ try {
+ reply = await messageHandler(e);
+ } catch (error) {
+ reply = error;
+ }
+ e.source.postMessage({ command: e.data.command, result: reply }, '*');
+}
+</script>