diff options
Diffstat (limited to 'toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js')
-rw-r--r-- | toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js | 4047 |
1 files changed, 0 insertions, 4047 deletions
diff --git a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js b/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js deleted file mode 100644 index 9a9610dda..000000000 --- a/toolkit/mozapps/update/tests/data/xpcshellUtilsAUS.js +++ /dev/null @@ -1,4047 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -/** - * Test log warnings that happen before the test has started - * "Couldn't get the user appdata directory. Crash events may not be produced." - * in nsExceptionHandler.cpp (possibly bug 619104) - * - * Test log warnings that happen after the test has finished - * "OOPDeinit() without successful OOPInit()" in nsExceptionHandler.cpp - * (bug 619104) - * "XPCOM objects created/destroyed from static ctor/dtor" in nsTraceRefcnt.cpp - * (possibly bug 457479) - * - * Other warnings printed to the test logs - * "site security information will not be persisted" in - * nsSiteSecurityService.cpp and the error in nsSystemInfo.cpp preceding this - * error are due to not having a profile when running some of the xpcshell - * tests. Since most xpcshell tests also log these errors these tests don't - * call do_get_profile unless necessary for the test. - * The "This method is lossy. Use GetCanonicalPath !" warning on Windows in - * nsLocalFileWin.cpp is from the call to GetNSSProfilePath in - * nsNSSComponent.cpp due to it using GetNativeCanonicalPath. - * "!mMainThread" in nsThreadManager.cpp are due to using timers and it might be - * possible to fix some or all of these in the test itself. - * "NS_FAILED(rv)" in nsThreadUtils.cpp are due to using timers and it might be - * possible to fix some or all of these in the test itself. - */ - -'use strict'; -/* eslint-disable no-undef */ - -const { classes: Cc, interfaces: Ci, manager: Cm, results: Cr, - utils: Cu } = Components; - -/* global INSTALL_LOCALE, MOZ_APP_NAME, BIN_SUFFIX, MOZ_APP_VENDOR */ -/* global MOZ_APP_BASENAME, APP_BIN_SUFFIX, APP_INFO_NAME, APP_INFO_VENDOR */ -/* global IS_WIN, IS_MACOSX, IS_UNIX, MOZ_VERIFY_MAR_SIGNATURE */ -/* global IS_AUTHENTICODE_CHECK_ENABLED */ -load("../data/xpcshellConstantsPP.js"); - -function getLogSuffix() { - if (IS_WIN) { - return "_win"; - } - if (IS_MACOSX) { - return "_mac"; - } - return "_linux"; -} - -Cu.import("resource://gre/modules/Services.jsm", this); -Cu.import("resource://gre/modules/ctypes.jsm", this); - -const DIR_MACOS = IS_MACOSX ? "Contents/MacOS/" : ""; -const DIR_RESOURCES = IS_MACOSX ? "Contents/Resources/" : ""; -const TEST_FILE_SUFFIX = IS_MACOSX ? "_mac" : ""; -const FILE_COMPLETE_MAR = "complete" + TEST_FILE_SUFFIX + ".mar"; -const FILE_PARTIAL_MAR = "partial" + TEST_FILE_SUFFIX + ".mar"; -const FILE_COMPLETE_PRECOMPLETE = "complete_precomplete" + TEST_FILE_SUFFIX; -const FILE_PARTIAL_PRECOMPLETE = "partial_precomplete" + TEST_FILE_SUFFIX; -const FILE_COMPLETE_REMOVEDFILES = "complete_removed-files" + TEST_FILE_SUFFIX; -const FILE_PARTIAL_REMOVEDFILES = "partial_removed-files" + TEST_FILE_SUFFIX; -const FILE_UPDATE_IN_PROGRESS_LOCK = "updated.update_in_progress.lock"; -const COMPARE_LOG_SUFFIX = getLogSuffix(); -const LOG_COMPLETE_SUCCESS = "complete_log_success" + COMPARE_LOG_SUFFIX; -const LOG_PARTIAL_SUCCESS = "partial_log_success" + COMPARE_LOG_SUFFIX; -const LOG_PARTIAL_FAILURE = "partial_log_failure" + COMPARE_LOG_SUFFIX; -const LOG_REPLACE_SUCCESS = "replace_log_success"; - -const USE_EXECV = IS_UNIX && !IS_MACOSX; - -const URL_HOST = "http://localhost"; - -const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX; -const FILE_COMPLETE_EXE = "complete.exe"; -const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX; -const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe"; -const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe"; -const FILE_OLD_VERSION_MAR = "old_version.mar"; -const FILE_PARTIAL_EXE = "partial.exe"; -const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX; -const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar"; - -const PERFORMING_STAGED_UPDATE = "Performing a staged update"; -const CALL_QUIT = "calling QuitProgressUI"; -const REMOVE_OLD_DIST_DIR = "removing old distribution directory"; -const MOVE_OLD_DIST_DIR = "Moving old distribution directory to new location"; -const ERR_UPDATE_IN_PROGRESS = "Update already in progress! Exiting"; -const ERR_RENAME_FILE = "rename_file: failed to rename file"; -const ERR_ENSURE_COPY = "ensure_copy: failed to copy the file"; -const ERR_UNABLE_OPEN_DEST = "unable to open destination file"; -const ERR_BACKUP_DISCARD = "backup_discard: unable to remove"; -const ERR_MOVE_DESTDIR_7 = "Moving destDir to tmpDir failed, err: 7"; -const ERR_BACKUP_CREATE_7 = "backup_create failed: 7"; -const ERR_LOADSOURCEFILE_FAILED = "LoadSourceFile failed"; - -const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result."; - -// Typical end of a message when calling assert -const MSG_SHOULD_EQUAL = " should equal the expected value"; -const MSG_SHOULD_EXIST = "the file or directory should exist"; -const MSG_SHOULD_NOT_EXIST = "the file or directory should not exist"; - -// All we care about is that the last modified time has changed so that Mac OS -// X Launch Services invalidates its cache so the test allows up to one minute -// difference in the last modified time. -const MAC_MAX_TIME_DIFFERENCE = 60000; - -// How many of do_execute_soon calls to wait before the test is aborted. -const MAX_TIMEOUT_RUNS = 20000; - -// Time in seconds the helper application should sleep before exiting. The -// helper can also be made to exit by writing |finish| to its input file. -const HELPER_SLEEP_TIMEOUT = 180; - -// Maximum number of milliseconds the process that is launched can run before -// the test will try to kill it. -const APP_TIMER_TIMEOUT = 120000; - -// How many of do_timeout calls using FILE_IN_USE_TIMEOUT_MS to wait before the -// test is aborted. -const FILE_IN_USE_MAX_TIMEOUT_RUNS = 60; -const FILE_IN_USE_TIMEOUT_MS = 1000; - -const PIPE_TO_NULL = IS_WIN ? ">nul" : "> /dev/null 2>&1"; - -const LOG_FUNCTION = do_print; - -const gHTTPHandlerPath = "updates.xml"; - -// This default value will be overridden when using the http server. -var gURLData = URL_HOST + "/"; - -var gTestID; - -var gTestserver; - -var gRegisteredServiceCleanup; - -var gCheckFunc; -var gResponseBody; -var gResponseStatusCode = 200; -var gRequestURL; -var gUpdateCount; -var gUpdates; -var gStatusCode; -var gStatusText; -var gStatusResult; - -var gProcess; -var gAppTimer; -var gHandle; - -var gGREDirOrig; -var gGREBinDirOrig; -var gAppDirOrig; - -// Variables are used instead of contants so tests can override these values if -// necessary. -var gCallbackBinFile = "callback_app" + BIN_SUFFIX; -var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; -var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX; -var gSvcOriginalLogContents; -var gUseTestAppDir = true; -// Some update staging failures can remove the update. This allows tests to -// specify that the status file and the active update should not be checked -// after an update is staged. -var gStagingRemovedUpdate = false; - -var gTimeoutRuns = 0; -var gFileInUseTimeoutRuns = 0; - -// Environment related globals -var gShouldResetEnv = undefined; -var gAddedEnvXRENoWindowsCrashDialog = false; -var gEnvXPCOMDebugBreak; -var gEnvXPCOMMemLeakLog; -var gEnvDyldLibraryPath; -var gEnvLdLibraryPath; -var gASanOptions; - -// Set to true to log additional information for debugging. To log additional -// information for an individual test set DEBUG_AUS_TEST to true in the test's -// run_test function. -var DEBUG_AUS_TEST = true; - -const DATA_URI_SPEC = Services.io.newFileURI(do_get_file("../data", false)).spec; -/* import-globals-from ../data/shared.js */ -Services.scriptloader.loadSubScript(DATA_URI_SPEC + "shared.js", this); - -var gTestFiles = []; -var gTestDirs = []; - -// Common files for both successful and failed updates. -var gTestFilesCommon = [ - { - description: "Should never change", - fileName: FILE_UPDATE_SETTINGS_INI, - relPathDir: DIR_RESOURCES, - originalContents: UPDATE_SETTINGS_CONTENTS, - compareContents: UPDATE_SETTINGS_CONTENTS, - originalFile: null, - compareFile: null, - originalPerms: 0o767, - comparePerms: 0o767 - }, { - description: "Should never change", - fileName: "channel-prefs.js", - relPathDir: DIR_RESOURCES + "defaults/pref/", - originalContents: "ShouldNotBeReplaced\n", - compareContents: "ShouldNotBeReplaced\n", - originalFile: null, - compareFile: null, - originalPerms: 0o767, - comparePerms: 0o767 - }]; - - // Files for a complete successful update. This can be used for a complete - // failed update by calling setTestFilesAndDirsForFailure. -var gTestFilesCompleteSuccess = [ - { - description: "Added by update.manifest (add)", - fileName: "precomplete", - relPathDir: DIR_RESOURCES, - originalContents: null, - compareContents: null, - originalFile: FILE_PARTIAL_PRECOMPLETE, - compareFile: FILE_COMPLETE_PRECOMPLETE, - originalPerms: 0o666, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "searchpluginstext0", - relPathDir: DIR_RESOURCES + "searchplugins/", - originalContents: "ToBeReplacedWithFromComplete\n", - compareContents: "FromComplete\n", - originalFile: null, - compareFile: null, - originalPerms: 0o775, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "searchpluginspng1.png", - relPathDir: DIR_RESOURCES + "searchplugins/", - originalContents: null, - compareContents: null, - originalFile: null, - compareFile: "complete.png", - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "searchpluginspng0.png", - relPathDir: DIR_RESOURCES + "searchplugins/", - originalContents: null, - compareContents: null, - originalFile: "partial.png", - compareFile: "complete.png", - originalPerms: 0o666, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "removed-files", - relPathDir: DIR_RESOURCES, - originalContents: null, - compareContents: null, - originalFile: FILE_PARTIAL_REMOVEDFILES, - compareFile: FILE_COMPLETE_REMOVEDFILES, - originalPerms: 0o666, - comparePerms: 0o644 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions1text0", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents: null, - compareContents: "FromComplete\n", - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions1png1.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents: null, - compareContents: null, - originalFile: "partial.png", - compareFile: "complete.png", - originalPerms: 0o666, - comparePerms: 0o644 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions1png0.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents: null, - compareContents: null, - originalFile: null, - compareFile: "complete.png", - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions0text0", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents: "ToBeReplacedWithFromComplete\n", - compareContents: "FromComplete\n", - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions0png1.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents: null, - compareContents: null, - originalFile: null, - compareFile: "complete.png", - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions0png0.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents: null, - compareContents: null, - originalFile: null, - compareFile: "complete.png", - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "exe0.exe", - relPathDir: DIR_MACOS, - originalContents: null, - compareContents: null, - originalFile: FILE_HELPER_BIN, - compareFile: FILE_COMPLETE_EXE, - originalPerms: 0o777, - comparePerms: 0o755 - }, { - description: "Added by update.manifest (add)", - fileName: "10text0", - relPathDir: DIR_RESOURCES + "1/10/", - originalContents: "ToBeReplacedWithFromComplete\n", - compareContents: "FromComplete\n", - originalFile: null, - compareFile: null, - originalPerms: 0o767, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "0exe0.exe", - relPathDir: DIR_RESOURCES + "0/", - originalContents: null, - compareContents: null, - originalFile: FILE_HELPER_BIN, - compareFile: FILE_COMPLETE_EXE, - originalPerms: 0o777, - comparePerms: 0o755 - }, { - description: "Added by update.manifest (add)", - fileName: "00text1", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: "ToBeReplacedWithFromComplete\n", - compareContents: "FromComplete\n", - originalFile: null, - compareFile: null, - originalPerms: 0o677, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "00text0", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: "ToBeReplacedWithFromComplete\n", - compareContents: "FromComplete\n", - originalFile: null, - compareFile: null, - originalPerms: 0o775, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "00png0.png", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: null, - compareContents: null, - originalFile: null, - compareFile: "complete.png", - originalPerms: 0o776, - comparePerms: 0o644 - }, { - description: "Removed by precomplete (remove)", - fileName: "20text0", - relPathDir: DIR_RESOURCES + "2/20/", - originalContents: "ToBeDeleted\n", - compareContents: null, - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: null - }, { - description: "Removed by precomplete (remove)", - fileName: "20png0.png", - relPathDir: DIR_RESOURCES + "2/20/", - originalContents: "ToBeDeleted\n", - compareContents: null, - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: null - }]; - -// Concatenate the common files to the end of the array. -gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon); - -// Files for a partial successful update. This can be used for a partial failed -// update by calling setTestFilesAndDirsForFailure. -var gTestFilesPartialSuccess = [ - { - description: "Added by update.manifest (add)", - fileName: "precomplete", - relPathDir: DIR_RESOURCES, - originalContents: null, - compareContents: null, - originalFile: FILE_COMPLETE_PRECOMPLETE, - compareFile: FILE_PARTIAL_PRECOMPLETE, - originalPerms: 0o666, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "searchpluginstext0", - relPathDir: DIR_RESOURCES + "searchplugins/", - originalContents: "ToBeReplacedWithFromPartial\n", - compareContents: "FromPartial\n", - originalFile: null, - compareFile: null, - originalPerms: 0o775, - comparePerms: 0o644 - }, { - description: "Patched by update.manifest if the file exists (patch-if)", - fileName: "searchpluginspng1.png", - relPathDir: DIR_RESOURCES + "searchplugins/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o666, - comparePerms: 0o666 - }, { - description: "Patched by update.manifest if the file exists (patch-if)", - fileName: "searchpluginspng0.png", - relPathDir: DIR_RESOURCES + "searchplugins/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o666, - comparePerms: 0o666 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions1text0", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents: null, - compareContents: "FromPartial\n", - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Patched by update.manifest if the parent directory exists (patch-if)", - fileName: "extensions1png1.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o666, - comparePerms: 0o666 - }, { - description: "Patched by update.manifest if the parent directory exists (patch-if)", - fileName: "extensions1png0.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions1/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o666, - comparePerms: 0o666 - }, { - description: "Added by update.manifest if the parent directory exists (add-if)", - fileName: "extensions0text0", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents: "ToBeReplacedWithFromPartial\n", - compareContents: "FromPartial\n", - originalFile: null, - compareFile: null, - originalPerms: 0o644, - comparePerms: 0o644 - }, { - description: "Patched by update.manifest if the parent directory exists (patch-if)", - fileName: "extensions0png1.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o644, - comparePerms: 0o644 - }, { - description: "Patched by update.manifest if the parent directory exists (patch-if)", - fileName: "extensions0png0.png", - relPathDir: DIR_RESOURCES + "distribution/extensions/extensions0/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o644, - comparePerms: 0o644 - }, { - description: "Patched by update.manifest (patch)", - fileName: "exe0.exe", - relPathDir: DIR_MACOS, - originalContents: null, - compareContents: null, - originalFile: FILE_COMPLETE_EXE, - compareFile: FILE_PARTIAL_EXE, - originalPerms: 0o755, - comparePerms: 0o755 - }, { - description: "Patched by update.manifest (patch)", - fileName: "0exe0.exe", - relPathDir: DIR_RESOURCES + "0/", - originalContents: null, - compareContents: null, - originalFile: FILE_COMPLETE_EXE, - compareFile: FILE_PARTIAL_EXE, - originalPerms: 0o755, - comparePerms: 0o755 - }, { - description: "Added by update.manifest (add)", - fileName: "00text0", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: "ToBeReplacedWithFromPartial\n", - compareContents: "FromPartial\n", - originalFile: null, - compareFile: null, - originalPerms: 0o644, - comparePerms: 0o644 - }, { - description: "Patched by update.manifest (patch)", - fileName: "00png0.png", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: null, - compareContents: null, - originalFile: "complete.png", - compareFile: "partial.png", - originalPerms: 0o666, - comparePerms: 0o666 - }, { - description: "Added by update.manifest (add)", - fileName: "20text0", - relPathDir: DIR_RESOURCES + "2/20/", - originalContents: null, - compareContents: "FromPartial\n", - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "20png0.png", - relPathDir: DIR_RESOURCES + "2/20/", - originalContents: null, - compareContents: null, - originalFile: null, - compareFile: "partial.png", - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Added by update.manifest (add)", - fileName: "00text2", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: null, - compareContents: "FromPartial\n", - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: 0o644 - }, { - description: "Removed by update.manifest (remove)", - fileName: "10text0", - relPathDir: DIR_RESOURCES + "1/10/", - originalContents: "ToBeDeleted\n", - compareContents: null, - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: null - }, { - description: "Removed by update.manifest (remove)", - fileName: "00text1", - relPathDir: DIR_RESOURCES + "0/00/", - originalContents: "ToBeDeleted\n", - compareContents: null, - originalFile: null, - compareFile: null, - originalPerms: null, - comparePerms: null - }]; - -// Concatenate the common files to the end of the array. -gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon); - -var gTestDirsCommon = [ - { - relPathDir: DIR_RESOURCES + "3/", - dirRemoved: false, - files: ["3text0", "3text1"], - filesRemoved: true - }, { - relPathDir: DIR_RESOURCES + "4/", - dirRemoved: true, - files: ["4text0", "4text1"], - filesRemoved: true - }, { - relPathDir: DIR_RESOURCES + "5/", - dirRemoved: true, - files: ["5test.exe", "5text0", "5text1"], - filesRemoved: true - }, { - relPathDir: DIR_RESOURCES + "6/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "7/", - dirRemoved: true, - files: ["7text0", "7text1"], - subDirs: ["70/", "71/"], - subDirFiles: ["7xtest.exe", "7xtext0", "7xtext1"] - }, { - relPathDir: DIR_RESOURCES + "8/", - dirRemoved: false - }, { - relPathDir: DIR_RESOURCES + "8/80/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "8/81/", - dirRemoved: false, - files: ["81text0", "81text1"] - }, { - relPathDir: DIR_RESOURCES + "8/82/", - dirRemoved: false, - subDirs: ["820/", "821/"] - }, { - relPathDir: DIR_RESOURCES + "8/83/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "8/84/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "8/85/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "8/86/", - dirRemoved: true, - files: ["86text0", "86text1"] - }, { - relPathDir: DIR_RESOURCES + "8/87/", - dirRemoved: true, - subDirs: ["870/", "871/"], - subDirFiles: ["87xtext0", "87xtext1"] - }, { - relPathDir: DIR_RESOURCES + "8/88/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "8/89/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "9/90/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "9/91/", - dirRemoved: false, - files: ["91text0", "91text1"] - }, { - relPathDir: DIR_RESOURCES + "9/92/", - dirRemoved: false, - subDirs: ["920/", "921/"] - }, { - relPathDir: DIR_RESOURCES + "9/93/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "9/94/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "9/95/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "9/96/", - dirRemoved: true, - files: ["96text0", "96text1"] - }, { - relPathDir: DIR_RESOURCES + "9/97/", - dirRemoved: true, - subDirs: ["970/", "971/"], - subDirFiles: ["97xtext0", "97xtext1"] - }, { - relPathDir: DIR_RESOURCES + "9/98/", - dirRemoved: true - }, { - relPathDir: DIR_RESOURCES + "9/99/", - dirRemoved: true - }]; - -// Directories for a complete successful update. This array can be used for a -// complete failed update by calling setTestFilesAndDirsForFailure. -var gTestDirsCompleteSuccess = [ - { - description: "Removed by precomplete (rmdir)", - relPathDir: DIR_RESOURCES + "2/20/", - dirRemoved: true - }, { - description: "Removed by precomplete (rmdir)", - relPathDir: DIR_RESOURCES + "2/", - dirRemoved: true - }]; - -// Concatenate the common files to the beginning of the array. -gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess); - -// Directories for a partial successful update. This array can be used for a -// partial failed update by calling setTestFilesAndDirsForFailure. -var gTestDirsPartialSuccess = [ - { - description: "Removed by update.manifest (rmdir)", - relPathDir: DIR_RESOURCES + "1/10/", - dirRemoved: true - }, { - description: "Removed by update.manifest (rmdir)", - relPathDir: DIR_RESOURCES + "1/", - dirRemoved: true - }]; - -// Concatenate the common files to the beginning of the array. -gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess); - -// This makes it possible to run most tests on xulrunner where the update -// channel default preference is not set. -if (MOZ_APP_NAME == "xulrunner") { - try { - gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); - } catch (e) { - setUpdateChannel("test_channel"); - } -} - -/** - * Helper function for setting up the test environment. - */ -function setupTestCommon() { - debugDump("start - general test setup"); - - Assert.strictEqual(gTestID, undefined, - "gTestID should be 'undefined' (setupTestCommon should " + - "only be called once)"); - - let caller = Components.stack.caller; - gTestID = caller.filename.toString().split("/").pop().split(".")[0]; - - // Tests that don't work with XULRunner. - const XUL_RUNNER_INCOMPATIBLE = ["marAppApplyUpdateAppBinInUseStageSuccess_win", - "marAppApplyUpdateStageSuccess", - "marAppApplyUpdateSuccess", - "marAppApplyUpdateAppBinInUseStageSuccessSvc_win", - "marAppApplyUpdateStageSuccessSvc", - "marAppApplyUpdateSuccessSvc"]; - // Replace with Array.prototype.includes when it has stabilized. - if (MOZ_APP_NAME == "xulrunner" && - XUL_RUNNER_INCOMPATIBLE.indexOf(gTestID) != -1) { - logTestInfo("Unable to run this test on xulrunner"); - return false; - } - - if (IS_SERVICE_TEST && !shouldRunServiceTest()) { - return false; - } - - do_test_pending(); - - setDefaultPrefs(); - - // Don't attempt to show a prompt when an update finishes. - Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true); - - gGREDirOrig = getGREDir(); - gGREBinDirOrig = getGREBinDir(); - gAppDirOrig = getAppBaseDir(); - - let applyDir = getApplyDirFile(null, true).parent; - - // Try to remove the directory used to apply updates and the updates directory - // on platforms other than Windows. Since the test hasn't ran yet and the - // directory shouldn't exist finished this is non-fatal for the test. - if (applyDir.exists()) { - debugDump("attempting to remove directory. Path: " + applyDir.path); - try { - removeDirRecursive(applyDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - applyDir.path + ", Exception: " + e); - // When the application doesn't exit properly it can cause the test to - // fail again on the second run with an NS_ERROR_FILE_ACCESS_DENIED error - // along with no useful information in the test log. To prevent this use - // a different directory for the test when it isn't possible to remove the - // existing test directory (bug 1294196). - gTestID += "_new"; - logTestInfo("using a new directory for the test by changing gTestID " + - "since there is an existing test directory that can't be " + - "removed, gTestID: " + gTestID); - } - } - - if (IS_WIN) { - Services.prefs.setBoolPref(PREF_APP_UPDATE_SERVICE_ENABLED, - IS_SERVICE_TEST ? true : false); - } - - // adjustGeneralPaths registers a cleanup function that calls end_test when - // it is defined as a function. - adjustGeneralPaths(); - // Logged once here instead of in the mock directory provider to lessen test - // log spam. - debugDump("Updates Directory (UpdRootD) Path: " + getMockUpdRootD().path); - - // This prevents a warning about not being able to find the greprefs.js file - // from being logged. - let grePrefsFile = getGREDir(); - if (!grePrefsFile.exists()) { - grePrefsFile.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - grePrefsFile.append("goanna.js"); - if (!grePrefsFile.exists()) { - grePrefsFile.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE); - } - - // Remove the updates directory on Windows and Mac OS X which is located - // outside of the application directory after the call to adjustGeneralPaths - // has set it up. Since the test hasn't ran yet and the directory shouldn't - // exist this is non-fatal for the test. - if (IS_WIN || IS_MACOSX) { - let updatesDir = getMockUpdRootD(); - if (updatesDir.exists()) { - debugDump("attempting to remove directory. Path: " + updatesDir.path); - try { - removeDirRecursive(updatesDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - updatesDir.path + ", Exception: " + e); - } - } - } - - debugDump("finish - general test setup"); - return true; -} - -/** - * Nulls out the most commonly used global vars used by tests to prevent leaks - * as needed and attempts to restore the system to its original state. - */ -function cleanupTestCommon() { - debugDump("start - general test cleanup"); - - // Force the update manager to reload the update data to prevent it from - // writing the old data to the files that have just been removed. - reloadUpdateManagerData(); - - if (gChannel) { - gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer); - } - - // Call app update's observe method passing xpcom-shutdown to test that the - // shutdown of app update runs without throwing or leaking. The observer - // method is used directly instead of calling notifyObservers so components - // outside of the scope of this test don't assert and thereby cause app update - // tests to fail. - gAUS.observe(null, "xpcom-shutdown", ""); - - gTestserver = null; - - if (IS_UNIX) { - // This will delete the launch script if it exists. - getLaunchScript(); - } - - if (IS_WIN && MOZ_APP_BASENAME) { - let appDir = getApplyDirFile(null, true); - let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; - const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + - "\\TaskBarIDs"; - let key = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(Ci.nsIWindowsRegKey); - try { - key.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, - Ci.nsIWindowsRegKey.ACCESS_ALL); - if (key.hasValue(appDir.path)) { - key.removeValue(appDir.path); - } - } catch (e) { - } - try { - key.open(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, - Ci.nsIWindowsRegKey.ACCESS_ALL); - if (key.hasValue(appDir.path)) { - key.removeValue(appDir.path); - } - } catch (e) { - } - } - - // The updates directory is located outside of the application directory and - // needs to be removed on Windows and Mac OS X. - if (IS_WIN || IS_MACOSX) { - let updatesDir = getMockUpdRootD(); - // Try to remove the directory used to apply updates. Since the test has - // already finished this is non-fatal for the test. - if (updatesDir.exists()) { - debugDump("attempting to remove directory. Path: " + updatesDir.path); - try { - removeDirRecursive(updatesDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - updatesDir.path + ", Exception: " + e); - } - if (IS_MACOSX) { - let updatesRootDir = gUpdatesRootDir.clone(); - while (updatesRootDir.path != updatesDir.path) { - if (updatesDir.exists()) { - debugDump("attempting to remove directory. Path: " + - updatesDir.path); - try { - // Try to remove the directory without the recursive flag set - // since the top level directory has already had its contents - // removed and the parent directory might still be used by a - // different test. - updatesDir.remove(false); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - updatesDir.path + ", Exception: " + e); - if (e == Cr.NS_ERROR_FILE_DIR_NOT_EMPTY) { - break; - } - } - } - updatesDir = updatesDir.parent; - } - } - } - } - - let applyDir = getApplyDirFile(null, true).parent; - - // Try to remove the directory used to apply updates. Since the test has - // already finished this is non-fatal for the test. - if (applyDir.exists()) { - debugDump("attempting to remove directory. Path: " + applyDir.path); - try { - removeDirRecursive(applyDir); - } catch (e) { - logTestInfo("non-fatal error removing directory. Path: " + - applyDir.path + ", Exception: " + e); - } - } - - resetEnvironment(); - - debugDump("finish - general test cleanup"); -} - -/** - * Helper function that calls do_test_finished that tracks whether a parallel - * run of a test passed when it runs synchronously so the log output can be - * inspected. - */ -function doTestFinish() { - if (DEBUG_AUS_TEST) { - // This prevents do_print errors from being printed by the xpcshell test - // harness due to nsUpdateService.js logging to the console when the - // app.update.log preference is true. - Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false); - gAUS.observe(null, "nsPref:changed", PREF_APP_UPDATE_LOG); - } - do_execute_soon(do_test_finished); -} - -/** - * Sets the most commonly used preferences used by tests - */ -function setDefaultPrefs() { - Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true); - if (DEBUG_AUS_TEST) { - // Enable Update logging - Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); - } else { - // Some apps set this preference to true by default - Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false); - } - // In case telemetry is enabled for xpcshell tests. - Services.prefs.setBoolPref(PREF_TOOLKIT_TELEMETRY_ENABLED, false); -} - -/** - * Helper function for updater binary tests that sets the appropriate values - * to check for update failures. - */ -function setTestFilesAndDirsForFailure() { - gTestFiles.forEach(function STFADFF_Files(aTestFile) { - aTestFile.compareContents = aTestFile.originalContents; - aTestFile.compareFile = aTestFile.originalFile; - aTestFile.comparePerms = aTestFile.originalPerms; - }); - - gTestDirs.forEach(function STFADFF_Dirs(aTestDir) { - aTestDir.dirRemoved = false; - if (aTestDir.filesRemoved) { - aTestDir.filesRemoved = false; - } - }); -} - -/** - * Helper function for updater binary tests that prevents the distribution - * directory files from being created. - */ -function preventDistributionFiles() { - gTestFiles = gTestFiles.filter(function(aTestFile) { - return aTestFile.relPathDir.indexOf("distribution/") == -1; - }); - - gTestDirs = gTestDirs.filter(function(aTestDir) { - return aTestDir.relPathDir.indexOf("distribution/") == -1; - }); -} - -/** - * On Mac OS X this sets the last modified time for the app bundle directory to - * a date in the past to test that the last modified time is updated when an - * update has been successfully applied (bug 600098). - */ -function setAppBundleModTime() { - if (!IS_MACOSX) { - return; - } - let now = Date.now(); - let yesterday = now - (1000 * 60 * 60 * 24); - let applyToDir = getApplyDirFile(); - applyToDir.lastModifiedTime = yesterday; -} - -/** - * On Mac OS X this checks that the last modified time for the app bundle - * directory has been updated when an update has been successfully applied - * (bug 600098). - */ -function checkAppBundleModTime() { - if (!IS_MACOSX) { - return; - } - let now = Date.now(); - let applyToDir = getApplyDirFile(); - let timeDiff = Math.abs(applyToDir.lastModifiedTime - now); - Assert.ok(timeDiff < MAC_MAX_TIME_DIFFERENCE, - "the last modified time on the apply to directory should " + - "change after a successful update"); -} - -/** - * On Mac OS X and Windows this checks if the post update '.running' file exists - * to determine if the post update binary was launched. - * - * @param aShouldExist - * Whether the post update '.running' file should exist. - */ -function checkPostUpdateRunningFile(aShouldExist) { - if (!IS_WIN && !IS_MACOSX) { - return; - } - let postUpdateRunningFile = getPostUpdateFile(".running"); - if (aShouldExist) { - Assert.ok(postUpdateRunningFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(postUpdateRunningFile.path)); - } else { - Assert.ok(!postUpdateRunningFile.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(postUpdateRunningFile.path)); - } -} - -/** - * Initializes the most commonly used settings and creates an instance of the - * update service stub. - */ -function standardInit() { - createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0"); - // Initialize the update service stub component - initUpdateServiceStub(); -} - -/** - * Helper function for getting the application version from the application.ini - * file. This will look in both the GRE and the application directories for the - * application.ini file. - * - * @return The version string from the application.ini file. - */ -function getAppVersion() { - // Read the application.ini and use its application version. - let iniFile = gGREDirOrig.clone(); - iniFile.append(FILE_APPLICATION_INI); - if (!iniFile.exists()) { - iniFile = gGREBinDirOrig.clone(); - iniFile.append(FILE_APPLICATION_INI); - } - Assert.ok(iniFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(iniFile.path)); - let iniParser = Cc["@mozilla.org/xpcom/ini-parser-factory;1"]. - getService(Ci.nsIINIParserFactory). - createINIParser(iniFile); - return iniParser.getString("App", "Version"); -} - -/** - * Helper function for getting the relative path to the directory where the - * application binary is located (e.g. <test_file_leafname>/dir.app/). - * - * Note: The dir.app subdirectory under <test_file_leafname> is needed for - * platforms other than Mac OS X so the tests can run in parallel due to - * update staging creating a lock file named moz_update_in_progress.lock in - * the parent directory of the installation directory. - * - * @return The relative path to the directory where application binary is - * located. - */ -function getApplyDirPath() { - return gTestID + "/dir.app/"; -} - -/** - * Helper function for getting the nsIFile for a file in the directory where the - * update will be applied. - * - * The files for the update are located two directories below the apply to - * directory since Mac OS X sets the last modified time for the root directory - * to the current time and if the update changes any files in the root directory - * then it wouldn't be possible to test (bug 600098). - * - * @param aRelPath (optional) - * The relative path to the file or directory to get from the root of - * the test's directory. If not specified the test's directory will be - * returned. - * @param aAllowNonexistent (optional) - * Whether the file must exist. If false or not specified the file must - * exist or the function will throw. - * @return The nsIFile for the file in the directory where the update will be - * applied. - * @throws If aAllowNonexistent is not specified or is false and the file or - * directory does not exist. - */ -function getApplyDirFile(aRelPath, aAllowNonexistent) { - let relpath = getApplyDirPath() + (aRelPath ? aRelPath : ""); - return do_get_file(relpath, aAllowNonexistent); -} - -/** - * Helper function for getting the nsIFile for a file in the directory where the - * update will be staged. - * - * The files for the update are located two directories below the stage - * directory since Mac OS X sets the last modified time for the root directory - * to the current time and if the update changes any files in the root directory - * then it wouldn't be possible to test (bug 600098). - * - * @param aRelPath (optional) - * The relative path to the file or directory to get from the root of - * the stage directory. If not specified the stage directory will be - * returned. - * @param aAllowNonexistent (optional) - * Whether the file must exist. If false or not specified the file must - * exist or the function will throw. - * @return The nsIFile for the file in the directory where the update will be - * staged. - * @throws If aAllowNonexistent is not specified or is false and the file or - * directory does not exist. - */ -function getStageDirFile(aRelPath, aAllowNonexistent) { - if (IS_MACOSX) { - let file = getMockUpdRootD(); - file.append(DIR_UPDATES); - file.append(DIR_PATCH); - file.append(DIR_UPDATED); - if (aRelPath) { - let pathParts = aRelPath.split("/"); - for (let i = 0; i < pathParts.length; i++) { - if (pathParts[i]) { - file.append(pathParts[i]); - } - } - } - if (!aAllowNonexistent) { - Assert.ok(file.exists(), - MSG_SHOULD_EXIST + getMsgPath(file.path)); - } - return file; - } - - let relpath = getApplyDirPath() + DIR_UPDATED + "/" + (aRelPath ? aRelPath : ""); - return do_get_file(relpath, aAllowNonexistent); -} - -/** - * Helper function for getting the relative path to the directory where the - * test data files are located. - * - * @return The relative path to the directory where the test data files are - * located. - */ -function getTestDirPath() { - return "../data/"; -} - -/** - * Helper function for getting the nsIFile for a file in the test data - * directory. - * - * @param aRelPath (optional) - * The relative path to the file or directory to get from the root of - * the test's data directory. If not specified the test's data - * directory will be returned. - * @param aAllowNonExists (optional) - * Whether or not to throw an error if the path exists. - * If not specified, then false is used. - * @return The nsIFile for the file in the test data directory. - * @throws If the file or directory does not exist. - */ -function getTestDirFile(aRelPath, aAllowNonExists) { - let relpath = getTestDirPath() + (aRelPath ? aRelPath : ""); - return do_get_file(relpath, !!aAllowNonExists); -} - -/** - * Helper function for getting the nsIFile for the maintenance service - * directory on Windows. - * - * @return The nsIFile for the maintenance service directory. - */ -function getMaintSvcDir() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - const CSIDL_PROGRAM_FILES = 0x26; - const CSIDL_PROGRAM_FILESX86 = 0x2A; - // This will return an empty string on our Win XP build systems. - let maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILESX86); - if (maintSvcDir) { - maintSvcDir.append("Mozilla Maintenance Service"); - debugDump("using CSIDL_PROGRAM_FILESX86 - maintenance service install " + - "directory path: " + maintSvcDir.path); - } - if (!maintSvcDir || !maintSvcDir.exists()) { - maintSvcDir = getSpecialFolderDir(CSIDL_PROGRAM_FILES); - if (maintSvcDir) { - maintSvcDir.append("Mozilla Maintenance Service"); - debugDump("using CSIDL_PROGRAM_FILES - maintenance service install " + - "directory path: " + maintSvcDir.path); - } - } - if (!maintSvcDir) { - do_throw("Unable to find the maintenance service install directory"); - } - - return maintSvcDir; -} - -/** - * Get the nsILocalFile for a Windows special folder determined by the CSIDL - * passed. - * - * @param aCSIDL - * The CSIDL for the Windows special folder. - * @return The nsILocalFile for the Windows special folder. - * @throws If called from a platform other than Windows. - */ -function getSpecialFolderDir(aCSIDL) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let lib = ctypes.open("shell32"); - let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW", - ctypes.winapi_abi, - ctypes.bool, /* bool(return) */ - ctypes.int32_t, /* HWND hwndOwner */ - ctypes.char16_t.ptr, /* LPTSTR lpszPath */ - ctypes.int32_t, /* int csidl */ - ctypes.bool /* BOOL fCreate */); - - let aryPath = ctypes.char16_t.array()(260); - let rv = SHGetSpecialFolderPath(0, aryPath, aCSIDL, false); - lib.close(); - - let path = aryPath.readString(); // Convert the c-string to js-string - if (!path) { - return null; - } - debugDump("SHGetSpecialFolderPath returned path: " + path); - let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - dir.initWithPath(path); - return dir; -} - -XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash", function test_gIDPH() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - // Figure out where we should check for a cached hash value - if (!MOZ_APP_BASENAME) { - return null; - } - - let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla"; - let appDir = getApplyDirFile(null, true); - - const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME + - "\\TaskBarIDs"; - let regKey = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(Ci.nsIWindowsRegKey); - try { - regKey.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, - Ci.nsIWindowsRegKey.ACCESS_ALL); - regKey.writeStringValue(appDir.path, gTestID); - return gTestID; - } catch (e) { - } - - try { - regKey.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH, - Ci.nsIWindowsRegKey.ACCESS_ALL); - regKey.writeStringValue(appDir.path, gTestID); - return gTestID; - } catch (e) { - logTestInfo("failed to create registry key. Registry Path: " + REG_PATH + - ", Key Name: " + appDir.path + ", Key Value: " + gTestID + - ", Exception " + e); - } - return null; -}); - -XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir", function test_gLADD() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - const CSIDL_LOCAL_APPDATA = 0x1c; - return getSpecialFolderDir(CSIDL_LOCAL_APPDATA); -}); - -XPCOMUtils.defineLazyGetter(this, "gProgFilesDir", function test_gPFD() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - const CSIDL_PROGRAM_FILES = 0x26; - return getSpecialFolderDir(CSIDL_PROGRAM_FILES); -}); - -/** - * Helper function for getting the update root directory used by the tests. This - * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir - * in nsXREDirProvider.cpp so an application will be able to find the update - * when running a test that launches the application. - */ -function getMockUpdRootD() { - if (IS_WIN) { - return getMockUpdRootDWin(); - } - - if (IS_MACOSX) { - return getMockUpdRootDMac(); - } - - return getApplyDirFile(DIR_MACOS, true); -} - -/** - * Helper function for getting the update root directory used by the tests. This - * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir - * in nsXREDirProvider.cpp so an application will be able to find the update - * when running a test that launches the application. - */ -function getMockUpdRootDWin() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let localAppDataDir = gLocalAppDataDir.clone(); - let progFilesDir = gProgFilesDir.clone(); - let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile).parent; - - let appDirPath = appDir.path; - let relPathUpdates = ""; - if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) { - relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) + - "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash; - } - - if (!relPathUpdates && progFilesDir) { - if (appDirPath.length > progFilesDir.path.length) { - if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) { - if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { - relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; - } else { - relPathUpdates += MOZ_APP_BASENAME; - } - relPathUpdates += appDirPath.substr(progFilesDir.path.length); - } - } - } - - if (!relPathUpdates) { - if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) { - relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME; - } else { - relPathUpdates += MOZ_APP_BASENAME; - } - relPathUpdates += "\\" + MOZ_APP_NAME; - } - - let updatesDir = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsILocalFile); - updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates); - return updatesDir; -} - -XPCOMUtils.defineLazyGetter(this, "gUpdatesRootDir", function test_gURD() { - if (!IS_MACOSX) { - do_throw("Mac OS X only function called by a different platform!"); - } - - let dir = Services.dirsvc.get("ULibDir", Ci.nsILocalFile); - dir.append("Caches"); - if (MOZ_APP_VENDOR || MOZ_APP_BASENAME) { - dir.append(MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME); - } else { - dir.append("Mozilla"); - } - dir.append(DIR_UPDATES); - return dir; -}); - -/** - * Helper function for getting the update root directory used by the tests. This - * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir - * in nsXREDirProvider.cpp so an application will be able to find the update - * when running a test that launches the application. - */ -function getMockUpdRootDMac() { - if (!IS_MACOSX) { - do_throw("Mac OS X only function called by a different platform!"); - } - - let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, Ci.nsIFile). - parent.parent.parent; - let appDirPath = appDir.path; - appDirPath = appDirPath.substr(0, appDirPath.length - 4); - - let pathUpdates = gUpdatesRootDir.path + appDirPath; - let updatesDir = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsILocalFile); - updatesDir.initWithPath(pathUpdates); - return updatesDir; -} - -/** - * Creates an update in progress lock file in the specified directory on - * Windows. - * - * @param aDir - * The nsIFile for the directory where the lock file should be created. - */ -function createUpdateInProgressLockFile(aDir) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let file = aDir.clone(); - file.append(FILE_UPDATE_IN_PROGRESS_LOCK); - file.create(file.NORMAL_FILE_TYPE, 0o444); - file.QueryInterface(Ci.nsILocalFileWin); - file.fileAttributesWin |= file.WFA_READONLY; - file.fileAttributesWin &= ~file.WFA_READWRITE; - Assert.ok(file.exists(), - MSG_SHOULD_EXIST + getMsgPath(file.path)); - Assert.ok(!file.isWritable(), - "the lock file should not be writeable"); -} - -/** - * Removes an update in progress lock file in the specified directory on - * Windows. - * - * @param aDir - * The nsIFile for the directory where the lock file is located. - */ -function removeUpdateInProgressLockFile(aDir) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let file = aDir.clone(); - file.append(FILE_UPDATE_IN_PROGRESS_LOCK); - file.QueryInterface(Ci.nsILocalFileWin); - file.fileAttributesWin |= file.WFA_READWRITE; - file.fileAttributesWin &= ~file.WFA_READONLY; - file.remove(false); - Assert.ok(!file.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(file.path)); -} - -/** - * Gets the test updater from the test data direcory. - * - * @return nsIFIle for the test updater. - */ -function getTestUpdater() { - let updater = getTestDirFile("updater.app", true); - if (!updater.exists()) { - updater = getTestDirFile(FILE_UPDATER_BIN); - if (!updater.exists()) { - do_throw("Unable to find the updater binary!"); - } - } - Assert.ok(updater.exists(), - MSG_SHOULD_EXIST + getMsgPath(updater.path)); - return updater; -} - -/** - * Copies the test updater to the GRE binary directory and returns the nsIFile - * for the copied test updater. - * - * @return nsIFIle for the copied test updater. - */ -function copyTestUpdaterToBinDir() { - let testUpdater = getTestUpdater(); - let updater = getGREBinDir(); - updater.append(testUpdater.leafName); - if (!updater.exists()) { - testUpdater.copyToFollowingLinks(updater.parent, updater.leafName); - } - return updater; -} - -/** - * Copies the test updater to the location where it will be launched to apply an - * update and returns the nsIFile for the copied test updater. - * - * @return nsIFIle for the copied test updater. - */ -function copyTestUpdaterForRunUsingUpdater() { - if (IS_WIN) { - return copyTestUpdaterToBinDir(); - } - - let testUpdater = getTestUpdater(); - let updater = getUpdatesPatchDir(); - updater.append(testUpdater.leafName); - if (!updater.exists()) { - testUpdater.copyToFollowingLinks(updater.parent, updater.leafName); - } - - if (IS_MACOSX) { - updater.append("Contents"); - updater.append("MacOS"); - updater.append("org.mozilla.updater"); - } - return updater; -} - -/** - * Logs the contents of an update log and for maintenance service tests this - * will log the contents of the latest maintenanceservice.log. - * - * @param aLogLeafName - * The leaf name of the update log. - */ -function logUpdateLog(aLogLeafName) { - let updateLog = getUpdateLog(aLogLeafName); - if (updateLog.exists()) { - // xpcshell tests won't display the entire contents so log each line. - let updateLogContents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); - updateLogContents = replaceLogPaths(updateLogContents); - let aryLogContents = updateLogContents.split("\n"); - logTestInfo("contents of " + updateLog.path + ":"); - aryLogContents.forEach(function RU_LC_FE(aLine) { - logTestInfo(aLine); - }); - } else { - logTestInfo("update log doesn't exist, path: " + updateLog.path); - } - - if (IS_SERVICE_TEST) { - let serviceLog = getMaintSvcDir(); - serviceLog.append("logs"); - serviceLog.append("maintenanceservice.log"); - if (serviceLog.exists()) { - // xpcshell tests won't display the entire contents so log each line. - let serviceLogContents = readFileBytes(serviceLog).replace(/\r\n/g, "\n"); - serviceLogContents = replaceLogPaths(serviceLogContents); - let aryLogContents = serviceLogContents.split("\n"); - logTestInfo("contents of " + serviceLog.path + ":"); - aryLogContents.forEach(function RU_LC_FE(aLine) { - logTestInfo(aLine); - }); - } else { - logTestInfo("maintenance service log doesn't exist, path: " + - serviceLog.path); - } - } -} - -/** - * Gets the maintenance service log contents. - */ -function readServiceLogFile() { - let file = getMaintSvcDir(); - file.append("logs"); - file.append("maintenanceservice.log"); - return readFile(file); -} - -/** - * Launches the updater binary to apply an update for updater tests. - * - * @param aExpectedStatus - * The expected value of update.status when the test finishes. For - * service tests passing STATE_PENDING or STATE_APPLIED will change the - * value to STATE_PENDING_SVC and STATE_APPLIED_SVC respectively. - * @param aSwitchApp - * If true the update should switch the application with an updated - * staged application and if false the update should be applied to the - * installed application. - * @param aExpectedExitValue - * The expected exit value from the updater binary for non-service - * tests. - * @param aCheckSvcLog - * Whether the service log should be checked for service tests. - * @param aPatchDirPath (optional) - * When specified the patch directory path to use for invalid argument - * tests otherwise the normal path will be used. - * @param aInstallDirPath (optional) - * When specified the install directory path to use for invalid - * argument tests otherwise the normal path will be used. - * @param aApplyToDirPath (optional) - * When specified the apply to / working directory path to use for - * invalid argument tests otherwise the normal path will be used. - * @param aCallbackPath (optional) - * When specified the callback path to use for invalid argument tests - * otherwise the normal path will be used. - */ -function runUpdate(aExpectedStatus, aSwitchApp, aExpectedExitValue, aCheckSvcLog, - aPatchDirPath, aInstallDirPath, aApplyToDirPath, - aCallbackPath) { - let isInvalidArgTest = !!aPatchDirPath || !!aInstallDirPath || - !!aApplyToDirPath || aCallbackPath; - - let svcOriginalLog; - if (IS_SERVICE_TEST) { - copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false); - copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false); - if (aCheckSvcLog) { - svcOriginalLog = readServiceLogFile(); - } - } - - // Copy the updater binary to the directory where it will apply updates. - let updateBin = copyTestUpdaterForRunUsingUpdater(); - Assert.ok(updateBin.exists(), - MSG_SHOULD_EXIST + getMsgPath(updateBin.path)); - - let updatesDirPath = aPatchDirPath || getUpdatesPatchDir().path; - let installDirPath = aInstallDirPath || getApplyDirFile(null, true).path; - let applyToDirPath = aApplyToDirPath || getApplyDirFile(null, true).path; - let stageDirPath = aApplyToDirPath || getStageDirFile(null, true).path; - - let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); - callbackApp.permissions = PERMS_DIRECTORY; - - setAppBundleModTime(); - - let args = [updatesDirPath, installDirPath]; - if (aSwitchApp) { - args[2] = stageDirPath; - args[3] = "0/replace"; - } else { - args[2] = applyToDirPath; - args[3] = "0"; - } - - let launchBin = IS_SERVICE_TEST && isInvalidArgTest ? callbackApp : updateBin; - - if (!isInvalidArgTest) { - args = args.concat([callbackApp.parent.path, callbackApp.path]); - args = args.concat(gCallbackArgs); - } else if (IS_SERVICE_TEST) { - args = ["launch-service", updateBin.path].concat(args); - } else if (aCallbackPath) { - args = args.concat([callbackApp.parent.path, aCallbackPath]); - } - - debugDump("launching the program: " + launchBin.path + " " + args.join(" ")); - - if (aSwitchApp && !isInvalidArgTest) { - // We want to set the env vars again - gShouldResetEnv = undefined; - } - - setEnvironment(); - - let process = Cc["@mozilla.org/process/util;1"]. - createInstance(Ci.nsIProcess); - process.init(launchBin); - process.run(true, args, args.length); - - resetEnvironment(); - - let status = readStatusFile(); - if ((!IS_SERVICE_TEST && process.exitValue != aExpectedExitValue) || - status != aExpectedStatus) { - if (process.exitValue != aExpectedExitValue) { - logTestInfo("updater exited with unexpected value! Got: " + - process.exitValue + ", Expected: " + aExpectedExitValue); - } - if (status != aExpectedStatus) { - logTestInfo("update status is not the expected status! Got: " + status + - ", Expected: " + aExpectedStatus); - } - logUpdateLog(FILE_LAST_UPDATE_LOG); - } - - if (!IS_SERVICE_TEST) { - Assert.equal(process.exitValue, aExpectedExitValue, - "the process exit value" + MSG_SHOULD_EQUAL); - } - Assert.equal(status, aExpectedStatus, - "the update status" + MSG_SHOULD_EQUAL); - - if (IS_SERVICE_TEST && aCheckSvcLog) { - let contents = readServiceLogFile(); - Assert.notEqual(contents, svcOriginalLog, - "the contents of the maintenanceservice.log should not " + - "be the same as the original contents"); - if (!isInvalidArgTest) { - Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1, - "the contents of the maintenanceservice.log should " + - "contain the successful launch string"); - } - } - - do_execute_soon(runUpdateFinished); -} - -/** - * Launches the helper binary synchronously with the specified arguments for - * updater tests. - * - * @param aArgs - * The arguments to pass to the helper binary. - * @return the process exit value returned by the helper binary. - */ -function runTestHelperSync(aArgs) { - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let process = Cc["@mozilla.org/process/util;1"]. - createInstance(Ci.nsIProcess); - process.init(helperBin); - debugDump("Running " + helperBin.path + " " + aArgs.join(" ")); - process.run(true, aArgs, aArgs.length); - return process.exitValue; -} - -/** - * Creates a symlink for updater tests. - */ -function createSymlink() { - let args = ["setup-symlink", "moz-foo", "moz-bar", "target", - getApplyDirFile().path + "/" + DIR_RESOURCES + "link"]; - let exitValue = runTestHelperSync(args); - Assert.equal(exitValue, 0, - "the helper process exit value should be 0"); - getApplyDirFile(DIR_RESOURCES + "link", false).permissions = 0o666; - args = ["setup-symlink", "moz-foo2", "moz-bar2", "target2", - getApplyDirFile().path + "/" + DIR_RESOURCES + "link2", "change-perm"]; - exitValue = runTestHelperSync(args); - Assert.equal(exitValue, 0, - "the helper process exit value should be 0"); -} - -/** - * Removes a symlink for updater tests. - */ -function removeSymlink() { - let args = ["remove-symlink", "moz-foo", "moz-bar", "target", - getApplyDirFile().path + "/" + DIR_RESOURCES + "link"]; - let exitValue = runTestHelperSync(args); - Assert.equal(exitValue, 0, - "the helper process exit value should be 0"); - args = ["remove-symlink", "moz-foo2", "moz-bar2", "target2", - getApplyDirFile().path + "/" + DIR_RESOURCES + "link2"]; - exitValue = runTestHelperSync(args); - Assert.equal(exitValue, 0, - "the helper process exit value should be 0"); -} - -/** - * Checks a symlink for updater tests. - */ -function checkSymlink() { - let args = ["check-symlink", - getApplyDirFile().path + "/" + DIR_RESOURCES + "link"]; - let exitValue = runTestHelperSync(args); - Assert.equal(exitValue, 0, - "the helper process exit value should be 0"); -} - -/** - * Sets the active update and related information for updater tests. - */ -function setupActiveUpdate() { - let state = IS_SERVICE_TEST ? STATE_PENDING_SVC : STATE_PENDING; - let channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL); - let patches = getLocalPatchString(null, null, null, null, null, "true", - state); - let updates = getLocalUpdateString(patches, null, null, null, null, null, - null, null, null, null, "true", channel); - writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); - writeVersionFile(DEFAULT_UPDATE_VERSION); - writeStatusFile(state); - reloadUpdateManagerData(); - Assert.ok(!!gUpdateManager.activeUpdate, - "the active update should be defined"); -} - -/** - * Gets the specified update log. - * - * @param aLogLeafName - * The leaf name of the log to get. - * @return nsIFile for the update log. - */ -function getUpdateLog(aLogLeafName) { - let updateLog = getUpdatesDir(); - if (aLogLeafName == FILE_UPDATE_LOG) { - updateLog.append(DIR_PATCH); - } - updateLog.append(aLogLeafName); - return updateLog; -} - -/** - * The update-staged observer for the call to nsIUpdateProcessor:processUpdate. - */ -const gUpdateStagedObserver = { - observe: function(aSubject, aTopic, aData) { - debugDump("observe called with topic: " + aTopic + ", data: " + aData); - if (aTopic == "update-staged") { - Services.obs.removeObserver(gUpdateStagedObserver, "update-staged"); - // The environment is reset after the update-staged observer topic because - // processUpdate in nsIUpdateProcessor uses a new thread and clearing the - // environment immediately after calling processUpdate can clear the - // environment before the updater is launched. - resetEnvironment(); - // Use do_execute_soon to prevent any failures from propagating to the - // update service. - do_execute_soon(checkUpdateStagedState.bind(null, aData)); - } - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) -}; - -/** - * Stages an update using nsIUpdateProcessor:processUpdate for updater tests. - * - * @param aCheckSvcLog - * Whether the service log should be checked for service tests. - */ -function stageUpdate(aCheckSvcLog) { - debugDump("start - attempting to stage update"); - - if (IS_SERVICE_TEST && aCheckSvcLog) { - gSvcOriginalLogContents = readServiceLogFile(); - } - - Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false); - - setAppBundleModTime(); - setEnvironment(); - // Stage the update. - Cc["@mozilla.org/updates/update-processor;1"]. - createInstance(Ci.nsIUpdateProcessor). - processUpdate(gUpdateManager.activeUpdate); - - // The environment is not reset here because processUpdate in - // nsIUpdateProcessor uses a new thread and clearing the environment - // immediately after calling processUpdate can clear the environment before - // the updater is launched. Instead it is reset after the update-staged - // observer topic. - - debugDump("finish - attempting to stage update"); -} - -/** - * Checks that the update state is correct as well as the expected files are - * present after staging and update for updater tests and then calls - * stageUpdateFinished. - * - * @param aUpdateState - * The update state received by the observer notification. - */ -function checkUpdateStagedState(aUpdateState) { - if (IS_WIN) { - if (IS_SERVICE_TEST) { - waitForServiceStop(false); - } else { - let updater = getApplyDirFile(FILE_UPDATER_BIN, true); - if (isFileInUse(updater)) { - do_timeout(FILE_IN_USE_TIMEOUT_MS, - checkUpdateStagedState.bind(null, aUpdateState)); - return; - } - } - } - - Assert.equal(aUpdateState, STATE_AFTER_STAGE, - "the notified state" + MSG_SHOULD_EQUAL); - - if (!gStagingRemovedUpdate) { - Assert.equal(readStatusState(), STATE_AFTER_STAGE, - "the status file state" + MSG_SHOULD_EQUAL); - - Assert.equal(gUpdateManager.activeUpdate.state, STATE_AFTER_STAGE, - "the update state" + MSG_SHOULD_EQUAL); - } - - Assert.equal(gUpdateManager.updateCount, 1, - "the update manager updateCount attribute" + MSG_SHOULD_EQUAL); - Assert.equal(gUpdateManager.getUpdateAt(0).state, STATE_AFTER_STAGE, - "the update state" + MSG_SHOULD_EQUAL); - - let log = getUpdateLog(FILE_LAST_UPDATE_LOG); - Assert.ok(log.exists(), - MSG_SHOULD_EXIST + getMsgPath(log.path)); - - log = getUpdateLog(FILE_UPDATE_LOG); - Assert.ok(!log.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); - - log = getUpdateLog(FILE_BACKUP_UPDATE_LOG); - Assert.ok(!log.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(log.path)); - - let stageDir = getStageDirFile(null, true); - if (STATE_AFTER_STAGE == STATE_APPLIED || - STATE_AFTER_STAGE == STATE_APPLIED_SVC) { - Assert.ok(stageDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(stageDir.path)); - } else { - Assert.ok(!stageDir.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(stageDir.path)); - } - - if (IS_SERVICE_TEST && gSvcOriginalLogContents !== undefined) { - let contents = readServiceLogFile(); - Assert.notEqual(contents, gSvcOriginalLogContents, - "the contents of the maintenanceservice.log should not " + - "be the same as the original contents"); - Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1, - "the contents of the maintenanceservice.log should " + - "contain the successful launch string"); - } - - do_execute_soon(stageUpdateFinished); -} - -/** - * Helper function to check whether the maintenance service updater tests should - * run. See bug 711660 for more details. - * - * @return true if the test should run and false if it shouldn't. - */ -function shouldRunServiceTest() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let binDir = getGREBinDir(); - let updaterBin = binDir.clone(); - updaterBin.append(FILE_UPDATER_BIN); - Assert.ok(updaterBin.exists(), - MSG_SHOULD_EXIST + ", leafName: " + updaterBin.leafName); - - let updaterBinPath = updaterBin.path; - if (/ /.test(updaterBinPath)) { - updaterBinPath = '"' + updaterBinPath + '"'; - } - - let isBinSigned = isBinarySigned(updaterBinPath); - - const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" + - "3932ecacee736d366d6436db0f55bce4"; - let key = Cc["@mozilla.org/windows-registry-key;1"]. - createInstance(Ci.nsIWindowsRegKey); - try { - key.open(Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH, - Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64); - } catch (e) { - // The build system could sign the files and not have the test registry key - // in which case we should fail the test if the updater binary is signed so - // the build system can be fixed by adding the registry key. - if (IS_AUTHENTICODE_CHECK_ENABLED) { - Assert.ok(!isBinSigned, - "the updater.exe binary should not be signed when the test " + - "registry key doesn't exist (if it is, build system " + - "configuration bug?)"); - } - - logTestInfo("this test can only run on the buildbot build system at this " + - "time"); - return false; - } - - // Check to make sure the service is installed - let args = ["wait-for-service-stop", "MozillaMaintenance", "10"]; - let exitValue = runTestHelperSync(args); - Assert.notEqual(exitValue, 0xEE, "the maintenance service should be " + - "installed (if not, build system configuration bug?)"); - - if (IS_AUTHENTICODE_CHECK_ENABLED) { - // The test registry key exists and IS_AUTHENTICODE_CHECK_ENABLED is true - // so the binaries should be signed. To run the test locally - // DISABLE_UPDATER_AUTHENTICODE_CHECK can be defined. - Assert.ok(isBinSigned, - "the updater.exe binary should be signed (if not, build system " + - "configuration bug?)"); - } - - // In case the machine is running an old maintenance service or if it - // is not installed, and permissions exist to install it. Then install - // the newer bin that we have since all of the other checks passed. - return attemptServiceInstall(); -} - -/** - * Helper function to check whether the a binary is signed. - * - * @param aBinPath - * The path to the file to check if it is signed. - * @return true if the file is signed and false if it isn't. - */ -function isBinarySigned(aBinPath) { - let args = ["check-signature", aBinPath]; - let exitValue = runTestHelperSync(args); - if (exitValue != 0) { - logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " + - exitValue + " for file " + aBinPath); - return false; - } - return true; -} - -/** - * Helper function for asynchronously setting up the application files required - * to launch the application for the updater tests by either copying or creating - * symlinks for the files. This is needed for Windows debug builds which can - * lock a file that is being copied so that the tests can run in parallel. After - * the files have been copied the setupUpdaterTestFinished function will be - * called. - */ -function setupAppFilesAsync() { - gTimeoutRuns++; - try { - setupAppFiles(); - } catch (e) { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " + - "files! Exception: " + e); - } - do_execute_soon(setupAppFilesAsync); - return; - } - - do_execute_soon(setupUpdaterTestFinished); -} - -/** - * Helper function for setting up the application files required to launch the - * application for the updater tests by either copying or creating symlinks to - * the files. - */ -function setupAppFiles() { - debugDump("start - copying or creating symlinks to application files " + - "for the test"); - - let destDir = getApplyDirFile(null, true); - if (!destDir.exists()) { - try { - destDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } catch (e) { - logTestInfo("unable to create directory! Path: " + destDir.path + - ", Exception: " + e); - do_throw(e); - } - } - - // Required files for the application or the test that aren't listed in the - // dependentlibs.list file. - let appFiles = [{relPath: FILE_APP_BIN, - inGreDir: false}, - {relPath: FILE_APPLICATION_INI, - inGreDir: true}, - {relPath: "dependentlibs.list", - inGreDir: true}]; - - // On Linux the updater.png must also be copied - if (IS_UNIX && !IS_MACOSX) { - appFiles.push({relPath: "icons/updater.png", - inGreDir: true}); - } - - // Read the dependent libs file leafnames from the dependentlibs.list file - // into the array. - let deplibsFile = gGREDirOrig.clone(); - deplibsFile.append("dependentlibs.list"); - let fis = Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(Ci.nsIFileInputStream); - fis.init(deplibsFile, 0x01, 0o444, Ci.nsIFileInputStream.CLOSE_ON_EOF); - fis.QueryInterface(Ci.nsILineInputStream); - - let hasMore; - let line = {}; - do { - hasMore = fis.readLine(line); - appFiles.push({relPath: line.value, - inGreDir: false}); - } while (hasMore); - - fis.close(); - - appFiles.forEach(function CMAF_FLN_FE(aAppFile) { - copyFileToTestAppDir(aAppFile.relPath, aAppFile.inGreDir); - }); - - copyTestUpdaterToBinDir(); - - debugDump("finish - copying or creating symlinks to application files " + - "for the test"); -} - -/** - * Copies the specified files from the dist/bin directory into the test's - * application directory. - * - * @param aFileRelPath - * The relative path to the source and the destination of the file to - * copy. - * @param aInGreDir - * Whether the file is located in the GRE directory which is - * <bundle>/Contents/Resources on Mac OS X and is the installation - * directory on all other platforms. If false the file must be in the - * GRE Binary directory which is <bundle>/Contents/MacOS on Mac OS X - * and is the installation directory on on all other platforms. - */ -function copyFileToTestAppDir(aFileRelPath, aInGreDir) { - // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its - // properties - let srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); - let destFile = aInGreDir ? getGREDir() : getGREBinDir(); - let fileRelPath = aFileRelPath; - let pathParts = fileRelPath.split("/"); - for (let i = 0; i < pathParts.length; i++) { - if (pathParts[i]) { - srcFile.append(pathParts[i]); - destFile.append(pathParts[i]); - } - } - - if (IS_MACOSX && !srcFile.exists()) { - debugDump("unable to copy file since it doesn't exist! Checking if " + - fileRelPath + ".app exists. Path: " + srcFile.path); - // gGREDirOrig and gGREBinDirOrig must always be cloned when changing its - // properties - srcFile = aInGreDir ? gGREDirOrig.clone() : gGREBinDirOrig.clone(); - destFile = aInGreDir ? getGREDir() : getGREBinDir(); - for (let i = 0; i < pathParts.length; i++) { - if (pathParts[i]) { - srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); - destFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : "")); - } - } - fileRelPath = fileRelPath + ".app"; - } - Assert.ok(srcFile.exists(), - MSG_SHOULD_EXIST + ", leafName: " + srcFile.leafName); - - // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a - // file extension and shouldSymlink will always be false on Windows. - let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" || - fileRelPath.substr(fileRelPath.length - 3) == ".so" || - fileRelPath.substr(fileRelPath.length - 6) == ".dylib"); - if (!shouldSymlink) { - if (!destFile.exists()) { - try { - srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName); - } catch (e) { - // Just in case it is partially copied - if (destFile.exists()) { - try { - destFile.remove(true); - } catch (ex) { - logTestInfo("unable to remove file that failed to copy! Path: " + - destFile.path); - } - } - do_throw("Unable to copy file! Path: " + srcFile.path + - ", Exception: " + ex); - } - } - } else { - try { - if (destFile.exists()) { - destFile.remove(false); - } - let ln = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile); - ln.initWithPath("/bin/ln"); - let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); - process.init(ln); - let args = ["-s", srcFile.path, destFile.path]; - process.run(true, args, args.length); - Assert.ok(destFile.isSymlink(), - destFile.leafName + " should be a symlink"); - } catch (e) { - do_throw("Unable to create symlink for file! Path: " + srcFile.path + - ", Exception: " + e); - } - } -} - -/** - * Attempts to upgrade the maintenance service if permissions are allowed. - * This is useful for XP where we have permission to upgrade in case an - * older service installer exists. Also if the user manually installed into - * a unprivileged location. - * - * @return true if the installed service is from this build. If the installed - * service is not from this build the test will fail instead of - * returning false. - */ -function attemptServiceInstall() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - let maintSvcDir = getMaintSvcDir(); - Assert.ok(maintSvcDir.exists(), - MSG_SHOULD_EXIST + ", leafName: " + maintSvcDir.leafName); - let oldMaintSvcBin = maintSvcDir.clone(); - oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); - Assert.ok(oldMaintSvcBin.exists(), - MSG_SHOULD_EXIST + ", leafName: " + oldMaintSvcBin.leafName); - let buildMaintSvcBin = getGREBinDir(); - buildMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); - if (readFileBytes(oldMaintSvcBin) == readFileBytes(buildMaintSvcBin)) { - debugDump("installed maintenance service binary is the same as the " + - "build's maintenance service binary"); - return true; - } - let backupMaintSvcBin = maintSvcDir.clone(); - backupMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN + ".backup"); - try { - if (backupMaintSvcBin.exists()) { - backupMaintSvcBin.remove(false); - } - oldMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN + ".backup"); - buildMaintSvcBin.copyTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); - backupMaintSvcBin.remove(false); - } catch (e) { - // Restore the original file in case the moveTo was successful. - if (backupMaintSvcBin.exists()) { - oldMaintSvcBin = maintSvcDir.clone(); - oldMaintSvcBin.append(FILE_MAINTENANCE_SERVICE_BIN); - if (!oldMaintSvcBin.exists()) { - backupMaintSvcBin.moveTo(maintSvcDir, FILE_MAINTENANCE_SERVICE_BIN); - } - } - Assert.ok(false, "should be able copy the test maintenance service to " + - "the maintenance service directory (if not, build system " + - "configuration bug?), path: " + maintSvcDir.path); - } - - return true; -} - -/** - * Waits for the applications that are launched by the maintenance service to - * stop. - */ -function waitServiceApps() { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - // maintenanceservice_installer.exe is started async during updates. - waitForApplicationStop("maintenanceservice_installer.exe"); - // maintenanceservice_tmp.exe is started async from the service installer. - waitForApplicationStop("maintenanceservice_tmp.exe"); - // In case the SCM thinks the service is stopped, but process still exists. - waitForApplicationStop("maintenanceservice.exe"); -} - -/** - * Waits for the maintenance service to stop. - */ -function waitForServiceStop(aFailTest) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - waitServiceApps(); - debugDump("waiting for the maintenance service to stop if necessary"); - // Use the helper bin to ensure the service is stopped. If not stopped, then - // wait for the service to stop (at most 120 seconds). - let args = ["wait-for-service-stop", "MozillaMaintenance", "120"]; - let exitValue = runTestHelperSync(args); - Assert.notEqual(exitValue, 0xEE, - "the maintenance service should exist"); - if (exitValue != 0) { - if (aFailTest) { - Assert.ok(false, "the maintenance service should stop, process exit " + - "value: " + exitValue); - } - logTestInfo("maintenance service did not stop which may cause test " + - "failures later, process exit value: " + exitValue); - } else { - debugDump("service stopped"); - } - waitServiceApps(); -} - -/** - * Waits for the specified application to stop. - * - * @param aApplication - * The application binary name to wait until it has stopped. - */ -function waitForApplicationStop(aApplication) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - debugDump("waiting for " + aApplication + " to stop if necessary"); - // Use the helper bin to ensure the application is stopped. If not stopped, - // then wait for it to stop (at most 120 seconds). - let args = ["wait-for-application-exit", aApplication, "120"]; - let exitValue = runTestHelperSync(args); - Assert.equal(exitValue, 0, - "the process should have stopped, process name: " + - aApplication); -} - - -/** - * Gets the platform specific shell binary that is launched using nsIProcess and - * in turn launches a binary used for the test (e.g. application, updater, - * etc.). A shell is used so debug console output can be redirected to a file so - * it doesn't end up in the test log. - * - * @return nsIFile for the shell binary to launch using nsIProcess. - */ -function getLaunchBin() { - let launchBin; - if (IS_WIN) { - launchBin = Services.dirsvc.get("WinD", Ci.nsIFile); - launchBin.append("System32"); - launchBin.append("cmd.exe"); - } else { - launchBin = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsILocalFile); - launchBin.initWithPath("/bin/sh"); - } - Assert.ok(launchBin.exists(), - MSG_SHOULD_EXIST + getMsgPath(launchBin.path)); - - return launchBin; -} - - -/** - * Locks a Windows directory. - * - * @param aDirPath - * The test file object that describes the file to make in use. - */ -function lockDirectory(aDirPath) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - debugDump("start - locking installation directory"); - const LPCWSTR = ctypes.char16_t.ptr; - const DWORD = ctypes.uint32_t; - const LPVOID = ctypes.voidptr_t; - const GENERIC_READ = 0x80000000; - const FILE_SHARE_READ = 1; - const FILE_SHARE_WRITE = 2; - const OPEN_EXISTING = 3; - const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000; - const INVALID_HANDLE_VALUE = LPVOID(0xffffffff); - let kernel32 = ctypes.open("kernel32"); - let CreateFile = kernel32.declare("CreateFileW", ctypes.default_abi, - LPVOID, LPCWSTR, DWORD, DWORD, - LPVOID, DWORD, DWORD, LPVOID); - gHandle = CreateFile(aDirPath, GENERIC_READ, - FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0), - OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0)); - Assert.notEqual(gHandle.toString(), INVALID_HANDLE_VALUE.toString(), - "the handle should not equal INVALID_HANDLE_VALUE"); - kernel32.close(); - debugDump("finish - locking installation directory"); -} - -/** - * Launches the test helper binary to make it in use for updater tests and then - * calls waitForHelperSleep. - * - * @param aTestFile - * The test file object that describes the file to make in use. - */ -function runHelperFileInUse(aRelPath, aCopyTestHelper) { - logTestInfo("aRelPath: " + aRelPath); - // Launch an existing file so it is in use during the update. - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let fileInUseBin = getApplyDirFile(aRelPath); - if (aCopyTestHelper) { - fileInUseBin.remove(false); - helperBin.copyTo(fileInUseBin.parent, fileInUseBin.leafName); - } - fileInUseBin.permissions = PERMS_DIRECTORY; - let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", - HELPER_SLEEP_TIMEOUT]; - let fileInUseProcess = Cc["@mozilla.org/process/util;1"]. - createInstance(Ci.nsIProcess); - fileInUseProcess.init(fileInUseBin); - fileInUseProcess.run(false, args, args.length); - - do_execute_soon(waitForHelperSleep); -} - -/** - * Launches the test helper binary and locks a file specified on the command - * line for updater tests and then calls waitForHelperSleep. - * - * @param aTestFile - * The test file object that describes the file to lock. - */ -function runHelperLockFile(aTestFile) { - // Exclusively lock an existing file so it is in use during the update. - let helperBin = getTestDirFile(FILE_HELPER_BIN); - let helperDestDir = getApplyDirFile(DIR_RESOURCES); - helperBin.copyTo(helperDestDir, FILE_HELPER_BIN); - helperBin = getApplyDirFile(DIR_RESOURCES + FILE_HELPER_BIN); - // Strip off the first two directories so the path has to be from the helper's - // working directory. - let lockFileRelPath = aTestFile.relPathDir.split("/"); - if (IS_MACOSX) { - lockFileRelPath = lockFileRelPath.slice(2); - } - lockFileRelPath = lockFileRelPath.join("/") + "/" + aTestFile.fileName; - let args = [getApplyDirPath() + DIR_RESOURCES, "input", "output", "-s", - HELPER_SLEEP_TIMEOUT, lockFileRelPath]; - let helperProcess = Cc["@mozilla.org/process/util;1"]. - createInstance(Ci.nsIProcess); - helperProcess.init(helperBin); - helperProcess.run(false, args, args.length); - - do_execute_soon(waitForHelperSleep); -} - -/** - * Helper function that waits until the helper has completed its operations and - * calls waitForHelperSleepFinished when it is finished. - */ -function waitForHelperSleep() { - gTimeoutRuns++; - // Give the lock file process time to lock the file before updating otherwise - // this test can fail intermittently on Windows debug builds. - let output = getApplyDirFile(DIR_RESOURCES + "output", true); - if (readFile(output) != "sleeping\n") { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " + - "finish its operation. Path: " + output.path); - } - // Uses do_timeout instead of do_execute_soon to lessen log spew. - do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperSleep); - return; - } - try { - output.remove(false); - } catch (e) { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper " + - "message file to no longer be in use. Path: " + output.path); - } - debugDump("failed to remove file. Path: " + output.path); - // Uses do_timeout instead of do_execute_soon to lessen log spew. - do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperSleep); - return; - } - waitForHelperSleepFinished(); -} - -/** - * Helper function that waits until the helper has finished its operations - * before calling waitForHelperFinishFileUnlock to verify that the helper's - * input and output directories are no longer in use. - */ -function waitForHelperFinished() { - // Give the lock file process time to lock the file before updating otherwise - // this test can fail intermittently on Windows debug builds. - let output = getApplyDirFile(DIR_RESOURCES + "output", true); - if (readFile(output) != "finished\n") { - // Uses do_timeout instead of do_execute_soon to lessen log spew. - do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperFinished); - return; - } - // Give the lock file process time to unlock the file before deleting the - // input and output files. - waitForHelperFinishFileUnlock(); -} - -/** - * Helper function that waits until the helper's input and output files are no - * longer in use before calling waitForHelperExitFinished. - */ -function waitForHelperFinishFileUnlock() { - try { - let output = getApplyDirFile(DIR_RESOURCES + "output", true); - if (output.exists()) { - output.remove(false); - } - let input = getApplyDirFile(DIR_RESOURCES + "input", true); - if (input.exists()) { - input.remove(false); - } - } catch (e) { - // Give the lock file process time to unlock the file before deleting the - // input and output files. - do_execute_soon(waitForHelperFinishFileUnlock); - return; - } - do_execute_soon(waitForHelperExitFinished); -} - -/** - * Helper function to tell the helper to finish and exit its sleep state. - */ -function waitForHelperExit() { - let input = getApplyDirFile(DIR_RESOURCES + "input", true); - writeFile(input, "finish\n"); - waitForHelperFinished(); -} - -/** - * Helper function for updater binary tests that creates the files and - * directories used by the test. - * - * @param aMarFile - * The mar file for the update test. - * @param aPostUpdateAsync - * When null the updater.ini is not created otherwise this parameter - * is passed to createUpdaterINI. - * @param aPostUpdateExeRelPathPrefix - * When aPostUpdateAsync null this value is ignored otherwise it is - * passed to createUpdaterINI. - */ -function setupUpdaterTest(aMarFile, aPostUpdateAsync, - aPostUpdateExeRelPathPrefix = "") { - let updatesPatchDir = getUpdatesPatchDir(); - if (!updatesPatchDir.exists()) { - updatesPatchDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - // Copy the mar that will be applied - let mar = getTestDirFile(aMarFile); - mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_MAR); - - let helperBin = getTestDirFile(FILE_HELPER_BIN); - helperBin.permissions = PERMS_DIRECTORY; - let afterApplyBinDir = getApplyDirFile(DIR_RESOURCES, true); - helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile); - helperBin.copyToFollowingLinks(afterApplyBinDir, gPostUpdateBinFile); - - gTestFiles.forEach(function SUT_TF_FE(aTestFile) { - if (aTestFile.originalFile || aTestFile.originalContents) { - let testDir = getApplyDirFile(aTestFile.relPathDir, true); - if (!testDir.exists()) { - testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - - let testFile; - if (aTestFile.originalFile) { - testFile = getTestDirFile(aTestFile.originalFile); - testFile.copyToFollowingLinks(testDir, aTestFile.fileName); - testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName); - } else { - testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName, - true); - writeFile(testFile, aTestFile.originalContents); - } - - // Skip these tests on Windows since chmod doesn't really set permissions - // on Windows. - if (!IS_WIN && aTestFile.originalPerms) { - testFile.permissions = aTestFile.originalPerms; - // Store the actual permissions on the file for reference later after - // setting the permissions. - if (!aTestFile.comparePerms) { - aTestFile.comparePerms = testFile.permissions; - } - } - } - }); - - // Add the test directory that will be updated for a successful update or left - // in the initial state for a failed update. - gTestDirs.forEach(function SUT_TD_FE(aTestDir) { - let testDir = getApplyDirFile(aTestDir.relPathDir, true); - if (!testDir.exists()) { - testDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - - if (aTestDir.files) { - aTestDir.files.forEach(function SUT_TD_F_FE(aTestFile) { - let testFile = getApplyDirFile(aTestDir.relPathDir + aTestFile, true); - if (!testFile.exists()) { - testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); - } - }); - } - - if (aTestDir.subDirs) { - aTestDir.subDirs.forEach(function SUT_TD_SD_FE(aSubDir) { - let testSubDir = getApplyDirFile(aTestDir.relPathDir + aSubDir, true); - if (!testSubDir.exists()) { - testSubDir.create(Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); - } - - if (aTestDir.subDirFiles) { - aTestDir.subDirFiles.forEach(function SUT_TD_SDF_FE(aTestFile) { - let testFile = getApplyDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true); - if (!testFile.exists()) { - testFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE); - } - }); - } - }); - } - }); - - setupActiveUpdate(); - - if (aPostUpdateAsync !== null) { - createUpdaterINI(aPostUpdateAsync, aPostUpdateExeRelPathPrefix); - } - - setupAppFilesAsync(); -} - -/** - * Helper function for updater binary tests that creates the update-settings.ini - * file. - */ -function createUpdateSettingsINI() { - let ini = getApplyDirFile(DIR_RESOURCES + FILE_UPDATE_SETTINGS_INI, true); - writeFile(ini, UPDATE_SETTINGS_CONTENTS); -} - -/** - * Helper function for updater binary tests that creates the updater.ini - * file. - * - * @param aIsExeAsync - * True or undefined if the post update process should be async. If - * undefined ExeAsync will not be added to the updater.ini file in - * order to test the default launch behavior which is async. - * @param aExeRelPathPrefix - * A string to prefix the ExeRelPath values in the updater.ini. - */ -function createUpdaterINI(aIsExeAsync, aExeRelPathPrefix) { - let exeArg = "ExeArg=post-update-async\n"; - let exeAsync = ""; - if (aIsExeAsync !== undefined) { - if (aIsExeAsync) { - exeAsync = "ExeAsync=true\n"; - } else { - exeArg = "ExeArg=post-update-sync\n"; - exeAsync = "ExeAsync=false\n"; - } - } - - if (aExeRelPathPrefix && IS_WIN) { - aExeRelPathPrefix = aExeRelPathPrefix.replace("/", "\\"); - } - - let exeRelPathMac = "ExeRelPath=" + aExeRelPathPrefix + DIR_RESOURCES + - gPostUpdateBinFile + "\n"; - let exeRelPathWin = "ExeRelPath=" + aExeRelPathPrefix + gPostUpdateBinFile + "\n"; - let updaterIniContents = "[Strings]\n" + - "Title=Update Test\n" + - "Info=Running update test " + gTestID + "\n\n" + - "[PostUpdateMac]\n" + - exeRelPathMac + - exeArg + - exeAsync + - "\n" + - "[PostUpdateWin]\n" + - exeRelPathWin + - exeArg + - exeAsync; - let updaterIni = getApplyDirFile(DIR_RESOURCES + FILE_UPDATER_INI, true); - writeFile(updaterIni, updaterIniContents); -} - -/** - * Gets the message log path used for assert checks to lessen the length printed - * to the log file. - * - * @param aPath - * The path to shorten for the log file. - * @return the message including the shortened path for the log file. - */ -function getMsgPath(aPath) { - return ", path: " + replaceLogPaths(aPath); -} - -/** - * Helper function that replaces the common part of paths in the update log's - * contents with <test_dir_path> for paths to the the test directory and - * <update_dir_path> for paths to the update directory. This is needed since - * Assert.equal will truncate what it prints to the xpcshell log file. - * - * @param aLogContents - * The update log file's contents. - * @return the log contents with the paths replaced. - */ -function replaceLogPaths(aLogContents) { - let logContents = aLogContents; - // Remove the majority of the path up to the test directory. This is needed - // since Assert.equal won't print long strings to the test logs. - let testDirPath = do_get_file(gTestID, false).path; - if (IS_WIN) { - // Replace \\ with \\\\ so the regexp works. - testDirPath = testDirPath.replace(/\\/g, "\\\\"); - } - logContents = logContents.replace(new RegExp(testDirPath, "g"), - "<test_dir_path>/" + gTestID); - let updatesDirPath = getMockUpdRootD().path; - if (IS_WIN) { - // Replace \\ with \\\\ so the regexp works. - updatesDirPath = updatesDirPath.replace(/\\/g, "\\\\"); - } - logContents = logContents.replace(new RegExp(updatesDirPath, "g"), - "<update_dir_path>/" + gTestID); - if (IS_WIN) { - // Replace \ with / - logContents = logContents.replace(/\\/g, "/"); - } - return logContents; -} - -/** - * Helper function for updater binary tests for verifying the contents of the - * update log after a successful update. - * - * @param aCompareLogFile - * The log file to compare the update log with. - * @param aStaged - * If the update log file is for a staged update. - * @param aReplace - * If the update log file is for a replace update. - * @param aExcludeDistDir - * Removes lines containing the distribution directory from the log - * file to compare the update log with. - */ -function checkUpdateLogContents(aCompareLogFile, aStaged = false, - aReplace = false, aExcludeDistDir = false) { - if (IS_UNIX && !IS_MACOSX) { - // The order that files are returned when enumerating the file system on - // Linux is not deterministic so skip checking the logs. - return; - } - - let updateLog = getUpdateLog(FILE_LAST_UPDATE_LOG); - let updateLogContents = readFileBytes(updateLog); - - // The channel-prefs.js is defined in gTestFilesCommon which will always be - // located to the end of gTestFiles when it is present. - if (gTestFiles.length > 1 && - gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && - !gTestFiles[gTestFiles.length - 1].originalContents) { - updateLogContents = updateLogContents.replace(/.*defaults\/.*/g, ""); - } - - if (gTestFiles.length > 2 && - gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && - !gTestFiles[gTestFiles.length - 2].originalContents) { - updateLogContents = updateLogContents.replace(/.*update-settings.ini.*/g, ""); - } - - // Skip the source/destination lines since they contain absolute paths. - // These could be changed to relative paths using <test_dir_path> and - // <update_dir_path> - updateLogContents = updateLogContents.replace(/PATCH DIRECTORY.*/g, ""); - updateLogContents = updateLogContents.replace(/INSTALLATION DIRECTORY.*/g, ""); - updateLogContents = updateLogContents.replace(/WORKING DIRECTORY.*/g, ""); - // Skip lines that log failed attempts to open the callback executable. - updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, ""); - - if (IS_MACOSX) { - // Skip lines that log moving the distribution directory for Mac v2 signing. - updateLogContents = updateLogContents.replace(/Moving old [^\n]*\nrename_file: .*/g, ""); - updateLogContents = updateLogContents.replace(/New distribution directory .*/g, ""); - } - - if (IS_WIN) { - // The FindFile results when enumerating the filesystem on Windows is not - // determistic so the results matching the following need to be fixed. - let re = new RegExp("([^\n]* 7\/7text1[^\n]*)\n" + - "([^\n]* 7\/7text0[^\n]*)\n", "g"); - updateLogContents = updateLogContents.replace(re, "$2\n$1\n"); - } - - if (aReplace) { - // Remove the lines which contain absolute paths - updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, ""); - updateLogContents = updateLogContents.replace(/^ensure_remove: failed to remove file: .*$/mg, ""); - updateLogContents = updateLogContents.replace(/^ensure_remove_recursive: unable to remove directory: .*$/mg, ""); - updateLogContents = updateLogContents.replace(/^Removing tmpDir failed, err: -1$/mg, ""); - updateLogContents = updateLogContents.replace(/^remove_recursive_on_reboot: .*$/mg, ""); - } - - // Remove carriage returns. - updateLogContents = updateLogContents.replace(/\r/g, ""); - // Replace error codes since they are different on each platform. - updateLogContents = updateLogContents.replace(/, err:.*\n/g, "\n"); - // Replace to make the log parsing happy. - updateLogContents = updateLogContents.replace(/non-fatal error /g, ""); - // Remove consecutive newlines - updateLogContents = updateLogContents.replace(/\n+/g, "\n"); - // Remove leading and trailing newlines - updateLogContents = updateLogContents.replace(/^\n|\n$/g, ""); - // Replace the log paths with <test_dir_path> and <update_dir_path> - updateLogContents = replaceLogPaths(updateLogContents); - - let compareLogContents = ""; - if (aCompareLogFile) { - compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile)); - } - - if (aStaged) { - compareLogContents = PERFORMING_STAGED_UPDATE + "\n" + compareLogContents; - } - - // The channel-prefs.js is defined in gTestFilesCommon which will always be - // located to the end of gTestFiles. - if (gTestFiles.length > 1 && - gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" && - !gTestFiles[gTestFiles.length - 1].originalContents) { - compareLogContents = compareLogContents.replace(/.*defaults\/.*/g, ""); - } - - if (gTestFiles.length > 2 && - gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI && - !gTestFiles[gTestFiles.length - 2].originalContents) { - compareLogContents = compareLogContents.replace(/.*update-settings.ini.*/g, ""); - } - - if (aExcludeDistDir) { - compareLogContents = compareLogContents.replace(/.*distribution\/.*/g, ""); - } - - // Remove leading and trailing newlines - compareLogContents = compareLogContents.replace(/\n+/g, "\n"); - // Remove leading and trailing newlines - compareLogContents = compareLogContents.replace(/^\n|\n$/g, ""); - - // Don't write the contents of the file to the log to reduce log spam - // unless there is a failure. - if (compareLogContents == updateLogContents) { - Assert.ok(true, "the update log contents" + MSG_SHOULD_EQUAL); - } else { - logTestInfo("the update log contents are not correct"); - logUpdateLog(FILE_LAST_UPDATE_LOG); - let aryLog = updateLogContents.split("\n"); - let aryCompare = compareLogContents.split("\n"); - // Pushing an empty string to both arrays makes it so either array's length - // can be used in the for loop below without going out of bounds. - aryLog.push(""); - aryCompare.push(""); - // xpcshell tests won't display the entire contents so log the first - // incorrect line. - for (let i = 0; i < aryLog.length; ++i) { - if (aryLog[i] != aryCompare[i]) { - logTestInfo("the first incorrect line in the update log is: " + - aryLog[i]); - Assert.equal(aryLog[i], aryCompare[i], - "the update log contents" + MSG_SHOULD_EQUAL); - } - } - // This should never happen! - do_throw("Unable to find incorrect update log contents!"); - } -} - -/** - * Helper function to check if the update log contains a string. - * - * @param aCheckString - * The string to check if the update log contains. - */ -function checkUpdateLogContains(aCheckString) { - let updateLog = getUpdateLog(FILE_LAST_UPDATE_LOG); - let updateLogContents = readFileBytes(updateLog).replace(/\r\n/g, "\n"); - updateLogContents = replaceLogPaths(updateLogContents); - Assert.notEqual(updateLogContents.indexOf(aCheckString), -1, - "the update log contents should contain value: " + - aCheckString); -} - -/** - * Helper function for updater binary tests for verifying the state of files and - * directories after a successful update. - * - * @param aGetFileFunc - * The function used to get the files in the directory to be checked. - * @param aStageDirExists - * If true the staging directory will be tested for existence and if - * false the staging directory will be tested for non-existence. - * @param aToBeDeletedDirExists - * On Windows, if true the tobedeleted directory will be tested for - * existence and if false the tobedeleted directory will be tested for - * non-existence. On all othere platforms it will be tested for - * non-existence. - */ -function checkFilesAfterUpdateSuccess(aGetFileFunc, aStageDirExists = false, - aToBeDeletedDirExists = false) { - debugDump("testing contents of files after a successful update"); - gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); - debugDump("testing file: " + testFile.path); - if (aTestFile.compareFile || aTestFile.compareContents) { - Assert.ok(testFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(testFile.path)); - - // Skip these tests on Windows since chmod doesn't really set permissions - // on Windows. - if (!IS_WIN && aTestFile.comparePerms) { - // Check if the permssions as set in the complete mar file are correct. - Assert.equal(testFile.permissions & 0xfff, - aTestFile.comparePerms & 0xfff, - "the file permissions" + MSG_SHOULD_EQUAL); - } - - let fileContents1 = readFileBytes(testFile); - let fileContents2 = aTestFile.compareFile ? - readFileBytes(getTestDirFile(aTestFile.compareFile)) : - aTestFile.compareContents; - // Don't write the contents of the file to the log to reduce log spam - // unless there is a failure. - if (fileContents1 == fileContents2) { - Assert.ok(true, "the file contents" + MSG_SHOULD_EQUAL); - } else { - Assert.equal(fileContents1, fileContents2, - "the file contents" + MSG_SHOULD_EQUAL); - } - } else { - Assert.ok(!testFile.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(testFile.path)); - } - }); - - debugDump("testing operations specified in removed-files were performed " + - "after a successful update"); - gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) { - let testDir = aGetFileFunc(aTestDir.relPathDir, true); - debugDump("testing directory: " + testDir.path); - if (aTestDir.dirRemoved) { - Assert.ok(!testDir.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(testDir.path)); - } else { - Assert.ok(testDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(testDir.path)); - - if (aTestDir.files) { - aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); - if (aTestDir.filesRemoved) { - Assert.ok(!testFile.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(testFile.path)); - } else { - Assert.ok(testFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(testFile.path)); - } - }); - } - - if (aTestDir.subDirs) { - aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { - let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); - Assert.ok(testSubDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(testSubDir.path)); - if (aTestDir.subDirFiles) { - aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + - aSubDir + aTestFile, true); - Assert.ok(testFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(testFile.path)); - }); - } - }); - } - } - }); - - checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists); -} - -/** - * Helper function for updater binary tests for verifying the state of files and - * directories after a failed update. - * - * @param aGetFileFunc - * The function used to get the files in the directory to be checked. - * @param aStageDirExists - * If true the staging directory will be tested for existence and if - * false the staging directory will be tested for non-existence. - * @param aToBeDeletedDirExists - * On Windows, if true the tobedeleted directory will be tested for - * existence and if false the tobedeleted directory will be tested for - * non-existence. On all othere platforms it will be tested for - * non-existence. - */ -function checkFilesAfterUpdateFailure(aGetFileFunc, aStageDirExists = false, - aToBeDeletedDirExists = false) { - debugDump("testing contents of files after a failed update"); - gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestFile.relPathDir + aTestFile.fileName, true); - debugDump("testing file: " + testFile.path); - if (aTestFile.compareFile || aTestFile.compareContents) { - Assert.ok(testFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(testFile.path)); - - // Skip these tests on Windows since chmod doesn't really set permissions - // on Windows. - if (!IS_WIN && aTestFile.comparePerms) { - // Check the original permssions are retained on the file. - Assert.equal(testFile.permissions & 0xfff, - aTestFile.comparePerms & 0xfff, - "the file permissions" + MSG_SHOULD_EQUAL); - } - - let fileContents1 = readFileBytes(testFile); - let fileContents2 = aTestFile.compareFile ? - readFileBytes(getTestDirFile(aTestFile.compareFile)) : - aTestFile.compareContents; - // Don't write the contents of the file to the log to reduce log spam - // unless there is a failure. - if (fileContents1 == fileContents2) { - Assert.ok(true, "the file contents" + MSG_SHOULD_EQUAL); - } else { - Assert.equal(fileContents1, fileContents2, - "the file contents" + MSG_SHOULD_EQUAL); - } - } else { - Assert.ok(!testFile.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(testFile.path)); - } - }); - - debugDump("testing operations specified in removed-files were not " + - "performed after a failed update"); - gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) { - let testDir = aGetFileFunc(aTestDir.relPathDir, true); - Assert.ok(testDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(testDir.path)); - - if (aTestDir.files) { - aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + aTestFile, true); - Assert.ok(testFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(testFile.path)); - }); - } - - if (aTestDir.subDirs) { - aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) { - let testSubDir = aGetFileFunc(aTestDir.relPathDir + aSubDir, true); - Assert.ok(testSubDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(testSubDir.path)); - if (aTestDir.subDirFiles) { - aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) { - let testFile = aGetFileFunc(aTestDir.relPathDir + - aSubDir + aTestFile, true); - Assert.ok(testFile.exists(), - MSG_SHOULD_EXIST + getMsgPath(testFile.path)); - }); - } - }); - } - }); - - checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists); -} - -/** - * Helper function for updater binary tests for verifying the state of common - * files and directories after a successful or failed update. - * - * @param aGetFileFunc - * the function used to get the files in the directory to be checked. - * @param aStageDirExists - * If true the staging directory will be tested for existence and if - * false the staging directory will be tested for non-existence. - * @param aToBeDeletedDirExists - * On Windows, if true the tobedeleted directory will be tested for - * existence and if false the tobedeleted directory will be tested for - * non-existence. On all othere platforms it will be tested for - * non-existence. - */ -function checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists, - aToBeDeletedDirExists) { - debugDump("testing extra directories"); - let stageDir = getStageDirFile(null, true); - if (aStageDirExists) { - Assert.ok(stageDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(stageDir.path)); - } else { - Assert.ok(!stageDir.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(stageDir.path)); - } - - let toBeDeletedDirExists = IS_WIN ? aToBeDeletedDirExists : false; - let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true); - if (toBeDeletedDirExists) { - Assert.ok(toBeDeletedDir.exists(), - MSG_SHOULD_EXIST + getMsgPath(toBeDeletedDir.path)); - } else { - Assert.ok(!toBeDeletedDir.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(toBeDeletedDir.path)); - } - - let updatingDir = getApplyDirFile("updating", true); - Assert.ok(!updatingDir.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(updatingDir.path)); - - if (stageDir.exists()) { - updatingDir = stageDir.clone(); - updatingDir.append("updating"); - Assert.ok(!updatingDir.exists(), - MSG_SHOULD_NOT_EXIST + getMsgPath(updatingDir.path)); - } - - debugDump("testing backup files should not be left behind in the " + - "application directory"); - let applyToDir = getApplyDirFile(null, true); - checkFilesInDirRecursive(applyToDir, checkForBackupFiles); - - if (stageDir.exists()) { - debugDump("testing backup files should not be left behind in the " + - "staging directory"); - applyToDir = getApplyDirFile(null, true); - checkFilesInDirRecursive(stageDir, checkForBackupFiles); - } -} - -/** - * Helper function for updater binary tests for verifying the contents of the - * updater callback application log which should contain the arguments passed to - * the callback application. - */ -function checkCallbackLog() { - let appLaunchLog = getApplyDirFile(DIR_RESOURCES + gCallbackArgs[1], true); - if (!appLaunchLog.exists()) { - // Uses do_timeout instead of do_execute_soon to lessen log spew. - do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackLog); - return; - } - - let expectedLogContents = gCallbackArgs.join("\n") + "\n"; - let logContents = readFile(appLaunchLog); - // It is possible for the log file contents check to occur before the log file - // contents are completely written so wait until the contents are the expected - // value. If the contents are never the expected value then the test will - // fail by timing out after gTimeoutRuns is greater than MAX_TIMEOUT_RUNS or - // the test harness times out the test. - if (logContents != expectedLogContents) { - gTimeoutRuns++; - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - logTestInfo("callback log contents are not correct"); - // This file doesn't contain full paths so there is no need to call - // replaceLogPaths. - let aryLog = logContents.split("\n"); - let aryCompare = expectedLogContents.split("\n"); - // Pushing an empty string to both arrays makes it so either array's length - // can be used in the for loop below without going out of bounds. - aryLog.push(""); - aryCompare.push(""); - // xpcshell tests won't display the entire contents so log the incorrect - // line. - for (let i = 0; i < aryLog.length; ++i) { - if (aryLog[i] != aryCompare[i]) { - logTestInfo("the first incorrect line in the callback log is: " + - aryLog[i]); - Assert.equal(aryLog[i], aryCompare[i], - "the callback log contents" + MSG_SHOULD_EQUAL); - } - } - // This should never happen! - do_throw("Unable to find incorrect callback log contents!"); - } - // Uses do_timeout instead of do_execute_soon to lessen log spew. - do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackLog); - return; - } - Assert.ok(true, "the callback log contents" + MSG_SHOULD_EQUAL); - - waitForFilesInUse(); -} - -/** - * Helper function for updater binary tests for getting the log and running - * files created by the test helper binary file when called with the post-update - * command line argument. - * - * @param aSuffix - * The string to append to the post update test helper binary path. - */ -function getPostUpdateFile(aSuffix) { - return getApplyDirFile(DIR_RESOURCES + gPostUpdateBinFile + aSuffix, true); -} - -/** - * Checks the contents of the updater post update binary log. When completed - * checkPostUpdateAppLogFinished will be called. - */ -function checkPostUpdateAppLog() { - // Only Mac OS X and Windows support post update. - if (IS_MACOSX || IS_WIN) { - gTimeoutRuns++; - let postUpdateLog = getPostUpdateFile(".log"); - if (!postUpdateLog.exists()) { - debugDump("postUpdateLog does not exist. Path: " + postUpdateLog.path); - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + - "process to create the post update log. Path: " + - postUpdateLog.path); - } - do_execute_soon(checkPostUpdateAppLog); - return; - } - - let logContents = readFile(postUpdateLog); - // It is possible for the log file contents check to occur before the log file - // contents are completely written so wait until the contents are the expected - // value. If the contents are never the expected value then the test will - // fail by timing out after gTimeoutRuns is greater than MAX_TIMEOUT_RUNS or - // the test harness times out the test. - if (logContents != "post-update\n") { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the post update " + - "process to create the expected contents in the post update log. Path: " + - postUpdateLog.path); - } - do_execute_soon(checkPostUpdateAppLog); - return; - } - Assert.ok(true, "the post update log contents" + MSG_SHOULD_EQUAL); - } - - do_execute_soon(checkPostUpdateAppLogFinished); -} - -/** - * Helper function to check if a file is in use on Windows by making a copy of - * a file and attempting to delete the original file. If the deletion is - * successful the copy of the original file is renamed to the original file's - * name and if the deletion is not successful the copy of the original file is - * deleted. - * - * @param aFile - * An nsIFile for the file to be checked if it is in use. - * @return true if the file can't be deleted and false otherwise. - */ -function isFileInUse(aFile) { - if (!IS_WIN) { - do_throw("Windows only function called by a different platform!"); - } - - if (!aFile.exists()) { - debugDump("file does not exist, path: " + aFile.path); - return false; - } - - let fileBak = aFile.parent; - fileBak.append(aFile.leafName + ".bak"); - try { - if (fileBak.exists()) { - fileBak.remove(false); - } - aFile.copyTo(aFile.parent, fileBak.leafName); - aFile.remove(false); - fileBak.moveTo(aFile.parent, aFile.leafName); - debugDump("file is not in use, path: " + aFile.path); - return false; - } catch (e) { - debugDump("file in use, path: " + aFile.path + ", exception: " + e); - try { - if (fileBak.exists()) { - fileBak.remove(false); - } - } catch (ex) { - logTestInfo("unable to remove backup file, path: " + - fileBak.path + ", exception: " + ex); - } - } - return true; -} - -/** - * Waits until files that are in use that break tests are no longer in use and - * then calls doTestFinish to end the test. - */ -function waitForFilesInUse() { - if (IS_WIN) { - let fileNames = [FILE_APP_BIN, FILE_UPDATER_BIN, - FILE_MAINTENANCE_SERVICE_INSTALLER_BIN]; - for (let i = 0; i < fileNames.length; ++i) { - let file = getApplyDirFile(fileNames[i], true); - if (isFileInUse(file)) { - do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForFilesInUse); - return; - } - } - } - - debugDump("calling doTestFinish"); - doTestFinish(); -} - -/** - * Helper function for updater binary tests for verifying there are no update - * backup files left behind after an update. - * - * @param aFile - * An nsIFile to check if it has moz-backup for its extension. - */ -function checkForBackupFiles(aFile) { - Assert.notEqual(getFileExtension(aFile), "moz-backup", - "the file's extension should not equal moz-backup" + - getMsgPath(aFile.path)); -} - -/** - * Helper function for updater binary tests for recursively enumerating a - * directory and calling a callback function with the file as a parameter for - * each file found. - * - * @param aDir - * A nsIFile for the directory to be deleted - * @param aCallback - * A callback function that will be called with the file as a - * parameter for each file found. - */ -function checkFilesInDirRecursive(aDir, aCallback) { - if (!aDir.exists()) { - do_throw("Directory must exist!"); - } - - let dirEntries = aDir.directoryEntries; - while (dirEntries.hasMoreElements()) { - let entry = dirEntries.getNext().QueryInterface(Ci.nsIFile); - - if (entry.exists()) { - if (entry.isDirectory()) { - checkFilesInDirRecursive(entry, aCallback); - } else { - aCallback(entry); - } - } - } -} - - -/** - * Helper function to override the update prompt component to verify whether it - * is called or not. - * - * @param aCallback - * The callback to call if the update prompt component is called. - */ -function overrideUpdatePrompt(aCallback) { - Cu.import("resource://testing-common/MockRegistrar.jsm"); - MockRegistrar.register("@mozilla.org/updates/update-prompt;1", UpdatePrompt, [aCallback]); -} - -function UpdatePrompt(aCallback) { - this._callback = aCallback; - - let fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded", - "showUpdateError", "showUpdateHistory", "showUpdateInstalled"]; - - fns.forEach(function UP_fns(aPromptFn) { - UpdatePrompt.prototype[aPromptFn] = function() { - if (!this._callback) { - return; - } - - let callback = this._callback[aPromptFn]; - if (!callback) { - return; - } - - callback.apply(this._callback, - Array.prototype.slice.call(arguments)); - }; - }); -} - -UpdatePrompt.prototype = { - flags: Ci.nsIClassInfo.SINGLETON, - getScriptableHelper: () => null, - getInterfaces: function(aCount) { - let interfaces = [Ci.nsISupports, Ci.nsIUpdatePrompt]; - aCount.value = interfaces.length; - return interfaces; - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIClassInfo, Ci.nsIUpdatePrompt]) -}; - -/* Update check listener */ -const updateCheckListener = { - onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) { - }, - - onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) { - gRequestURL = aRequest.channel.originalURI.spec; - gUpdateCount = aUpdateCount; - gUpdates = aUpdates; - debugDump("url = " + gRequestURL + ", " + - "request.status = " + aRequest.status + ", " + - "updateCount = " + aUpdateCount); - // Use a timeout to allow the XHR to complete - do_execute_soon(gCheckFunc); - }, - - onError: function UCL_onError(aRequest, aUpdate) { - gRequestURL = aRequest.channel.originalURI.spec; - gStatusCode = aRequest.status; - if (gStatusCode == 0) { - gStatusCode = aRequest.channel.QueryInterface(Ci.nsIRequest).status; - } - gStatusText = aUpdate.statusText ? aUpdate.statusText : null; - debugDump("url = " + gRequestURL + ", " + - "request.status = " + gStatusCode + ", " + - "update.statusText = " + gStatusText); - // Use a timeout to allow the XHR to complete - do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate)); - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIUpdateCheckListener]) -}; - -/* Update download listener - nsIRequestObserver */ -const downloadListener = { - onStartRequest: function DL_onStartRequest(aRequest, aContext) { - }, - - onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) { - }, - - onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) { - }, - - onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) { - gStatusResult = aStatus; - // Use a timeout to allow the request to complete - do_execute_soon(gCheckFunc); - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, - Ci.nsIProgressEventSink]) -}; - -/** - * Helper for starting the http server used by the tests - */ -function start_httpserver() { - let dir = getTestDirFile(); - debugDump("http server directory path: " + dir.path); - - if (!dir.isDirectory()) { - do_throw("A file instead of a directory was specified for HttpServer " + - "registerDirectory! Path: " + dir.path); - } - - let { HttpServer } = Cu.import("resource://testing-common/httpd.js", {}); - gTestserver = new HttpServer(); - gTestserver.registerDirectory("/", dir); - gTestserver.registerPathHandler("/" + gHTTPHandlerPath, pathHandler); - gTestserver.start(-1); - let testserverPort = gTestserver.identity.primaryPort; - gURLData = URL_HOST + ":" + testserverPort + "/"; - debugDump("http server port = " + testserverPort); -} - -/** - * Custom path handler for the http server - * - * @param aMetadata - * The http metadata for the request. - * @param aResponse - * The http response for the request. - */ -function pathHandler(aMetadata, aResponse) { - aResponse.setHeader("Content-Type", "text/xml", false); - aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK"); - aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length); -} - -/** - * Helper for stopping the http server used by the tests - * - * @param aCallback - * The callback to call after stopping the http server. - */ -function stop_httpserver(aCallback) { - Assert.ok(!!aCallback, "the aCallback parameter should be defined"); - gTestserver.stop(aCallback); -} - -/** - * Creates an nsIXULAppInfo - * - * @param aID - * The ID of the test application - * @param aName - * A name for the test application - * @param aVersion - * The version of the application - * @param aPlatformVersion - * The gecko version of the application - */ -function createAppInfo(aID, aName, aVersion, aPlatformVersion) { - const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1"; - const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}"); - let ifaces = [Ci.nsIXULAppInfo, Ci.nsIXULRuntime]; - if (IS_WIN) { - ifaces.push(Ci.nsIWinAppHelper); - } - const XULAppInfo = { - vendor: APP_INFO_VENDOR, - name: aName, - ID: aID, - version: aVersion, - appBuildID: "2007010101", - platformVersion: aPlatformVersion, - platformBuildID: "2007010101", - inSafeMode: false, - logConsoleErrors: true, - OS: "XPCShell", - XPCOMABI: "noarch-spidermonkey", - - QueryInterface: XPCOMUtils.generateQI(ifaces) - }; - - const XULAppInfoFactory = { - createInstance: function(aOuter, aIID) { - if (aOuter == null) { - return XULAppInfo.QueryInterface(aIID); - } - throw Cr.NS_ERROR_NO_AGGREGATION; - } - }; - - let registrar = Cm.QueryInterface(Ci.nsIComponentRegistrar); - registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo", - XULAPPINFO_CONTRACTID, XULAppInfoFactory); -} - -/** - * Returns the platform specific arguments used by nsIProcess when launching - * the application. - * - * @param aExtraArgs (optional) - * An array of extra arguments to append to the default arguments. - * @return an array of arguments to be passed to nsIProcess. - * - * Note: a shell is necessary to pipe the application's console output which - * would otherwise pollute the xpcshell log. - * - * Command line arguments used when launching the application: - * -no-remote prevents shell integration from being affected by an existing - * application process. - * -test-process-updates makes the application exit after being relaunched by - * the updater. - * the platform specific string defined by PIPE_TO_NULL to output both stdout - * and stderr to null. This is needed to prevent output from the application - * from ending up in the xpchsell log. - */ -function getProcessArgs(aExtraArgs) { - if (!aExtraArgs) { - aExtraArgs = []; - } - - let appBinPath = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false).path; - if (/ /.test(appBinPath)) { - appBinPath = '"' + appBinPath + '"'; - } - - let args; - if (IS_UNIX) { - let launchScript = getLaunchScript(); - // Precreate the script with executable permissions - launchScript.create(Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); - - let scriptContents = "#! /bin/sh\n"; - scriptContents += appBinPath + " -no-remote -test-process-updates " + - aExtraArgs.join(" ") + " " + PIPE_TO_NULL; - writeFile(launchScript, scriptContents); - debugDump("created " + launchScript.path + " containing:\n" + - scriptContents); - args = [launchScript.path]; - } else { - args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-test-process-updates"]. - concat(aExtraArgs).concat([PIPE_TO_NULL]); - } - return args; -} - -/** - * Gets a file path for the application to dump its arguments into. This is used - * to verify that a callback application is launched. - * - * @return the file for the application to dump its arguments into. - */ -function getAppArgsLogPath() { - let appArgsLog = do_get_file("/" + gTestID + "_app_args_log", true); - if (appArgsLog.exists()) { - appArgsLog.remove(false); - } - let appArgsLogPath = appArgsLog.path; - if (/ /.test(appArgsLogPath)) { - appArgsLogPath = '"' + appArgsLogPath + '"'; - } - return appArgsLogPath; -} - -/** - * Gets the nsIFile reference for the shell script to launch the application. If - * the file exists it will be removed by this function. - * - * @return the nsIFile for the shell script to launch the application. - */ -function getLaunchScript() { - let launchScript = do_get_file("/" + gTestID + "_launch.sh", true); - if (launchScript.exists()) { - launchScript.remove(false); - } - return launchScript; -} - -/** - * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so - * xpcshell tests can run in parallel and to keep the environment clean. - */ -function adjustGeneralPaths() { - let dirProvider = { - getFile: function AGP_DP_getFile(aProp, aPersistent) { - aPersistent.value = true; - switch (aProp) { - case NS_GRE_DIR: - if (gUseTestAppDir) { - return getApplyDirFile(DIR_RESOURCES, true); - } - break; - case NS_GRE_BIN_DIR: - if (gUseTestAppDir) { - return getApplyDirFile(DIR_MACOS, true); - } - break; - case XRE_EXECUTABLE_FILE: - if (gUseTestAppDir) { - return getApplyDirFile(DIR_MACOS + FILE_APP_BIN, true); - } - break; - case XRE_UPDATE_ROOT_DIR: - return getMockUpdRootD(); - } - return null; - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]) - }; - let ds = Services.dirsvc.QueryInterface(Ci.nsIDirectoryService); - ds.QueryInterface(Ci.nsIProperties).undefine(NS_GRE_DIR); - ds.QueryInterface(Ci.nsIProperties).undefine(NS_GRE_BIN_DIR); - ds.QueryInterface(Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE); - ds.registerProvider(dirProvider); - do_register_cleanup(function AGP_cleanup() { - debugDump("start - unregistering directory provider"); - - if (gAppTimer) { - debugDump("start - cancel app timer"); - gAppTimer.cancel(); - gAppTimer = null; - debugDump("finish - cancel app timer"); - } - - if (gProcess && gProcess.isRunning) { - debugDump("start - kill process"); - try { - gProcess.kill(); - } catch (e) { - debugDump("kill process failed. Exception: " + e); - } - gProcess = null; - debugDump("finish - kill process"); - } - - if (gHandle) { - try { - debugDump("start - closing handle"); - let kernel32 = ctypes.open("kernel32"); - let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi, - ctypes.bool, /* return*/ - ctypes.voidptr_t /* handle*/); - if (!CloseHandle(gHandle)) { - debugDump("call to CloseHandle failed"); - } - kernel32.close(); - gHandle = null; - debugDump("finish - closing handle"); - } catch (e) { - debugDump("call to CloseHandle failed. Exception: " + e); - } - } - - // Call end_test first before the directory provider is unregistered - if (typeof end_test == typeof Function) { - debugDump("calling end_test"); - end_test(); - } - - ds.unregisterProvider(dirProvider); - cleanupTestCommon(); - - debugDump("finish - unregistering directory provider"); - }); -} - -/** - * The timer callback to kill the process if it takes too long. - */ -const gAppTimerCallback = { - notify: function TC_notify(aTimer) { - gAppTimer = null; - if (gProcess.isRunning) { - logTestInfo("attempting to kill process"); - gProcess.kill(); - } - Assert.ok(false, "launch application timer expired"); - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]) -}; - -/** - * Launches an application to apply an update. - */ -function runUpdateUsingApp(aExpectedStatus) { - /** - * The observer for the call to nsIProcess:runAsync. When completed - * runUpdateFinished will be called. - */ - const processObserver = { - observe: function PO_observe(aSubject, aTopic, aData) { - debugDump("topic: " + aTopic + ", process exitValue: " + - gProcess.exitValue); - resetEnvironment(); - if (gAppTimer) { - gAppTimer.cancel(); - gAppTimer = null; - } - Assert.equal(gProcess.exitValue, 0, - "the application process exit value should be 0"); - Assert.equal(aTopic, "process-finished", - "the application process observer topic should be " + - "process-finished"); - - if (IS_SERVICE_TEST) { - waitForServiceStop(false); - } - - do_execute_soon(afterAppExits); - }, - QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]) - }; - - function afterAppExits() { - gTimeoutRuns++; - - if (IS_WIN) { - waitForApplicationStop(FILE_UPDATER_BIN); - } - - let status; - try { - status = readStatusFile(); - } catch (e) { - logTestInfo("error reading status file, exception: " + e); - } - // Don't proceed until the update's status is the expected value. - if (status != aExpectedStatus) { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - logUpdateLog(FILE_UPDATE_LOG); - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " + - "status to equal: " + - aExpectedStatus + - ", current status: " + status); - } else { - do_timeout(FILE_IN_USE_TIMEOUT_MS, afterAppExits); - } - return; - } - - // Don't check for an update log when the code in nsUpdateDriver.cpp skips - // updating. - if (aExpectedStatus != STATE_PENDING && - aExpectedStatus != STATE_PENDING_SVC && - aExpectedStatus != STATE_APPLIED && - aExpectedStatus != STATE_APPLIED_SVC) { - // Don't proceed until the update log has been created. - let log = getUpdateLog(FILE_UPDATE_LOG); - if (!log.exists()) { - if (gTimeoutRuns > MAX_TIMEOUT_RUNS) { - do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the update " + - "log to be created. Path: " + log.path); - } - do_timeout(FILE_IN_USE_TIMEOUT_MS, afterAppExits); - return; - } - } - - do_execute_soon(runUpdateFinished); - } - - debugDump("start - launching application to apply update"); - - let appBin = getApplyDirFile(DIR_MACOS + FILE_APP_BIN, false); - - let launchBin = getLaunchBin(); - let args = getProcessArgs(); - debugDump("launching " + launchBin.path + " " + args.join(" ")); - - gProcess = Cc["@mozilla.org/process/util;1"]. - createInstance(Ci.nsIProcess); - gProcess.init(launchBin); - - gAppTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - gAppTimer.initWithCallback(gAppTimerCallback, APP_TIMER_TIMEOUT, - Ci.nsITimer.TYPE_ONE_SHOT); - - setEnvironment(); - debugDump("launching application"); - gProcess.runAsync(args, args.length, processObserver); - - debugDump("finish - launching application to apply update"); -} - -/** - * Sets the environment that will be used by the application process when it is - * launched. - */ -function setEnvironment() { - // Prevent setting the environment more than once. - if (gShouldResetEnv !== undefined) { - return; - } - - gShouldResetEnv = true; - - // See bug 1279108. - if (gEnv.exists("ASAN_OPTIONS")) { - gASanOptions = gEnv.get("ASAN_OPTIONS"); - gEnv.set("ASAN_OPTIONS", gASanOptions + ":detect_leaks=0"); - } else { - gEnv.set("ASAN_OPTIONS", "detect_leaks=0"); - } - - if (IS_WIN && !gEnv.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { - gAddedEnvXRENoWindowsCrashDialog = true; - debugDump("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + - "variable to 1... previously it didn't exist"); - gEnv.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1"); - } - - if (IS_UNIX) { - let appGreBinDir = gGREBinDirOrig.clone(); - let envGreBinDir = Cc["@mozilla.org/file/local;1"]. - createInstance(Ci.nsILocalFile); - let shouldSetEnv = true; - if (IS_MACOSX) { - if (gEnv.exists("DYLD_LIBRARY_PATH")) { - gEnvDyldLibraryPath = gEnv.get("DYLD_LIBRARY_PATH"); - envGreBinDir.initWithPath(gEnvDyldLibraryPath); - if (envGreBinDir.path == appGreBinDir.path) { - gEnvDyldLibraryPath = null; - shouldSetEnv = false; - } - } - - if (shouldSetEnv) { - debugDump("setting DYLD_LIBRARY_PATH environment variable value to " + - appGreBinDir.path); - gEnv.set("DYLD_LIBRARY_PATH", appGreBinDir.path); - } - } else { - if (gEnv.exists("LD_LIBRARY_PATH")) { - gEnvLdLibraryPath = gEnv.get("LD_LIBRARY_PATH"); - envGreBinDir.initWithPath(gEnvLdLibraryPath); - if (envGreBinDir.path == appGreBinDir.path) { - gEnvLdLibraryPath = null; - shouldSetEnv = false; - } - } - - if (shouldSetEnv) { - debugDump("setting LD_LIBRARY_PATH environment variable value to " + - appGreBinDir.path); - gEnv.set("LD_LIBRARY_PATH", appGreBinDir.path); - } - } - } - - if (gEnv.exists("XPCOM_MEM_LEAK_LOG")) { - gEnvXPCOMMemLeakLog = gEnv.get("XPCOM_MEM_LEAK_LOG"); - debugDump("removing the XPCOM_MEM_LEAK_LOG environment variable... " + - "previous value " + gEnvXPCOMMemLeakLog); - gEnv.set("XPCOM_MEM_LEAK_LOG", ""); - } - - if (gEnv.exists("XPCOM_DEBUG_BREAK")) { - gEnvXPCOMDebugBreak = gEnv.get("XPCOM_DEBUG_BREAK"); - debugDump("setting the XPCOM_DEBUG_BREAK environment variable to " + - "warn... previous value " + gEnvXPCOMDebugBreak); - } else { - debugDump("setting the XPCOM_DEBUG_BREAK environment variable to " + - "warn... previously it didn't exist"); - } - - gEnv.set("XPCOM_DEBUG_BREAK", "warn"); - - if (IS_SERVICE_TEST) { - debugDump("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1"); - gEnv.set("MOZ_NO_SERVICE_FALLBACK", "1"); - } -} - -/** - * Sets the environment back to the original values after launching the - * application. - */ -function resetEnvironment() { - // Prevent resetting the environment more than once. - if (gShouldResetEnv !== true) { - return; - } - - gShouldResetEnv = false; - - // Restore previous ASAN_OPTIONS if there were any. - gEnv.set("ASAN_OPTIONS", gASanOptions ? gASanOptions : ""); - - if (gEnvXPCOMMemLeakLog) { - debugDump("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + - gEnvXPCOMMemLeakLog); - gEnv.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog); - } - - if (gEnvXPCOMDebugBreak) { - debugDump("setting the XPCOM_DEBUG_BREAK environment variable back to " + - gEnvXPCOMDebugBreak); - gEnv.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak); - } else if (gEnv.exists("XPCOM_DEBUG_BREAK")) { - debugDump("clearing the XPCOM_DEBUG_BREAK environment variable"); - gEnv.set("XPCOM_DEBUG_BREAK", ""); - } - - if (IS_UNIX) { - if (IS_MACOSX) { - if (gEnvDyldLibraryPath) { - debugDump("setting DYLD_LIBRARY_PATH environment variable value " + - "back to " + gEnvDyldLibraryPath); - gEnv.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath); - } else if (gEnvDyldLibraryPath !== null) { - debugDump("removing DYLD_LIBRARY_PATH environment variable"); - gEnv.set("DYLD_LIBRARY_PATH", ""); - } - } else if (gEnvLdLibraryPath) { - debugDump("setting LD_LIBRARY_PATH environment variable value back " + - "to " + gEnvLdLibraryPath); - gEnv.set("LD_LIBRARY_PATH", gEnvLdLibraryPath); - } else if (gEnvLdLibraryPath !== null) { - debugDump("removing LD_LIBRARY_PATH environment variable"); - gEnv.set("LD_LIBRARY_PATH", ""); - } - } - - if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) { - debugDump("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " + - "variable"); - gEnv.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); - } - - if (IS_SERVICE_TEST) { - debugDump("removing MOZ_NO_SERVICE_FALLBACK environment variable"); - gEnv.set("MOZ_NO_SERVICE_FALLBACK", ""); - } -} |