toolkit/mozapps/update/tests/chrome/utils.js

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* Any copyright is dedicated to the Public Domain.
     2  * http://creativecommons.org/publicdomain/zero/1.0/
     3  */
     5 /**
     6  * Test Definition
     7  *
     8  * Most tests can use an array named TESTS that will perform most if not all of
     9  * the necessary checks. Each element in the array must be an object with the
    10  * following possible properties. Additional properties besides the ones listed
    11  * below can be added as needed.
    12  *
    13  * overrideCallback (optional)
    14  *   The function to call for the next test. This is typically called when the
    15  *   wizard page changes but can also be called for other events by the previous
    16  *   test. If this property isn't defined then the defailtCallback function will
    17  *   be called. If this property is defined then all other properties are
    18  *   optional.
    19  *
    20  * pageid (required unless overrideCallback is specified)
    21  *   The expected pageid for the wizard. This property is required unless the
    22  *   overrideCallback property is defined.
    23  *
    24  * extraStartFunction (optional)
    25  *   The function to call at the beginning of the defaultCallback function. If
    26  *   the function returns true the defaultCallback function will return early
    27  *   which allows waiting for a specific condition to be evaluated in the
    28  *   function specified in the extraStartFunction property before continuing
    29  *   with the test.
    30  *
    31  * extraCheckFunction (optional)
    32  *   The function to call to perform extra checks in the defaultCallback
    33  *   function.
    34  *
    35  * extraDelayedCheckFunction (optional)
    36  *   The function to call to perform extra checks in the delayedDefaultCallback
    37  *   function.
    38  *
    39  * buttonStates (optional)
    40  *   A javascript object representing the expected hidden and disabled attribute
    41  *   values for the buttons of the current wizard page. The values are checked
    42  *   in the delayedDefaultCallback function. For information about the structure
    43  *   of this object refer to the getExpectedButtonStates and checkButtonStates
    44  *   functions.
    45  *
    46  * buttonClick (optional)
    47  *   The current wizard page button to click at the end of the
    48  *   delayedDefaultCallback function. If the buttonClick property is defined
    49  *   then the extraDelayedFinishFunction property can't be specified due to race
    50  *   conditions in some of the tests and if both of them are specified the test
    51  *   will intentionally throw.
    52  *
    53  * extraDelayedFinishFunction (optional)
    54  *   The function to call at the end of the delayedDefaultCallback function.
    55  *   If the extraDelayedFinishFunction property is defined then the buttonClick
    56  *   property can't be specified due to race conditions in some of the tests and
    57  *   if both of them are specified the test will intentionally throw.
    58  *
    59  * ranTest (should not be specified)
    60  *   When delayedDefaultCallback is called a property named ranTest is added to
    61  *   the current test so it is possible to verify that each test in the TESTS
    62  *   array has ran.
    63  *
    64  * prefHasUserValue (optional)
    65  *   For comparing the expected value defined by this property with the return
    66  *   value of prefHasUserValue using gPrefToCheck for the preference name in the
    67  *   checkPrefHasUserValue function.
    68  *
    69  * expectedRadioGroupSelectedIndex (optional)
    70  *   For comparing the expected selectedIndex attribute value of the wizard's
    71  *   license page radiogroup selectedIndex attribute in the
    72  *   checkRadioGroupSelectedIndex function.
    73  *
    74  * expectedRemoteContentState (optional)
    75  *   For comparing the expected remotecontent state attribute value of the
    76  *   wizard's billboard and license pages in the checkRemoteContentState and
    77  *   waitForRemoteContentLoaded functions.
    78  *
    79  *
    80  * Test Add-ons
    81  *
    82  * All tests include the test add-ons specified in the TEST_ADDONS array and
    83  * the only thing that can be configured is whether the noupdate test add-on is
    84  * disabled (see below). The add-on names are in the format of typename_X where
    85  * X is a number to make the add-on ID unique and typename is one of the values
    86  * specified below:
    87  *
    88  * appdisabled
    89  *   disabled by the application due to being incompatible with the current
    90  *   toolkit version.
    91  *
    92  * compatible
    93  *   compatible with the current toolkit version and the update's toolkit
    94  *   version.
    95  *
    96  * noupdate
    97  *   the add-on is compatible with the current toolkit version and does not have
    98  *   an update to make it compatible with the update's toolkit version. Tests
    99  *   that need to have all add-ons compatible for the application update can
   100  *   disable this add-on by setting the gDisableNoUpdateAddon variable to true.
   101  *
   102  * updatecompatibility
   103  *   the add-on is compatible with the current toolkit version and has a
   104  *   compatibility update to make it compatible with the update's toolkit
   105  *   version.
   106  *
   107  * updateversion
   108  *   the add-on is compatible with the current toolkit version and has a version
   109  *   update to make it compatible with the update's toolkit version.
   110  *
   111  * userdisabled
   112  *   disabled by the user and compatible with the current toolkit version but
   113  *   not the update's toolkit version. This add-on will be disabled after its
   114  *   install completes.
   115  */
   117 Components.utils.import("resource://gre/modules/AddonManager.jsm");
   119 // The tests have to use the pageid instead of the pageIndex due to the
   120 // app update wizard's access method being random.
   121 const PAGEID_DUMMY            = "dummy";                 // Done
   122 const PAGEID_CHECKING         = "checking";              // Done
   123 const PAGEID_PLUGIN_UPDATES   = "pluginupdatesfound";
   124 const PAGEID_NO_UPDATES_FOUND = "noupdatesfound";        // Done
   125 const PAGEID_MANUAL_UPDATE    = "manualUpdate"; // Tested on license load failure
   126 const PAGEID_UNSUPPORTED      = "unsupported";           // Done
   127 const PAGEID_INCOMPAT_CHECK   = "incompatibleCheck";     // Done
   128 const PAGEID_FOUND_BASIC      = "updatesfoundbasic";     // Done
   129 const PAGEID_FOUND_BILLBOARD  = "updatesfoundbillboard"; // Done
   130 const PAGEID_LICENSE          = "license";               // Done
   131 const PAGEID_INCOMPAT_LIST    = "incompatibleList";      // Done
   132 const PAGEID_DOWNLOADING      = "downloading";           // Done
   133 const PAGEID_ERRORS           = "errors";                // Done
   134 const PAGEID_ERROR_EXTRA      = "errorextra";            // Done
   135 const PAGEID_ERROR_PATCHING   = "errorpatching";         // Done
   136 const PAGEID_FINISHED         = "finished";              // Done
   137 const PAGEID_FINISHED_BKGRD   = "finishedBackground";    // Done
   138 const PAGEID_INSTALLED        = "installed";             // Done
   140 const UPDATE_WINDOW_NAME = "Update:Wizard";
   142 const URL_HOST = "http://example.com";
   143 const URL_PATH_UPDATE_XML = "/chrome/toolkit/mozapps/update/tests/chrome/update.sjs";
   144 const REL_PATH_DATA = "chrome/toolkit/mozapps/update/tests/data";
   146 const URL_HTTP_UPDATE_XML = URL_HOST + URL_PATH_UPDATE_XML;
   147 const URL_HTTPS_UPDATE_XML = "https://example.com" + URL_PATH_UPDATE_XML;
   149 const URI_UPDATE_PROMPT_DIALOG  = "chrome://mozapps/content/update/updates.xul";
   151 const ADDON_ID_SUFFIX = "@appupdatetest.mozilla.org";
   152 const ADDON_PREP_DIR = "appupdateprep";
   153 // Preference for storing add-ons that are disabled by the tests to prevent them
   154 // from interefering with the tests.
   155 const PREF_DISABLEDADDONS = "app.update.test.disabledAddons";
   156 const PREF_EM_HOTFIX_ID = "extensions.hotfix.id";
   157 const TEST_ADDONS = [ "appdisabled_1", "appdisabled_2",
   158                       "compatible_1", "compatible_2",
   159                       "noupdate_1", "noupdate_2",
   160                       "updatecompatibility_1", "updatecompatibility_2",
   161                       "updateversion_1", "updateversion_2",
   162                       "userdisabled_1", "userdisabled_2", "hotfix" ];
   164 var gURLData = URL_HOST + "/" + REL_PATH_DATA + "/";
   166 var gTestTimeout = 240000; // 4 minutes
   167 var gTimeoutTimer;
   169 // The number of SimpleTest.executeSoon calls to perform when waiting on an
   170 // update window to close before giving up.
   171 const CLOSE_WINDOW_TIMEOUT_MAXCOUNT = 10;
   172 // Counter for the SimpleTest.executeSoon when waiting on an update window to
   173 // close before giving up.
   174 var gCloseWindowTimeoutCounter = 0;
   176 // The following vars are for restoring previous preference values (if present)
   177 // when the test finishes.
   178 var gAppUpdateEnabled;            // app.update.enabled
   179 var gAppUpdateMetroEnabled;       // app.update.metro.enabled
   180 var gAppUpdateServiceEnabled;     // app.update.service.enabled
   181 var gAppUpdateStagingEnabled;     // app.update.staging.enabled
   182 var gAppUpdateURLDefault;         // app.update.url (default prefbranch)
   183 var gAppUpdateURL;                // app.update.url.override
   184 var gExtUpdateURL;                // extensions.update.url
   186 var gTestCounter = -1;
   187 var gWin;
   188 var gDocElem;
   189 var gPrefToCheck;
   190 var gDisableNoUpdateAddon = false;
   192 // Set to true to log additional information for debugging. To log additional
   193 // information for an individual test set DEBUG_AUS_TEST to true in the test's
   194 // onload function.
   195 var DEBUG_AUS_TEST = true;
   197 #include ../shared.js
   199 /**
   200  * The current test in TESTS array.
   201  */
   202 this.__defineGetter__("gTest", function() {
   203   return TESTS[gTestCounter];
   204 });
   206 /**
   207  * The current test's callback. This will either return the callback defined in
   208  * the test's overrideCallback property or defaultCallback if the
   209  * overrideCallback property is undefined.
   210  */
   211 this.__defineGetter__("gCallback", function() {
   212   return gTest.overrideCallback ? gTest.overrideCallback
   213                                 : defaultCallback;
   214 });
   216 /**
   217  * The remotecontent element for the current page if one exists or null if a
   218  * remotecontent element doesn't exist.
   219  */
   220 this.__defineGetter__("gRemoteContent", function() {
   221   switch (gTest.pageid) {
   222     case PAGEID_FOUND_BILLBOARD:
   223       return gWin.document.getElementById("updateMoreInfoContent");
   224     case PAGEID_LICENSE:
   225       return gWin.document.getElementById("licenseContent");
   226   }
   227   return null;
   228 });
   230 /**
   231  * The state for the remotecontent element if one exists or null if a
   232  * remotecontent element doesn't exist.
   233  */
   234 this.__defineGetter__("gRemoteContentState", function() {
   235   if (gRemoteContent) {
   236     return gRemoteContent.getAttribute("state");
   237   }
   238   return null;
   239 });
   241 /**
   242  * The radiogroup for the license page.
   243  */
   244 this.__defineGetter__("gAcceptDeclineLicense", function() {
   245   return gWin.document.getElementById("acceptDeclineLicense");
   246 });
   248 /**
   249  * The listbox for the incompatibleList page.
   250  */
   251 this.__defineGetter__("gIncompatibleListbox", function() {
   252   return gWin.document.getElementById("incompatibleListbox");
   253 });
   255 /**
   256  * Default test run function that can be used by most tests. This function uses
   257  * protective measures to prevent the test from failing provided by
   258  * |runTestDefaultWaitForWindowClosed| helper functions to prevent failure due
   259  * to a previous test failure.
   260  */
   261 function runTestDefault() {
   262   debugDump("entering");
   264   if (!("@mozilla.org/zipwriter;1" in AUS_Cc)) {
   265     ok(false, "nsIZipWriter is required to run these tests");
   266     return;
   267   }
   269   SimpleTest.waitForExplicitFinish();
   271   runTestDefaultWaitForWindowClosed();
   272 }
   274 /**
   275  * If an update window is found SimpleTest.executeSoon can callback before the
   276  * update window is fully closed especially with debug builds. If an update
   277  * window is found this function will call itself using SimpleTest.executeSoon
   278  * up to the amount declared in CLOSE_WINDOW_TIMEOUT_MAXCOUNT until the update
   279  * window has closed before continuing the test.
   280  */
   281 function runTestDefaultWaitForWindowClosed() {
   282   gCloseWindowTimeoutCounter++;
   283   if (gCloseWindowTimeoutCounter > CLOSE_WINDOW_TIMEOUT_MAXCOUNT) {
   284     try {
   285       finishTest();
   286     }
   287     catch (e) {
   288       finishTestDefault();
   289     }
   290     return;
   291   }
   293   // The update window should not be open at this time. If it is the call to
   294   // |closeUpdateWindow| will close it and cause the test to fail.
   295   if (closeUpdateWindow()) {
   296     SimpleTest.executeSoon(runTestDefaultWaitForWindowClosed);
   297   }
   298   else {
   299     Services.ww.registerNotification(gWindowObserver);
   301     gCloseWindowTimeoutCounter = 0;
   303     setupFiles();
   304     setupPrefs();
   305     removeUpdateDirsAndFiles();
   306     reloadUpdateManagerData();
   307     setupAddons(runTest);
   308   }
   309 }
   311 /**
   312  * Default test finish function that can be used by most tests. This function
   313  * uses protective measures to prevent the next test from failing provided by
   314  * |finishTestDefaultWaitForWindowClosed| helper functions to prevent failure
   315  * due to an update window being left open.
   316  */
   317 function finishTestDefault() {
   318   debugDump("entering");
   319   if (gTimeoutTimer) {
   320     gTimeoutTimer.cancel();
   321     gTimeoutTimer = null;
   322   }
   324   if (gChannel) {
   325     debugDump("channel = " + gChannel);
   326     gChannel = null;
   327     gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
   328   }
   330   verifyTestsRan();
   332   resetPrefs();
   333   resetFiles();
   334   removeUpdateDirsAndFiles();
   335   reloadUpdateManagerData();
   337   Services.ww.unregisterNotification(gWindowObserver);
   338   if (gDocElem) {
   339     gDocElem.removeEventListener("pageshow", onPageShowDefault, false);
   340   }
   342   finishTestDefaultWaitForWindowClosed();
   343 }
   345 /**
   346  * nsITimerCallback for the timeout timer to cleanly finish a test if the Update
   347  * Window doesn't close for a test. This allows the next test to run properly if
   348  * a previous test fails.
   349  *
   350  * @param  aTimer
   351  *         The nsITimer that fired.
   352  */
   353 function finishTestTimeout(aTimer) {
   354   ok(false, "Test timed out. Maximum time allowed is " + (gTestTimeout / 1000) +
   355      " seconds");
   357   try {
   358     finishTest();
   359   }
   360   catch (e) {
   361     finishTestDefault();
   362   }
   363 }
   365 /**
   366  * If an update window is found SimpleTest.executeSoon can callback before the
   367  * update window is fully closed especially with debug builds. If an update
   368  * window is found this function will call itself using SimpleTest.executeSoon
   369  * up to the amount declared in CLOSE_WINDOW_TIMEOUT_MAXCOUNT until the update
   370  * window has closed before finishing the test.
   371  */
   372 function finishTestDefaultWaitForWindowClosed() {
   373   gCloseWindowTimeoutCounter++;
   374   if (gCloseWindowTimeoutCounter > CLOSE_WINDOW_TIMEOUT_MAXCOUNT) {
   375     SimpleTest.finish();
   376     return;
   377   }
   379   // The update window should not be open at this time. If it is the call to
   380   // |closeUpdateWindow| will close it and cause the test to fail.
   381   if (closeUpdateWindow()) {
   382     SimpleTest.executeSoon(finishTestDefaultWaitForWindowClosed);
   383   }
   384   else {
   385     SimpleTest.finish();
   386   }
   387 }
   389 /**
   390  * Default callback for the wizard's documentElement pageshow listener. This
   391  * will return early for event's where the originalTarget's nodeName is not
   392  * wizardpage.
   393  */
   394 function onPageShowDefault(aEvent) {
   395   if (!gTimeoutTimer) {
   396     debugDump("gTimeoutTimer is null... returning early");
   397     return;
   398   }
   400   // Return early if the event's original target isn't for a wizardpage element.
   401   // This check is necessary due to the remotecontent element firing pageshow.
   402   if (aEvent.originalTarget.nodeName != "wizardpage") {
   403     debugDump("only handles events with an originalTarget nodeName of " +
   404               "|wizardpage|. aEvent.originalTarget.nodeName = " +
   405               aEvent.originalTarget.nodeName + "... returning early");
   406     return;
   407   }
   409   gTestCounter++;
   410   gCallback(aEvent);
   411 }
   413 /**
   414  * Default callback that can be used by most tests.
   415  */
   416 function defaultCallback(aEvent) {
   417   if (!gTimeoutTimer) {
   418     debugDump("gTimeoutTimer is null... returning early");
   419     return;
   420   }
   422   debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid +
   423             ", aEvent.originalTarget.nodeName: " +
   424             aEvent.originalTarget.nodeName);
   426   if (gTest && gTest.extraStartFunction) {
   427     debugDump("calling extraStartFunction " + gTest.extraStartFunction.name);
   428     if (gTest.extraStartFunction(aEvent)) {
   429       debugDump("extraStartFunction early return");
   430       return;
   431     }
   432   }
   434   is(gDocElem.currentPage.pageid, gTest.pageid,
   435      "Checking currentPage.pageid equals " + gTest.pageid + " in pageshow");
   437   // Perform extra checks if specified by the test
   438   if (gTest.extraCheckFunction) {
   439     debugDump("calling extraCheckFunction " + gTest.extraCheckFunction.name);
   440     gTest.extraCheckFunction();
   441   }
   443   // The wizard page buttons' disabled and hidden attributes are set after the
   444   // pageshow event so use executeSoon to allow them to be set so their disabled
   445   // and hidden attribute values can be checked.
   446   SimpleTest.executeSoon(delayedDefaultCallback);
   447 }
   449 /**
   450  * Delayed default callback called using executeSoon in defaultCallback which
   451  * allows the wizard page buttons' disabled and hidden attributes to be set
   452  * before checking their values.
   453  */
   454 function delayedDefaultCallback() {
   455   if (!gTimeoutTimer) {
   456     debugDump("gTimeoutTimer is null... returning early");
   457     return;
   458   }
   460   if (!gTest) {
   461     debugDump("gTest is null... returning early");
   462     return;
   463   }
   465   debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid);
   467   // Verify the pageid hasn't changed after executeSoon was called.
   468   is(gDocElem.currentPage.pageid, gTest.pageid,
   469      "Checking currentPage.pageid equals " + gTest.pageid + " after " +
   470      "executeSoon");
   472   checkButtonStates();
   474   // Perform delayed extra checks if specified by the test
   475   if (gTest.extraDelayedCheckFunction) {
   476     debugDump("calling extraDelayedCheckFunction " +
   477               gTest.extraDelayedCheckFunction.name);
   478     gTest.extraDelayedCheckFunction();
   479   }
   481   // Used to verify that this test has been performed
   482   gTest.ranTest = true;
   484   if (gTest.buttonClick) {
   485     debugDump("clicking " + gTest.buttonClick + " button");
   486     if(gTest.extraDelayedFinishFunction) {
   487       throw("Tests cannot have a buttonClick and an extraDelayedFinishFunction property");
   488     }
   489     gDocElem.getButton(gTest.buttonClick).click();
   490   }
   491   else if (gTest.extraDelayedFinishFunction) {
   492     debugDump("calling extraDelayedFinishFunction " +
   493               gTest.extraDelayedFinishFunction.name);
   494     gTest.extraDelayedFinishFunction();
   495   }
   496 }
   498 /**
   499  * Checks the wizard page buttons' disabled and hidden attributes values are
   500  * correct. If an expected button id is not specified then the expected disabled
   501  * and hidden attribute value is true.
   502  */
   503 function checkButtonStates() {
   504   debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid);
   506   const buttonNames = ["extra1", "extra2", "back", "next", "finish", "cancel"];
   507   let buttonStates = getExpectedButtonStates();
   508   buttonNames.forEach(function(aButtonName) {
   509     let button = gDocElem.getButton(aButtonName);
   510     let hasHidden = aButtonName in buttonStates &&
   511                     "hidden" in buttonStates[aButtonName];
   512     let hidden = hasHidden ? buttonStates[aButtonName].hidden : true;
   513     let hasDisabled = aButtonName in buttonStates &&
   514                       "disabled" in buttonStates[aButtonName];
   515     let disabled = hasDisabled ? buttonStates[aButtonName].disabled : true;
   516     is(button.hidden, hidden, "Checking " + aButtonName + " button " +
   517        "hidden attribute value equals " + (hidden ? "true" : "false"));
   518     is(button.disabled, disabled, "Checking " + aButtonName + " button " +
   519        "disabled attribute value equals " + (disabled ? "true" : "false"));
   520   });
   521 }
   523 /**
   524  * Returns the expected disabled and hidden attribute values for the buttons of
   525  * the current wizard page.
   526  */
   527 function getExpectedButtonStates() {
   528   // Allow individual tests to override the expected button states.
   529   if (gTest.buttonStates) {
   530     return gTest.buttonStates;
   531   }
   533   switch (gTest.pageid) {
   534     case PAGEID_CHECKING:
   535     case PAGEID_INCOMPAT_CHECK:
   536       return { cancel: { disabled: false, hidden: false } };
   537     case PAGEID_FOUND_BASIC:
   538     case PAGEID_FOUND_BILLBOARD:
   539       if (gTest.neverButton) {
   540         return { extra1: { disabled: false, hidden: false },
   541                  extra2: { disabled: false, hidden: false },
   542                  next  : { disabled: false, hidden: false } }
   543       }
   544       return { extra1: { disabled: false, hidden: false },
   545                next  : { disabled: false, hidden: false } };
   546     case PAGEID_LICENSE:
   547       if (gRemoteContentState != "loaded" ||
   548           gAcceptDeclineLicense.selectedIndex != 0) {
   549         return { extra1: { disabled: false, hidden: false },
   550                  next  : { disabled: true, hidden: false } };
   551       }
   552       return { extra1: { disabled: false, hidden: false },
   553                next  : { disabled: false, hidden: false } };
   554     case PAGEID_INCOMPAT_LIST:
   555       return { extra1: { disabled: false, hidden: false },
   556                next  : { disabled: false, hidden: false } };
   557     case PAGEID_DOWNLOADING:
   558       return { extra1: { disabled: false, hidden: false } };
   559     case PAGEID_NO_UPDATES_FOUND:
   560     case PAGEID_MANUAL_UPDATE:
   561     case PAGEID_UNSUPPORTED:
   562     case PAGEID_ERRORS:
   563     case PAGEID_ERROR_EXTRA:
   564     case PAGEID_INSTALLED:
   565       return { finish: { disabled: false, hidden: false } };
   566     case PAGEID_ERROR_PATCHING:
   567       return { next  : { disabled: false, hidden: false } };
   568     case PAGEID_FINISHED:
   569     case PAGEID_FINISHED_BKGRD:
   570       return { extra1: { disabled: false, hidden: false },
   571                finish: { disabled: false, hidden: false } };
   572   }
   573   return null;
   574 }
   576 /**
   577  * Adds a load event listener to the current remotecontent element.
   578  */
   579 function addRemoteContentLoadListener() {
   580   debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid);
   582   gRemoteContent.addEventListener("load", remoteContentLoadListener, false);
   583 }
   585 /**
   586  * The nsIDOMEventListener for a remotecontent load event.
   587  */
   588 function remoteContentLoadListener(aEvent) {
   589   // Return early if the event's original target's nodeName isn't remotecontent.
   590   if (aEvent.originalTarget.nodeName != "remotecontent") {
   591     debugDump("only handles events with an originalTarget nodeName of " +
   592               "|remotecontent|. aEvent.originalTarget.nodeName = " +
   593               aEvent.originalTarget.nodeName);
   594     return;
   595   }
   597   gTestCounter++;
   598   gCallback(aEvent);
   599 }
   601 /**
   602  * Waits until a remotecontent element to finish loading which is determined
   603  * by the current test's expectedRemoteContentState property and then removes
   604  * the event listener.
   605  *
   606  * Note: tests that use this function should not test the state of the
   607  *      remotecontent since this will check the expected state.
   608  *
   609  * @return false if the remotecontent has loaded and its state is the state
   610  *         specified in the current test's expectedRemoteContentState
   611  *         property... otherwise true.
   612  */
   613 function waitForRemoteContentLoaded(aEvent) {
   614   // Return early until the remotecontent has loaded with the state that is
   615   // expected or isn't the event's originalTarget.
   616   if (gRemoteContentState != gTest.expectedRemoteContentState ||
   617       aEvent.originalTarget != gRemoteContent) {
   618     debugDump("returning early\n" +
   619               "gRemoteContentState: " + gRemoteContentState + "\n" +
   620               "expectedRemoteContentState: " +
   621               gTest.expectedRemoteContentState + "\n" +
   622               "aEvent.originalTarget.nodeName: " +
   623               aEvent.originalTarget.nodeName);
   624     return true;
   625   }
   627   gRemoteContent.removeEventListener("load", remoteContentLoadListener, false);
   628   return false;
   629 }
   631 /**
   632  * Compares the value of the remotecontent state attribute with the value
   633  * specified in the test's expectedRemoteContentState property.
   634  */
   635 function checkRemoteContentState() {
   636   is(gRemoteContentState, gTest.expectedRemoteContentState, "Checking remote " +
   637      "content state equals " + gTest.expectedRemoteContentState + " - pageid " +
   638      gTest.pageid);
   639 }
   641 /**
   642  * Adds a select event listener to the license radiogroup element and clicks
   643  * the radio element specified in the current test's radioClick property.
   644  */
   645 function addRadioGroupSelectListenerAndClick() {
   646   debugDump("entering - TESTS[" + gTestCounter + "], pageid: " + gTest.pageid);
   648   gAcceptDeclineLicense.addEventListener("select", radioGroupSelectListener,
   649                                          false);
   650   gWin.document.getElementById(gTest.radioClick).click();
   651 }
   653 /**
   654  * The nsIDOMEventListener for the license radiogroup select event.
   655  */
   656 function radioGroupSelectListener(aEvent) {
   657   // Return early if the event's original target's nodeName isn't radiogroup.
   658   if (aEvent.originalTarget.nodeName != "radiogroup") {
   659     debugDump("only handles events with an originalTarget nodeName of " +
   660               "|radiogroup|. aEvent.originalTarget.nodeName = " +
   661               aEvent.originalTarget.nodeName);
   662     return;
   663   }
   665   gAcceptDeclineLicense.removeEventListener("select", radioGroupSelectListener,
   666                                             false);
   667   gTestCounter++;
   668   gCallback(aEvent);
   669 }
   671 /**
   672  * Compares the value of the License radiogroup's selectedIndex attribute with
   673  * the value specified in the test's expectedRadioGroupSelectedIndex property.
   674  */
   675 function checkRadioGroupSelectedIndex() {
   676   is(gAcceptDeclineLicense.selectedIndex, gTest.expectedRadioGroupSelectedIndex,
   677      "Checking license radiogroup selectedIndex equals " +
   678      gTest.expectedRadioGroupSelectedIndex);
   679 }
   681 /**
   682  * Checks that only incompatible add-ons (e.g. noupdate_X add-ons) that don't
   683  * have an update are listed in the add-ons incompatible list.
   684  */
   685 function checkIncompatbleList() {
   686   for (let i = 0; i < gIncompatibleListbox.itemCount; i++) {
   687     let label = gIncompatibleListbox.getItemAtIndex(i).label;
   688     // Use indexOf since locales can change the text displayed
   689     ok(label.indexOf("noupdate") != -1, "Checking that only incompatible " + 
   690        "add-ons that don't have an update are listed in the incompatible list");
   691   }
   692 }
   694 /**
   695  * Compares the return value of prefHasUserValue for the preference specified in
   696  * gPrefToCheck with the value passed in the aPrefHasValue parameter or the
   697  * value specified in the current test's prefHasUserValue property if
   698  * aPrefHasValue is undefined.
   699  *
   700  * @param  aPrefHasValue (optional)
   701  *         The expected value returned from prefHasUserValue for the preference
   702  *         specified in gPrefToCheck. If aPrefHasValue is undefined the value
   703  *         of the current test's prefHasUserValue property will be used.
   704  */
   705 function checkPrefHasUserValue(aPrefHasValue) {
   706   let prefHasUserValue = aPrefHasValue === undefined ? gTest.prefHasUserValue
   707                                                      : aPrefHasValue;
   708   is(Services.prefs.prefHasUserValue(gPrefToCheck), prefHasUserValue,
   709      "Checking prefHasUserValue for preference " + gPrefToCheck + " equals " +
   710      (prefHasUserValue ? "true" : "false"));
   711 }
   713 /**
   714  * Checks whether the link is hidden (general background update check error or
   715  * a certificate attribute check error with an update) or not (certificate
   716  * attribute check error without an update) on the errorextra page and that the
   717  * app.update.cert.errors and app.update.backgroundErrors preferences do not
   718  & have a user value.
   719  *
   720  * @param  aShouldBeHidden (optional)
   721  *         The expected value for the label's hidden attribute for the link. If
   722  *         aShouldBeHidden is undefined the value of the current test's
   723  *         shouldBeHidden property will be used.
   724  */
   725 function checkErrorExtraPage(aShouldBeHidden) {
   726   let shouldBeHidden = aShouldBeHidden === undefined ? gTest.shouldBeHidden
   727                                                      : aShouldBeHidden;
   728   is(gWin.document.getElementById("errorExtraLinkLabel").hidden, shouldBeHidden,
   729      "Checking errorExtraLinkLabel hidden attribute equals " +
   730      (shouldBeHidden ? "true" : "false"));
   732   is(gWin.document.getElementById(gTest.displayedTextElem).hidden, false,
   733      "Checking " + gTest.displayedTextElem + " should not be hidden");
   735   ok(!Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_ERRORS),
   736      "Preference " + PREF_APP_UPDATE_CERT_ERRORS + " should not have a " +
   737      "user value");
   739   ok(!Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS),
   740      "Preference " + PREF_APP_UPDATE_BACKGROUNDERRORS + " should not have a " +
   741      "user value");
   742 }
   744 /**
   745  * Gets the update version info for the update url parameters to send to
   746  * update.sjs.
   747  *
   748  * @param  aAppVersion (optional)
   749  *         The application version for the update snippet. If not specified the
   750  *         current application version will be used.
   751  * @param  aPlatformVersion (optional)
   752  *         The platform version for the update snippet. If not specified the
   753  *         current platform version will be used.
   754  * @return The url parameters for the application and platform version to send
   755  *         to update.sjs.
   756  */
   757 function getVersionParams(aAppVersion, aPlatformVersion) {
   758   let appInfo = Services.appinfo;
   759   return "&appVersion=" + (aAppVersion ? aAppVersion : appInfo.version) +
   760          "&platformVersion=" + (aPlatformVersion ? aPlatformVersion
   761                                                  : appInfo.platformVersion);
   762 }
   764 /**
   765  * Gets an application version that is greater than the current application
   766  * version. The version is created by taking the first sequence from the current
   767  * application version and adding 1 to it.
   768  *
   769  * @return A version string greater than the current application version string.
   770  */
   771 function getNewerAppVersion() {
   772   let appVersion = Services.appinfo.version.split(".")[0];
   773   appVersion++;
   774   return appVersion;
   775 }
   777 /**
   778  * Gets a platform version that is greater than the current platform version.
   779  * The version is created by taking the first sequence from the current platform
   780  * version and adding 1 to it.
   781  *
   782  * @return A version string greater than the current platform version string.
   783  */
   784 function getNewerPlatformVersion() {
   785   let platformVersion = Services.appinfo.platformVersion.split(".")[0];
   786   platformVersion++;
   787   return platformVersion;
   788 }
   790 /**
   791  * Verifies that all tests ran.
   792  */
   793 function verifyTestsRan() {
   794   debugDump("entering");
   796   // Return early if there are no tests defined.
   797   if (!TESTS) {
   798     return;
   799   }
   801   gTestCounter = -1;
   802   for (let i = 0; i < TESTS.length; ++i) {
   803     gTestCounter++;
   804     let test = TESTS[i];
   805     let msg = "Checking if TESTS[" + i + "] test was performed... " +
   806               "callback function name = " + gCallback.name + ", " +
   807               "pageid = " + test.pageid;
   808     ok(test.ranTest, msg);
   809   }
   810 }
   812 /**
   813  * Creates a backup of files the tests need to modify so they can be restored to
   814  * the original file when the test has finished and then modifies the files.
   815  */
   816 function setupFiles() {
   817   // Backup the updater-settings.ini file if it exists by moving it.
   818   let baseAppDir = getAppBaseDir();
   819   let updateSettingsIni = baseAppDir.clone();
   820   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
   821   if (updateSettingsIni.exists()) {
   822     updateSettingsIni.moveTo(baseAppDir, FILE_UPDATE_SETTINGS_INI_BAK);
   823   }
   824   updateSettingsIni = baseAppDir.clone();
   825   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
   826   writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
   827 }
   829 /**
   830  * Sets the most common preferences used by tests to values used by the majority
   831  * of the tests and when necessary saves the preference's original values if
   832  * present so they can be set back to the original values when the test has
   833  * finished.
   834  */
   835 function setupPrefs() {
   836   if (DEBUG_AUS_TEST) {
   837     Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true);
   838   }
   840   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) {
   841     gAppUpdateURL = Services.prefs.getCharPref(PREF_APP_UPDATE_URL_OVERRIDE);
   842   }
   844   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) {
   845     gAppUpdateEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_ENABLED);
   846   }
   847   Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
   849   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_METRO_ENABLED)) {
   850     gAppUpdateMetroEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_METRO_ENABLED);
   851   }
   852   Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true);
   854   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) {
   855     gAppUpdateServiceEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED);
   856   }
   857   Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, false);
   859   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) {
   860     gAppUpdateStagingEnabled = Services.prefs.getBoolPref(PREF_APP_UPDATE_STAGING_ENABLED);
   861   }
   862   Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, false);
   864   if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) {
   865     gExtUpdateURL = Services.prefs.getCharPref(PREF_EXTENSIONS_UPDATE_URL);
   866   }
   867   let extUpdateUrl = URL_HTTP_UPDATE_XML + "?addonID=%ITEM_ID%" +
   868                      "&platformVersion=" + getNewerPlatformVersion();
   869   Services.prefs.setCharPref(PREF_EXTENSIONS_UPDATE_URL, extUpdateUrl);
   871   Services.prefs.setIntPref(PREF_APP_UPDATE_IDLETIME, 0);
   872   Services.prefs.setIntPref(PREF_APP_UPDATE_PROMPTWAITTIME, 0);
   873   Services.prefs.setBoolPref(PREF_EXTENSIONS_STRICT_COMPAT, true);
   874   Services.prefs.setCharPref(PREF_EM_HOTFIX_ID, "hotfix" + ADDON_ID_SUFFIX);
   875 }
   877 /**
   878  * Restores files that were backed up for the tests and general file cleanup.
   879  */
   880 function resetFiles() {
   881   // Restore the backed up updater-settings.ini if it exists.
   882   let baseAppDir = getAppBaseDir();
   883   let updateSettingsIni = baseAppDir.clone();
   884   updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI_BAK);
   885   if (updateSettingsIni.exists()) {
   886     updateSettingsIni.moveTo(baseAppDir, FILE_UPDATE_SETTINGS_INI);
   887   }
   889   // Not being able to remove the "updated" directory will not adversely affect
   890   // subsequent tests so wrap it in a try block and don't test whether its
   891   // removal was successful.
   892   let updatedDir = getUpdatedDir();
   893   if (updatedDir.exists()) {
   894     try {
   895       removeDirRecursive(updatedDir);
   896     }
   897     catch (e) {
   898       dump("Unable to remove directory\n" +
   899            "path: " + updatedDir.path + "\n" +
   900            "Exception: " + e + "\n");
   901     }
   902   }
   903 }
   905 /**
   906  * Resets the most common preferences used by tests to their original values.
   907  */
   908 function resetPrefs() {
   909   if (gAppUpdateURL !== undefined) {
   910     Services.prefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, gAppUpdateURL);
   911   }
   912   else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_OVERRIDE)) {
   913     Services.prefs.clearUserPref(PREF_APP_UPDATE_URL_OVERRIDE);
   914   }
   916   if (gAppUpdateURLDefault) {
   917     gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_URL, gAppUpdateURLDefault);
   918   }
   920   if (gAppUpdateEnabled !== undefined) {
   921     Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, gAppUpdateEnabled);
   922   }
   923   else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_ENABLED)) {
   924     Services.prefs.clearUserPref(PREF_APP_UPDATE_ENABLED);
   925   }
   927   if (gAppUpdateMetroEnabled !== undefined) {
   928     Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, gAppUpdateMetroEnabled);
   929   }
   930   else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_METRO_ENABLED)) {
   931     Services.prefs.clearUserPref(PREF_APP_UPDATE_METRO_ENABLED);
   932   }
   934   if (gAppUpdateServiceEnabled !== undefined) {
   935     Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, gAppUpdateServiceEnabled);
   936   }
   937   else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SERVICE_ENABLED)) {
   938     Services.prefs.clearUserPref(PREF_APP_UPDATE_SERVICE_ENABLED);
   939   }
   941   if (gAppUpdateStagingEnabled !== undefined) {
   942     Services.prefs.setBoolPref(PREF_APP_UPDATE_STAGING_ENABLED, gAppUpdateStagingEnabled);
   943   }
   944   else if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_STAGING_ENABLED)) {
   945     Services.prefs.clearUserPref(PREF_APP_UPDATE_STAGING_ENABLED);
   946   }
   948   if (gExtUpdateURL !== undefined) {
   949     Services.prefs.setCharPref(PREF_EXTENSIONS_UPDATE_URL, gExtUpdateURL);
   950   }
   951   else if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_UPDATE_URL)) {
   952     Services.prefs.clearUserPref(PREF_EXTENSIONS_UPDATE_URL);
   953   }
   955   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_IDLETIME)) {
   956     Services.prefs.clearUserPref(PREF_APP_UPDATE_IDLETIME);
   957   }
   959   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_PROMPTWAITTIME)) {
   960     Services.prefs.clearUserPref(PREF_APP_UPDATE_PROMPTWAITTIME);
   961   }
   963   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_URL_DETAILS)) {
   964     Services.prefs.clearUserPref(PREF_APP_UPDATE_URL_DETAILS);
   965   }
   967   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_SHOW_INSTALLED_UI)) {
   968     Services.prefs.clearUserPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI);
   969   }
   971   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED)) {
   972     Services.prefs.clearUserPref(PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED);
   973   }
   975   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_LOG)) {
   976     Services.prefs.clearUserPref(PREF_APP_UPDATE_LOG);
   977   }
   979   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_ERRORS)) {
   980     Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_ERRORS);
   981   }
   983   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_MAXERRORS)) {
   984     Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_MAXERRORS);
   985   }
   987   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDERRORS)) {
   988     Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDERRORS);
   989   }
   991   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_BACKGROUNDMAXERRORS)) {
   992     Services.prefs.clearUserPref(PREF_APP_UPDATE_BACKGROUNDMAXERRORS);
   993   }
   995   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_INVALID_ATTR_NAME)) {
   996     Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_INVALID_ATTR_NAME);
   997   }
   999   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_REQUIREBUILTIN)) {
  1000     Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_REQUIREBUILTIN);
  1003   if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_CHECKATTRS)) {
  1004     Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_CHECKATTRS);
  1007   try {
  1008     CERT_ATTRS.forEach(function(aCertAttrName) {
  1009       Services.prefs.clearUserPref(PREF_APP_UPDATE_CERTS_BRANCH + "1." +
  1010                                    aCertAttrName);
  1011     });
  1013   catch (e) {
  1016   try {
  1017     Services.prefs.deleteBranch(PREF_APP_UPDATE_NEVER_BRANCH);
  1019   catch(e) {
  1022   if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_STRICT_COMPAT)) {
  1023 		Services.prefs.clearUserPref(PREF_EXTENSIONS_STRICT_COMPAT);
  1026   if (Services.prefs.prefHasUserValue(PREF_EM_HOTFIX_ID)) {
  1027     Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
  1031 function setupTimer(aTestTimeout) {
  1032   gTestTimeout = aTestTimeout;
  1033   if (gTimeoutTimer) {
  1034     gTimeoutTimer.cancel();
  1035     gTimeoutTimer = null;
  1037   gTimeoutTimer = AUS_Cc["@mozilla.org/timer;1"].
  1038                   createInstance(AUS_Ci.nsITimer);
  1039   gTimeoutTimer.initWithCallback(finishTestTimeout, gTestTimeout,
  1040                                  AUS_Ci.nsITimer.TYPE_ONE_SHOT);
  1043 /**
  1044  * Disables pre-existing add-ons so they don't interfere with the tests,
  1045  * installs the test add-ons, sets the noupdate test add-ons' userDisabled value
  1046  * for the test, and calls the callback specified in the aCallback parameter. If
  1047  * the app.update.test.disabledAddons has a user value then setting the noupdate
  1048  * test add-ons' userDisabled value for the test is the only thing that is done.
  1050  * @param  aCallback
  1051  *         A callback to call after all operations have completed.
  1052  */
  1053 function setupAddons(aCallback) {
  1054   debugDump("entering");
  1056   // Sets the appropriate userDisabled value for the noupdate test add-ons based
  1057   // on the value of gDisableNoUpdateAddon and calls the callback specified in
  1058   // setupAddons aCallback parameter.
  1059   function setNoUpdateAddonsDisabledState() {
  1060     AddonManager.getAllAddons(function(aAddons) {
  1061       aAddons.forEach(function(aAddon) {
  1062         if (aAddon.name.indexOf("noupdate") != 0)
  1063           return;
  1065         if (gDisableNoUpdateAddon) {
  1066           if (!aAddon.userDisabled) {
  1067             aAddon.userDisabled = true;
  1070         else {
  1071           if (aAddon.userDisabled) {
  1072             aAddon.userDisabled = false;
  1075       });
  1076       // Start the timout timer before the update window is displayed so it can
  1077       // clean up tests that don't successfully display the update window.
  1078       setupTimer(gTestTimeout);
  1079       aCallback();
  1080     });
  1083   // If the app.update.test.disabledAddons preference exists the pre-existing
  1084   // add-ons have already been disabled so they don't interfere with the tests,
  1085   // the test add-ons have already been installed, and the only thing that needs
  1086   // to be done is setting the appropriate userDisabled value for the noupdate
  1087   // test add-ons.
  1088   if (Services.prefs.prefHasUserValue(PREF_DISABLEDADDONS)) {
  1089     setNoUpdateAddonsDisabledState();
  1090     return;
  1093   // Disable all pre-existing enabled addons so they don't interfere with the
  1094   // tests.
  1095   AddonManager.getAllAddons(function(aAddons) {
  1096     let disabledAddons = [];
  1097     aAddons.forEach(function(aAddon) {
  1098       // If an addon's type equals plugin it is skipped since
  1099       // checking plugins compatibility information isn't supported at this
  1100       // time (also see bug 566787). Also, SCOPE_APPLICATION add-ons are
  1101       // excluded by app update so there is no reason to disable them.
  1102       if (aAddon.type != "plugin" && !aAddon.appDisabled &&
  1103           !aAddon.userDisabled &&
  1104           aAddon.scope != AddonManager.SCOPE_APPLICATION) {
  1105         disabledAddons.push(aAddon);
  1106         aAddon.userDisabled = true;
  1108     });
  1109     // If there are no pre-existing add-ons the preference value will be an
  1110     // empty string.
  1111     Services.prefs.setCharPref(PREF_DISABLEDADDONS, disabledAddons.join(" "));
  1113     // Install the test add-ons.
  1114     let xpiFiles = getTestAddonXPIFiles();
  1115     let xpiCount = xpiFiles.length;
  1116     let installs = [];
  1117     xpiFiles.forEach(function(aFile) {
  1118       AddonManager.getInstallForFile(aFile, function(aInstall) {
  1119         if (!aInstall) {
  1120           throw "No AddonInstall created for " + aFile.path;
  1123         installs.push(aInstall);
  1125         if (--xpiCount == 0) {
  1126           let installCount = installs.length;
  1127           function installCompleted(aInstall) {
  1128             aInstall.removeListener(listener);
  1130             if (getAddonTestType(aInstall.addon.name) == "userdisabled") {
  1131               aInstall.addon.userDisabled = true;
  1133             if (--installCount == 0) {
  1134               setNoUpdateAddonsDisabledState();
  1138           let listener = {
  1139             onDownloadFailed: installCompleted,
  1140             onDownloadCancelled: installCompleted,
  1141             onInstallFailed: installCompleted,
  1142             onInstallCancelled: installCompleted,
  1143             onInstallEnded: installCompleted
  1144           };
  1146           installs.forEach(function(aInstall) {
  1147             aInstall.addListener(listener);
  1148             aInstall.install();
  1149           });
  1151       });
  1152     });
  1153   });
  1156 /**
  1157  * Uninstalls the test add-ons, enables add-ons that were disabled when the
  1158  * test started, and calls the callback specified in the aCallback parameter.
  1160  * @param  aCallback
  1161  *         A callback to call after all operations have completed.
  1162  */
  1163 function resetAddons(aCallback) {
  1164   debugDump("entering");
  1165   // If test_9999_cleanup.xul is ran by itself then the test add-ons will not
  1166   // have been installed and any pre-existing add-ons will not have been
  1167   // disabled so return early.
  1168   if (!Services.prefs.prefHasUserValue(PREF_DISABLEDADDONS)) {
  1169     debugDump("preference " + PREF_DISABLEDADDONS + " doesn't exist... " +
  1170               "returning early");
  1171     aCallback();
  1172     return;
  1175   // Uninstall the test add-ons.
  1176   let count = TEST_ADDONS.length;
  1177   function uninstallCompleted(aAddon) {
  1178     if (--count == 0) {
  1179       AddonManager.removeAddonListener(listener);
  1181       // Enable the pre-existing add-ons that were disabled so they wouldn't
  1182       // interfere with the tests.
  1183       let disabledAddons = Services.prefs.getCharPref(PREF_DISABLEDADDONS).split(" ");
  1184       Services.prefs.clearUserPref(PREF_DISABLEDADDONS);
  1185       AddonManager.getAllAddons(function(aAddons) {
  1186         aAddons.forEach(function(aAddon) {
  1187           if (disabledAddons.indexOf(aAddon.id)) {
  1188             aAddon.userDisabled = false;
  1190         });
  1191         aCallback();
  1192       });
  1196   let listener = {
  1197     onUninstalled: uninstallCompleted
  1198   };
  1200   AddonManager.addAddonListener(listener);
  1201   TEST_ADDONS.forEach(function(aName) {
  1202     AddonManager.getAddonByID(aName + ADDON_ID_SUFFIX, function(aAddon) {
  1203       aAddon.uninstall();
  1204     });
  1205   });
  1208 /**
  1209  * Helper function to get the string before the '_' character in an add-on's
  1210  * name or id which is used to determine the add-on test type used by the tests.
  1212  * @param  aName
  1213  *         The test add-on's name or id.
  1214  * @return The string before the '_' character in the string passed in the aName
  1215  *         parameter.
  1216  */
  1217 function getAddonTestType(aName) {
  1218   return aName.split("_")[0];
  1221 /**
  1222  * Helper function to create add-on xpi files for the default test add-ons.
  1224  * @return An array with each member being an nsILocalFile for an add-on XPI
  1225  *         file.
  1226  */
  1227 function getTestAddonXPIFiles() {
  1228   let addonPrepDir = Services.dirsvc.get(NS_APP_USER_PROFILE_50_DIR,
  1229                                          AUS_Ci.nsILocalFile);
  1230   addonPrepDir.append(ADDON_PREP_DIR);
  1232   let bootstrap = addonPrepDir.clone();
  1233   bootstrap.append("bootstrap.js");
  1234   // If a previous test has already created bootstrap.js don't create it again.
  1235   if (!bootstrap.exists()) {
  1236     let bootstrapContents = "function install(data, reason){ }\n" +
  1237                             "function startup(data, reason){ }\n" +
  1238                             "function shutdown(data, reason){ }\n" +
  1239                             "function uninstall(data, reason){ }\n";
  1240     writeFile(bootstrap, bootstrapContents);
  1243   let installRDF = addonPrepDir.clone();
  1244   installRDF.append("install.rdf");
  1246   let xpiFiles = [];
  1247   TEST_ADDONS.forEach(function(aName) {
  1248     let xpiFile = addonPrepDir.clone();
  1249     xpiFile.append(aName + ".xpi");
  1251     if (installRDF.exists())
  1252       installRDF.remove(false);
  1253     writeFile(installRDF, getInstallRDFString(aName));
  1254     gZipW.open(xpiFile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE);
  1255     gZipW.addEntryFile(installRDF.leafName,
  1256                        AUS_Ci.nsIZipWriter.COMPRESSION_DEFAULT, installRDF,
  1257                        false);
  1258     gZipW.addEntryFile(bootstrap.leafName,
  1259                        AUS_Ci.nsIZipWriter.COMPRESSION_DEFAULT, bootstrap,
  1260                        false);
  1261     gZipW.close();
  1262     xpiFiles.push(xpiFile);
  1263   });
  1265   return xpiFiles;
  1268 /**
  1269  * Helper function to gets the string representation of the contents of the
  1270  * add-on's install.rdf file.
  1272  * @param  aName
  1273  *         The string to use for the add-on's name which is also used to
  1274  *         construct the local-part in RFC 5322 format of the add-on's ID.
  1275  * @return A string representation of the contents of the add-on's install.rdf
  1276  *         file.
  1277  */
  1278 function getInstallRDFString(aName) {
  1279   let maxVersion = Services.appinfo.platformVersion;
  1280   switch (getAddonTestType(aName)) {
  1281     case "compatible":
  1282       maxVersion = getNewerPlatformVersion();
  1283       break;
  1284     case "appdisabled":
  1285       maxVersion = "0.1";
  1286       break;
  1289   return "<?xml version=\"1.0\"?>\n" +
  1290          "<RDF xmlns=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n" +
  1291          "  xmlns:em=\"http://www.mozilla.org/2004/em-rdf#\">\n" +
  1292          "  <Description about=\"urn:mozilla:install-manifest\">\n" +
  1293          "    <em:id>" + aName + ADDON_ID_SUFFIX + "</em:id>\n" +
  1294          "    <em:version>1.0</em:version>\n" +
  1295          "    <em:bootstrap>true</em:bootstrap>\n" +
  1296          "    <em:name>" + aName + "</em:name>\n" +
  1297          "    <em:description>Test Description</em:description>\n" +
  1298          "    <em:targetApplication>\n" +
  1299          "      <Description>\n" +
  1300          "        <em:id>toolkit@mozilla.org</em:id>\n" +
  1301          "        <em:minVersion>undefined</em:minVersion>\n" +
  1302          "        <em:maxVersion>" + maxVersion + "</em:maxVersion>\n" +
  1303          "      </Description>\n" +
  1304          "    </em:targetApplication>\n" +
  1305          "  </Description>\n" +
  1306          "</RDF>";
  1309 /**
  1310  * Closes the update window if it is open and causes the test to fail if an
  1311  * update window is found.
  1313  * @return true if an update window was found, otherwise false.
  1314  */
  1315 function closeUpdateWindow() {
  1316   let updateWindow = getUpdateWindow();
  1317   if (!updateWindow)
  1318     return false;
  1320   ok(false, "Found an existing Update Window from the current or a previous " +
  1321             "test... attempting to close it.");
  1322   updateWindow.close();
  1323   return true;
  1326 /**
  1327  * Gets the update window.
  1329  * @return The nsIDOMWindow for the Update Window if it is open and null
  1330  *         if it isn't.
  1331  */
  1332 function getUpdateWindow() {
  1333   return Services.wm.getMostRecentWindow(UPDATE_WINDOW_NAME);
  1336 /**
  1337  * Helper for background check errors.
  1338  */
  1339 var errorsPrefObserver = {
  1340   observedPref: null,
  1341   maxErrorPref: null,
  1343   /**
  1344    * Sets up a preference observer and sets the associated maximum errors
  1345    * preference used for background notification.
  1347    * @param  aObservePref
  1348    *         The preference to observe.
  1349    * @param  aMaxErrorPref
  1350    *         The maximum errors preference.
  1351    * @param  aMaxErrorCount
  1352    *         The value to set the app.update.cert.maxErrors preference to.
  1353    */
  1354   init: function(aObservePref, aMaxErrorPref, aMaxErrorCount) {
  1355     this.observedPref = aObservePref;
  1356     this.maxErrorPref = aMaxErrorPref;
  1358     let maxErrors = aMaxErrorCount ? aMaxErrorCount : 2;
  1359     Services.prefs.setIntPref(aMaxErrorPref, maxErrors);
  1360     Services.prefs.addObserver(aObservePref, this, false);
  1361   },
  1363   /**
  1364    * Preference observer for the preference specified in |this.observedPref|.
  1365    */
  1366   observe: function XPI_observe(aSubject, aTopic, aData) {
  1367     if (aData == this.observedPref) {
  1368       let errCount = Services.prefs.getIntPref(this.observedPref);
  1369       let errMax = Services.prefs.getIntPref(this.maxErrorPref);
  1370       if (errCount >= errMax) {
  1371         debugDump("removing pref observer");
  1372         Services.prefs.removeObserver(this.observedPref, this);
  1374       else {
  1375         debugDump("notifying AUS");
  1376         SimpleTest.executeSoon(function() {
  1377           gAUS.notify(null);
  1378         });
  1382 };
  1384 /**
  1385  * nsIObserver for receiving window open and close notifications.
  1386  */
  1387 var gWindowObserver = {
  1388   observe: function WO_observe(aSubject, aTopic, aData) {
  1389     let win = aSubject.QueryInterface(AUS_Ci.nsIDOMEventTarget);
  1391     if (aTopic == "domwindowclosed") {
  1392       if (win.location != URI_UPDATE_PROMPT_DIALOG) {
  1393         debugDump("domwindowclosed event for window not being tested - " +
  1394                   "location: " + win.location + "... returning early");
  1395         return;
  1397       // Allow tests the ability to provide their own function (it must be
  1398       // named finishTest) for finishing the test.
  1399       try {
  1400         finishTest();
  1402       catch (e) {
  1403         finishTestDefault();
  1405       return;
  1408     win.addEventListener("load", function WO_observe_onLoad() {
  1409       win.removeEventListener("load", WO_observe_onLoad, false);
  1410       // Ignore windows other than the update UI window.
  1411       if (win.location != URI_UPDATE_PROMPT_DIALOG) {
  1412         debugDump("load event for window not being tested - location: " +
  1413                   win.location + "... returning early");
  1414         return;
  1417       // The first wizard page should always be the dummy page.
  1418       let pageid = win.document.documentElement.currentPage.pageid;
  1419       if (pageid != PAGEID_DUMMY) {
  1420         // This should never happen but if it does this will provide a clue
  1421         // for diagnosing the cause.
  1422         ok(false, "Unexpected load event - pageid got: " + pageid +
  1423            ", expected: " + PAGEID_DUMMY + "... returning early");
  1424         return;
  1427       gWin = win;
  1428       gDocElem = gWin.document.documentElement;
  1429       gDocElem.addEventListener("pageshow", onPageShowDefault, false);
  1430     }, false);
  1432 };

mercurial