summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/compute-pressure
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /testing/web-platform/tests/compute-pressure
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
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.any.js93
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_detached_iframe.tentative.https.html95
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.any.js44
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.any.js37
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.any.js67
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.any.js32
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.any.js35
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.any.js19
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.any.js19
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.any.js25
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_not_triggered.tentative.https.window.js50
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_triggered.tentative.https.window.js56
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.any.js21
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.any.js29
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.any.js79
-rw-r--r--testing/web-platform/tests/compute-pressure/compute_pressure_update_toJSON.tentative.https.any.js17
-rw-r--r--testing/web-platform/tests/compute-pressure/idlharness.https.any.js15
-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.html57
-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.html64
-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/compute-pressure-allowed-by-permissions-policy-worker.js22
-rw-r--r--testing/web-platform/tests/compute-pressure/resources/compute-pressure-disabled-by-permissions-policy-worker.js18
-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
32 files changed, 1129 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..7695c4a33e
--- /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://w3c.github.io/compute-pressure/) specification.
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.any.js
new file mode 100644
index 0000000000..28322ced72
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_basic.tentative.https.any.js
@@ -0,0 +1,93 @@
+// META: timeout=long
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'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);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.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('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+
+ return promise_rejects_dom(t, 'AbortError', 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);
+ t.add_cleanup(() => observer.disconnect());
+ observePromises.push(observer.observe('cpu'));
+ }));
+ }
+
+ await Promise.all(observePromises);
+
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.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('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+ assert_true(observer1_changes.length === 1);
+ assert_equals(observer1_changes[0][0].source, 'cpu');
+ 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].source, 'cpu');
+ 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..5511a14704
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_detached_iframe.tentative.https.html
@@ -0,0 +1,95 @@
+<!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>
+<script src="/resources/test-only-api.js"></script>
+<script src="resources/pressure-helpers.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(() => {});
+ 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(() => {});
+
+ await observer.observe('cpu');
+
+ iframe.remove();
+
+ // Calling disconnect() from a detached iframe should not crash.
+ observer.disconnect();
+}, 'PressureObserver.disconnect() on detached frame returns');
+
+pressure_test(async (t, mockPressureService) => {
+ const iframe = document.createElement('iframe');
+ document.body.appendChild(iframe);
+ const frame_window = iframe.contentWindow;
+
+ const observer = new frame_window.PressureObserver(() => {});
+ const iframe_DOMException = frame_window.DOMException;
+
+ // await is intentionally not used here. We want to remove the iframe while
+ // the returned Promise settles.
+ 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);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+ assert_equals(changes[0].state, 'critical');
+}, 'Detaching frame while PressureObserver.observe() settles');
+
+pressure_test(async (t, mockPressureService) => {
+ 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');
+ });
+
+ await observer.observe('cpu');
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+
+ 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.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.any.js
new file mode 100644
index 0000000000..1d188fad8b
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect.tentative.https.any.js
@@ -0,0 +1,44 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'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');
+
+pressure_test(async (t, mockPressureService) => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(change => {
+ observer1_changes.push(change);
+ });
+ 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();
+ });
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu').catch(reject);
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+
+ 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_equals(observer2_changes[0][0].state, 'critical');
+}, 'Stopped PressureObserver do not receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.any.js
new file mode 100644
index 0000000000..74d37bd6e5
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_idempotent.tentative.https.any.js
@@ -0,0 +1,37 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ });
+ 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, 'AbortError', promise);
+
+ const observer2_changes = [];
+ await new Promise((resolve, reject) => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ });
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu').catch(reject);
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+
+ assert_equals(
+ observer1_changes.length, 0,
+ 'stopped observers should not receive callbacks');
+
+ assert_equals(observer2_changes.length, 1);
+ assert_equals(observer2_changes[0][0].state, 'critical');
+}, 'Stopped PressureObserver do not receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.any.js
new file mode 100644
index 0000000000..9b545fbe1c
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_disconnect_immediately.tentative.https.any.js
@@ -0,0 +1,67 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ });
+ 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, 'AbortError', promise);
+
+ const observer2_changes = [];
+ await new Promise((resolve, reject) => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ });
+ t.add_cleanup(() => observer2.disconnect());
+ observer2.observe('cpu').catch(reject);
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+
+ 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_equals(observer2_changes[0][0].state, 'critical');
+}, 'Stopped PressureObserver do not receive changes');
+
+pressure_test(async (t, mockPressureService) => {
+ const observer1_changes = [];
+ const observer1 = new PressureObserver(changes => {
+ observer1_changes.push(changes);
+ });
+ t.add_cleanup(() => observer1.disconnect());
+
+ const observer2_changes = [];
+ await new Promise(async resolve => {
+ const observer2 = new PressureObserver(changes => {
+ observer2_changes.push(changes);
+ resolve();
+ });
+ t.add_cleanup(() => observer2.disconnect());
+ const promise = observer1.observe('cpu');
+ observer2.observe('cpu');
+ observer1.disconnect();
+ await promise_rejects_dom(t, 'AbortError', promise);
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+
+ assert_equals(
+ observer1_changes.length, 0,
+ 'stopped observers should not receive callbacks');
+
+ assert_equals(observer2_changes.length, 1);
+ assert_equals(observer2_changes[0][0].state, 'critical');
+}, '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.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.any.js
new file mode 100644
index 0000000000..dde92932dd
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_duplicate_updates.tentative.https.any.js
@@ -0,0 +1,32 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'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('cpu', '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('cpu', '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.');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.any.js
new file mode 100644
index 0000000000..c8cef5beca
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_multiple.tentative.https.any.js
@@ -0,0 +1,35 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const changes1_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const changes2_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ const changes3_promise = new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ });
+
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+
+ const [changes1, changes2, changes3] =
+ await Promise.all([changes1_promise, changes2_promise, changes3_promise]);
+
+ for (const changes of [changes1, changes2, changes3]) {
+ assert_equals(changes[0].state, 'critical');
+ }
+}, 'Three PressureObserver instances receive changes');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.any.js
new file mode 100644
index 0000000000..5dc3804b2f
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_idempotent.tentative.https.any.js
@@ -0,0 +1,19 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const update = await new Promise((resolve, reject) => {
+ const observer = new PressureObserver(resolve);
+ t.add_cleanup(() => observer.disconnect());
+ observer.observe('cpu').catch(reject);
+ observer.observe('cpu').catch(reject);
+ observer.observe('cpu').catch(reject);
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+
+ assert_equals(update[0].state, 'critical');
+}, 'PressureObserver.observe() is idempotent');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.any.js
new file mode 100644
index 0000000000..8eafeb356d
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_observe_unobserve_failure.tentative.https.any.js
@@ -0,0 +1,19 @@
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+promise_test(async t => {
+ const observer =
+ new PressureObserver(t.unreached_func('oops should not end up here'));
+ 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'));
+ 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.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.any.js
new file mode 100644
index 0000000000..69999819d9
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_options.tentative.https.any.js
@@ -0,0 +1,25 @@
+// META: global=window,dedicatedworker,sharedworker
+
+'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_rate_obfuscation_mitigation_not_triggered.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_not_triggered.tentative.https.window.js
new file mode 100644
index 0000000000..cb1aa432ce
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_not_triggered.tentative.https.window.js
@@ -0,0 +1,50 @@
+// META: timeout=long
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const sampleRateInHz = 10;
+ const readings = ['nominal', 'fair', 'serious', 'critical'];
+ // Normative values for rate obfuscation parameters.
+ // https://w3c.github.io/compute-pressure/#rate-obfuscation-normative-parameters.
+ const minPenaltyTimeInMs = 5000;
+ const minChangesThreshold = 50;
+
+ const changes = await new Promise(async resolve => {
+ const observerChanges = [];
+ const observer = new PressureObserver(changes => {
+ observerChanges.push(changes);
+ }, {sampleRate: sampleRateInHz});
+
+ observer.observe('cpu');
+ mockPressureService.startPlatformCollector(sampleRateInHz);
+ 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 < minChangesThreshold) {
+ mockPressureService.setPressureUpdate(
+ 'cpu', readings[i++ % readings.length]);
+ // Allow tasks to run (avoid a micro-task loop).
+ await new Promise((resolve) => t.step_timeout(resolve, 0));
+ await t.step_wait(
+ () => mockPressureService.updatesDelivered() >= i,
+ `At least ${i} readings have been delivered`);
+ }
+ observer.disconnect();
+ resolve(observerChanges);
+ });
+ assert_equals(changes.length, minChangesThreshold);
+
+ for (let i = 0; i < (changes.length - 1); i++) {
+ // Because no penalty should be triggered, the timestamp difference
+ // between samples should be less than the minimum penalty.
+ assert_less_than(
+ changes[i + 1][0].time - changes[i][0].time, minPenaltyTimeInMs,
+ 'Not in sample time boundaries');
+ }
+}, 'No rate obfuscation mitigation should happen, when number of changes is below minimum changes before penalty');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_triggered.tentative.https.window.js b/testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_triggered.tentative.https.window.js
new file mode 100644
index 0000000000..11dcc3c70a
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_rate_obfuscation_mitigation_triggered.tentative.https.window.js
@@ -0,0 +1,56 @@
+// META: timeout=long
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+pressure_test(async (t, mockPressureService) => {
+ const sampleRateInHz = 25;
+ const readings = ['nominal', 'fair', 'serious', 'critical'];
+ // Normative values for rate obfuscation parameters.
+ // https://w3c.github.io/compute-pressure/#rate-obfuscation-normative-parameters.
+ const minPenaltyTimeInMs = 5000;
+ const maxChangesThreshold = 100;
+ const minChangesThreshold = 50;
+ let gotPenalty = false;
+ await new Promise(async resolve => {
+ const observerChanges = [];
+ const observer = new PressureObserver(changes => {
+ if (observerChanges.length >= (minChangesThreshold - 1)) {
+ const lastSample = observerChanges.at(-1);
+ if ((changes[0].time - lastSample[0].time) >= minPenaltyTimeInMs) {
+ // The update delivery might still be working even if
+ // maxChangesThreshold have been reached and before disconnect() is
+ // processed.
+ // Therefore we are adding a flag to dismiss any updates after the
+ // penalty is detected, which is the condition for the test to pass.
+ gotPenalty = true;
+ observer.disconnect();
+ resolve();
+ }
+ }
+ observerChanges.push(changes);
+ }, {sampleRate: sampleRateInHz});
+
+ observer.observe('cpu');
+ mockPressureService.startPlatformCollector(sampleRateInHz);
+ 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 <= maxChangesThreshold || !gotPenalty) {
+ mockPressureService.setPressureUpdate(
+ 'cpu', readings[i++ % readings.length]);
+ // Allow tasks to run (avoid a micro-task loop).
+ await new Promise((resolve) => t.step_timeout(resolve, 0));
+ await t.step_wait(
+ () => mockPressureService.updatesDelivered() >= i,
+ `At least ${i} readings have been delivered`);
+ }
+
+ assert_true(gotPenalty, 'Penalty not triggered');
+
+ });
+}, 'Rate obfuscation mitigation should have been triggered, when changes is higher than minimum changes before penalty');
diff --git a/testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.any.js
new file mode 100644
index 0000000000..63f2666cca
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_supported_sources.tentative.https.any.js
@@ -0,0 +1,21 @@
+// META: global=window,dedicatedworker,sharedworker
+
+'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.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.any.js
new file mode 100644
index 0000000000..d93c9b5c88
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_take_records.tentative.https.any.js
@@ -0,0 +1,29 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'use strict';
+
+test(t => {
+ const observer = new PressureObserver(
+ t.unreached_func('This callback should not have been called.'));
+
+ const records = observer.takeRecords();
+ assert_equals(records.length, 0, 'No record before observe');
+}, 'Calling takeRecords() before observe()');
+
+pressure_test(async (t, mockPressureService) => {
+ let observer;
+ const changes = await new Promise(resolve => {
+ observer = new PressureObserver(resolve);
+ t.add_cleanup(() => observer.disconnect());
+
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+ assert_equals(changes[0].state, 'critical');
+
+ 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.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.any.js
new file mode 100644
index 0000000000..f283caa6ba
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_timestamp.tentative.https.any.js
@@ -0,0 +1,79 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+'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(
+ 'cpu', 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('cpu', 'critical');
+ mockPressureService.startPlatformCollector(sampleRate);
+ await t.step_wait(() => pressureChanges.length == 1);
+ observer.disconnect();
+ resolve();
+ });
+
+ await new Promise(async resolve => {
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('cpu', '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/compute_pressure_update_toJSON.tentative.https.any.js b/testing/web-platform/tests/compute-pressure/compute_pressure_update_toJSON.tentative.https.any.js
new file mode 100644
index 0000000000..0024d69754
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/compute_pressure_update_toJSON.tentative.https.any.js
@@ -0,0 +1,17 @@
+// META: script=/resources/test-only-api.js
+// META: script=resources/pressure-helpers.js
+// META: global=window,dedicatedworker,sharedworker
+
+pressure_test(async (t, mockPressureService) => {
+ const changes = await new Promise(resolve => {
+ const observer = new PressureObserver(resolve);
+ observer.observe('cpu');
+ mockPressureService.setPressureUpdate('cpu', 'critical');
+ mockPressureService.startPlatformCollector(/*sampleRate=*/ 5.0);
+ });
+ assert_true(changes.length === 1);
+ const json = changes[0].toJSON();
+ assert_equals(json.state, 'critical');
+ assert_equals(json.source, 'cpu');
+ assert_equals(typeof json.time, 'number');
+}, 'Basic functionality test');
diff --git a/testing/web-platform/tests/compute-pressure/idlharness.https.any.js b/testing/web-platform/tests/compute-pressure/idlharness.https.any.js
new file mode 100644
index 0000000000..e828996232
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/idlharness.https.any.js
@@ -0,0 +1,15 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+// META: global=window,dedicatedworker,sharedworker
+
+// https://w3c.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..643e672949
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-allowed-by-permissions-policy.https.html
@@ -0,0 +1,57 @@
+<!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}.`);
+
+fetch_tests_from_worker(new Worker(
+'/compute-pressure/resources/compute-pressure-allowed-by-permissions-policy-worker.js'));
+</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..55a997283b
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/permissions-policy/compute-pressure-disabled-by-permissions-policy.https.html
@@ -0,0 +1,64 @@
+<!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}.`);
+
+fetch_tests_from_worker(new Worker(
+ '/compute-pressure/resources/compute-pressure-disabled-by-permissions-policy-worker.js'));
+</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..35f09b7b07
--- /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://w3c.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/compute-pressure-allowed-by-permissions-policy-worker.js b/testing/web-platform/tests/compute-pressure/resources/compute-pressure-allowed-by-permissions-policy-worker.js
new file mode 100644
index 0000000000..590ac52cfd
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/resources/compute-pressure-allowed-by-permissions-policy-worker.js
@@ -0,0 +1,22 @@
+'use strict';
+
+importScripts('/resources/testharness.js');
+
+const header = 'permissions policy header "compute-pressure=*"';
+let workerType;
+
+if (typeof postMessage === 'function') {
+ workerType = 'dedicated';
+}
+
+promise_test(async () => {
+ try {
+ const observer = new PressureObserver(() => {});
+ await observer.observe('cpu');
+ observer.disconnect();
+ } catch (e) {
+ assert_unreached('expected promise to resolve.');
+ }
+}, `$Inherited ${header} allows ${workerType} workers.`);
+
+done();
diff --git a/testing/web-platform/tests/compute-pressure/resources/compute-pressure-disabled-by-permissions-policy-worker.js b/testing/web-platform/tests/compute-pressure/resources/compute-pressure-disabled-by-permissions-policy-worker.js
new file mode 100644
index 0000000000..90ed0a7857
--- /dev/null
+++ b/testing/web-platform/tests/compute-pressure/resources/compute-pressure-disabled-by-permissions-policy-worker.js
@@ -0,0 +1,18 @@
+'use strict';
+
+importScripts('/resources/testharness.js');
+
+const header = 'Permissions-Policy header compute-pressure=()';
+let workerType;
+
+if (typeof postMessage === 'function') {
+ workerType = 'dedicated';
+}
+
+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'));
+}, `$Inherited ${header} disallows ${workerType} workers.`);
+
+done();
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..6b2b309792
--- /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'); }, 1000);
+ });
+ } 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>