michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0: /* vim: set ts=2 et sw=2 tw=80: */
michael@0: /* Any copyright is dedicated to the Public Domain.
michael@0: * http://creativecommons.org/publicdomain/zero/1.0/
michael@0: */
michael@0:
michael@0: const PREF_POSTUPDATE = "app.update.postupdate";
michael@0: const PREF_MSTONE = "browser.startup.homepage_override.mstone";
michael@0: const PREF_OVERRIDE_URL = "startup.homepage_override_url";
michael@0:
michael@0: const DEFAULT_PREF_URL = "http://pref.example.com/";
michael@0: const DEFAULT_UPDATE_URL = "http://example.com/";
michael@0:
michael@0: const XML_EMPTY = "";
michael@0:
michael@0: const XML_PREFIX = "";
michael@0:
michael@0: // nsBrowserContentHandler.js defaultArgs tests
michael@0: const BCH_TESTS = [
michael@0: {
michael@0: description: "no mstone change and no update",
michael@0: noPostUpdatePref: true,
michael@0: noMstoneChange: true
michael@0: }, {
michael@0: description: "mstone changed and no update",
michael@0: noPostUpdatePref: true,
michael@0: prefURL: DEFAULT_PREF_URL
michael@0: }, {
michael@0: description: "no mstone change and update with 'showURL' for actions",
michael@0: actions: "showURL",
michael@0: noMstoneChange: true
michael@0: }, {
michael@0: description: "update without actions",
michael@0: prefURL: DEFAULT_PREF_URL
michael@0: }, {
michael@0: description: "update with 'showURL' for actions",
michael@0: actions: "showURL",
michael@0: prefURL: DEFAULT_PREF_URL
michael@0: }, {
michael@0: description: "update with 'showURL' for actions and openURL",
michael@0: actions: "showURL",
michael@0: openURL: DEFAULT_UPDATE_URL
michael@0: }, {
michael@0: description: "update with 'showURL showAlert' for actions",
michael@0: actions: "showAlert showURL",
michael@0: prefURL: DEFAULT_PREF_URL
michael@0: }, {
michael@0: description: "update with 'showAlert showURL' for actions and openURL",
michael@0: actions: "showAlert showURL",
michael@0: openURL: DEFAULT_UPDATE_URL
michael@0: }, {
michael@0: description: "update with 'showURL showNotification' for actions",
michael@0: actions: "showURL showNotification",
michael@0: prefURL: DEFAULT_PREF_URL
michael@0: }, {
michael@0: description: "update with 'showNotification showURL' for actions and " +
michael@0: "openURL",
michael@0: actions: "showNotification showURL",
michael@0: openURL: DEFAULT_UPDATE_URL
michael@0: }, {
michael@0: description: "update with 'showAlert showURL showNotification' for actions",
michael@0: actions: "showAlert showURL showNotification",
michael@0: prefURL: DEFAULT_PREF_URL
michael@0: }, {
michael@0: description: "update with 'showNotification showURL showAlert' for " +
michael@0: "actions and openURL",
michael@0: actions: "showNotification showURL showAlert",
michael@0: openURL: DEFAULT_UPDATE_URL
michael@0: }, {
michael@0: description: "update with 'showAlert' for actions",
michael@0: actions: "showAlert"
michael@0: }, {
michael@0: description: "update with 'showAlert showNotification' for actions",
michael@0: actions: "showAlert showNotification"
michael@0: }, {
michael@0: description: "update with 'showNotification' for actions",
michael@0: actions: "showNotification"
michael@0: }, {
michael@0: description: "update with 'showNotification showAlert' for actions",
michael@0: actions: "showNotification showAlert"
michael@0: }, {
michael@0: description: "update with 'silent' for actions",
michael@0: actions: "silent"
michael@0: }, {
michael@0: description: "update with 'silent showURL showAlert showNotification' " +
michael@0: "for actions and openURL",
michael@0: actions: "silent showURL showAlert showNotification"
michael@0: }
michael@0: ];
michael@0:
michael@0: var gOriginalMStone;
michael@0: var gOriginalOverrideURL;
michael@0:
michael@0: this.__defineGetter__("gBG", function() {
michael@0: delete this.gBG;
michael@0: return this.gBG = Cc["@mozilla.org/browser/browserglue;1"].
michael@0: getService(Ci.nsIBrowserGlue).
michael@0: QueryInterface(Ci.nsIObserver);
michael@0: });
michael@0:
michael@0: function test()
michael@0: {
michael@0: waitForExplicitFinish();
michael@0:
michael@0: // Reset the startup page pref since it may have been set by other tests
michael@0: // and we will assume it is default.
michael@0: Services.prefs.clearUserPref('browser.startup.page');
michael@0:
michael@0: if (gPrefService.prefHasUserValue(PREF_MSTONE)) {
michael@0: gOriginalMStone = gPrefService.getCharPref(PREF_MSTONE);
michael@0: }
michael@0:
michael@0: if (gPrefService.prefHasUserValue(PREF_OVERRIDE_URL)) {
michael@0: gOriginalOverrideURL = gPrefService.getCharPref(PREF_OVERRIDE_URL);
michael@0: }
michael@0:
michael@0: testDefaultArgs();
michael@0: }
michael@0:
michael@0: var gWindowCatcher = {
michael@0: windowsOpen: 0,
michael@0: finishCalled: false,
michael@0: start: function() {
michael@0: Services.ww.registerNotification(this);
michael@0: },
michael@0:
michael@0: finish: function(aFunc) {
michael@0: Services.ww.unregisterNotification(this);
michael@0: this.finishFunc = aFunc;
michael@0: if (this.windowsOpen > 0)
michael@0: return;
michael@0:
michael@0: this.finishFunc();
michael@0: },
michael@0:
michael@0: closeWindow: function (win) {
michael@0: info("window catcher closing window: " + win.document.documentURI);
michael@0: win.close();
michael@0: this.windowsOpen--;
michael@0: if (this.finishFunc) {
michael@0: this.finish(this.finishFunc);
michael@0: }
michael@0: },
michael@0:
michael@0: windowLoad: function (win) {
michael@0: executeSoon(this.closeWindow.bind(this, win));
michael@0: },
michael@0:
michael@0: observe: function(subject, topic, data) {
michael@0: if (topic != "domwindowopened")
michael@0: return;
michael@0:
michael@0: this.windowsOpen++;
michael@0: let win = subject.QueryInterface(Ci.nsIDOMWindow);
michael@0: info("window catcher caught window opening: " + win.document.documentURI);
michael@0: win.addEventListener("load", function () {
michael@0: win.removeEventListener("load", arguments.callee, false);
michael@0: gWindowCatcher.windowLoad(win);
michael@0: }, false);
michael@0: }
michael@0: };
michael@0:
michael@0: function finish_test()
michael@0: {
michael@0: // Reset browser.startup.homepage_override.mstone to the original value or
michael@0: // clear it if it didn't exist.
michael@0: if (gOriginalMStone) {
michael@0: gPrefService.setCharPref(PREF_MSTONE, gOriginalMStone);
michael@0: } else if (gPrefService.prefHasUserValue(PREF_MSTONE)) {
michael@0: gPrefService.clearUserPref(PREF_MSTONE);
michael@0: }
michael@0:
michael@0: // Reset startup.homepage_override_url to the original value or clear it if
michael@0: // it didn't exist.
michael@0: if (gOriginalOverrideURL) {
michael@0: gPrefService.setCharPref(PREF_OVERRIDE_URL, gOriginalOverrideURL);
michael@0: } else if (gPrefService.prefHasUserValue(PREF_OVERRIDE_URL)) {
michael@0: gPrefService.clearUserPref(PREF_OVERRIDE_URL);
michael@0: }
michael@0:
michael@0: writeUpdatesToXMLFile(XML_EMPTY);
michael@0: reloadUpdateManagerData();
michael@0:
michael@0: finish();
michael@0: }
michael@0:
michael@0: // Test the defaultArgs returned by nsBrowserContentHandler after an update
michael@0: function testDefaultArgs()
michael@0: {
michael@0: // Clear any pre-existing override in defaultArgs that are hanging around.
michael@0: // This will also set the browser.startup.homepage_override.mstone preference
michael@0: // if it isn't already set.
michael@0: Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs;
michael@0:
michael@0: let originalMstone = gPrefService.getCharPref(PREF_MSTONE);
michael@0:
michael@0: gPrefService.setCharPref(PREF_OVERRIDE_URL, DEFAULT_PREF_URL);
michael@0:
michael@0: writeUpdatesToXMLFile(XML_EMPTY);
michael@0: reloadUpdateManagerData();
michael@0:
michael@0: for (let i = 0; i < BCH_TESTS.length; i++) {
michael@0: let test = BCH_TESTS[i];
michael@0: ok(true, "Test nsBrowserContentHandler " + (i + 1) + ": " + test.description);
michael@0:
michael@0: if (test.actions) {
michael@0: let actionsXML = " actions=\"" + test.actions + "\"";
michael@0: if (test.openURL) {
michael@0: actionsXML += " openURL=\"" + test.openURL + "\"";
michael@0: }
michael@0: writeUpdatesToXMLFile(XML_PREFIX + actionsXML + XML_SUFFIX);
michael@0: } else {
michael@0: writeUpdatesToXMLFile(XML_EMPTY);
michael@0: }
michael@0:
michael@0: reloadUpdateManagerData();
michael@0:
michael@0: let noOverrideArgs = Cc["@mozilla.org/browser/clh;1"].
michael@0: getService(Ci.nsIBrowserHandler).defaultArgs;
michael@0:
michael@0: let overrideArgs = "";
michael@0: if (test.prefURL) {
michael@0: overrideArgs = test.prefURL;
michael@0: } else if (test.openURL) {
michael@0: overrideArgs = test.openURL;
michael@0: }
michael@0:
michael@0: if (overrideArgs == "" && noOverrideArgs) {
michael@0: overrideArgs = noOverrideArgs;
michael@0: } else if (noOverrideArgs) {
michael@0: overrideArgs += "|" + noOverrideArgs;
michael@0: }
michael@0:
michael@0: if (test.noMstoneChange === undefined) {
michael@0: gPrefService.setCharPref(PREF_MSTONE, "PreviousMilestone");
michael@0: }
michael@0:
michael@0: if (test.noPostUpdatePref == undefined) {
michael@0: gPrefService.setBoolPref(PREF_POSTUPDATE, true);
michael@0: }
michael@0:
michael@0: let defaultArgs = Cc["@mozilla.org/browser/clh;1"].
michael@0: getService(Ci.nsIBrowserHandler).defaultArgs;
michael@0: is(defaultArgs, overrideArgs, "correct value returned by defaultArgs");
michael@0:
michael@0: if (test.noMstoneChange === undefined || test.noMstoneChange != true) {
michael@0: let newMstone = gPrefService.getCharPref(PREF_MSTONE);
michael@0: is(originalMstone, newMstone, "preference " + PREF_MSTONE +
michael@0: " should have been updated");
michael@0: }
michael@0:
michael@0: if (gPrefService.prefHasUserValue(PREF_POSTUPDATE)) {
michael@0: gPrefService.clearUserPref(PREF_POSTUPDATE);
michael@0: }
michael@0: }
michael@0:
michael@0: testShowNotification();
michael@0: }
michael@0:
michael@0: // nsBrowserGlue.js _showUpdateNotification notification tests
michael@0: const BG_NOTIFY_TESTS = [
michael@0: {
michael@0: description: "'silent showNotification' actions should not display a notification",
michael@0: actions: "silent showNotification"
michael@0: }, {
michael@0: description: "'showNotification' for actions should display a notification",
michael@0: actions: "showNotification"
michael@0: }, {
michael@0: description: "no actions and empty updates.xml",
michael@0: }, {
michael@0: description: "'showAlert' for actions should not display a notification",
michael@0: actions: "showAlert"
michael@0: }, {
michael@0: // This test MUST be the last test in the array to test opening the url
michael@0: // provided by the updates.xml.
michael@0: description: "'showNotification' for actions with custom notification " +
michael@0: "attributes should display a notification",
michael@0: actions: "showNotification",
michael@0: notificationText: "notification text",
michael@0: notificationURL: DEFAULT_UPDATE_URL,
michael@0: notificationButtonLabel: "button label",
michael@0: notificationButtonAccessKey: "b"
michael@0: }
michael@0: ];
michael@0:
michael@0: // Test showing a notification after an update
michael@0: // _showUpdateNotification in nsBrowserGlue.js
michael@0: function testShowNotification()
michael@0: {
michael@0: let gTestBrowser = gBrowser.selectedBrowser;
michael@0: let notifyBox = gBrowser.getNotificationBox(gTestBrowser);
michael@0:
michael@0: // Catches any windows opened by these tests (e.g. alert windows) and closes
michael@0: // them
michael@0: gWindowCatcher.start();
michael@0:
michael@0: for (let i = 0; i < BG_NOTIFY_TESTS.length; i++) {
michael@0: let test = BG_NOTIFY_TESTS[i];
michael@0: ok(true, "Test showNotification " + (i + 1) + ": " + test.description);
michael@0:
michael@0: if (test.actions) {
michael@0: let actionsXML = " actions=\"" + test.actions + "\"";
michael@0: if (test.notificationText) {
michael@0: actionsXML += " notificationText=\"" + test.notificationText + "\"";
michael@0: }
michael@0: if (test.notificationURL) {
michael@0: actionsXML += " notificationURL=\"" + test.notificationURL + "\"";
michael@0: }
michael@0: if (test.notificationButtonLabel) {
michael@0: actionsXML += " notificationButtonLabel=\"" + test.notificationButtonLabel + "\"";
michael@0: }
michael@0: if (test.notificationButtonAccessKey) {
michael@0: actionsXML += " notificationButtonAccessKey=\"" + test.notificationButtonAccessKey + "\"";
michael@0: }
michael@0: writeUpdatesToXMLFile(XML_PREFIX + actionsXML + XML_SUFFIX);
michael@0: } else {
michael@0: writeUpdatesToXMLFile(XML_EMPTY);
michael@0: }
michael@0:
michael@0: reloadUpdateManagerData();
michael@0: gPrefService.setBoolPref(PREF_POSTUPDATE, true);
michael@0:
michael@0: gBG.observe(null, "browser-glue-test", "post-update-notification");
michael@0:
michael@0: let updateBox = notifyBox.getNotificationWithValue("post-update-notification");
michael@0: if (test.actions && test.actions.indexOf("showNotification") != -1 &&
michael@0: test.actions.indexOf("silent") == -1) {
michael@0: ok(updateBox, "Update notification box should have been displayed");
michael@0: if (updateBox) {
michael@0: if (test.notificationText) {
michael@0: is(updateBox.label, test.notificationText, "Update notification box " +
michael@0: "should have the label provided by the update");
michael@0: }
michael@0: if (test.notificationButtonLabel) {
michael@0: var button = updateBox.getElementsByTagName("button").item(0);
michael@0: is(button.label, test.notificationButtonLabel, "Update notification " +
michael@0: "box button should have the label provided by the update");
michael@0: if (test.notificationButtonAccessKey) {
michael@0: let accessKey = button.getAttribute("accesskey");
michael@0: is(accessKey, test.notificationButtonAccessKey, "Update " +
michael@0: "notification box button should have the accesskey " +
michael@0: "provided by the update");
michael@0: }
michael@0: }
michael@0: // The last test opens an url and verifies the url from the updates.xml
michael@0: // is correct.
michael@0: if (i == (BG_NOTIFY_TESTS.length - 1)) {
michael@0: // Wait for any windows caught by the windowcatcher to close
michael@0: gWindowCatcher.finish(function () {
michael@0: button.click();
michael@0: gBrowser.selectedBrowser.addEventListener("load", function () {
michael@0: gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
michael@0: testNotificationURL();
michael@0: }, true);
michael@0: });
michael@0: } else {
michael@0: notifyBox.removeAllNotifications(true);
michael@0: }
michael@0: } else if (i == (BG_NOTIFY_TESTS.length - 1)) {
michael@0: // If updateBox is null the test has already reported errors so bail
michael@0: finish_test();
michael@0: }
michael@0: } else {
michael@0: ok(!updateBox, "Update notification box should not have been displayed");
michael@0: }
michael@0:
michael@0: let prefHasUserValue = gPrefService.prefHasUserValue(PREF_POSTUPDATE);
michael@0: is(prefHasUserValue, false, "preference " + PREF_POSTUPDATE +
michael@0: " shouldn't have a user value");
michael@0: }
michael@0: }
michael@0:
michael@0: // Test opening the url provided by the updates.xml in the last test
michael@0: function testNotificationURL()
michael@0: {
michael@0: ok(true, "Test testNotificationURL: clicking the notification button " +
michael@0: "opened the url specified by the update");
michael@0: let href = gBrowser.selectedBrowser.contentWindow.location.href;
michael@0: let expectedURL = BG_NOTIFY_TESTS[BG_NOTIFY_TESTS.length - 1].notificationURL;
michael@0: is(href, expectedURL, "The url opened from the notification should be the " +
michael@0: "url provided by the update");
michael@0: gBrowser.removeCurrentTab();
michael@0: window.focus();
michael@0: finish_test();
michael@0: }
michael@0:
michael@0: /* Reloads the update metadata from disk */
michael@0: function reloadUpdateManagerData()
michael@0: {
michael@0: Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager).
michael@0: QueryInterface(Ci.nsIObserver).observe(null, "um-reload-update-data", "");
michael@0: }
michael@0:
michael@0:
michael@0: function writeUpdatesToXMLFile(aText)
michael@0: {
michael@0: const PERMS_FILE = 0644;
michael@0:
michael@0: const MODE_WRONLY = 0x02;
michael@0: const MODE_CREATE = 0x08;
michael@0: const MODE_TRUNCATE = 0x20;
michael@0:
michael@0: let file = Cc["@mozilla.org/file/directory_service;1"].
michael@0: getService(Ci.nsIProperties).
michael@0: get("UpdRootD", Ci.nsIFile);
michael@0: file.append("updates.xml");
michael@0: let fos = Cc["@mozilla.org/network/file-output-stream;1"].
michael@0: createInstance(Ci.nsIFileOutputStream);
michael@0: if (!file.exists()) {
michael@0: file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
michael@0: }
michael@0: fos.init(file, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
michael@0: fos.write(aText, aText.length);
michael@0: fos.close();
michael@0: }