Bug 1263304 - Add a mochitest for asynchronously calling waitUntil(). r=bkelly
☠☠ backed out by 41f7289afbe3 ☠ ☠
authorCatalin Badea <catalin.badea392@gmail.com>
Fri, 11 Nov 2016 00:07:15 +0200
changeset 352155 2c423ac723b6c7cfec1261f0b828bc05942a8677
parent 352154 b2d3c6629a37d02c1f57e6bb3465ba3e35ff81de
child 352156 3ded216ab58b2c2f5106d34dcf17e793b154f466
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-esr52@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbkelly
bugs1263304
milestone52.0a1
Bug 1263304 - Add a mochitest for asynchronously calling waitUntil(). r=bkelly
dom/workers/test/serviceworkers/async_waituntil_worker.js
dom/workers/test/serviceworkers/mochitest.ini
dom/workers/test/serviceworkers/test_async_waituntil.html
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/async_waituntil_worker.js
@@ -0,0 +1,46 @@
+var keepAlivePromise;
+var resolvePromise;
+var result = "Failed";
+
+onactivate = function(event) {
+  event.waitUntil(clients.claim());
+}
+
+onmessage = function(event) {
+  if (event.data === "Start") {
+    event.waitUntil(Promise.reject());
+
+    keepAlivePromise = new Promise(function(resolve, reject) {
+      resolvePromise = resolve;
+    });
+
+    result = "Success";
+    event.waitUntil(keepAlivePromise);
+    event.source.postMessage("Started");
+  } else if (event.data === "Result") {
+    event.source.postMessage(result);
+    if (resolvePromise !== undefined) {
+      resolvePromise();
+    }
+  }
+}
+
+addEventListener('fetch', e => {
+  let respondWithPromise = new Promise(function(res, rej) {
+    setTimeout(() => {
+      res(new Response("ok"));
+    }, 0);
+  });
+  e.respondWith(respondWithPromise);
+  // Test that waitUntil can be called in the promise handler of the existing
+  // lifetime extension promise.
+  respondWithPromise.then(() => {
+    e.waitUntil(clients.matchAll().then((cls) => {
+      if (cls.length != 1) {
+        dump("ERROR: no controlled clients.\n");
+      }
+      client = cls[0];
+      client.postMessage("Done");
+    }));
+  });
+});
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -207,16 +207,17 @@ support-files =
   blocking_install_event_worker.js
   sw_bad_mime_type.js
   sw_bad_mime_type.js^headers^
   error_reporting_helpers.js
   fetch.js
   hello.html
   create_another_sharedWorker.html
   sharedWorker_fetch.js
+  async_waituntil_worker.js
 
 [test_bug1151916.html]
 [test_bug1240436.html]
 [test_claim.html]
 [test_claim_fetch.html]
 [test_claim_oninstall.html]
 [test_close.html]
 [test_controller.html]
@@ -310,8 +311,9 @@ tags = openwindow
 [test_strict_mode_warning.html]
 [test_third_party_iframes.html]
 [test_unregister.html]
 [test_unresolved_fetch_interception.html]
 [test_workerUnregister.html]
 [test_workerUpdate.html]
 [test_workerupdatefoundevent.html]
 [test_xslt.html]
+[test_async_waituntil.html]
new file mode 100644
--- /dev/null
+++ b/dom/workers/test/serviceworkers/test_async_waituntil.html
@@ -0,0 +1,97 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+  Test that:
+  1. waitUntil() waits for each individual promise separately, even if
+     one of them was rejected.
+  2. waitUntil() can be called asynchronously as long as there is still
+     a pending extension promise.
+  -->
+<head>
+  <title>Test for Bug 1263304</title>
+  <script src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script src="error_reporting_helpers.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+  <meta http-equiv="Content-type" content="text/html;charset=UTF-8">
+</head>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1263304">Mozilla Bug 1263304</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="text/javascript">
+add_task(function setupPrefs() {
+  return SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", true],
+  ]});
+});
+
+function wait_for_message(expected_message) {
+  return new Promise(function(resolve, reject) {
+    navigator.serviceWorker.onmessage = function(event) {
+      navigator.serviceWorker.onmessage = null;
+      ok(event.data === expected_message, "Received expected message event: " + event.data);
+      resolve();
+    }
+  });
+}
+
+add_task(function* async_wait_until() {
+  var worker;
+  let registration = yield navigator.serviceWorker.register(
+    "async_waituntil_worker.js", { scope: "./"} )
+    .then(function(registration) {
+      worker = registration.installing;
+      return new Promise(function(resolve) {
+        worker.addEventListener('statechange', function() {
+          if (worker.state === 'activated') {
+            resolve(registration);
+          }
+        });
+      });
+    });
+
+  // The service worker will claim us when it becomes active.
+  ok(navigator.serviceWorker.controller, "Controlled");
+
+  // This will make the service worker die immediately if there are no pending
+  // waitUntil promises to keep it alive.
+  yield SpecialPowers.pushPrefEnv({"set": [
+    ["dom.serviceWorkers.idle_timeout", 0],
+    ["dom.serviceWorkers.idle_extended_timeout", 299999]]});
+
+  // The service worker will wait on two promises, one of which
+  // will be rejected. We check whether the SW is killed using
+  // the value of a global variable.
+  let waitForStart = wait_for_message("Started");
+  worker.postMessage("Start");
+  yield waitForStart;
+
+  yield new Promise((res, rej) => {
+    setTimeout(res, 0);
+  });
+
+  let waitResult = wait_for_message("Success");
+  worker.postMessage("Result");
+  yield waitResult;
+
+  // Test the behaviour of calling waitUntil asynchronously. The important
+  // part is that we receive the message event.
+  let waitForMessage = wait_for_message("Done");
+  yield fetch("doesnt_exist.html").then(() => {
+    ok(true, "Fetch was successful.");
+  });
+  yield waitForMessage;
+
+  yield SpecialPowers.popPrefEnv();
+  yield SpecialPowers.popPrefEnv();
+  yield registration.unregister();
+});
+</script>
+</body>
+</html>