1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/components/test/browser_bug538331.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,431 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* vim: set ts=2 et sw=2 tw=80: */ 1.6 +/* Any copyright is dedicated to the Public Domain. 1.7 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.8 + */ 1.9 + 1.10 +const PREF_POSTUPDATE = "app.update.postupdate"; 1.11 +const PREF_MSTONE = "browser.startup.homepage_override.mstone"; 1.12 +const PREF_OVERRIDE_URL = "startup.homepage_override_url"; 1.13 + 1.14 +const DEFAULT_PREF_URL = "http://pref.example.com/"; 1.15 +const DEFAULT_UPDATE_URL = "http://example.com/"; 1.16 + 1.17 +const XML_EMPTY = "<?xml version=\"1.0\"?><updates xmlns=" + 1.18 + "\"http://www.mozilla.org/2005/app-update\"></updates>"; 1.19 + 1.20 +const XML_PREFIX = "<updates xmlns=\"http://www.mozilla.org/2005/app-update\"" + 1.21 + "><update appVersion=\"1.0\" buildID=\"20080811053724\" " + 1.22 + "channel=\"nightly\" displayVersion=\"Version 1.0\" " + 1.23 + "extensionVersion=\"1.0\" installDate=\"1238441400314\" " + 1.24 + "isCompleteUpdate=\"true\" name=\"Update Test 1.0\" " + 1.25 + "serviceURL=\"https://example.com/\" showNeverForVersion=" + 1.26 + "\"false\" showPrompt=\"false\" type=" + 1.27 + "\"minor\" version=\"version 1.0\" detailsURL=" + 1.28 + "\"http://example.com/\" previousAppVersion=\"1.0\" " + 1.29 + "statusText=\"The Update was successfully installed\" " + 1.30 + "foregroundDownload=\"true\""; 1.31 + 1.32 +const XML_SUFFIX = "><patch type=\"complete\" URL=\"http://example.com/\" " + 1.33 + "hashFunction=\"MD5\" hashValue=" + 1.34 + "\"6232cd43a1c77e30191c53a329a3f99d\" size=\"775\" " + 1.35 + "selected=\"true\" state=\"succeeded\"/></update></updates>"; 1.36 + 1.37 +// nsBrowserContentHandler.js defaultArgs tests 1.38 +const BCH_TESTS = [ 1.39 + { 1.40 + description: "no mstone change and no update", 1.41 + noPostUpdatePref: true, 1.42 + noMstoneChange: true 1.43 + }, { 1.44 + description: "mstone changed and no update", 1.45 + noPostUpdatePref: true, 1.46 + prefURL: DEFAULT_PREF_URL 1.47 + }, { 1.48 + description: "no mstone change and update with 'showURL' for actions", 1.49 + actions: "showURL", 1.50 + noMstoneChange: true 1.51 + }, { 1.52 + description: "update without actions", 1.53 + prefURL: DEFAULT_PREF_URL 1.54 + }, { 1.55 + description: "update with 'showURL' for actions", 1.56 + actions: "showURL", 1.57 + prefURL: DEFAULT_PREF_URL 1.58 + }, { 1.59 + description: "update with 'showURL' for actions and openURL", 1.60 + actions: "showURL", 1.61 + openURL: DEFAULT_UPDATE_URL 1.62 + }, { 1.63 + description: "update with 'showURL showAlert' for actions", 1.64 + actions: "showAlert showURL", 1.65 + prefURL: DEFAULT_PREF_URL 1.66 + }, { 1.67 + description: "update with 'showAlert showURL' for actions and openURL", 1.68 + actions: "showAlert showURL", 1.69 + openURL: DEFAULT_UPDATE_URL 1.70 + }, { 1.71 + description: "update with 'showURL showNotification' for actions", 1.72 + actions: "showURL showNotification", 1.73 + prefURL: DEFAULT_PREF_URL 1.74 + }, { 1.75 + description: "update with 'showNotification showURL' for actions and " + 1.76 + "openURL", 1.77 + actions: "showNotification showURL", 1.78 + openURL: DEFAULT_UPDATE_URL 1.79 + }, { 1.80 + description: "update with 'showAlert showURL showNotification' for actions", 1.81 + actions: "showAlert showURL showNotification", 1.82 + prefURL: DEFAULT_PREF_URL 1.83 + }, { 1.84 + description: "update with 'showNotification showURL showAlert' for " + 1.85 + "actions and openURL", 1.86 + actions: "showNotification showURL showAlert", 1.87 + openURL: DEFAULT_UPDATE_URL 1.88 + }, { 1.89 + description: "update with 'showAlert' for actions", 1.90 + actions: "showAlert" 1.91 + }, { 1.92 + description: "update with 'showAlert showNotification' for actions", 1.93 + actions: "showAlert showNotification" 1.94 + }, { 1.95 + description: "update with 'showNotification' for actions", 1.96 + actions: "showNotification" 1.97 + }, { 1.98 + description: "update with 'showNotification showAlert' for actions", 1.99 + actions: "showNotification showAlert" 1.100 + }, { 1.101 + description: "update with 'silent' for actions", 1.102 + actions: "silent" 1.103 + }, { 1.104 + description: "update with 'silent showURL showAlert showNotification' " + 1.105 + "for actions and openURL", 1.106 + actions: "silent showURL showAlert showNotification" 1.107 + } 1.108 +]; 1.109 + 1.110 +var gOriginalMStone; 1.111 +var gOriginalOverrideURL; 1.112 + 1.113 +this.__defineGetter__("gBG", function() { 1.114 + delete this.gBG; 1.115 + return this.gBG = Cc["@mozilla.org/browser/browserglue;1"]. 1.116 + getService(Ci.nsIBrowserGlue). 1.117 + QueryInterface(Ci.nsIObserver); 1.118 +}); 1.119 + 1.120 +function test() 1.121 +{ 1.122 + waitForExplicitFinish(); 1.123 + 1.124 + // Reset the startup page pref since it may have been set by other tests 1.125 + // and we will assume it is default. 1.126 + Services.prefs.clearUserPref('browser.startup.page'); 1.127 + 1.128 + if (gPrefService.prefHasUserValue(PREF_MSTONE)) { 1.129 + gOriginalMStone = gPrefService.getCharPref(PREF_MSTONE); 1.130 + } 1.131 + 1.132 + if (gPrefService.prefHasUserValue(PREF_OVERRIDE_URL)) { 1.133 + gOriginalOverrideURL = gPrefService.getCharPref(PREF_OVERRIDE_URL); 1.134 + } 1.135 + 1.136 + testDefaultArgs(); 1.137 +} 1.138 + 1.139 +var gWindowCatcher = { 1.140 + windowsOpen: 0, 1.141 + finishCalled: false, 1.142 + start: function() { 1.143 + Services.ww.registerNotification(this); 1.144 + }, 1.145 + 1.146 + finish: function(aFunc) { 1.147 + Services.ww.unregisterNotification(this); 1.148 + this.finishFunc = aFunc; 1.149 + if (this.windowsOpen > 0) 1.150 + return; 1.151 + 1.152 + this.finishFunc(); 1.153 + }, 1.154 + 1.155 + closeWindow: function (win) { 1.156 + info("window catcher closing window: " + win.document.documentURI); 1.157 + win.close(); 1.158 + this.windowsOpen--; 1.159 + if (this.finishFunc) { 1.160 + this.finish(this.finishFunc); 1.161 + } 1.162 + }, 1.163 + 1.164 + windowLoad: function (win) { 1.165 + executeSoon(this.closeWindow.bind(this, win)); 1.166 + }, 1.167 + 1.168 + observe: function(subject, topic, data) { 1.169 + if (topic != "domwindowopened") 1.170 + return; 1.171 + 1.172 + this.windowsOpen++; 1.173 + let win = subject.QueryInterface(Ci.nsIDOMWindow); 1.174 + info("window catcher caught window opening: " + win.document.documentURI); 1.175 + win.addEventListener("load", function () { 1.176 + win.removeEventListener("load", arguments.callee, false); 1.177 + gWindowCatcher.windowLoad(win); 1.178 + }, false); 1.179 + } 1.180 +}; 1.181 + 1.182 +function finish_test() 1.183 +{ 1.184 + // Reset browser.startup.homepage_override.mstone to the original value or 1.185 + // clear it if it didn't exist. 1.186 + if (gOriginalMStone) { 1.187 + gPrefService.setCharPref(PREF_MSTONE, gOriginalMStone); 1.188 + } else if (gPrefService.prefHasUserValue(PREF_MSTONE)) { 1.189 + gPrefService.clearUserPref(PREF_MSTONE); 1.190 + } 1.191 + 1.192 + // Reset startup.homepage_override_url to the original value or clear it if 1.193 + // it didn't exist. 1.194 + if (gOriginalOverrideURL) { 1.195 + gPrefService.setCharPref(PREF_OVERRIDE_URL, gOriginalOverrideURL); 1.196 + } else if (gPrefService.prefHasUserValue(PREF_OVERRIDE_URL)) { 1.197 + gPrefService.clearUserPref(PREF_OVERRIDE_URL); 1.198 + } 1.199 + 1.200 + writeUpdatesToXMLFile(XML_EMPTY); 1.201 + reloadUpdateManagerData(); 1.202 + 1.203 + finish(); 1.204 +} 1.205 + 1.206 +// Test the defaultArgs returned by nsBrowserContentHandler after an update 1.207 +function testDefaultArgs() 1.208 +{ 1.209 + // Clear any pre-existing override in defaultArgs that are hanging around. 1.210 + // This will also set the browser.startup.homepage_override.mstone preference 1.211 + // if it isn't already set. 1.212 + Cc["@mozilla.org/browser/clh;1"].getService(Ci.nsIBrowserHandler).defaultArgs; 1.213 + 1.214 + let originalMstone = gPrefService.getCharPref(PREF_MSTONE); 1.215 + 1.216 + gPrefService.setCharPref(PREF_OVERRIDE_URL, DEFAULT_PREF_URL); 1.217 + 1.218 + writeUpdatesToXMLFile(XML_EMPTY); 1.219 + reloadUpdateManagerData(); 1.220 + 1.221 + for (let i = 0; i < BCH_TESTS.length; i++) { 1.222 + let test = BCH_TESTS[i]; 1.223 + ok(true, "Test nsBrowserContentHandler " + (i + 1) + ": " + test.description); 1.224 + 1.225 + if (test.actions) { 1.226 + let actionsXML = " actions=\"" + test.actions + "\""; 1.227 + if (test.openURL) { 1.228 + actionsXML += " openURL=\"" + test.openURL + "\""; 1.229 + } 1.230 + writeUpdatesToXMLFile(XML_PREFIX + actionsXML + XML_SUFFIX); 1.231 + } else { 1.232 + writeUpdatesToXMLFile(XML_EMPTY); 1.233 + } 1.234 + 1.235 + reloadUpdateManagerData(); 1.236 + 1.237 + let noOverrideArgs = Cc["@mozilla.org/browser/clh;1"]. 1.238 + getService(Ci.nsIBrowserHandler).defaultArgs; 1.239 + 1.240 + let overrideArgs = ""; 1.241 + if (test.prefURL) { 1.242 + overrideArgs = test.prefURL; 1.243 + } else if (test.openURL) { 1.244 + overrideArgs = test.openURL; 1.245 + } 1.246 + 1.247 + if (overrideArgs == "" && noOverrideArgs) { 1.248 + overrideArgs = noOverrideArgs; 1.249 + } else if (noOverrideArgs) { 1.250 + overrideArgs += "|" + noOverrideArgs; 1.251 + } 1.252 + 1.253 + if (test.noMstoneChange === undefined) { 1.254 + gPrefService.setCharPref(PREF_MSTONE, "PreviousMilestone"); 1.255 + } 1.256 + 1.257 + if (test.noPostUpdatePref == undefined) { 1.258 + gPrefService.setBoolPref(PREF_POSTUPDATE, true); 1.259 + } 1.260 + 1.261 + let defaultArgs = Cc["@mozilla.org/browser/clh;1"]. 1.262 + getService(Ci.nsIBrowserHandler).defaultArgs; 1.263 + is(defaultArgs, overrideArgs, "correct value returned by defaultArgs"); 1.264 + 1.265 + if (test.noMstoneChange === undefined || test.noMstoneChange != true) { 1.266 + let newMstone = gPrefService.getCharPref(PREF_MSTONE); 1.267 + is(originalMstone, newMstone, "preference " + PREF_MSTONE + 1.268 + " should have been updated"); 1.269 + } 1.270 + 1.271 + if (gPrefService.prefHasUserValue(PREF_POSTUPDATE)) { 1.272 + gPrefService.clearUserPref(PREF_POSTUPDATE); 1.273 + } 1.274 + } 1.275 + 1.276 + testShowNotification(); 1.277 +} 1.278 + 1.279 +// nsBrowserGlue.js _showUpdateNotification notification tests 1.280 +const BG_NOTIFY_TESTS = [ 1.281 + { 1.282 + description: "'silent showNotification' actions should not display a notification", 1.283 + actions: "silent showNotification" 1.284 + }, { 1.285 + description: "'showNotification' for actions should display a notification", 1.286 + actions: "showNotification" 1.287 + }, { 1.288 + description: "no actions and empty updates.xml", 1.289 + }, { 1.290 + description: "'showAlert' for actions should not display a notification", 1.291 + actions: "showAlert" 1.292 + }, { 1.293 + // This test MUST be the last test in the array to test opening the url 1.294 + // provided by the updates.xml. 1.295 + description: "'showNotification' for actions with custom notification " + 1.296 + "attributes should display a notification", 1.297 + actions: "showNotification", 1.298 + notificationText: "notification text", 1.299 + notificationURL: DEFAULT_UPDATE_URL, 1.300 + notificationButtonLabel: "button label", 1.301 + notificationButtonAccessKey: "b" 1.302 + } 1.303 +]; 1.304 + 1.305 +// Test showing a notification after an update 1.306 +// _showUpdateNotification in nsBrowserGlue.js 1.307 +function testShowNotification() 1.308 +{ 1.309 + let gTestBrowser = gBrowser.selectedBrowser; 1.310 + let notifyBox = gBrowser.getNotificationBox(gTestBrowser); 1.311 + 1.312 + // Catches any windows opened by these tests (e.g. alert windows) and closes 1.313 + // them 1.314 + gWindowCatcher.start(); 1.315 + 1.316 + for (let i = 0; i < BG_NOTIFY_TESTS.length; i++) { 1.317 + let test = BG_NOTIFY_TESTS[i]; 1.318 + ok(true, "Test showNotification " + (i + 1) + ": " + test.description); 1.319 + 1.320 + if (test.actions) { 1.321 + let actionsXML = " actions=\"" + test.actions + "\""; 1.322 + if (test.notificationText) { 1.323 + actionsXML += " notificationText=\"" + test.notificationText + "\""; 1.324 + } 1.325 + if (test.notificationURL) { 1.326 + actionsXML += " notificationURL=\"" + test.notificationURL + "\""; 1.327 + } 1.328 + if (test.notificationButtonLabel) { 1.329 + actionsXML += " notificationButtonLabel=\"" + test.notificationButtonLabel + "\""; 1.330 + } 1.331 + if (test.notificationButtonAccessKey) { 1.332 + actionsXML += " notificationButtonAccessKey=\"" + test.notificationButtonAccessKey + "\""; 1.333 + } 1.334 + writeUpdatesToXMLFile(XML_PREFIX + actionsXML + XML_SUFFIX); 1.335 + } else { 1.336 + writeUpdatesToXMLFile(XML_EMPTY); 1.337 + } 1.338 + 1.339 + reloadUpdateManagerData(); 1.340 + gPrefService.setBoolPref(PREF_POSTUPDATE, true); 1.341 + 1.342 + gBG.observe(null, "browser-glue-test", "post-update-notification"); 1.343 + 1.344 + let updateBox = notifyBox.getNotificationWithValue("post-update-notification"); 1.345 + if (test.actions && test.actions.indexOf("showNotification") != -1 && 1.346 + test.actions.indexOf("silent") == -1) { 1.347 + ok(updateBox, "Update notification box should have been displayed"); 1.348 + if (updateBox) { 1.349 + if (test.notificationText) { 1.350 + is(updateBox.label, test.notificationText, "Update notification box " + 1.351 + "should have the label provided by the update"); 1.352 + } 1.353 + if (test.notificationButtonLabel) { 1.354 + var button = updateBox.getElementsByTagName("button").item(0); 1.355 + is(button.label, test.notificationButtonLabel, "Update notification " + 1.356 + "box button should have the label provided by the update"); 1.357 + if (test.notificationButtonAccessKey) { 1.358 + let accessKey = button.getAttribute("accesskey"); 1.359 + is(accessKey, test.notificationButtonAccessKey, "Update " + 1.360 + "notification box button should have the accesskey " + 1.361 + "provided by the update"); 1.362 + } 1.363 + } 1.364 + // The last test opens an url and verifies the url from the updates.xml 1.365 + // is correct. 1.366 + if (i == (BG_NOTIFY_TESTS.length - 1)) { 1.367 + // Wait for any windows caught by the windowcatcher to close 1.368 + gWindowCatcher.finish(function () { 1.369 + button.click(); 1.370 + gBrowser.selectedBrowser.addEventListener("load", function () { 1.371 + gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true); 1.372 + testNotificationURL(); 1.373 + }, true); 1.374 + }); 1.375 + } else { 1.376 + notifyBox.removeAllNotifications(true); 1.377 + } 1.378 + } else if (i == (BG_NOTIFY_TESTS.length - 1)) { 1.379 + // If updateBox is null the test has already reported errors so bail 1.380 + finish_test(); 1.381 + } 1.382 + } else { 1.383 + ok(!updateBox, "Update notification box should not have been displayed"); 1.384 + } 1.385 + 1.386 + let prefHasUserValue = gPrefService.prefHasUserValue(PREF_POSTUPDATE); 1.387 + is(prefHasUserValue, false, "preference " + PREF_POSTUPDATE + 1.388 + " shouldn't have a user value"); 1.389 + } 1.390 +} 1.391 + 1.392 +// Test opening the url provided by the updates.xml in the last test 1.393 +function testNotificationURL() 1.394 +{ 1.395 + ok(true, "Test testNotificationURL: clicking the notification button " + 1.396 + "opened the url specified by the update"); 1.397 + let href = gBrowser.selectedBrowser.contentWindow.location.href; 1.398 + let expectedURL = BG_NOTIFY_TESTS[BG_NOTIFY_TESTS.length - 1].notificationURL; 1.399 + is(href, expectedURL, "The url opened from the notification should be the " + 1.400 + "url provided by the update"); 1.401 + gBrowser.removeCurrentTab(); 1.402 + window.focus(); 1.403 + finish_test(); 1.404 +} 1.405 + 1.406 +/* Reloads the update metadata from disk */ 1.407 +function reloadUpdateManagerData() 1.408 +{ 1.409 + Cc["@mozilla.org/updates/update-manager;1"].getService(Ci.nsIUpdateManager). 1.410 + QueryInterface(Ci.nsIObserver).observe(null, "um-reload-update-data", ""); 1.411 +} 1.412 + 1.413 + 1.414 +function writeUpdatesToXMLFile(aText) 1.415 +{ 1.416 + const PERMS_FILE = 0644; 1.417 + 1.418 + const MODE_WRONLY = 0x02; 1.419 + const MODE_CREATE = 0x08; 1.420 + const MODE_TRUNCATE = 0x20; 1.421 + 1.422 + let file = Cc["@mozilla.org/file/directory_service;1"]. 1.423 + getService(Ci.nsIProperties). 1.424 + get("UpdRootD", Ci.nsIFile); 1.425 + file.append("updates.xml"); 1.426 + let fos = Cc["@mozilla.org/network/file-output-stream;1"]. 1.427 + createInstance(Ci.nsIFileOutputStream); 1.428 + if (!file.exists()) { 1.429 + file.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); 1.430 + } 1.431 + fos.init(file, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0); 1.432 + fos.write(aText, aText.length); 1.433 + fos.close(); 1.434 +}