Bug 1170543 - Part 5: Import actiation.https.html wpt test from blink. r=asuth, a=sledru
authorBen Kelly <ben@wanderview.com>
Wed, 27 Jul 2016 20:36:11 -0400
changeset 340146 b8fa569b3a324ba3f18be3ecf314029210aab3f4
parent 340145 42b9f972ca983f9d88f10a459fa9f06b49ef495f
child 340147 bfb16f4837b7c239a181f317e79ed9ac79b31c87
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, sledru
bugs1170543
milestone49.0a2
Bug 1170543 - Part 5: Import actiation.https.html wpt test from blink. r=asuth, a=sledru
testing/web-platform/meta/MANIFEST.json
testing/web-platform/tests/service-workers/service-worker/activation.https.html
testing/web-platform/tests/service-workers/service-worker/resources/mint-new-worker.py
--- a/testing/web-platform/meta/MANIFEST.json
+++ b/testing/web-platform/meta/MANIFEST.json
@@ -36037,16 +36037,22 @@
           }
         ],
         "fetch/api/basic/request-referrer.html": [
           {
             "path": "fetch/api/basic/request-referrer.html",
             "url": "/fetch/api/basic/request-referrer.html"
           }
         ],
+        "service-workers/service-worker/activation.https.html": [
+          {
+            "path": "service-workers/service-worker/activation.https.html",
+            "url": "/service-workers/service-worker/activation.https.html"
+          }
+        ],
         "service-workers/service-worker/controller-on-disconnect.https.html": [
           {
             "path": "service-workers/service-worker/controller-on-disconnect.https.html",
             "url": "/service-workers/service-worker/controller-on-disconnect.https.html"
           }
         ],
         "web-animations/timing-model/animations/current-time.html": [
           {
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/service-workers/service-worker/activation.https.html
@@ -0,0 +1,148 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>service worker: activation</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="resources/test-helpers.sub.js"></script>
+<script>
+// Registers, waits for activation, then unregisters on a dummy scope.
+//
+// This helper can be used in tests that assert that activation doesn't happen.
+// It would not be sufficient to check the .waiting/.active properties once,
+// since activation could be scheduled and just hasn't happened yet. Since this
+// helper shows that activation of another registration completed, we can be
+// sure that activation really will not happen.
+function wait_for_activation_on_dummy_scope(t) {
+  var dummy_scope = 'resources/there/is/no/there/there';
+  var registration;
+  return navigator.serviceWorker.register('resources/empty-worker.js',
+      { scope: dummy_scope })
+    .then(r => {
+        registration = r;
+        return wait_for_state(t, registration.installing, 'activated');
+      })
+    .then(() => registration.unregister());
+}
+// Returns {registration, iframe}, where |registration| has an active and
+// waiting worker. The active worker controls |iframe| and has an inflight
+// message event that can be finished by calling
+// |registration.active.postMessage('go')|.
+function setup_activation_test(t, scope, worker_url) {
+  var registration;
+  var iframe;
+  return navigator.serviceWorker.getRegistration(scope)
+    .then(r => {
+        if (r)
+          return r.unregister();
+      })
+    .then(() => {
+        // Create an in-scope iframe. Do this prior to registration to avoid
+        // racing between an update triggered by navigation and the update()
+        // call below.
+        return with_iframe(scope);
+      })
+    .then(f => {
+        iframe = f;
+        // Create an active worker.
+        return navigator.serviceWorker.register(worker_url, { scope: scope });
+      })
+    .then(r => {
+        registration = r;
+        add_result_callback(() => registration.unregister());
+        return wait_for_state(t, r.installing, 'activated');
+      })
+    .then(() => {
+        // Check that the frame was claimed.
+        assert_not_equals(
+            iframe.contentWindow.navigator.serviceWorker.controller, null);
+        // Create an in-flight request.
+        registration.active.postMessage('wait');
+        // Now there is both a controllee and an in-flight request.
+        // Initiate an update.
+        return registration.update();
+      })
+    .then(() => {
+        // Wait for a waiting worker.
+        return wait_for_state(t, registration.installing, 'installed');
+      })
+    .then(() => {
+        return wait_for_activation_on_dummy_scope(t);
+      })
+    .then(() => {
+        assert_not_equals(registration.waiting, null);
+        assert_not_equals(registration.active, null);
+        return Promise.resolve({registration: registration, iframe: iframe});
+      });
+}
+promise_test(t => {
+    var scope = 'resources/no-controllee';
+    var worker_url = 'resources/mint-new-worker.py';
+    var registration;
+    var iframe;
+    var new_worker;
+    return setup_activation_test(t, scope, worker_url)
+      .then(result => {
+          registration = result.registration;
+          iframe = result.iframe;
+          // Finish the in-flight request.
+          registration.active.postMessage('go');
+          return wait_for_activation_on_dummy_scope(t);
+        })
+      .then(() => {
+          // The new worker is still waiting. Remove the frame and it should
+          // activate.
+          new_worker = registration.waiting;
+          assert_equals(new_worker.state, 'installed');
+          var reached_active = wait_for_state(t, new_worker, 'activating');
+          iframe.remove();
+          return reached_active;
+        })
+      .then(() => {
+          assert_equals(new_worker, registration.active);
+        });
+  }, 'loss of controllees triggers activation');
+promise_test(t => {
+    var scope = 'resources/no-request';
+    var worker_url = 'resources/mint-new-worker.py';
+    var registration;
+    var iframe;
+    var new_worker;
+    return setup_activation_test(t, scope, worker_url)
+      .then(result => {
+          registration = result.registration;
+          iframe = result.iframe;
+          // Remove the iframe.
+          iframe.remove();
+          return new Promise(resolve => setTimeout(resolve, 0));
+        })
+      .then(() => {
+          // Finish the request.
+          new_worker = registration.waiting;
+          var reached_active = wait_for_state(t, new_worker, 'activating');
+          registration.active.postMessage('go');
+          return reached_active;
+        })
+      .then(() => {
+          assert_equals(registration.active, new_worker);
+        });
+  }, 'finishing a request triggers activation');
+promise_test(t => {
+    var scope = 'resources/skip-waiting';
+    var worker_url = 'resources/mint-new-worker.py?skip-waiting';
+    var registration;
+    var new_worker;
+    return setup_activation_test(t, scope, worker_url)
+      .then(result => {
+          registration = result.registration;
+          // Finish the request. The iframe does not need to be removed because
+          // skipWaiting() was called.
+          new_worker = registration.waiting;
+          var reached_active = wait_for_state(t, new_worker, 'activating');
+          registration.active.postMessage('go');
+          return reached_active;
+        })
+      .then(() => {
+          assert_equals(registration.active, new_worker);
+        });
+  }, 'skipWaiting bypasses no controllee requirement');
+</script>
new file mode 100644
--- /dev/null
+++ b/testing/web-platform/tests/service-workers/service-worker/resources/mint-new-worker.py
@@ -0,0 +1,25 @@
+import time
+
+body = '''
+onactivate = (e) => e.waitUntil(clients.claim());
+var resolve_wait_until;
+var wait_until = new Promise(resolve => {
+    resolve_wait_until = resolve;
+  });
+onmessage = (e) => {
+    if (e.data == 'wait')
+      e.waitUntil(wait_until);
+    if (e.data == 'go')
+      resolve_wait_until();
+  };'''
+
+def main(request, response):
+    headers = [('Cache-Control', 'no-cache, must-revalidate'),
+               ('Pragma', 'no-cache'),
+               ('Content-Type', 'application/javascript')]
+
+    skipWaiting = ''
+    if 'skip-waiting' in request.GET:
+      skipWaiting = 'skipWaiting();'
+
+    return headers, '/* %s %s */ %s %s' % (time.time(), time.clock(), skipWaiting, body)