Sat, 03 Jan 2015 20:18:00 +0100
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);
1001 }
1003 if (Services.prefs.prefHasUserValue(PREF_APP_UPDATE_CERT_CHECKATTRS)) {
1004 Services.prefs.clearUserPref(PREF_APP_UPDATE_CERT_CHECKATTRS);
1005 }
1007 try {
1008 CERT_ATTRS.forEach(function(aCertAttrName) {
1009 Services.prefs.clearUserPref(PREF_APP_UPDATE_CERTS_BRANCH + "1." +
1010 aCertAttrName);
1011 });
1012 }
1013 catch (e) {
1014 }
1016 try {
1017 Services.prefs.deleteBranch(PREF_APP_UPDATE_NEVER_BRANCH);
1018 }
1019 catch(e) {
1020 }
1022 if (Services.prefs.prefHasUserValue(PREF_EXTENSIONS_STRICT_COMPAT)) {
1023 Services.prefs.clearUserPref(PREF_EXTENSIONS_STRICT_COMPAT);
1024 }
1026 if (Services.prefs.prefHasUserValue(PREF_EM_HOTFIX_ID)) {
1027 Services.prefs.clearUserPref(PREF_EM_HOTFIX_ID);
1028 }
1029 }
1031 function setupTimer(aTestTimeout) {
1032 gTestTimeout = aTestTimeout;
1033 if (gTimeoutTimer) {
1034 gTimeoutTimer.cancel();
1035 gTimeoutTimer = null;
1036 }
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);
1041 }
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.
1049 *
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;
1068 }
1069 }
1070 else {
1071 if (aAddon.userDisabled) {
1072 aAddon.userDisabled = false;
1073 }
1074 }
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 });
1081 }
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;
1091 }
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;
1107 }
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;
1121 }
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;
1132 }
1133 if (--installCount == 0) {
1134 setNoUpdateAddonsDisabledState();
1135 }
1136 }
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 });
1150 }
1151 });
1152 });
1153 });
1154 }
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.
1159 *
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;
1173 }
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;
1189 }
1190 });
1191 aCallback();
1192 });
1193 }
1194 }
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 });
1206 }
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.
1211 *
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];
1219 }
1221 /**
1222 * Helper function to create add-on xpi files for the default test add-ons.
1223 *
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);
1241 }
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;
1266 }
1268 /**
1269 * Helper function to gets the string representation of the contents of the
1270 * add-on's install.rdf file.
1271 *
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;
1287 }
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>";
1307 }
1309 /**
1310 * Closes the update window if it is open and causes the test to fail if an
1311 * update window is found.
1312 *
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;
1324 }
1326 /**
1327 * Gets the update window.
1328 *
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);
1334 }
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.
1346 *
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);
1373 }
1374 else {
1375 debugDump("notifying AUS");
1376 SimpleTest.executeSoon(function() {
1377 gAUS.notify(null);
1378 });
1379 }
1380 }
1381 }
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;
1396 }
1397 // Allow tests the ability to provide their own function (it must be
1398 // named finishTest) for finishing the test.
1399 try {
1400 finishTest();
1401 }
1402 catch (e) {
1403 finishTestDefault();
1404 }
1405 return;
1406 }
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;
1415 }
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;
1425 }
1427 gWin = win;
1428 gDocElem = gWin.document.documentElement;
1429 gDocElem.addEventListener("pageshow", onPageShowDefault, false);
1430 }, false);
1431 }
1432 };