Bug 1636345 [wpt PR 23472] - [idle] Replace stop() with an AbortSignal, a=testonly
authorReilly Grant <reillyg@chromium.org>
Wed, 13 May 2020 09:49:02 +0000
changeset 531166 0ff5e06c6a796fa76f9de07fd495c61973ef422a
parent 531165 2b05123fd17f98cf88058a2afafe22593493457e
child 531167 d3455a129c4eb6504ab34995763eae573451573d
push id37435
push userapavel@mozilla.com
push dateWed, 20 May 2020 15:28:23 +0000
treeherdermozilla-central@5415da14ec9a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstestonly
bugs1636345, 23472, 878979, 2189631, 767018
milestone78.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1636345 [wpt PR 23472] - [idle] Replace stop() with an AbortSignal, a=testonly Automatic update from web-platform-tests [idle] Replace stop() with an AbortSignal This change replaces the stop() method on IdleDetector with an AbortSignal provided as an argument to start(). To allow the detector to be started multiple times the options are now always passed to start() rather than the constructor. New options replace previously configured options if specified. Explainer PR: https://github.com/WICG/idle-detection/issues/19 Bug: 878979 Change-Id: I26418cc3c08a02d77483b7d1b6744c16c17efd08 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2189631 Auto-Submit: Reilly Grant <reillyg@chromium.org> Reviewed-by: Ayu Ishii <ayui@chromium.org> Commit-Queue: Reilly Grant <reillyg@chromium.org> Cr-Commit-Position: refs/heads/master@{#767018} -- wpt-commits: dc329e1a648b156a9c0191357f39344a2a28a037 wpt-pr: 23472
testing/web-platform/tests/idle-detection/basics.tentative.https.window.js
testing/web-platform/tests/idle-detection/idle-detection.idl
testing/web-platform/tests/idle-detection/idlharness.https.window.js
testing/web-platform/tests/idle-detection/interceptor.https.html
testing/web-platform/tests/idle-detection/resources/idlharness-worker.js
--- a/testing/web-platform/tests/idle-detection/basics.tentative.https.window.js
+++ b/testing/web-platform/tests/idle-detection/basics.tentative.https.window.js
@@ -20,53 +20,79 @@ promise_test(async t => {
                 'status has a valid user state');
   assert_true(['locked', 'unlocked'].includes(status.state.screen),
                 'status has a valid screen state');
 }, 'start() basics');
 
 promise_test(async t => {
   let used = false;
 
-  new IdleDetector({
+  const detector = new IdleDetector();
+  detector.start({
     get threshold() {
       used = true;
       return 60000;
     }
   });
 
-  assert_true(used, 'constructor options "threshold" member was used');
-}, 'constructor uses threshold property');
+  assert_true(used, 'start() options "threshold" member was used');
+}, 'start() uses threshold property');
 
 promise_test(async t => {
-  assert_throws_js(TypeError, () => new IdleDetector({threshold: 0}));
-}, 'constructor throws with invalid threshold (0)');
+  let used = false;
+
+  const controller = new AbortController();
+  const detector = new IdleDetector();
+  detector.start({
+    get signal() {
+      used = true;
+      return controller.signal;
+    }
+  });
+
+  assert_true(used, 'start() options "signal" member was used');
+}, 'start() uses signal property');
+
 
 promise_test(async t => {
-  assert_throws_js(TypeError, () => new IdleDetector({threshold: 59000}));
-}, 'constructor throws with threshold below minimum (59000)');
+  const detector = new IdleDetector();
+  await promise_rejects_js(t, TypeError, detector.start({threshold: 0}));
+}, 'start() rejects with invalid threshold (0)');
 
 promise_test(async t => {
-  new IdleDetector({threshold: 60000});
-}, 'constructor allows threshold (60000)');
+  const detector = new IdleDetector();
+  await promise_rejects_js(t, TypeError, detector.start({threshold: 59000}));
+}, 'start() rejects with threshold below minimum (59000)');
 
 promise_test(async t => {
-  new IdleDetector({threshold: 61000});
-}, 'constructor allows threshold (61000)');
+  const detector = new IdleDetector();
+  await detector.start({threshold: 60000});
+}, 'start() rejects threshold (60000)');
 
 promise_test(async t => {
-  assert_throws_js(TypeError, () => new IdleDetector({threshold: null}));
-}, 'constructor throws with invalid threshold (null)');
+  const detector = new IdleDetector();
+  await detector.start({threshold: 61000});
+}, 'start() allows threshold (61000)');
+
+promise_test(async t => {
+  const detector = new IdleDetector();
+  await promise_rejects_js(t, TypeError, detector.start({threshold: null}));
+}, 'start() rejects with invalid threshold (null)');
 
 promise_test(async t => {
-  assert_throws_js(TypeError, () => new IdleDetector({threshold: -1}));
-}, 'constructor throws with invalid threshold (-1)');
+  const detector = new IdleDetector();
+  await promise_rejects_js(t, TypeError, detector.start({threshold: -1}));
+}, 'start() rejects with invalid threshold (-1)');
 
 promise_test(async t => {
-  assert_throws_js(TypeError, () => new IdleDetector({threshold: NaN}));
-}, 'constructor throws with invalid threshold (NaN)');
+  const detector = new IdleDetector();
+  await promise_rejects_js(t, TypeError, detector.start({threshold: NaN}));
+}, 'start() rejects with invalid threshold (NaN)');
 
 promise_test(async t => {
-  new IdleDetector();
-}, 'constructor uses a default value for the threshold when none is passed');
+  const detector = new IdleDetector();
+  await detector.start();
+}, 'start() uses a default value for the threshold when none is passed');
 
 promise_test(async t => {
-  new IdleDetector({threshold: undefined});
-}, 'constructor uses a default value for the threshold');
+  const detector = new IdleDetector();
+  await detector.start({threshold: undefined});
+}, 'start() uses a default value for the threshold');
--- a/testing/web-platform/tests/idle-detection/idle-detection.idl
+++ b/testing/web-platform/tests/idle-detection/idle-detection.idl
@@ -1,21 +1,21 @@
 dictionary IdleOptions {
-  [EnforceRange] unsigned long threshold = 60000;
+  [EnforceRange] unsigned long threshold;
+  AbortSignal signal;
 };
 
 [
   SecureContext,
-  Constructor(optional IdleOptions options),
   Exposed=(Window,Worker)
 ] interface IdleDetector : EventTarget {
+  constructor();
   readonly attribute IdleState state;
   attribute EventHandler onchange;
-  Promise<any> start();
-  void stop();
+  Promise<any> start(optional IdleOptions options = {});
 };
 
 [
   SecureContext,
   Exposed=(Window,Worker)
 ] interface IdleState {
   readonly attribute UserIdleState user;
   readonly attribute ScreenIdleState screen;
--- a/testing/web-platform/tests/idle-detection/idlharness.https.window.js
+++ b/testing/web-platform/tests/idle-detection/idlharness.https.window.js
@@ -18,17 +18,17 @@ promise_test(async (t) => {
     srcs.map(i => fetch(i).then(r => r.text()))
   );
 
   const idl_array = new IdlArray();
   idl_array.add_idls(idle);
   idl_array.add_dependency_idls(dom);
   idl_array.add_dependency_idls(html);
 
-  self.idle = new IdleDetector({threshold: 60000});
+  self.idle = new IdleDetector();
   let watcher = new EventWatcher(t, self.idle, ["change"]);
   let initial_state = watcher.wait_for("change");
   await self.idle.start();
   await initial_state;
 
   idl_array.add_objects({
     IdleDetector: ['idle'],
     IdleState: ['idle.state']
--- a/testing/web-platform/tests/idle-detection/interceptor.https.html
+++ b/testing/web-platform/tests/idle-detection/interceptor.https.html
@@ -24,27 +24,28 @@ promise_test(async t => {
       return Promise.resolve({
         state: {
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.LOCKED
         }
       });
   });
 
-  let detector = new IdleDetector({threshold: 60000});
-  let watcher = new EventWatcher(t, detector, ["change"]);
-  let initial_state = watcher.wait_for("change");
+  const controller = new AbortController();
+  const detector = new IdleDetector();
+  const watcher = new EventWatcher(t, detector, ["change"]);
+  const initial_state = watcher.wait_for("change");
 
-  await detector.start();
+  await detector.start({ signal: controller.signal });
   await initial_state;
 
   assert_equals(detector.state.user, "active");
   assert_equals(detector.state.screen, "locked");
 
-  detector.stop();
+  controller.abort();
 }, 'start()');
 
 promise_test(async t => {
   // Verifies that an event is thrown when a change of state from IDLE to ACTIVE
   // is detected.
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       let first = Promise.resolve({
         state: {
@@ -58,30 +59,31 @@ promise_test(async t => {
           user: UserIdleState.IDLE,
           screen: ScreenIdleState.UNLOCKED
         });
       }, 0);
 
       return first;
     });
 
-  let detector = new IdleDetector({threshold: 60000});
-  let watcher = new EventWatcher(t, detector, ["change"]);
-  let initial_state = watcher.wait_for("change");
+  const controller = new AbortController();
+  const detector = new IdleDetector();
+  const watcher = new EventWatcher(t, detector, ["change"]);
+  const initial_state = watcher.wait_for("change");
 
-  await detector.start();
+  await detector.start({ signal: controller.signal });
   await initial_state;
 
   // Wait for the first change in state.
   await watcher.wait_for("change");
 
   assert_equals(detector.state.user, "idle");
   assert_equals(detector.state.screen, "unlocked");
 
-  detector.stop();
+  controller.abort();
 }, 'updates once');
 
 
 promise_test(async t => {
   // Simulates the user being active, going idle and then going back active
   // again.
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       let first = Promise.resolve({
@@ -103,179 +105,173 @@ promise_test(async t => {
         monitorPtr.update({
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.UNLOCKED
         });
       }, 1);
       return first;
     });
 
-  let detector = new IdleDetector({threshold: 60000});
-  let watcher = new EventWatcher(t, detector, ["change"]);
-  let initial_state = watcher.wait_for("change");
+  const controller = new AbortController();
+  const detector = new IdleDetector();
+  const watcher = new EventWatcher(t, detector, ["change"]);
+  const initial_state = watcher.wait_for("change");
 
-  await detector.start();
+  await detector.start({ signal: controller.signal });
   await initial_state;
 
   // Waits for the first event.
   await watcher.wait_for("change");
   assert_equals(detector.state.user, "idle");
 
   // Waits for the second event.
   await watcher.wait_for("change");
   assert_equals(detector.state.user, "active");
 
-  detector.stop();
+  controller.abort();
 }, 'updates twice');
 
 promise_test(async t => {
   // Simulates a locked screen.
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       return Promise.resolve({
         state: {
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.LOCKED
         }
       });
     });
 
-  let detector = new IdleDetector({threshold: 60000});
-  let watcher = new EventWatcher(t, detector, ["change"]);
-  let initial_state = watcher.wait_for("change");
+  const controller = new AbortController();
+  const detector = new IdleDetector();
+  const watcher = new EventWatcher(t, detector, ["change"]);
+  const initial_state = watcher.wait_for("change");
 
-  await detector.start();
+  await detector.start({ signal: controller.signal });
   await initial_state;
 
   assert_equals(detector.state.screen, "locked");
 
-  detector.stop();
+  controller.abort();
 }, 'locked screen');
 
 promise_test(async t => {
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       return Promise.resolve({
         state: {
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.LOCKED
         }
       });
   });
 
