1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/mozapps/update/tests/chrome/utils.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1432 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + * http://creativecommons.org/publicdomain/zero/1.0/ 1.6 + */ 1.7 + 1.8 +/** 1.9 + * Test Definition 1.10 + * 1.11 + * Most tests can use an array named TESTS that will perform most if not all of 1.12 + * the necessary checks. Each element in the array must be an object with the 1.13 + * following possible properties. Additional properties besides the ones listed 1.14 + * below can be added as needed. 1.15 + * 1.16 + * overrideCallback (optional) 1.17 + * The function to call for the next test. This is typically called when the 1.18 + * wizard page changes but can also be called for other events by the previous 1.19 + * test. If this property isn't defined then the defailtCallback function will 1.20 + * be called. If this property is defined then all other properties are 1.21 + * optional. 1.22 + * 1.23 + * pageid (required unless overrideCallback is specified) 1.24 + * The expected pageid for the wizard. This property is required unless the 1.25 + * overrideCallback property is defined. 1.26 + * 1.27 + * extraStartFunction (optional) 1.28 + * The function to call at the beginning of the defaultCallback function. If 1.29 + * the function returns true the defaultCallback function will return early 1.30 + * which allows waiting for a specific condition to be evaluated in the 1.31 + * function specified in the extraStartFunction property before continuing 1.32 + * with the test. 1.33 + * 1.34 + * extraCheckFunction (optional) 1.35 + * The function to call to perform extra checks in the defaultCallback 1.36 + * function. 1.37 + * 1.38 + * extraDelayedCheckFunction (optional) 1.39 + * The function to call to perform extra checks in the delayedDefaultCallback 1.40 + * function. 1.41 + * 1.42 + * buttonStates (optional) 1.43 + * A javascript object representing the expected hidden and disabled attribute 1.44 + * values for the buttons of the current wizard page. The values are checked 1.45 + * in the delayedDefaultCallback function. For information about the structure 1.46 + * of this object refer to the getExpectedButtonStates and checkButtonStates 1.47 + * functions. 1.48 + * 1.49 + * buttonClick (optional) 1.50 + * The current wizard page button to click at the end of the 1.51 + * delayedDefaultCallback function. If the buttonClick property is defined 1.52 + * then the extraDelayedFinishFunction property can't be specified due to race 1.53 + * conditions in some of the tests and if both of them are specified the test 1.54 + * will intentionally throw. 1.55 + * 1.56 + * extraDelayedFinishFunction (optional) 1.57 + * The function to call at the end of the delayedDefaultCallback function. 1.58 + * If the extraDelayedFinishFunction property is defined then the buttonClick 1.59 + * property can't be specified due to race conditions in some of the tests and 1.60 + * if both of them are specified the test will intentionally throw. 1.61 + * 1.62 + * ranTest (should not be specified) 1.63 + * When delayedDefaultCallback is called a property named ranTest is added to 1.64 + * the current test so it is possible to verify that each test in the TESTS 1.65 + * array has ran. 1.66 + * 1.67 + * prefHasUserValue (optional) 1.68 + * For comparing the expected value defined by this property with the return 1.69 + * value of prefHasUserValue using gPrefToCheck for the preference name in the 1.70 + * checkPrefHasUserValue function. 1.71 + * 1.72 + * expectedRadioGroupSelectedIndex (optional) 1.73 + * For comparing the expected selectedIndex attribute value of the wizard's 1.74 + * license page radiogroup selectedIndex attribute in the 1.75 + * checkRadioGroupSelectedIndex function. 1.76 + * 1.77 + * expectedRemoteContentState (optional) 1.78 + * For comparing the expected remotecontent state attribute value of the 1.79 + * wizard's billboard and license pages in the checkRemoteContentState and 1.80 + * waitForRemoteContentLoaded functions. 1.81 + * 1.82 + * 1.83 + * Test Add-ons 1.84 + * 1.85 + * All tests include the test add-ons specified in the TEST_ADDONS array and 1.86 + * the only thing that can be configured is whether the noupdate test add-on is 1.87 + * disabled (see below). The add-on names are in the format of typename_X where 1.88 + * X is a number to make the add-on ID unique and typename is one of the values 1.89 + * specified below: 1.90 + * 1.91 + * appdisabled 1.92 + * disabled by the application due to being incompatible with the current 1.93 + * toolkit version. 1.94 + * 1.95 + * compatible 1.96 + * compatible with the current toolkit version and the update's toolkit 1.97 + * version. 1.98 + * 1.99 + * noupdate 1.100 + * the add-on is compatible with the current toolkit version and does not have 1.101 + * an update to make it compatible with the update's toolkit version. Tests 1.102 + * that need to have all add-ons compatible for the application update can 1.103 + * disable this add-on by setting the gDisableNoUpdateAddon variable to true. 1.104 + * 1.105 + * updatecompatibility 1.106 + * the add-on is compatible with the current toolkit version and has a 1.107 + * compatibility update to make it compatible with the update's toolkit 1.108 + * version. 1.109 + * 1.110 + * updateversion 1.111 + * the add-on is compatible with the current toolkit version and has a version 1.112 + * update to make it compatible with the update's toolkit version. 1.113 + * 1.114 + * userdisabled 1.115 + * disabled by the user and compatible with the current toolkit version but 1.116 + * not the update's toolkit version. This add-on will be disabled after its 1.117 + * install completes. 1.118 + */ 1.119 + 1.120 +Components.utils.import("resource://gre/modules/AddonManager.jsm"); 1.121 + 1.122 +// The tests have to use the pageid instead of the pageIndex due to the 1.123 +// app update wizard's access method being random. 1.124 +const PAGEID_DUMMY = "dummy"; // Done 1.125 +const PAGEID_CHECKING = "checking"; // Done 1.126 +const PAGEID_PLUGIN_UPDATES = "pluginupdatesfound"; 1.127 +const PAGEID_NO_UPDATES_FOUND = "noupdatesfound"; // Done 1.128 +const PAGEID_MANUAL_UPDATE = "manualUpdate"; // Tested on license load failure 1.129 +const PAGEID_UNSUPPORTED = "unsupported"; // Done 1.130 +const PAGEID_INCOMPAT_CHECK = "incompatibleCheck"; // Done 1.131 +const PAGEID_FOUND_BASIC = "updatesfoundbasic"; // Done 1.132 +const PAGEID_FOUND_BILLBOARD = "updatesfoundbillboard"; // Done 1.133 +const PAGEID_LICENSE = "license"; // Done 1.134 +const PAGEID_INCOMPAT_LIST = "incompatibleList"; // Done 1.135 +const PAGEID_DOWNLOADING = "downloading"; // Done 1.136 +const PAGEID_ERRORS = "errors"; // Done 1.137 +const PAGEID_ERROR_EXTRA = "errorextra"; // Done 1.138 +const PAGEID_ERROR_PATCHING = "errorpatching"; // Done 1.139 +const PAGEID_FINISHED = "finished"; // Done 1.140 +const PAGEID_FINISHED_BKGRD = "finishedBackground"; // Done 1.141 +const PAGEID_INSTALLED = "installed"; // Done 1.142 + 1.143 +const UPDATE_WINDOW_NAME = "Update:Wizard"; 1.144 + 1.145 +const URL_HOST = "http://example.com"; 1.146 +const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs"; 1.147 +const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data"; 1.148 + 1.149 +const URL_HTTP_UPDATE_XML = URL_HOST + URL_PATH_UPDATE_XML; 1.150 +const URL_HTTPS_UPDATE_XML = "https://example.com" + URL_PATH_UPDATE_XML; 1.151 + 1.152 +const URI_UPDATE_PROMPT_DIALOG = "chrome://mozapps/content/update/updates.xul"; 1.153 + 1.154 +const ADDON_ID_SUFFIX = "@appupdatetest.mozilla.org"; 1.155 +const ADDON_PREP_DIR = "appupdateprep"; 1.156 +// Preference for storing add-ons that are disabled by the tests to prevent them 1.157 +// from interefering with the tests. 1.158 +const PREF_DISABLEDADDONS = "app.update.test.disabledAddons"; 1.159 +const PREF_EM_HOTFIX_ID = "extensions.hotfix.id"; 1.160 +const TEST_ADDONS = [ "appdisabled_1", "appdisabled_2", 1.161 + "compatible_1", "compatible_2", 1.162 + "noupdate_1", "noupdate_2", 1.163 + "updatecompatibility_1", "updatecompatibility_2", 1.164 + "updateversion_1", "updateversion_2", 1.165 + "userdisabled_1", "userdisabled_2", "hotfix" ]; 1.166 + 1.167 +var gURLData = URL_HOST + "/" + REL_PATH_DATA + "/"; 1.168 + 1.169 +var gTestTimeout = 240000; // 4 minutes 1.170 +var gTimeoutTimer; 1.171 + 1.172 +// The number of SimpleTest.executeSoon calls to perform when waiting on an 1.173 +// update window to close before giving up. 1.174 +const CLOSE_WINDOW_TIMEOUT_MAXCOUNT = 10; 1.175 +// Counter for the SimpleTest.executeSoon when waiting on an update window to 1.176 +// close before giving up. 1.177 +var gCloseWindowTimeoutCounter = 0; 1.178 + 1.179 +// The following vars are for restoring previous preference values (if present) 1.180 +// when the test finishes. 1.181 +var gAppUpdateEnabled; // app.update.enabled 1.182 +var gAppUpdateMetroEnabled; // app.update.metro.enabled 1.183 +var gAppUpdateServiceEnabled; // app.update.service.enabled 1.184 +var gAppUpdateStagingEnabled; // app.update.staging.enabled 1.185 +var gAppUpdateURLDefault; // app.update.url (default prefbranch) 1.186 +var gAppUpdateURL; // app.update.url.override 1.187 +var gExtUpdateURL; // extensions.update.url 1.188 + 1.189 +var gTestCounter = -1; 1.190 +var gWin; 1.191 +var gDocElem; 1.192 +var gPrefToCheck; 1.193 +var gDisableNoUpdateAddon = false; 1.194 + 1.195 +// Set to true to log additional information for debugging. To log additional 1.196 +// information for an individual test set DEBUG_AUS_TEST to true in the test's 1.197 +// onload function. 1.198 +var DEBUG_AUS_TEST = true; 1.199 + 1.200 +#include ../shared.js 1.201 + 1.202 +/** 1.203 + * The current test in TESTS array. 1.204 + */ 1.205 +this.__defineGetter__("gTest", function() { 1.206 + return TESTS[gTestCounter]; 1.207 +}); 1.208 + 1.209 +/** 1.210 + * The current test's callback. This will either return the callback defined in 1.211 + * the test's overrideCallback property or defaultCallback if the 1.212 + * overrideCallback property is undefined. 1.213 + */ 1.214 +this.__defineGetter__("gCallback", function() { 1.215 + return gTest.overrideCallback ? gTest.overrideCallback 1.216 + : defaultCallback; 1.217 +}); 1.218 + 1.219 +/** 1.220 + * The remotecontent element for the current page if one exists or null if a 1.221 + * remotecontent element doesn't exist. 1.222 + */ 1.223 +this.__defineGetter__("gRemoteContent", function() { 1.224 + switch (gTest.pageid) { 1.225 + case PAGEID_FOUND_BILLBOARD: 1.226 + return gWin.document.getElementById("updateMoreInfoContent"); 1.227 + case PAGEID_LICENSE: 1.228 + return gWin.document.getElementById("licenseContent"); 1.229 + } 1.230 + return null; 1.231 +}); 1.232 + 1.233 +/** 1.234 + * The state for the remotecontent element if one exists or null if a 1.235 + * remotecontent element doesn't exist. 1.236 + */ 1.237 +this.__defineGetter__("gRemoteContentState", function() { 1.238 + if (gRemoteContent) { 1.239 + return gRemoteContent.getAttribute("state"); 1.240 + } 1.241 + return null; 1.242 +}); 1.243 + 1.244 +/** 1.245 + * The radiogroup for the license page. 1.246 + */ 1.247 +this.__defineGetter__("gAcceptDeclineLicense", function() { 1.248 + return gWin.document.getElementById("acceptDeclineLicense"); 1.249 +}); 1.250 + 1.251 +/** 1.252 + * The listbox for the incompatibleList page. 1.253 + */ 1.254 +this.__defineGetter__("gIncompatibleListbox", function() { 1.255 + return gWin.document.getElementById("incompatibleListbox"); 1.256 +}); 1.257 + 1.258 +/** 1.259 + * Default test run function that can be used by most tests. This function uses 1.260 + * protective measures to prevent the test from failing provided by 1.261 + * |runTestDefaultWaitForWindowClosed| helper functions to prevent failure due 1.262 + * to a previous test failure. 1.263 + */ 1.264 +function runTestDefault() { 1.265 + debugDump("entering"); 1.266 + 1.267 + if (!("@mozilla.org/zipwriter;1" in AUS_Cc)) { 1.268 + ok(false, "nsIZipWriter is required to run these tests"); 1.269 + return; 1.270 + } 1.271 + 1.272 + SimpleTest.waitForExplicitFinish(); 1.273 + 1.274 + runTestDefaultWaitForWindowClosed(); 1.275 +} 1.276 + 1.277 +/** 1.278 + * If an update window is found SimpleTest.executeSoon can callback before the 1.279 + * update window is fully closed especially with debug builds. If an update 1.280 + * window is found this function will call itself using SimpleTest.executeSoon 1.281 + * up to the amount declared in CLOSE_WINDOW_TIMEOUT_MAXCOUNT until the update 1.282 + * window has closed before continuing the test. 1.283 + */ 1.284 +function runTestDefaultWaitForWindowClosed() { 1.285 + gCloseWindowTimeoutCounter++; 1.286 + if (gCloseWindowTimeoutCounter > CLOSE_WINDOW_TIMEOUT_MAXCOUNT) { 1.287 + try { 1.288 + finishTest(); 1.289 + } 1.290 + catch (e) { 1.291 + finishTestDefault(); 1.292 + } 1.293 + return; 1.294 + } 1.295 + 1.296 + // The update window should not be open at this time. If it is the call to 1.297 + // |closeUpdateWindow| will close it and cause the test to fail. 1.298 + if (closeUpdateWindow()) { 1.299 + SimpleTest.executeSoon(runTestDefaultWaitForWindowClosed); 1.300 + } 1.301 + else { 1.302 + Services.ww.registerNotification(gWindowObserver); 1.303 + 1.304 + gCloseWindowTimeoutCounter = 0; 1.305 + 1.306 + setupFiles(); 1.307 + setupPrefs(); 1.308 + removeUpdateDirsAndFiles(); 1.309 + reloadUpdateManagerData(); 1.310 + setupAddons(runTest); 1.311 + } 1.312 +} 1.313 + 1.314 +/** 1.315 + * Default test finish function that can be used by most tests. This function 1.316 + * uses protective measures to prevent the next test from failing provided by 1.317 + * |finishTestDefaultWaitForWindowClosed| helper functions to prevent failure 1.318 + * due to an update window being left open. 1.319 + */ 1.320 +function finishTestDefault() { 1.321 + debugDump("entering"); 1.322 + if (gTimeoutTimer) { 1.323 + gTimeoutTimer.cancel(); 1.324 + gTimeoutTimer = null; 1.325 + } 1.326 + 1.327 + if (gChannel) { 1.328 + debugDump("channel = " + gChannel); 1.329 + gChannel = null; 1.330 + gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer); 1.331 + } 1.332 + 1.333 + verifyTestsRan(); 1.334 + 1.335 + resetPrefs(); 1.336 + resetFiles(); 1.337 + removeUpdateDirsAndFiles(); 1.338 + reloadUpdateManagerData(); 1.339 + 1.340 + Services.ww.unregisterNotification(gWindowObserver); 1.341 + if (gDocElem) { 1.342 + gDocElem.removeEventListener("pageshow", onPageShowDefault, false); 1.343 + } 1.344 + 1.345 + finishTestDefaultWaitForWindowClosed(); 1.346 +} 1.347 + 1.348 +/** 1.349 + * nsITimerCallback for the timeout timer to cleanly finish a test if the Update 1.350 + * Window doesn't close for a test. This allows the next test to run properly if 1.351 + * a previous test fails. 1.352 + * 1.353 + * @param aTimer 1.354 + * The nsITimer that fired. 1.355 + */ 1.356 +function finishTestTimeout(aTimer) { 1.357 + ok(false, "Test timed out. Maximum time allowed is " + (gTestTimeout / 1000) + 1.358 + " seconds"); 1.359 + 1.360 + try { 1.361 + finishTest(); 1.362 + } 1.363 + catch (e) { 1.364 + finishTestDefault(); 1.365 + } 1.366 +} 1.367 + 1.368 +/** 1.369 + * If an update window is found SimpleTest.executeSoon can callback before the 1.370 + * update window is fully closed especially with debug builds. If an update 1.371 + * window is found this function will call itself using SimpleTest.executeSoon 1.372 + * up to the amount declared in CLOSE_WINDOW_TIMEOUT_MAXCOUNT until the update 1.373 + * window has closed before finishing the test. 1.374 + */ 1.375 +function finishTestDefaultWaitForWindowClosed() { 1.376 + gCloseWindowTimeoutCounter++; 1.377 + if (gCloseWindowTimeoutCounter > CLOSE_WINDOW_TIMEOUT_MAXCOUNT) { 1.378 + SimpleTest.finish(); 1.379 + return; 1.380 + } 1.381 + 1.382 + // The update window should not be open at this time. If it is the call to 1.383 + // |closeUpdateWindow| will close it and cause the test to fail. 1.384 + if (closeUpdateWindow()) { 1.385 + SimpleTest.executeSoon(finishTestDefaultWaitForWindowClosed); 1.386 + } 1.387 + else { 1.388 + SimpleTest.finish(); 1.389 + } 1.390 +} 1.391 + 1.392 +/** 1.393 + * Default callback for the wizard's documentElement pageshow listener. This 1.394 + * will return early for event's where the originalTarget's nodeName is not 1.395 + * wizardpage. 1.396 + */ 1.397 +function onPageShowDefault(aEvent) { 1.398 + if (!gTimeoutTimer) { 1.399 + debugDump("gTimeoutTimer is null... returning early"); 1.400 + return; 1.401 + } 1.402 + 1.403 + // Return early if the event's original target isn't for a wizardpage element. 1.404 + // This check is necessary due to the remotecontent element firing pageshow. 1.405 + if (aEvent.originalTarget.nodeName != "wizardpage") { 1.406 + debugDump("only handles events with an originalTarget nodeName of " + 1.407 + "|wizardpage|. aEvent.originalTarget.nodeName = " + 1.408 + aEvent.originalTarget.nodeName + "... returning early"); 1.409 + return; 1.410 + } 1.411 + 1.412 + gTestCounter++; 1.413 + gCallback(aEvent); 1.414 +} 1.415 + 1.416 +/** 1.417 + * Default callback that can be used by most tests. 1.418 + */ 1.419 +function defaultCallback(aEvent) { 1.420 + if (!gTimeoutTimer) { 1.421 + debugDump("gTimeoutTimer is null... returning early"); 1.422 + return; 1.423 + } 1.424 + 1.425 + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid + 1.426 + ", aEvent.originalTarget.nodeName: " + 1.427 + aEvent.originalTarget.nodeName); 1.428 + 1.429 + if (gTest && gTest.extraStartFunction) { 1.430 + debugDump("calling extraStartFunction " + gTest.extraStartFunction.name); 1.431 + if (gTest.extraStartFunction(aEvent)) { 1.432 + debugDump("extraStartFunction early return"); 1.433 + return; 1.434 + } 1.435 + } 1.436 + 1.437 + is(gDocElem.currentPage.pageid, gTest.pageid, 1.438 + "Checking currentPage.pageid equals " + gTest.pageid + " in pageshow"); 1.439 + 1.440 + // Perform extra checks if specified by the test 1.441 + if (gTest.extraCheckFunction) { 1.442 + debugDump("calling extraCheckFunction " + gTest.extraCheckFunction.name); 1.443 + gTest.extraCheckFunction(); 1.444 + } 1.445 + 1.446 + // The wizard page buttons' disabled and hidden attributes are set after the 1.447 + // pageshow event so use executeSoon to allow them to be set so their disabled 1.448 + // and hidden attribute values can be checked. 1.449 + SimpleTest.executeSoon(delayedDefaultCallback); 1.450 +} 1.451 + 1.452 +/** 1.453 + * Delayed default callback called using executeSoon in defaultCallback which 1.454 + * allows the wizard page buttons' disabled and hidden attributes to be set 1.455 + * before checking their values. 1.456 + */ 1.457 +function delayedDefaultCallback() { 1.458 + if (!gTimeoutTimer) { 1.459 + debugDump("gTimeoutTimer is null... returning early"); 1.460 + return; 1.461 + } 1.462 + 1.463 + if (!gTest) { 1.464 + debugDump("gTest is null... returning early"); 1.465 + return; 1.466 + } 1.467 + 1.468 + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid); 1.469 + 1.470 + // Verify the pageid hasn't changed after executeSoon was called. 1.471 + is(gDocElem.currentPage.pageid, gTest.pageid, 1.472 + "Checking currentPage.pageid equals " + gTest.pageid + " after " + 1.473 + "executeSoon"); 1.474 + 1.475 + checkButtonStates(); 1.476 + 1.477 + // Perform delayed extra checks if specified by the test 1.478 + if (gTest.extraDelayedCheckFunction) { 1.479 + debugDump("calling extraDelayedCheckFunction " + 1.480 + gTest.extraDelayedCheckFunction.name); 1.481 + gTest.extraDelayedCheckFunction(); 1.482 + } 1.483 + 1.484 + // Used to verify that this test has been performed 1.485 + gTest.ranTest = true; 1.486 + 1.487 + if (gTest.buttonClick) { 1.488 + debugDump("clicking " + gTest.buttonClick + " button"); 1.489 + if(gTest.extraDelayedFinishFunction) { 1.490 + throw("Tests cannot have a buttonClick and an extraDelayedFinishFunction property"); 1.491 + } 1.492 + gDocElem.getButton(gTest.buttonClick).click(); 1.493 + } 1.494 + else if (gTest.extraDelayedFinishFunction) { 1.495 + debugDump("calling extraDelayedFinishFunction " + 1.496 + gTest.extraDelayedFinishFunction.name); 1.497 + gTest.extraDelayedFinishFunction(); 1.498 + } 1.499 +} 1.500 + 1.501 +/** 1.502 + * Checks the wizard page buttons' disabled and hidden attributes values are 1.503 + * correct. If an expected button id is not specified then the expected disabled 1.504 + * and hidden attribute value is true. 1.505 + */ 1.506 +function checkButtonStates() { 1.507 + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid); 1.508 + 1.509 + const buttonNames = ["extra1", "extra2", "back", "next", "finish", "cancel"]; 1.510 + let buttonStates = getExpectedButtonStates(); 1.511 + buttonNames.forEach(function(aButtonName) { 1.512 + let button = gDocElem.getButton(aButtonName); 1.513 + let hasHidden = aButtonName in buttonStates && 1.514 + "hidden" in buttonStates[aButtonName]; 1.515 + let hidden = hasHidden ? buttonStates[aButtonName].hidden : true; 1.516 + let hasDisabled = aButtonName in buttonStates && 1.517 + "disabled" in buttonStates[aButtonName]; 1.518 + let disabled = hasDisabled ? buttonStates[aButtonName].disabled : true; 1.519 + is(button.hidden, hidden, "Checking " + aButtonName + " button " + 1.520 + "hidden attribute value equals " + (hidden ? "true" : "false")); 1.521 + is(button.disabled, disabled, "Checking " + aButtonName + " button " + 1.522 + "disabled attribute value equals " + (disabled ? "true" : "false")); 1.523 + }); 1.524 +} 1.525 + 1.526 +/** 1.527 + * Returns the expected disabled and hidden attribute values for the buttons of 1.528 + * the current wizard page. 1.529 + */ 1.530 +function getExpectedButtonStates() { 1.531 + // Allow individual tests to override the expected button states. 1.532 + if (gTest.buttonStates) { 1.533 + return gTest.buttonStates; 1.534 + } 1.535 + 1.536 + switch (gTest.pageid) { 1.537 + case PAGEID_CHECKING: 1.538 + case PAGEID_INCOMPAT_CHECK: 1.539 + return { cancel: { disabled: false, hidden: false } }; 1.540 + case PAGEID_FOUND_BASIC: 1.541 + case PAGEID_FOUND_BILLBOARD: 1.542 + if (gTest.neverButton) { 1.543 + return { extra1: { disabled: false, hidden: false }, 1.544 + extra2: { disabled: false, hidden: false }, 1.545 + next : { disabled: false, hidden: false } } 1.546 + } 1.547 + return { extra1: { disabled: false, hidden: false }, 1.548 + next : { disabled: false, hidden: false } }; 1.549 + case PAGEID_LICENSE: 1.550 + if (gRemoteContentState != "loaded" || 1.551 + gAcceptDeclineLicense.selectedIndex != 0) { 1.552 + return { extra1: { disabled: false, hidden: false }, 1.553 + next : { disabled: true, hidden: false } }; 1.554 + } 1.555 + return { extra1: { disabled: false, hidden: false }, 1.556 + next : { disabled: false, hidden: false } }; 1.557 + case PAGEID_INCOMPAT_LIST: 1.558 + return { extra1: { disabled: false, hidden: false }, 1.559 + next : { disabled: false, hidden: false } }; 1.560 + case PAGEID_DOWNLOADING: 1.561 + return { extra1: { disabled: false, hidden: false } }; 1.562 + case PAGEID_NO_UPDATES_FOUND: 1.563 + case PAGEID_MANUAL_UPDATE: 1.564 + case PAGEID_UNSUPPORTED: 1.565 + case PAGEID_ERRORS: 1.566 + case PAGEID_ERROR_EXTRA: 1.567 + case PAGEID_INSTALLED: 1.568 + return { finish: { disabled: false, hidden: false } }; 1.569 + case PAGEID_ERROR_PATCHING: 1.570 + return { next : { disabled: false, hidden: false } }; 1.571 + case PAGEID_FINISHED: 1.572 + case PAGEID_FINISHED_BKGRD: 1.573 + return { extra1: { disabled: false, hidden: false }, 1.574 + finish: { disabled: false, hidden: false } }; 1.575 + } 1.576 + return null; 1.577 +} 1.578 + 1.579 +/** 1.580 + * Adds a load event listener to the current remotecontent element. 1.581 + */ 1.582 +function addRemoteContentLoadListener() { 1.583 + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid); 1.584 + 1.585 + gRemoteContent.addEventListener("load", remoteContentLoadListener, false); 1.586 +} 1.587 + 1.588 +/** 1.589 + * The nsIDOMEventListener for a remotecontent load event. 1.590 + */ 1.591 +function remoteContentLoadListener(aEvent) { 1.592 + // Return early if the event's original target's nodeName isn't remotecontent. 1.593 + if (aEvent.originalTarget.nodeName != "remotecontent") { 1.594 + debugDump("only handles events with an originalTarget nodeName of " + 1.595 + "|remotecontent|. aEvent.originalTarget.nodeName = " + 1.596 + aEvent.originalTarget.nodeName); 1.597 + return; 1.598 + } 1.599 + 1.600 + gTestCounter++; 1.601 + gCallback(aEvent); 1.602 +} 1.603 + 1.604 +/** 1.605 + * Waits until a remotecontent element to finish loading which is determined 1.606 + * by the current test's expectedRemoteContentState property and then removes 1.607 + * the event listener. 1.608 + * 1.609 + * Note: tests that use this function should not test the state of the 1.610 + * remotecontent since this will check the expected state. 1.611 + * 1.612 + * @return false if the remotecontent has loaded and its state is the state 1.613 + * specified in the current test's expectedRemoteContentState 1.614 + * property... otherwise true. 1.615 + */ 1.616 +function waitForRemoteContentLoaded(aEvent) { 1.617 + // Return early until the remotecontent has loaded with the state that is 1.618 + // expected or isn't the event's originalTarget. 1.619 + if (gRemoteContentState != gTest.expectedRemoteContentState || 1.620 + aEvent.originalTarget != gRemoteContent) { 1.621 + debugDump("returning early\n" + 1.622 + "gRemoteContentState: " + gRemoteContentState + "\n" + 1.623 + "expectedRemoteContentState: " + 1.624 + gTest.expectedRemoteContentState + "\n" + 1.625 + "aEvent.originalTarget.nodeName: " + 1.626 + aEvent.originalTarget.nodeName); 1.627 + return true; 1.628 + } 1.629 + 1.630 + gRemoteContent.removeEventListener("load", remoteContentLoadListener, false); 1.631 + return false; 1.632 +} 1.633 + 1.634 +/** 1.635 + * Compares the value of the remotecontent state attribute with the value 1.636 + * specified in the test's expectedRemoteContentState property. 1.637 + */ 1.638 +function checkRemoteContentState() { 1.639 + is(gRemoteContentState, gTest.expectedRemoteContentState, "Checking remote " + 1.640 + "content state equals " + gTest.expectedRemoteContentState + " - pageid " + 1.641 + gTest.pageid); 1.642 +} 1.643 + 1.644 +/** 1.645 + * Adds a select event listener to the license radiogroup element and clicks 1.646 + * the radio element specified in the current test's radioClick property. 1.647 + */ 1.648 +function addRadioGroupSelectListenerAndClick() { 1.649 + debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid); 1.650 + 1.651 + gAcceptDeclineLicense.addEventListener("select", radioGroupSelectListener, 1.652 + false); 1.653 + gWin.document.getElementById(gTest.radioClick).click(); 1.654 +} 1.655 + 1.656 +/** 1.657 + * The nsIDOMEventListener for the license radiogroup select event. 1.658 + */ 1.659 +function radioGroupSelectListener(aEvent) { 1.660 + // Return early if the event's original target's nodeName isn't radiogroup. 1.661 + if (aEvent.originalTarget.nodeName != "radiogroup") { 1.662 + debugDump("only handles events with an originalTarget nodeName of " + 1.663 + "|radiogroup|. aEvent.originalTarget.nodeName = " + 1.664 + aEvent.originalTarget.nodeName); 1.665 + return; 1.666 + } 1.667 + 1.668 + gAcceptDeclineLicense.removeEventListener("select", radioGroupSelectListener, 1.669 + false); 1.670 + gTestCounter++; 1.671 + gCallback(aEvent); 1.672 +} 1.673 + 1.674 +/** 1.675 + * Compares the value of the License radiogroup's selectedIndex attribute with 1.676 + * the value specified in the test's expectedRadioGroupSelectedIndex property. 1.677 + */ 1.678 +function checkRadioGroupSelectedIndex() { 1.679 + is(gAcceptDeclineLicense.selectedIndex, gTest.expectedRadioGroupSelectedIndex, 1.680 + "Checking license radiogroup selectedIndex equals " + 1.681 + gTest.expectedRadioGroupSelectedIndex); 1.682 +} 1.683 + 1.684 +/** 1.685 + * Checks that only incompatible add-ons (e.g. noupdate_X add-ons) that don't 1.686 + * have an update are listed in the add-ons incompatible list. 1.687 + */ 1.688 +function checkIncompatbleList() { 1.689 + for (let i = 0; i < gIncompatibleListbox.itemCount; i++) { 1.690 + let label = gIncompatibleListbox.getItemAtIndex(i).label; 1.691 + // Use indexOf since locales can change the text displayed 1.692 + ok(label.indexOf("noupdate") != -1, "Checking that only incompatible " + 1.693 + "add-ons that don't have an update are listed in the incompatible list"); 1.694 + } 1.695 +} 1.696 + 1.697 +/** 1.698 + * Compares the return value of prefHasUserValue for the preference specified in 1.699 + * gPrefToCheck with the value passed in the aPrefHasValue parameter or the 1.700 + * value specified in the current test's prefHasUserValue property if 1.701 + * aPrefHasValue is undefined. 1.702 + * 1.703 + * @param aPrefHasValue (optional) 1.704 + * The expected value returned from prefHasUserValue for the preference 1.705 + * specified in gPrefToCheck. If aPrefHasValue is undefined the value 1.706 + * of the current test's prefHasUserValue property will be used. 1.707 + */ 1.708 +function checkPrefHasUserValue(aPrefHasValue) { 1.709 + let prefHasUserValue = aPrefHasValue === undefined ? gTest.prefHasUserValue 1.710 + : aPrefHasValue; 1.711 + is(Services.prefs.prefHasUserValue(gPrefToCheck), prefHasUserValue, 1.712 + "Checking prefHasUserValue for preference " + gPrefToCheck + " equals " + 1.713 + (prefHasUserValue ? "true" : "false")); 1.714 +} 1.715 + 1.716 +/** 1.717 + * Checks whether the link is hidden (general background update check error or 1.718 + * a certificate attribute check error with an update) or not (certificate 1.719 + * attribute check error without an update) on the errorextra page and that the 1.720 + * app.update.cert.errors and app.update.backgroundErrors preferences do not 1.721 + & have a user value. 1.722 + * 1.723 + * @param aShouldBeHidden (optional) 1.724 + * The expected value for the label's hidden attribute for the link. If 1.725 + * aShouldBeHidden is undefined the value of the current test's 1.726 + * shouldBeHidden property will be used. 1.727 + */ 1.728 +function checkErrorExtraPage(aShouldBeHidden) { 1.729 + let shouldBeHidden = aShouldBeHidden === undefined ? gTest.shouldBeHidden 1.730 + : aShouldBeHidden; 1.731 + is(gWin.document.getElementById("errorExtraLinkLabel").hidden, shouldBeHidden, 1.732 + "Checking errorExtraLinkLabel hidden attribute equals " + 1.733 + (shouldBeHidden ? "true" : "false")); 1.734 + 1.735 + is(gWin.document.getElementById(gTest.displayedTextElem).hidden, false, 1.736 + "Checking " + gTest.displayedTextElem + " should not be hidden"); 1.737 + 1.738 + ok(!Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_ERRORS), 1.739 + "Preference " + PREF_APP_UPDATE_CERT_ERRORS + " should not have a " + 1.740 + "user value"); 1.741 + 1.742 + ok(!Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS), 1.743 + "Preference " + PREF_APP_UPDATE_BACKGROUNDERRORS + " should not have a " + 1.744 + "user value"); 1.745 +} 1.746 + 1.747 +/** 1.748 + * Gets the update version info for the update url parameters to send to 1.749 + * update.sjs. 1.750 + * 1.751 + * @param aAppVersion (optional) 1.752 + * The application version for the update snippet. If not specified the 1.753 + * current application version will be used. 1.754 + * @param aPlatformVersion (optional) 1.755 + * The platform version for the update snippet. If not specified the 1.756 + * current platform version will be used. 1.757 + * @return The url parameters for the application and platform version to send 1.758 + * to update.sjs. 1.759 + */ 1.760 +function getVersionParams(aAppVersion, aPlatformVersion) { 1.761 + let appInfo = Services.appinfo; 1.762 + return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version) + 1.763 + "&platformVersion=" + (aPlatformVersion ? aPlatformVersion 1.764 + : appInfo.platformVersion); 1.765 +} 1.766 + 1.767 +/** 1.768 + * Gets an application version that is greater than the current application 1.769 + * version. The version is created by taking the first sequence from the current 1.770 + * application version and adding 1 to it. 1.771 + * 1.772 + * @return A version string greater than the current application version string. 1.773 + */ 1.774 +function getNewerAppVersion() { 1.775 + let appVersion = Services.appinfo.version.split(".")[0]; 1.776 + appVersion++; 1.777 + return appVersion; 1.778 +} 1.779 + 1.780 +/** 1.781 + * Gets a platform version that is greater than the current platform version. 1.782 + * The version is created by taking the first sequence from the current platform 1.783 + * version and adding 1 to it. 1.784 + * 1.785 + * @return A version string greater than the current platform version string. 1.786 + */ 1.787 +function getNewerPlatformVersion() { 1.788 + let platformVersion = Services.appinfo.platformVersion.split(".")[0]; 1.789 + platformVersion++; 1.790 + return platformVersion; 1.791 +} 1.792 + 1.793 +/** 1.794 + * Verifies that all tests ran. 1.795 + */ 1.796 +function verifyTestsRan() { 1.797 + debugDump("entering"); 1.798 + 1.799 + // Return early if there are no tests defined. 1.800 + if (!TESTS) { 1.801 + return; 1.802 + } 1.803 + 1.804 + gTestCounter = -1; 1.805 + for (let i = 0; i < TESTS.length; ++i) { 1.806 + gTestCounter++; 1.807 + let test = TESTS[i]; 1.808 + let msg = "Checking if TESTS[" + i + "] test was performed... " + 1.809 + "callback function name = " + gCallback.name + ", " + 1.810 + "pageid = " + test.pageid; 1.811 + ok(test.ranTest, msg); 1.812 + } 1.813 +} 1.814 + 1.815 +/** 1.816 + * Creates a backup of files the tests need to modify so they can be restored to 1.817 + * the original file when the test has finished and then modifies the files. 1.818 + */ 1.819 +function setupFiles() { 1.820 + // Backup the updater-settings.ini file if it exists by moving it. 1.821 + let baseAppDir = getAppBaseDir(); 1.822 + let updateSettingsIni = baseAppDir.clone(); 1.823 + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); 1.824 + if (updateSettingsIni.exists()) { 1.825 + updateSettingsIni.moveTo(baseAppDir, FILE_UPDATE_SETTINGS_INI_BAK); 1.826 + } 1.827 + updateSettingsIni = baseAppDir.clone(); 1.828 + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI); 1.829 + writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS); 1.830 +} 1.831 + 1.832 +/** 1.833 + * Sets the most common preferences used by tests to values used by the majority 1.834 + * of the tests and when necessary saves the preference's original values if 1.835 + * present so they can be set back to the original values when the test has 1.836 + * finished. 1.837 + */ 1.838 +function setupPrefs() { 1.839 + if (DEBUG_AUS_TEST) { 1.840 + Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); 1.841 + } 1.842 + 1.843 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { 1.844 + gAppUpdateURL = Services.prefs.getCharPref(PREF_APP_UPDATE_URL_OVERRIDE); 1.845 + } 1.846 + 1.847 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) { 1.848 + gAppUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED); 1.849 + } 1.850 + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); 1.851 + 1.852 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_METRO_ENABLED)) { 1.853 + gAppUpdateMetroEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_METRO_ENABLED); 1.854 + } 1.855 + Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true); 1.856 + 1.857 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) { 1.858 + gAppUpdateServiceEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED); 1.859 + } 1.860 + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false); 1.861 + 1.862 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) { 1.863 + gAppUpdateStagingEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED); 1.864 + } 1.865 + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false); 1.866 + 1.867 + if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) { 1.868 + gExtUpdateURL = Services.prefs.getCharPref(PREF_EXTENSIONS_UPDATE_URL); 1.869 + } 1.870 + let extUpdateUrl = URL_HTTP_UPDATE_XML + "?addonID=%ITEM_ID%" + 1.871 + "&platformVersion=" + getNewerPlatformVersion(); 1.872 + Services.prefs.setCharPref(PREF_EXTENSIONS_UPDATE_URL, extUpdateUrl); 1.873 + 1.874 + Services.prefs.setIntPref(PREF_APP_UPDATE_IDLETIME, 0); 1.875 + Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 0); 1.876 + Services.prefs.setBoolPref(PREF_EXTENSIONS_STRICT_COMPAT, true); 1.877 + Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, "hotfix" + ADDON_ID_SUFFIX); 1.878 +} 1.879 + 1.880 +/** 1.881 + * Restores files that were backed up for the tests and general file cleanup. 1.882 + */ 1.883 +function resetFiles() { 1.884 + // Restore the backed up updater-settings.ini if it exists. 1.885 + let baseAppDir = getAppBaseDir(); 1.886 + let updateSettingsIni = baseAppDir.clone(); 1.887 + updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK); 1.888 + if (updateSettingsIni.exists()) { 1.889 + updateSettingsIni.moveTo(baseAppDir, FILE_UPDATE_SETTINGS_INI); 1.890 + } 1.891 + 1.892 + // Not being able to remove the "updated" directory will not adversely affect 1.893 + // subsequent tests so wrap it in a try block and don't test whether its 1.894 + // removal was successful. 1.895 + let updatedDir = getUpdatedDir(); 1.896 + if (updatedDir.exists()) { 1.897 + try { 1.898 + removeDirRecursive(updatedDir); 1.899 + } 1.900 + catch (e) { 1.901 + dump("Unable to remove directory\n" + 1.902 + "path: " + updatedDir.path + "\n" + 1.903 + "Exception: " + e + "\n"); 1.904 + } 1.905 + } 1.906 +} 1.907 + 1.908 +/** 1.909 + * Resets the most common preferences used by tests to their original values. 1.910 + */ 1.911 +function resetPrefs() { 1.912 + if (gAppUpdateURL !== undefined) { 1.913 + Services.prefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, gAppUpdateURL); 1.914 + } 1.915 + else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) { 1.916 + Services.prefs.clearUserPref(PREF_APP_UPDATE_URL_OVERRIDE); 1.917 + } 1.918 + 1.919 + if (gAppUpdateURLDefault) { 1.920 + gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_URL, gAppUpdateURLDefault); 1.921 + } 1.922 + 1.923 + if (gAppUpdateEnabled !== undefined) { 1.924 + Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, gAppUpdateEnabled); 1.925 + } 1.926 + else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) { 1.927 + Services.prefs.clearUserPref(PREF_APP_UPDATE_ENABLED); 1.928 + } 1.929 + 1.930 + if (gAppUpdateMetroEnabled !== undefined) { 1.931 + Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, gAppUpdateMetroEnabled); 1.932 + } 1.933 + else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_METRO_ENABLED)) { 1.934 + Services.prefs.clearUserPref(PREF_APP_UPDATE_METRO_ENABLED); 1.935 + } 1.936 + 1.937 + if (gAppUpdateServiceEnabled !== undefined) { 1.938 + Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, gAppUpdateServiceEnabled); 1.939 + } 1.940 + else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) { 1.941 + Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ENABLED); 1.942 + } 1.943 + 1.944 + if (gAppUpdateStagingEnabled !== undefined) { 1.945 + Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, gAppUpdateStagingEnabled); 1.946 + } 1.947 + else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) { 1.948 + Services.prefs.clearUserPref(PREF_APP_UPDATE_STAGING_ENABLED); 1.949 + } 1.950 + 1.951 + if (gExtUpdateURL !== undefined) { 1.952 + Services.prefs.setCharPref(PREF_EXTENSIONS_UPDATE_URL, gExtUpdateURL); 1.953 + } 1.954 + else if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) { 1.955 + Services.prefs.clearUserPref(PREF_EXTENSIONS_UPDATE_URL); 1.956 + } 1.957 + 1.958 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_IDLETIME)) { 1.959 + Services.prefs.clearUserPref(PREF_APP_UPDATE_IDLETIME); 1.960 + } 1.961 + 1.962 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_PROMPTWAITTIME)) { 1.963 + Services.prefs.clearUserPref(PREF_APP_UPDATE_PROMPTWAITTIME); 1.964 + } 1.965 + 1.966 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_DETAILS)) { 1.967 + Services.prefs.clearUserPref(PREF_APP_UPDATE_URL_DETAILS); 1.968 + } 1.969 + 1.970 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SHOW_INSTALLED_UI)) { 1.971 + Services.prefs.clearUserPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI); 1.972 + } 1.973 + 1.974 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED)) { 1.975 + Services.prefs.clearUserPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED); 1.976 + } 1.977 + 1.978 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_LOG)) { 1.979 + Services.prefs.clearUserPref(PREF_APP_UPDATE_LOG); 1.980 + } 1.981 + 1.982 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_ERRORS)) { 1.983 + Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_ERRORS); 1.984 + } 1.985 + 1.986 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_MAXERRORS)) { 1.987 + Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_MAXERRORS); 1.988 + } 1.989 + 1.990 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) { 1.991 + Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS); 1.992 + } 1.993 + 1.994 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDMAXERRORS)) { 1.995 + Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDMAXERRORS); 1.996 + } 1.997 + 1.998 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_INVALID_ATTR_NAME)) { 1.999 + Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_INVALID_ATTR_NAME); 1.1000 + } 1.1001 + 1.1002 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_REQUIREBUILTIN)) { 1.1003 + Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_REQUIREBUILTIN); 1.1004 + } 1.1005 + 1.1006 + if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_CHECKATTRS)) { 1.1007 + Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_CHECKATTRS); 1.1008 + } 1.1009 + 1.1010 + try { 1.1011 + CERT_ATTRS.forEach(function(aCertAttrName) { 1.1012 + Services.prefs.clearUserPref(PREF_APP_UPDATE_CERTS_BRANCH + "1." + 1.1013 + aCertAttrName); 1.1014 + }); 1.1015 + } 1.1016 + catch (e) { 1.1017 + } 1.1018 + 1.1019 + try { 1.1020 + Services.prefs.deleteBranch(PREF_APP_UPDATE_NEVER_BRANCH); 1.1021 + } 1.1022 + catch(e) { 1.1023 + } 1.1024 + 1.1025 + if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_STRICT_COMPAT)) { 1.1026 + Services.prefs.clearUserPref(PREF_EXTENSIONS_STRICT_COMPAT); 1.1027 + } 1.1028 + 1.1029 + if (Services.prefs.prefHasUserValue(PREF_EM_HOTFIX_ID)) { 1.1030 + Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID); 1.1031 + } 1.1032 +} 1.1033 + 1.1034 +function setupTimer(aTestTimeout) { 1.1035 + gTestTimeout = aTestTimeout; 1.1036 + if (gTimeoutTimer) { 1.1037 + gTimeoutTimer.cancel(); 1.1038 + gTimeoutTimer = null; 1.1039 + } 1.1040 + gTimeoutTimer = AUS_Cc["@mozilla.org/timer;1"]. 1.1041 + createInstance(AUS_Ci.nsITimer); 1.1042 + gTimeoutTimer.initWithCallback(finishTestTimeout, gTestTimeout, 1.1043 + AUS_Ci.nsITimer.TYPE_ONE_SHOT); 1.1044 +} 1.1045 + 1.1046 +/** 1.1047 + * Disables pre-existing add-ons so they don't interfere with the tests, 1.1048 + * installs the test add-ons, sets the noupdate test add-ons' userDisabled value 1.1049 + * for the test, and calls the callback specified in the aCallback parameter. If 1.1050 + * the app.update.test.disabledAddons has a user value then setting the noupdate 1.1051 + * test add-ons' userDisabled value for the test is the only thing that is done. 1.1052 + * 1.1053 + * @param aCallback 1.1054 + * A callback to call after all operations have completed. 1.1055 + */ 1.1056 +function setupAddons(aCallback) { 1.1057 + debugDump("entering"); 1.1058 + 1.1059 + // Sets the appropriate userDisabled value for the noupdate test add-ons based 1.1060 + // on the value of gDisableNoUpdateAddon and calls the callback specified in 1.1061 + // setupAddons aCallback parameter. 1.1062 + function setNoUpdateAddonsDisabledState() { 1.1063 + AddonManager.getAllAddons(function(aAddons) { 1.1064 + aAddons.forEach(function(aAddon) { 1.1065 + if (aAddon.name.indexOf("noupdate") != 0) 1.1066 + return; 1.1067 + 1.1068 + if (gDisableNoUpdateAddon) { 1.1069 + if (!aAddon.userDisabled) { 1.1070 + aAddon.userDisabled = true; 1.1071 + } 1.1072 + } 1.1073 + else { 1.1074 + if (aAddon.userDisabled) { 1.1075 + aAddon.userDisabled = false; 1.1076 + } 1.1077 + } 1.1078 + }); 1.1079 + // Start the timout timer before the update window is displayed so it can 1.1080 + // clean up tests that don't successfully display the update window. 1.1081 + setupTimer(gTestTimeout); 1.1082 + aCallback(); 1.1083 + }); 1.1084 + } 1.1085 + 1.1086 + // If the app.update.test.disabledAddons preference exists the pre-existing 1.1087 + // add-ons have already been disabled so they don't interfere with the tests, 1.1088 + // the test add-ons have already been installed, and the only thing that needs 1.1089 + // to be done is setting the appropriate userDisabled value for the noupdate 1.1090 + // test add-ons. 1.1091 + if (Services.prefs.prefHasUserValue(PREF_DISABLEDADDONS)) { 1.1092 + setNoUpdateAddonsDisabledState(); 1.1093 + return; 1.1094 + } 1.1095 + 1.1096 + // Disable all pre-existing enabled addons so they don't interfere with the 1.1097 + // tests. 1.1098 + AddonManager.getAllAddons(function(aAddons) { 1.1099 + let disabledAddons = []; 1.1100 + aAddons.forEach(function(aAddon) { 1.1101 + // If an addon's type equals plugin it is skipped since 1.1102 + // checking plugins compatibility information isn't supported at this 1.1103 + // time (also see bug 566787). Also, SCOPE_APPLICATION add-ons are 1.1104 + // excluded by app update so there is no reason to disable them. 1.1105 + if (aAddon.type != "plugin" && !aAddon.appDisabled && 1.1106 + !aAddon.userDisabled && 1.1107 + aAddon.scope != AddonManager.SCOPE_APPLICATION) { 1.1108 + disabledAddons.push(aAddon); 1.1109 + aAddon.userDisabled = true; 1.1110 + } 1.1111 + }); 1.1112 + // If there are no pre-existing add-ons the preference value will be an 1.1113 + // empty string. 1.1114 + Services.prefs.setCharPref(PREF_DISABLEDADDONS, disabledAddons.join(" ")); 1.1115 + 1.1116 + // Install the test add-ons. 1.1117 + let xpiFiles = getTestAddonXPIFiles(); 1.1118 + let xpiCount = xpiFiles.length; 1.1119 + let installs = []; 1.1120 + xpiFiles.forEach(function(aFile) { 1.1121 + AddonManager.getInstallForFile(aFile, function(aInstall) { 1.1122 + if (!aInstall) { 1.1123 + throw "No AddonInstall created for " + aFile.path; 1.1124 + } 1.1125 + 1.1126 + installs.push(aInstall); 1.1127 + 1.1128 + if (--xpiCount == 0) { 1.1129 + let installCount = installs.length; 1.1130 + function installCompleted(aInstall) { 1.1131 + aInstall.removeListener(listener); 1.1132 + 1.1133 + if (getAddonTestType(aInstall.addon.name) == "userdisabled") { 1.1134 + aInstall.addon.userDisabled = true; 1.1135 + } 1.1136 + if (--installCount == 0) { 1.1137 + setNoUpdateAddonsDisabledState(); 1.1138 + } 1.1139 + } 1.1140 + 1.1141 + let listener = { 1.1142 + onDownloadFailed: installCompleted, 1.1143 + onDownloadCancelled: installCompleted, 1.1144 + onInstallFailed: installCompleted, 1.1145 + onInstallCancelled: installCompleted, 1.1146 + onInstallEnded: installCompleted 1.1147 + }; 1.1148 + 1.1149 + installs.forEach(function(aInstall) { 1.1150 + aInstall.addListener(listener); 1.1151 + aInstall.install(); 1.1152 + }); 1.1153 + } 1.1154 + }); 1.1155 + }); 1.1156 + }); 1.1157 +} 1.1158 + 1.1159 +/** 1.1160 + * Uninstalls the test add-ons, enables add-ons that were disabled when the 1.1161 + * test started, and calls the callback specified in the aCallback parameter. 1.1162 + * 1.1163 + * @param aCallback 1.1164 + * A callback to call after all operations have completed. 1.1165 + */ 1.1166 +function resetAddons(aCallback) { 1.1167 + debugDump("entering"); 1.1168 + // If test_9999_cleanup.xul is ran by itself then the test add-ons will not 1.1169 + // have been installed and any pre-existing add-ons will not have been 1.1170 + // disabled so return early. 1.1171 + if (!Services.prefs.prefHasUserValue(PREF_DISABLEDADDONS)) { 1.1172 + debugDump("preference " + PREF_DISABLEDADDONS + " doesn't exist... " + 1.1173 + "returning early"); 1.1174 + aCallback(); 1.1175 + return; 1.1176 + } 1.1177 + 1.1178 + // Uninstall the test add-ons. 1.1179 + let count = TEST_ADDONS.length; 1.1180 + function uninstallCompleted(aAddon) { 1.1181 + if (--count == 0) { 1.1182 + AddonManager.removeAddonListener(listener); 1.1183 + 1.1184 + // Enable the pre-existing add-ons that were disabled so they wouldn't 1.1185 + // interfere with the tests. 1.1186 + let disabledAddons = Services.prefs.getCharPref(PREF_DISABLEDADDONS).split(" "); 1.1187 + Services.prefs.clearUserPref(PREF_DISABLEDADDONS); 1.1188 + AddonManager.getAllAddons(function(aAddons) { 1.1189 + aAddons.forEach(function(aAddon) { 1.1190 + if (disabledAddons.indexOf(aAddon.id)) { 1.1191 + aAddon.userDisabled = false; 1.1192 + } 1.1193 + }); 1.1194 + aCallback(); 1.1195 + }); 1.1196 + } 1.1197 + } 1.1198 + 1.1199 + let listener = { 1.1200 + onUninstalled: uninstallCompleted 1.1201 + }; 1.1202 + 1.1203 + AddonManager.addAddonListener(listener); 1.1204 + TEST_ADDONS.forEach(function(aName) { 1.1205 + AddonManager.getAddonByID(aName + ADDON_ID_SUFFIX, function(aAddon) { 1.1206 + aAddon.uninstall(); 1.1207 + }); 1.1208 + }); 1.1209 +} 1.1210 + 1.1211 +/** 1.1212 + * Helper function to get the string before the '_' character in an add-on's 1.1213 + * name or id which is used to determine the add-on test type used by the tests. 1.1214 + * 1.1215 + * @param aName 1.1216 + * The test add-on's name or id. 1.1217 + * @return The string before the '_' character in the string passed in the aName 1.1218 + * parameter. 1.1219 + */ 1.1220 +function getAddonTestType(aName) { 1.1221 + return aName.split("_")[0]; 1.1222 +} 1.1223 + 1.1224 +/** 1.1225 + * Helper function to create add-on xpi files for the default test add-ons. 1.1226 + * 1.1227 + * @return An array with each member being an nsILocalFile for an add-on XPI 1.1228 + * file. 1.1229 + */ 1.1230 +function getTestAddonXPIFiles() { 1.1231 + let addonPrepDir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR, 1.1232 + AUS_Ci.nsILocalFile); 1.1233 + addonPrepDir.append(ADDON_PREP_DIR); 1.1234 + 1.1235 + let bootstrap = addonPrepDir.clone(); 1.1236 + bootstrap.append("bootstrap.js"); 1.1237 + // If a previous test has already created bootstrap.js don't create it again. 1.1238 + if (!bootstrap.exists()) { 1.1239 + let bootstrapContents = "function install(data, reason){ }\n" + 1.1240 + "function startup(data, reason){ }\n" + 1.1241 + "function shutdown(data, reason){ }\n" + 1.1242 + "function uninstall(data, reason){ }\n"; 1.1243 + writeFile(bootstrap, bootstrapContents); 1.1244 + } 1.1245 + 1.1246 + let installRDF = addonPrepDir.clone(); 1.1247 + installRDF.append("install.rdf"); 1.1248 + 1.1249 + let xpiFiles = []; 1.1250 + TEST_ADDONS.forEach(function(aName) { 1.1251 + let xpiFile = addonPrepDir.clone(); 1.1252 + xpiFile.append(aName + ".xpi"); 1.1253 + 1.1254 + if (installRDF.exists()) 1.1255 + installRDF.remove(false); 1.1256 + writeFile(installRDF, getInstallRDFString(aName)); 1.1257 + gZipW.open(xpiFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE); 1.1258 + gZipW.addEntryFile(installRDF.leafName, 1.1259 + AUS_Ci.nsIZipWriter.COMPRESSION_DEFAULT, installRDF, 1.1260 + false); 1.1261 + gZipW.addEntryFile(bootstrap.leafName, 1.1262 + AUS_Ci.nsIZipWriter.COMPRESSION_DEFAULT, bootstrap, 1.1263 + false); 1.1264 + gZipW.close(); 1.1265 + xpiFiles.push(xpiFile); 1.1266 + }); 1.1267 + 1.1268 + return xpiFiles; 1.1269 +} 1.1270 + 1.1271 +/** 1.1272 + * Helper function to gets the string representation of the contents of the 1.1273 + * add-on's install.rdf file. 1.1274 + * 1.1275 + * @param aName 1.1276 + * The string to use for the add-on's name which is also used to 1.1277 + * construct the local-part in RFC 5322 format of the add-on's ID. 1.1278 + * @return A string representation of the contents of the add-on's install.rdf 1.1279 + * file. 1.1280 + */ 1.1281 +function getInstallRDFString(aName) { 1.1282 + let maxVersion = Services.appinfo.platformVersion; 1.1283 + switch (getAddonTestType(aName)) { 1.1284 + case "compatible": 1.1285 + maxVersion = getNewerPlatformVersion(); 1.1286 + break; 1.1287 + case "appdisabled": 1.1288 + maxVersion = "0.1"; 1.1289 + break; 1.1290 + } 1.1291 + 1.1292 + return "<?xml version=\"1.0\"?>\n" + 1.1293 + "<RDF xmlns=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n" + 1.1294 + " xmlns:em=\"http://www.mozilla.org/2004/em-rdf#\">\n" + 1.1295 + " <Description about=\"urn:mozilla:install-manifest\">\n" + 1.1296 + " <em:id>" + aName + ADDON_ID_SUFFIX + "</em:id>\n" + 1.1297 + " <em:version>1.0</em:version>\n" + 1.1298 + " <em:bootstrap>true</em:bootstrap>\n" + 1.1299 + " <em:name>" + aName + "</em:name>\n" + 1.1300 + " <em:description>Test Description</em:description>\n" + 1.1301 + " <em:targetApplication>\n" + 1.1302 + " <Description>\n" + 1.1303 + " <em:id>toolkit@mozilla.org</em:id>\n" + 1.1304 + " <em:minVersion>undefined</em:minVersion>\n" + 1.1305 + " <em:maxVersion>" + maxVersion + "</em:maxVersion>\n" + 1.1306 + " </Description>\n" + 1.1307 + " </em:targetApplication>\n" + 1.1308 + " </Description>\n" + 1.1309 + "</RDF>"; 1.1310 +} 1.1311 + 1.1312 +/** 1.1313 + * Closes the update window if it is open and causes the test to fail if an 1.1314 + * update window is found. 1.1315 + * 1.1316 + * @return true if an update window was found, otherwise false. 1.1317 + */ 1.1318 +function closeUpdateWindow() { 1.1319 + let updateWindow = getUpdateWindow(); 1.1320 + if (!updateWindow) 1.1321 + return false; 1.1322 + 1.1323 + ok(false, "Found an existing Update Window from the current or a previous " + 1.1324 + "test... attempting to close it."); 1.1325 + updateWindow.close(); 1.1326 + return true; 1.1327 +} 1.1328 + 1.1329 +/** 1.1330 + * Gets the update window. 1.1331 + * 1.1332 + * @return The nsIDOMWindow for the Update Window if it is open and null 1.1333 + * if it isn't. 1.1334 + */ 1.1335 +function getUpdateWindow() { 1.1336 + return Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME); 1.1337 +} 1.1338 + 1.1339 +/** 1.1340 + * Helper for background check errors. 1.1341 + */ 1.1342 +var errorsPrefObserver = { 1.1343 + observedPref: null, 1.1344 + maxErrorPref: null, 1.1345 + 1.1346 + /** 1.1347 + * Sets up a preference observer and sets the associated maximum errors 1.1348 + * preference used for background notification. 1.1349 + * 1.1350 + * @param aObservePref 1.1351 + * The preference to observe. 1.1352 + * @param aMaxErrorPref 1.1353 + * The maximum errors preference. 1.1354 + * @param aMaxErrorCount 1.1355 + * The value to set the app.update.cert.maxErrors preference to. 1.1356 + */ 1.1357 + init: function(aObservePref, aMaxErrorPref, aMaxErrorCount) { 1.1358 + this.observedPref = aObservePref; 1.1359 + this.maxErrorPref = aMaxErrorPref; 1.1360 + 1.1361 + let maxErrors = aMaxErrorCount ? aMaxErrorCount : 2; 1.1362 + Services.prefs.setIntPref(aMaxErrorPref, maxErrors); 1.1363 + Services.prefs.addObserver(aObservePref, this, false); 1.1364 + }, 1.1365 + 1.1366 + /** 1.1367 + * Preference observer for the preference specified in |this.observedPref|. 1.1368 + */ 1.1369 + observe: function XPI_observe(aSubject, aTopic, aData) { 1.1370 + if (aData == this.observedPref) { 1.1371 + let errCount = Services.prefs.getIntPref(this.observedPref); 1.1372 + let errMax = Services.prefs.getIntPref(this.maxErrorPref); 1.1373 + if (errCount >= errMax) { 1.1374 + debugDump("removing pref observer"); 1.1375 + Services.prefs.removeObserver(this.observedPref, this); 1.1376 + } 1.1377 + else { 1.1378 + debugDump("notifying AUS"); 1.1379 + SimpleTest.executeSoon(function() { 1.1380 + gAUS.notify(null); 1.1381 + }); 1.1382 + } 1.1383 + } 1.1384 + } 1.1385 +}; 1.1386 + 1.1387 +/** 1.1388 + * nsIObserver for receiving window open and close notifications. 1.1389 + */ 1.1390 +var gWindowObserver = { 1.1391 + observe: function WO_observe(aSubject, aTopic, aData) { 1.1392 + let win = aSubject.QueryInterface(AUS_Ci.nsIDOMEventTarget); 1.1393 + 1.1394 + if (aTopic == "domwindowclosed") { 1.1395 + if (win.location != URI_UPDATE_PROMPT_DIALOG) { 1.1396 + debugDump("domwindowclosed event for window not being tested - " + 1.1397 + "location: " + win.location + "... returning early"); 1.1398 + return; 1.1399 + } 1.1400 + // Allow tests the ability to provide their own function (it must be 1.1401 + // named finishTest) for finishing the test. 1.1402 + try { 1.1403 + finishTest(); 1.1404 + } 1.1405 + catch (e) { 1.1406 + finishTestDefault(); 1.1407 + } 1.1408 + return; 1.1409 + } 1.1410 + 1.1411 + win.addEventListener("load", function WO_observe_onLoad() { 1.1412 + win.removeEventListener("load", WO_observe_onLoad, false); 1.1413 + // Ignore windows other than the update UI window. 1.1414 + if (win.location != URI_UPDATE_PROMPT_DIALOG) { 1.1415 + debugDump("load event for window not being tested - location: " + 1.1416 + win.location + "... returning early"); 1.1417 + return; 1.1418 + } 1.1419 + 1.1420 + // The first wizard page should always be the dummy page. 1.1421 + let pageid = win.document.documentElement.currentPage.pageid; 1.1422 + if (pageid != PAGEID_DUMMY) { 1.1423 + // This should never happen but if it does this will provide a clue 1.1424 + // for diagnosing the cause. 1.1425 + ok(false, "Unexpected load event - pageid got: " + pageid + 1.1426 + ", expected: " + PAGEID_DUMMY + "... returning early"); 1.1427 + return; 1.1428 + } 1.1429 + 1.1430 + gWin = win; 1.1431 + gDocElem = gWin.document.documentElement; 1.1432 + gDocElem.addEventListener("pageshow", onPageShowDefault, false); 1.1433 + }, false); 1.1434 + } 1.1435 +};