Bug 1398518 - Fix test_ext_notifications.html intermittency and re-enable it. r=mixedpuppy

Based on what I've been able to reproduce locally using --verify, there is a chance that
the notifications created by the test case named `test_notifications_populated_getAll`
may have been removed before the `browser.notifications.getAll` is going to retrieve them,
and when this happens the test gets stuck because `browser.test.notifyPass("getAll populated");`
is never reached, and the test timeouts.

This patch includes the following changes to prevent the intermittent failure described above:

- add a new head_notifications.js support file and create a new MockAlertsService test helper that
  loads a chrome script which replace the alerts service with a mock service (based on a
  similar mock defined in dom/notification/test/mochitest/MockServices.js), the mocked alert
  service doesn't close the notification until the test case itself has called
  `MockAlertsService.clearNotifications` (so that the test shouldn't fail intermittently as
  described above).

- applies the changes needed on test_ext_notifications.html to make use of the MockAlertsService

Differential Revision: https://phabricator.services.mozilla.com/D17863

--HG--
rename : dom/notification/test/mochitest/MockServices.js => toolkit/components/extensions/test/mochitest/head_notifications.js
extra : moz-landing-system : lando
This commit is contained in:
Luca Greco 2019-01-30 18:05:34 +00:00
Родитель ac88918290
Коммит 8372c1ce21
3 изменённых файлов: 135 добавлений и 7 удалений

Просмотреть файл

@ -0,0 +1,108 @@
"use strict";
/* exported MockAlertsService */
function mockServicesChromeScript() {
const MOCK_ALERTS_CID = Components.ID("{48068bc2-40ab-4904-8afd-4cdfb3a385f3}");
const ALERTS_SERVICE_CONTRACT_ID = "@mozilla.org/alerts-service;1";
const {setTimeout} = ChromeUtils.import("resource://gre/modules/Timer.jsm", {});
const registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
let activeNotifications = Object.create(null);
const mockAlertsService = {
showPersistentNotification: function(persistentData, alert, alertListener) {
this.showAlert(alert, alertListener);
},
showAlert: function(alert, listener) {
activeNotifications[alert.name] = {
listener: listener,
cookie: alert.cookie,
title: alert.title,
};
// fake async alert show event
if (listener) {
setTimeout(function() {
listener.observe(null, "alertshow", alert.cookie);
}, 100);
}
},
showAlertNotification: function(imageUrl, title, text, textClickable,
cookie, alertListener, name) {
this.showAlert({
name: name,
cookie: cookie,
title: title,
}, alertListener);
},
closeAlert: function(name) {
let alertNotification = activeNotifications[name];
if (alertNotification) {
if (alertNotification.listener) {
alertNotification.listener.observe(null, "alertfinished", alertNotification.cookie);
}
delete activeNotifications[name];
}
},
QueryInterface: ChromeUtils.generateQI(["nsIAlertsService"]),
createInstance: function(outer, iid) {
if (outer != null) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return this.QueryInterface(iid);
},
};
registrar.registerFactory(MOCK_ALERTS_CID, "alerts service",
ALERTS_SERVICE_CONTRACT_ID,
mockAlertsService);
function closeAllNotifications() {
for (let alertName of Object.keys(activeNotifications)) {
mockAlertsService.closeAlert(alertName);
}
}
const {addMessageListener, sendAsyncMessage} = this;
addMessageListener("mock-alert-service:unregister", () => {
closeAllNotifications();
activeNotifications = null;
registrar.unregisterFactory(MOCK_ALERTS_CID, mockAlertsService);
sendAsyncMessage("mock-alert-service:unregistered");
});
addMessageListener("mock-alert-service:close-notifications", closeAllNotifications);
sendAsyncMessage("mock-alert-service:registered");
}
const MockAlertsService = {
async register() {
if (this._chromeScript) {
throw new Error("MockAlertsService already registered");
}
this._chromeScript = SpecialPowers.loadChromeScript(mockServicesChromeScript);
await this._chromeScript.promiseOneMessage("mock-alert-service:registered");
},
async unregister() {
if (!this._chromeScript) {
throw new Error("MockAlertsService not registered");
}
this._chromeScript.sendAsyncMessage("mock-alert-service:unregister");
return this._chromeScript.promiseOneMessage("mock-alert-service:unregistered").then(() => {
this._chromeScript.destroy();
this._chromeScript = null;
});
},
async closeNotifications() {
await this._chromeScript.sendAsyncMessage("mock-alert-service:close-notifications");
},
};

Просмотреть файл

@ -38,6 +38,7 @@ support-files =
file_with_about_blank.html
head.js
head_cookies.js
head_notifications.js
head_unlimitedStorage.js
head_webrequest.js
hsts.sjs
@ -96,7 +97,6 @@ skip-if = os == 'android' # Android does not support multiple windows.
[test_ext_new_tab_processType.html]
skip-if = (verify && debug && (os == 'linux' || os == 'mac'))
[test_ext_notifications.html]
skip-if = os == "win" # Bug 1398518
[test_ext_protocolHandlers.html]
skip-if = (toolkit == 'android') # bug 1342577
[test_ext_redirect_jar.html]

Просмотреть файл

@ -5,6 +5,7 @@
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/AddTask.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head_notifications.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
@ -18,6 +19,10 @@ let image = atob("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAA" +
"ACnej3aAAAAAXRSTlMAQObYZgAAAApJREFUCNdjYAAAAAIAAeIhvDMAAAAASUVORK5CYII=");
const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer;
add_task(async function setup_mock_alert_service() {
await MockAlertsService.register();
});
add_task(async function test_notification() {
async function background() {
let opts = {
@ -46,7 +51,7 @@ add_task(async function test_notification() {
});
add_task(async function test_notification_events() {
function background() {
async function background() {
let opts = {
type: "basic",
title: "Testing Notification",
@ -67,17 +72,19 @@ add_task(async function test_notification_events() {
browser.test.assertEq(createdId, id, "onShown received the expected id.");
let newId = await browser.notifications.create(id, opts);
browser.test.assertEq(createdId, newId, "create returned the expected id.");
browser.test.sendMessage("created");
browser.test.sendMessage("notification-created-twice");
});
// Test onClosed listener.
browser.notifications.onClosed.addListener(function listener(id) {
browser.notifications.onClosed.removeListener(listener);
browser.test.assertEq(createdId, id, "onClosed received the expected id.");
browser.test.sendMessage("closed");
browser.test.sendMessage("notification-closed");
});
browser.notifications.create(createdId, opts);
await browser.notifications.create(createdId, opts);
browser.test.sendMessage("notification-created-once");
}
let extension = ExtensionTestUtils.loadExtension({
@ -86,9 +93,17 @@ add_task(async function test_notification_events() {
},
background,
});
await extension.startup();
await extension.awaitMessage("closed");
await extension.awaitMessage("created");
await extension.awaitMessage("notification-created-once");
await MockAlertsService.closeNotifications();
await extension.awaitMessage("notification-closed");
await extension.awaitMessage("notification-created-twice");
await MockAlertsService.closeNotifications();
await extension.unload();
});
@ -122,6 +137,7 @@ add_task(async function test_notification_clear() {
},
background,
});
await extension.startup();
await extension.awaitFinish();
await extension.unload();
@ -275,6 +291,10 @@ add_task(async function test_notifications_different_contexts() {
await extension.unload();
});
add_task(async function teardown_mock_alert_service() {
await MockAlertsService.unregister();
});
</script>
</body>