-  let detector = new IdleDetector({threshold: 60000});
+  const controller = new AbortController();
+  const detector = new IdleDetector();
 
   let event = new Promise((resolve, reject) => {
     detector.onchange = resolve;
   });
 
-  await detector.start();
+  await detector.start({ signal: controller.signal });
 
   // Waits for the first event.
   await event;
 
   assert_equals(detector.state.user, "active");
   assert_equals(detector.state.screen, "locked");
 
-  detector.stop();
+  controller.abort();
 }, 'IdleDetector.onchange');
 
 promise_test(async t => {
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       return Promise.resolve({
         state: {
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.UNLOCKED
         }
       });
     });
 
-  let detector = new IdleDetector({threshold: 60000});
-
-  let watcher = new EventWatcher(t, detector, ["change"]);
-  let initial_state = watcher.wait_for("change");
+  const controller = new AbortController();
+  const detector = new IdleDetector();
 
-  // Calling start() multiple times should be safe.
-  await Promise.all([
-    detector.start(),
-    detector.start(),
-    detector.start(),
-    detector.start()
-  ]);
+  const watcher = new EventWatcher(t, detector, ["change"]);
+  const initial_state = watcher.wait_for("change");
+
+  // Only the first call to start() is allowed.
+  const start_promise = detector.start();
+  await promise_rejects_dom(t, 'InvalidStateError', detector.start());
+  await start_promise;
 
   await initial_state;
   assert_equals(detector.state.user, "active");
   assert_equals(detector.state.screen, "unlocked");
 
