Bug 1246341 - Add a test for push event error reporting. r=dragana
MozReview-Commit-ID: LABOJnYtpD5
--- a/dom/push/PushNotifier.cpp
+++ b/dom/push/PushNotifier.cpp
@@ -59,19 +59,16 @@ PushNotifier::NotifyPush(const nsACStrin
{
return NotifyPush(aScope, aPrincipal, aMessageId, Nothing());
}
NS_IMETHODIMP
PushNotifier::NotifySubscriptionChange(const nsACString& aScope,
nsIPrincipal* aPrincipal)
{
- if (XRE_IsContentProcess()) {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
nsresult rv;
if (ShouldNotifyObservers(aPrincipal)) {
rv = NotifySubscriptionChangeObservers(aScope);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
if (ShouldNotifyWorkers(aPrincipal)) {
@@ -83,19 +80,16 @@ PushNotifier::NotifySubscriptionChange(c
return NS_OK;
}
nsresult
PushNotifier::NotifyPush(const nsACString& aScope, nsIPrincipal* aPrincipal,
const nsAString& aMessageId,
const Maybe<nsTArray<uint8_t>>& aData)
{
- if (XRE_IsContentProcess()) {
- return NS_ERROR_NOT_IMPLEMENTED;
- }
nsresult rv;
if (ShouldNotifyObservers(aPrincipal)) {
rv = NotifyPushObservers(aScope, aData);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
}
if (ShouldNotifyWorkers(aPrincipal)) {
--- a/dom/push/PushNotifier.h
+++ b/dom/push/PushNotifier.h
@@ -20,19 +20,18 @@
namespace mozilla {
namespace dom {
/**
* `PushNotifier` implements the `nsIPushNotifier` interface. This service
* forwards incoming push messages to service workers running in the content
* process, and emits XPCOM observer notifications for system subscriptions.
*
- * The XPCOM service can only be used from the main process. Callers running
- * in the content process should use
- * `ServiceWorkerManager::SendPush{SubscriptionChange}Event` directly.
+ * This service exists solely to support `PushService.jsm`. Other callers
+ * should use `ServiceWorkerManager` directly.
*/
class PushNotifier final : public nsIPushNotifier
{
public:
PushNotifier();
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(PushNotifier, nsIPushNotifier)
new file mode 100644
--- /dev/null
+++ b/dom/push/test/error_worker.js
@@ -0,0 +1,10 @@
+this.onpush = function(event) {
+ var request = event.data.json();
+ if (request.type == "exception") {
+ throw new Error("Uncaught exception");
+ }
+ if (request.type == "rejection") {
+ event.waitUntil(Promise.reject(
+ new Error("Unhandled rejection")));
+ }
+};
--- a/dom/push/test/mochitest.ini
+++ b/dom/push/test/mochitest.ini
@@ -2,22 +2,24 @@
subsuite = push
support-files =
worker.js
push-server.sjs
frame.html
webpush.js
lifetime_worker.js
test_utils.js
+ error_worker.js
skip-if = os == "android" || toolkit == "gonk"
[test_has_permissions.html]
[test_permissions.html]
[test_register.html]
[test_multiple_register.html]
[test_multiple_register_during_service_activation.html]
[test_unregister.html]
[test_multiple_register_different_scope.html]
[test_subscription_change.html]
[test_data.html]
# Disabled for too many intermittent failures (bug 1164432)
# [test_try_registering_offline_disabled.html]
[test_serviceworker_lifetime.html]
+[test_error_reporting.html]
new file mode 100644
--- /dev/null
+++ b/dom/push/test/test_error_reporting.html
@@ -0,0 +1,156 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+Bug 1246341: Report message delivery failures to the Push server.
+
+Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/licenses/publicdomain/
+
+-->
+<head>
+ <title>Test for Bug 1246341</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <script type="text/javascript" src="/tests/dom/push/test/test_utils.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=1246341">Mozilla Bug 1246341</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+
+<script class="testbody" type="text/javascript">
+
+ var pushNotifier = SpecialPowers.Cc["@mozilla.org/push/Notifier;1"]
+ .getService(SpecialPowers.Ci.nsIPushNotifier);
+
+ var MOCK_PUSH_SERVICE_CID = SpecialPowers.wrap(
+ SpecialPowers.Components).ID("{ded2b14c-165d-4a9f-b312-a85971e289ee}");
+ var MOCK_PUSH_SERVICE_CONTRACT_ID = "@mozilla.org/push/Service;1";
+
+ var registrar = SpecialPowers.wrap(SpecialPowers.Components).manager.
+ QueryInterface(SpecialPowers.Ci.nsIComponentRegistrar);
+
+ var reporters = new Map();
+ var mockPushService = SpecialPowers.wrapCallbackObject({
+
+ // nsISupports methods
+ QueryInterface(iid) {
+ if (SpecialPowers.wrap(iid).equals(SpecialPowers.Ci.nsISupports) ||
+ SpecialPowers.wrap(iid).equals(SpecialPowers.Ci.nsIPushService) ||
+ SpecialPowers.wrap(iid).equals(SpecialPowers.Ci.nsIPushErrorReporter)) {
+ return this;
+ }
+ throw SpecialPowers.Components.results.NS_ERROR_NO_INTERFACE;
+ },
+ createInstance(outer, iid) {
+ if (outer != null) {
+ throw SpecialPowers.Components.results.NS_ERROR_NO_AGGREGATION;
+ }
+ return this.QueryInterface(iid);
+ },
+
+ // nsIPushService methods
+ subscribe(scope, principal, callback) {
+ callback.onPushSubscription(SpecialPowers.Cr.NS_OK, {
+ endpoint: "https://example.com/push",
+ pushCount: 0,
+ lastPush: 0,
+ quota: -1,
+ quotaApplies() {
+ return false;
+ },
+ isExpired() {
+ return false;
+ },
+ getKey(name) {
+ return null;
+ },
+ });
+ },
+ unsubscribe(scope, principal, callback) {
+ callback.onUnsubscribe(SpecialPowers.Cr.NS_OK, true);
+ },
+ getSubscription(scope, principal, callback) {
+ callback.onPushSubscription(SpecialPowers.Cr.NS_OK, null);
+ },
+ clearForDomain(domain, callback) {
+ callback.onClear(SpecialPowers.Cr.NS_OK);
+ },
+
+ // nsIPushErrorReporter methods
+ reportDeliveryError(messageId, reason) {
+ ok(reporters.has(messageId),
+ 'Unexpected error reported for message ' + messageId);
+ var resolve = reporters.get(messageId);
+ reporters.delete(messageId);
+ resolve(reason);
+ },
+ });
+
+ SimpleTest.registerCleanupFunction(() => {
+ registrar.unregisterFactory(MOCK_PUSH_SERVICE_CID, mockPushService);
+ });
+
+ var registration;
+ add_task(function* start() {
+ registrar.registerFactory(MOCK_PUSH_SERVICE_CID, "Push Service",
+ MOCK_PUSH_SERVICE_CONTRACT_ID,
+ mockPushService);
+ yield setupPrefs();
+ yield setPushPermission(true);
+
+ var url = "error_worker.js" + "?" + (Math.random());
+ registration = yield navigator.serviceWorker.register(url, {scope: "."});
+ });
+
+ var controlledFrame;
+ add_task(function* createControlledIFrame() {
+ controlledFrame = yield injectControlledFrame();
+ });
+
+ var pushSubscription;
+ add_task(function* subscribe() {
+ pushSubscription = yield registration.pushManager.subscribe();
+ });
+
+ var idCounter = 1;
+ function waitForDeliveryError(request) {
+ return new Promise(resolve => {
+ var data = new TextEncoder("utf-8").encode(JSON.stringify(request));
+ var principal = SpecialPowers.wrap(document).nodePrincipal;
+
+ let messageId = "message-" + (idCounter++);
+ reporters.set(messageId, resolve);
+ pushNotifier.notifyPushWithData(registration.scope, principal, messageId,
+ data.length, data);
+ });
+ }
+
+ add_task(function* reportErrors() {
+ var reason = yield waitForDeliveryError({ type: "exception" });
+ is(reason, SpecialPowers.Ci.nsIPushErrorReporter.DELIVERY_UNCAUGHT_EXCEPTION,
+ "Should report uncaught exceptions");
+
+ reason = yield waitForDeliveryError({ type: "rejection" });
+ is(reason, SpecialPowers.Ci.nsIPushErrorReporter.DELIVERY_UNHANDLED_REJECTION,
+ "Should report unhandled rejections");
+ });
+
+ add_task(function* unsubscribe() {
+ controlledFrame.remove();
+ yield pushSubscription.unsubscribe();
+ });
+
+ add_task(function* unregister() {
+ yield registration.unregister();
+ });
+
+</script>
+</body>
+</html>
+