Bug 1189543 - `pushManager.getSubscription()` should return `null` for nonexistent push subscriptions in workers. r=nsm
authorKit Cambridge <kcambridge@mozilla.com>
Tue, 04 Aug 2015 13:43:23 -0700
changeset 287879 0e68d7a16ed852a833ac0d3d4b5ff0c54bf2573b
parent 287878 7b2a1ef36fcb715267e20baee84f7b26fc51bad8
child 287880 7911162321be494e5336ccd645f5d98286e22dc1
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersnsm
bugs1189543
milestone42.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 1189543 - `pushManager.getSubscription()` should return `null` for nonexistent push subscriptions in workers. r=nsm
dom/push/PushManager.cpp
dom/push/test/mochitest.ini
dom/push/test/test_push_manager_worker.html
dom/push/test/worker.js
--- a/dom/push/PushManager.cpp
+++ b/dom/push/PushManager.cpp
@@ -439,19 +439,23 @@ public:
   { }
 
   bool
   WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
   {
     nsRefPtr<PromiseWorkerProxy> proxy = mProxy.forget();
     nsRefPtr<Promise> promise = proxy->GetWorkerPromise();
     if (NS_SUCCEEDED(mStatus)) {
-      nsRefPtr<WorkerPushSubscription> sub =
-        new WorkerPushSubscription(mEndpoint, mScope);
-      promise->MaybeResolve(sub);
+      if (mEndpoint.IsEmpty()) {
+        promise->MaybeResolve(JS::NullHandleValue);
+      } else {
+        nsRefPtr<WorkerPushSubscription> sub =
+          new WorkerPushSubscription(mEndpoint, mScope);
+        promise->MaybeResolve(sub);
+      }
     } else {
       promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
     }
 
     proxy->CleanUp(aCx);
     return true;
   }
 private:
--- a/dom/push/test/mochitest.ini
+++ b/dom/push/test/mochitest.ini
@@ -16,8 +16,10 @@ skip-if = os == "android" || toolkit == 
 [test_multiple_register_during_service_activation.html]
 skip-if = os == "android" || toolkit == "gonk"
 [test_unregister.html]
 skip-if = os == "android" || toolkit == "gonk"
 [test_multiple_register_different_scope.html]
 skip-if = os == "android" || toolkit == "gonk"
 [test_try_registering_offline_disabled.html]
 skip-if = os == "android" || toolkit == "gonk"
+[test_push_manager_worker.html]
+skip-if = os == "android" || toolkit == "gonk"
new file mode 100644
--- /dev/null
+++ b/dom/push/test/test_push_manager_worker.html
@@ -0,0 +1,101 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 1184574: Expose PushManager to workers.
+
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/licenses/publicdomain/
+
+-->
+<head>
+  <title>Test for Bug 1184574</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.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=1184574">Mozilla Bug 1184574</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="text/javascript">
+
+  var registration;
+
+  function start() {
+    return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."})
+    .then(swr => { registration = swr; return swr; });
+  }
+
+  function unregisterSW() {
+    return registration.unregister().then(function(result) {
+      ok(result, "Unregister should return true.");
+    }, function(e) {
+      dump("Unregistering the SW failed with " + e + "\n");
+    });
+  }
+
+  function setupPushNotification(swr) {
+    return swr.pushManager.subscribe().then(
+      pushSubscription => {
+        ok(true, "successful registered for push notification");
+        return pushSubscription;
+      }, error => {
+        ok(false, "could not register for push notification");
+      });
+  }
+
+  function getNewEndpointFromWorker(pushSubscription) {
+    return new Promise((resolve, reject) => {
+      var channel = new MessageChannel();
+      channel.port1.onmessage = e => {
+        (e.data.error ? reject : resolve)(e.data);
+      };
+      registration.active.postMessage({
+        endpoint: pushSubscription.endpoint,
+      }, [channel.port2]);
+    }).then(data => {
+      return registration.pushManager.getSubscription().then(
+        pushSubscription => {
+          is(data.endpoint, pushSubscription.endpoint,
+             "Wrong push endpoint in parent");
+          return pushSubscription;
+      });
+    });
+  }
+
+  function unregisterPushNotification(pushSubscription) {
+    return pushSubscription.unsubscribe().then(
+      result => {
+      ok(result, "unsubscribe() on existing subscription should return true.");
+      return pushSubscription;
+    }, error => {
+      ok(false, "unsubscribe() should never fail.");
+    });
+  }
+
+  function runTest() {
+    start()
+    .then(setupPushNotification)
+    .then(getNewEndpointFromWorker)
+    .then(unregisterPushNotification)
+    .then(unregisterSW)
+    .catch(function(e) {
+      ok(false, "Some test failed with error " + e);
+    }).then(SimpleTest.finish);
+  }
+
+  SpecialPowers.pushPrefEnv({"set": [
+    ["dom.push.enabled", true],
+    ["dom.serviceWorkers.exemptFromPerDomainMax", true],
+    ["dom.serviceWorkers.enabled", true],
+    ["dom.serviceWorkers.testing.enabled", true]
+    ]}, runTest);
+  SpecialPowers.addPermission('push', true, document);
+  SimpleTest.waitForExplicitFinish();
+</script>
+</body>
+</html>
--- a/dom/push/test/worker.js
+++ b/dom/push/test/worker.js
@@ -1,16 +1,46 @@
 // Any copyright is dedicated to the Public Domain.
 // http://creativecommons.org/licenses/publicdomain/
 
+// This worker is used for two types of tests. `handlePush` sends messages to
+// `frame.html`, which verifies that the worker can receive push messages.
+
+// `handleMessage` receives a message from `test_push_manager_worker.html`, and
+// verifies that `PushManager` can be used from the worker.
+
 this.onpush = handlePush;
+this.onmessage = handleMessage;
 
 function handlePush(event) {
 
   self.clients.matchAll().then(function(result) {
     // FIXME(nsm): Bug 1149195 will fix data exposure.
     if (event instanceof PushEvent && !('data' in event)) {
       result[0].postMessage({type: "finished", okay: "yes"});
       return;
     }
     result[0].postMessage({type: "finished", okay: "no"});
   });
 }
+
+function handleMessage(event) {
+  self.registration.pushManager.getSubscription().then(subscription => {
+    if (subscription.endpoint != event.data.endpoint) {
+      throw new Error("Wrong push endpoint in worker");
+    }
+    return subscription.unsubscribe();
+  }).then(result => {
+    if (!result) {
+      throw new Error("Error dropping subscription in worker");
+    }
+    return self.registration.pushManager.getSubscription();
+  }).then(subscription => {
+    if (subscription) {
+      throw new Error("Subscription not dropped in worker");
+    }
+    return self.registration.pushManager.subscribe();
+  }).then(subscription => {
+    event.ports[0].postMessage({endpoint: subscription.endpoint});
+  }).catch(error => {
+    event.ports[0].postMessage({error: error});
+  });
+}