-  // Calling stop() multiple times should be safe.
-  await Promise.all([
-    detector.stop(),
-    detector.stop(),
-    detector.stop(),
-    detector.stop()
-  ]);
+  // Calling abort() multiple times is safe.
+  controller.abort();
+  controller.abort();
+  controller.abort();
+  controller.abort();
 }, 'Safe to call start() or stop() multiple times');
 
 promise_test(async t => {
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       return Promise.resolve({
         state: {
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.UNLOCKED
         }
       });
     });
 
-  let detector = new IdleDetector({threshold: 60000});
-
-  // Calling stop() before start() is a no-op.
-  detector.stop();
-
-  let watcher = new EventWatcher(t, detector, ["change"]);
-  let initial_state = watcher.wait_for("change");
+  const controller = new AbortController();
+  const detector = new IdleDetector();
 
-  await detector.start();
-  await initial_state;
+  // Calling abort() before start() causes start() to fail.
+  controller.abort();
 
-  assert_equals(detector.state.user, "active");
-  assert_equals(detector.state.screen, "unlocked");
-
-  detector.stop();
+  await promise_rejects_dom(
+      t, 'AbortError', detector.start({ signal: controller.signal }));
 }, 'Calling stop() after start() is a no-op');
 
 promise_test(async t => {
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       return Promise.resolve({
         state: {
           user: UserIdleState.ACTIVE,
           screen: ScreenIdleState.UNLOCKED
         }
       });
     });
 
