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: }