-  let detector = new IdleDetector({threshold: 60000});
-
-  let watcher = new EventWatcher(t, detector, ["change"]);
+  let controller = new AbortController();
+  const detector = new IdleDetector();
+  const watcher = new EventWatcher(t, detector, ["change"]);
   let initial_state = watcher.wait_for("change");
 
-  await detector.start();
+  await detector.start({ signal: controller.signal });
   await initial_state;
 
-  detector.stop();
+  controller.abort();
 
   expect(addMonitor).andReturn((threshold, monitorPtr) => {
       return Promise.resolve({
         state: {
           user: UserIdleState.IDLE,
           screen: ScreenIdleState.LOCKED
         }
       });
     });
 
   // Restarting the monitor.
+  controller = new AbortController();
+
   initial_state = watcher.wait_for("change");
-  await detector.start();
+  await detector.start({ signal: controller.signal });
   await initial_state;
   assert_equals(detector.state.user, "idle");
   assert_equals(detector.state.screen, "locked");
 
-  detector.stop();
+  controller.abort();
 }, 'Calling start() after stop(): re-starting monitor.');
 
 </script>
--- a/testing/web-platform/tests/idle-detection/resources/idlharness-worker.js
+++ b/testing/web-platform/tests/idle-detection/resources/idlharness-worker.js
@@ -2,17 +2,17 @@
 
 importScripts("/resources/testharness.js");
 importScripts("/resources/WebIDLParser.js", "/resources/idlharness.js");
 
 idl_test(
     ['../idle-detection/idle-detection'],
     ['dom', 'html'],
     async (idl_array, t) => {
-      self.idle = new IdleDetector({threshold: 60000});
+      self.idle = new IdleDetector();
       let watcher = new EventWatcher(t, self.idle, ["change"]);
       let initial_state = watcher.wait_for("change");
       await self.idle.start();
       await initial_state;
 
       idl_array.add_objects({
         IdleDetector: ['idle'],
         IdleState: ['idle.state']