From 0ba1bc22accf10a60ced587c778e2502abd46bb0 Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Wed, 4 Jan 2012 23:19:14 -0500 Subject: [PATCH] Bug 481815 - Automated tests for updates using the maintenance service; r=rstrong. --HG-- rename : toolkit/mozapps/update/test/unit/test_0110_general.js => toolkit/mozapps/update/test/unit/test_0110_general_svc.js rename : toolkit/mozapps/update/test/unit/test_0111_general.js => toolkit/mozapps/update/test/unit/test_0111_general_svc.js rename : toolkit/mozapps/update/test/unit/test_0112_general.js => toolkit/mozapps/update/test/unit/test_0112_general_svc.js rename : toolkit/mozapps/update/test/unit/test_0120_channelChange_complete.js => toolkit/mozapps/update/test/unit/test_0120_channelChange_complete_svc.js rename : toolkit/mozapps/update/test/unit/test_0150_appBinReplaced_xp_win_complete.js => toolkit/mozapps/update/test/unit/test_0150_appBinReplaced_xp_win_complete_svc.js rename : toolkit/mozapps/update/test/unit/test_0151_appBinPatched_xp_win_partial.js => toolkit/mozapps/update/test/unit/test_0151_appBinPatched_xp_win_partial_svc.js rename : toolkit/mozapps/update/test/unit/test_0160_appInUse_xp_win_complete.js => toolkit/mozapps/update/test/unit/test_0160_appInUse_xp_win_complete_svc.js rename : toolkit/mozapps/update/test/unit/test_0170_fileLocked_xp_win_complete.js => toolkit/mozapps/update/test/unit/test_0170_fileLocked_xp_win_complete_svc.js rename : toolkit/mozapps/update/test/unit/test_0171_fileLocked_xp_win_partial.js => toolkit/mozapps/update/test/unit/test_0171_fileLocked_xp_win_partial_svc.js rename : toolkit/mozapps/update/test/unit/test_0180_fileInUse_xp_win_complete.js => toolkit/mozapps/update/test/unit/test_0180_fileInUse_xp_win_complete_svc.js rename : toolkit/mozapps/update/test/unit/test_0181_fileInUse_xp_win_partial.js => toolkit/mozapps/update/test/unit/test_0181_fileInUse_xp_win_partial_svc.js rename : toolkit/mozapps/update/test/unit/test_0182_rmrfdirFileInUse_xp_win_complete.js => toolkit/mozapps/update/test/unit/test_0182_rmrfdirFileInUse_xp_win_complete_svc.js rename : toolkit/mozapps/update/test/unit/test_0183_rmrfdirFileInUse_xp_win_partial.js => toolkit/mozapps/update/test/unit/test_0183_rmrfdirFileInUse_xp_win_partial_svc.js rename : toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update.js => toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update_svc.js --- .../update/test/unit/head_update.js.in | 574 ++++++++++++++++++ .../test/unit/test_0000_bootstrap_svc.js | 39 ++ .../update/test/unit/test_0110_general_svc.js | 296 +++++++++ .../update/test/unit/test_0111_general_svc.js | 304 ++++++++++ .../update/test/unit/test_0112_general_svc.js | 299 +++++++++ .../test_0120_channelChange_complete_svc.js | 264 ++++++++ ...0150_appBinReplaced_xp_win_complete_svc.js | 218 +++++++ ...t_0151_appBinPatched_xp_win_partial_svc.js | 220 +++++++ .../test_0160_appInUse_xp_win_complete_svc.js | 234 +++++++ ...est_0170_fileLocked_xp_win_complete_svc.js | 236 +++++++ ...test_0171_fileLocked_xp_win_partial_svc.js | 237 ++++++++ ...test_0180_fileInUse_xp_win_complete_svc.js | 233 +++++++ .../test_0181_fileInUse_xp_win_partial_svc.js | 236 +++++++ ...82_rmrfdirFileInUse_xp_win_complete_svc.js | 243 ++++++++ ...183_rmrfdirFileInUse_xp_win_partial_svc.js | 284 +++++++++ .../unit/test_0200_app_launch_apply_update.js | 334 ---------- .../test_0200_app_launch_apply_update_svc.js | 250 ++++++++ toolkit/mozapps/update/test/unit/xpcshell.ini | 3 + .../unit/xpcshell_updater_windows_svc.ini | 15 + toolkit/xre/nsAppRunner.cpp | 14 + toolkit/xre/nsUpdateDriver.cpp | 27 + xpcom/io/SpecialSystemDirectory.cpp | 4 + xpcom/io/SpecialSystemDirectory.h | 1 + xpcom/io/nsDirectoryService.cpp | 4 + xpcom/io/nsDirectoryServiceAtomList.h | 1 + xpcom/io/nsDirectoryServiceDefs.h | 1 + 26 files changed, 4237 insertions(+), 334 deletions(-) create mode 100644 toolkit/mozapps/update/test/unit/test_0000_bootstrap_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0110_general_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0111_general_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0112_general_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0120_channelChange_complete_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0150_appBinReplaced_xp_win_complete_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0151_appBinPatched_xp_win_partial_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0160_appInUse_xp_win_complete_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0170_fileLocked_xp_win_complete_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0171_fileLocked_xp_win_partial_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0180_fileInUse_xp_win_complete_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0181_fileInUse_xp_win_partial_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0182_rmrfdirFileInUse_xp_win_complete_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0183_rmrfdirFileInUse_xp_win_partial_svc.js create mode 100644 toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update_svc.js create mode 100644 toolkit/mozapps/update/test/unit/xpcshell_updater_windows_svc.ini diff --git a/toolkit/mozapps/update/test/unit/head_update.js.in b/toolkit/mozapps/update/test/unit/head_update.js.in index b7195d7f90bf..688b4105b81f 100644 --- a/toolkit/mozapps/update/test/unit/head_update.js.in +++ b/toolkit/mozapps/update/test/unit/head_update.js.in @@ -104,6 +104,8 @@ const ERR_RENAME_FILE = "rename_file: failed to rename file"; const ERR_UNABLE_OPEN_DEST = "unable to open destination file"; const ERR_BACKUP_DISCARD = "backup_discard: unable to remove"; +const LOG_SVC_SUCCESSFUL_LAUNCH = "updater.exe was launched and run successfully!"; + // variables are used instead of contants so tests can override these values var gCallbackBinFile = "callback_app" + BIN_SUFFIX; var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; @@ -111,6 +113,10 @@ var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; // Time to wait for the test helper process before continuing the test const TEST_HELPER_TIMEOUT = 100; +// Use a copy of the main application executable for the test to avoid main +// executable in use errors. +const FILE_WIN_TEST_EXE = "aus_test_app.exe"; + var gTestserver; var gXHR; @@ -445,6 +451,142 @@ function runUpdate() { return process.exitValue; } +let gServiceLaunchedCallbackLog = null; +let gServiceLaunchedCallbackArgs = null; + +/** + * Helper function for updater tests for launching the updater using the + * maintenance service to apply a mar file. + * + * @param aInitialStatus the initial value of update.status + * @param aExpectedStatus the expected value of update.status when the test finishes + * @param aCallback the function to be called when the update is finished + * @param aUpdatesDir the updates root directory to use (optional) + * @param aCheckSvcLog whether the service log should be checked (optional) + */ +function runUpdateUsingService(aInitialStatus, aExpectedStatus, + aCallback, aUpdatesDir, aCheckSvcLog) { + // Check the service logs for a successful update + function checkServiceLogs(aOriginalContents) { + let contents = readServiceLogFile(); + logTestInfo("The contents of maintenanceservice.log:\n" + contents + "\n"); + do_check_neq(contents, aOriginalContents); + do_check_neq(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1); + } + function readServiceLogFile() { + let file = AUS_Cc["@mozilla.org/file/directory_service;1"]. + getService(AUS_Ci.nsIProperties). + get("CmAppData", AUS_Ci.nsIFile); + file.append("Mozilla"); + file.append("logs"); + file.append("maintenanceservice.log"); + return readFile(file); + } + + // Prevent the cleanup function from begin run more than once + if (typeof(gRegisteredServiceCleanup) === "undefined") { + gRegisteredServiceCleanup = true; + + do_register_cleanup(function serviceCleanup() { + resetEnvironment(); + + // Remove the copy of the application executable used for the test on + // Windows if it exists. + let appBinCopy = getCurrentProcessDir(); + appBinCopy.append(FILE_WIN_TEST_EXE); + if (appBinCopy.exists()) { + appBinCopy.remove(false); + } + + // This will delete the app console log file if it exists. + getAppConsoleLogPath(); + + // This will delete the app arguments log file if it exists. + getAppArgsLogPath(); + }); + } + + if (aCheckSvcLog === undefined) { + aCheckSvcLog = true; // default to true + } + + let svcOriginalLog; + if (aCheckSvcLog) { + svcOriginalLog = readServiceLogFile(); + } + + let appArgsLogPath = getAppArgsLogPath(); + gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, ""); + + let updatesDir = aUpdatesDir || do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + let file = updatesDir.clone(); + file.append(FILE_UPDATE_STATUS); + writeFile(file, aInitialStatus + "\n"); + + // sanity check + do_check_eq(readStatusFile(updatesDir), aInitialStatus); + + gServiceLaunchedCallbackArgs = [ + "-no-remote", + "-process-updates", + "-dump-args", + appArgsLogPath + ]; + + let launchBin = getLaunchBin(); + let args = getProcessArgs(["-dump-args", appArgsLogPath]); + logTestInfo("launching " + launchBin.path + " " + args.join(" ")); + + let process = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + process.init(launchBin); + + // Override the update root directory + gEnvUpdateRootOverride = updatesDir.path; + gEnvAppDirOverride = getApplyDirFile(null).path; + + setEnvironment(); + + // We can't get sync behavior here since Firefox does not wait for the + // process launched through the service to finish. Since the service + // launches the updater in the background, providing an observer argument + // doesn't solve anything either, so we will rely on watching the + // update.status file instead. + process.runAsync(args, args.length); + + resetEnvironment(); + + function timerCallback(timer) { + // Wait for the expected status + let status = readStatusFile(updatesDir); + // For failed status, we don't care what the failure code is + if (aExpectedStatus == STATE_FAILED) { + status = status.split(": ")[0]; + } + if (status == STATE_PENDING) { + logTestInfo("Still waiting to see the " + aExpectedStatus + + " status, got " + status + " for now..."); + return; + } + do_check_eq(status, aExpectedStatus); + + timer.cancel(); + timer = null; + + // Give the service enough time to write its log and finish up + do_timeout(1000, function() { + if (aCheckSvcLog) { + checkServiceLogs(svcOriginalLog); + } + + aCallback(); + }); + } + + let timer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer); + timer.initWithCallback(timerCallback, 1000, timer.TYPE_REPEATING_SLACK); +} + /** * Gets the platform specific shell binary that is launched using nsIProcess and * in turn launches the updater. @@ -700,6 +842,7 @@ function checkUpdateLogContains(aCheckString) { let updateLog = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX, true); updateLog.append(FILE_UPDATE_LOG); let updateLogContents = readFileBytes(updateLog); + logTestInfo("log file contents:\n" + updateLogContents + "\n"); do_check_true(updateLogContents.indexOf(aCheckString) != -1); } @@ -909,6 +1052,27 @@ function checkCallbackAppLog() { do_timeout(TEST_HELPER_TIMEOUT, do_test_finished); } +/** + * Helper function for updater service tests for verifying the contents of the + * updater callback application log which should contain the arguments passed to + * the callback application. + */ +function checkCallbackServiceLog() { + do_check_neq(gServiceLaunchedCallbackLog, null); + + let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n"; + let logFile = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile); + logFile.initWithPath(gServiceLaunchedCallbackLog); + let logContents = readFile(logFile); + + logTestInfo("testing that the callback application successfully launched " + + "and the expected command line arguments passed to it"); + do_check_eq(logContents, expectedLogContents); + + // Use a timeout to give any files that were in use additional time to close. + do_timeout(TEST_HELPER_TIMEOUT, do_test_finished); +} + /** * Helper function for updater binary tests for verifying there are no update * backup files left behind after an update. @@ -1168,3 +1332,413 @@ var gDirProvider = { } }; Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService).registerProvider(gDirProvider); + +/** + * Returns the platform specific arguments used by nsIProcess when launching + * the application. + * + * @param aExtraArgs optional array of extra arguments + * @return an array of arguments to be passed to nsIProcess. + * + * Notes: + * 1. Mozilla universal binaries that contain both i386 and x86_64 on Mac OS X + * 10.5.x must be launched using the i386 architecture. + * 2. 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. + * -process-updates makes the application exits after being relaunched by the + * updater. + * 1> pipes stdout to a file. + * appConsoleLogPath is the file path to pipe the output from the shell. + * Otherwise the output from the application will end up in the xpchsell log. + * 2>&1 pipes stderr to sdout. + */ +function getProcessArgs(aExtraArgs) { + if (!aExtraArgs) { + aExtraArgs = []; + } + + // Pipe the output from the launched application to a file so the output from + // its console isn't present in the xpcshell log. + let appConsoleLogPath = getAppConsoleLogPath(); + + let args; + if (IS_UNIX) { + let launchScript = getLaunchScript(); + // Precreate the script with executable permissions + launchScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); + + let scriptContents = "#! /bin/sh\n"; + // On Mac OS X versions prior to 10.6 the i386 acrhitecture must be used. + if (gIsLessThanMacOSX_10_6) { + scriptContents += "arch -arch i386 "; + } + scriptContents += gAppBinPath + " -no-remote -process-updates " + + aExtraArgs.join(" ") + " 1> " + + appConsoleLogPath + " 2>&1"; + writeFile(launchScript, scriptContents); + logTestInfo("created " + launchScript.path + " containing:\n" + + scriptContents); + args = [launchScript.path]; + } + else { + args = ["/D", "/Q", "/C", gAppBinPath, "-no-remote", "-process-updates"]. + concat(aExtraArgs). + concat(["1>", appConsoleLogPath, "2>&1"]); + } + return args; +} + +/** + * Gets a file path for piping the console output from the application so it + * doesn't appear in the xpcshell log file. + * + * @return path to the file for piping the console output from the application. + */ +function getAppConsoleLogPath() { + let appConsoleLog = do_get_file("/", true); + appConsoleLog.append("app_console_log"); + if (appConsoleLog.exists()) { + appConsoleLog.remove(false); + } + let appConsoleLogPath = appConsoleLog.path; + if (/ /.test(appConsoleLogPath)) { + appConsoleLogPath = '"' + appConsoleLogPath + '"'; + } + return appConsoleLogPath; +} + +/** + * 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("/", true); + appArgsLog.append("app_args_log"); + 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("/", true); + launchScript.append("launch.sh"); + if (launchScript.exists()) { + launchScript.remove(false); + } + return launchScript; +} + +// A shell script is used to get the OS version due to nsSystemInfo not +// returning the actual OS version. It is possible to get the actual OS version +// using ctypes but it would be more complicated than using a shell script. +XPCOMUtils.defineLazyGetter(this, "gIsLessThanMacOSX_10_6", function test_gMacVer() { + if (!IS_MACOSX) { + return false; + } + + let [versionScript, versionFile] = getVersionScriptAndFile(); + // Precreate the script with executable permissions + versionScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); + let scriptContents = "#! /bin/sh\nsw_vers -productVersion >> " + versionFile.path; + writeFile(versionScript, scriptContents); + logTestInfo("created " + versionScript.path + " shell script containing:\n" + + scriptContents); + + let versionScriptPath = versionScript.path; + if (/ /.test(versionScriptPath)) { + versionScriptPath = '"' + versionScriptPath + '"'; + } + + + let launchBin = getLaunchBin(); + let args = [versionScriptPath]; + let process = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + process.init(launchBin); + process.run(true, args, args.length); + if (process.exitValue != 0) { + do_throw("Version script exited with " + process.exitValue + "... unable " + + "to get Mac OS X version!"); + } + + let version = readFile(versionFile).split("\n")[0]; + logTestInfo("executing on Mac OS X verssion " + version); + + return (Services.vc.compare(version, "10.6") < 0) +}); + +/** + * Checks for the existence of a platform specific application binary that can + * be used for the test and gets its path if it is found. + * + * Note: The application shell scripts for launching the application work on all + * platforms that provide a launch shell script except for Mac OS X 10.5 which + * is why this test uses the binaries to launch the application. + */ +XPCOMUtils.defineLazyGetter(this, "gAppBinPath", function test_gAppBinPath() { + let processDir = getAppDir(); + let appBin = processDir.clone(); + appBin.append(APP_BIN_NAME + APP_BIN_SUFFIX); + if (appBin.exists()) { + if (IS_WIN) { + let appBinCopy = processDir.clone(); + appBinCopy.append(FILE_WIN_TEST_EXE); + if (appBinCopy.exists()) { + appBinCopy.remove(false); + } + appBin.copyTo(processDir, FILE_WIN_TEST_EXE); + appBin = processDir.clone(); + appBin.append(FILE_WIN_TEST_EXE); + } + let appBinPath = appBin.path; + if (/ /.test(appBinPath)) { + appBinPath = '"' + appBinPath + '"'; + } + return appBinPath; + } + return null; +}); + +let gWindowsBinDir = null; + +/** + * This dummy function just returns false. Tests which wish to adjust the app + * directory on Mac OS X should define a real version of this function. + */ +function shouldAdjustPathsOnMac() { + return false; +} + +/** + * This function returns the current process directory on Windows and Linux, and + * the application bundle directory on Mac. + */ +function getAppDir() { + let dir = getCurrentProcessDir(); + if (shouldAdjustPathsOnMac()) { + // objdir/dist/bin/../NightlyDebug.app/Contents/MacOS + dir = dir.parent; + dir.append(BUNDLE_NAME); + dir.append("Contents"); + dir.append("MacOS"); + } else if (IS_WIN && gWindowsBinDir) { + dir = gWindowsBinDir.clone(); + } + return dir; +} + +/** + * Gets the nsIFile references for the shell script to retrieve the Mac OS X + * version and the nsIFile to pipe the output of the shell script. If either of + * these files exist they will be removed by this function. + * + * @return array containing two nsIFile references. The first array member is + * the nsIFile for the shell script to launch to get the Mac OS X + * version and the second array member is the nsIFile for the piped + * output from the shell script. + */ +function getVersionScriptAndFile() { + let versionScript = do_get_file("/", true); + let versionFile = versionScript.clone(); + versionScript.append("get_version.sh"); + if (versionScript.exists()) { + versionScript.remove(false); + } + versionFile.append("version.out"); + if (versionFile.exists()) { + versionFile.remove(false); + } + return [versionScript, versionFile]; +} + +// Environment related globals +let gShouldResetEnv = undefined; +let gAddedEnvXRENoWindowsCrashDialog = false; +let gEnvXPCOMDebugBreak; +let gEnvXPCOMMemLeakLog; +let gEnvDyldLibraryPath; +let gEnvLdLibraryPath; +let gEnvUpdateRootOverride = null; +let gEnvAppDirOverride = null; + +/** + * 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; + + let env = AUS_Cc["@mozilla.org/process/environment;1"]. + getService(AUS_Ci.nsIEnvironment); + if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { + gAddedEnvXRENoWindowsCrashDialog = true; + logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + + "variable to 1... previously it didn't exist"); + env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1"); + } + + if (IS_UNIX) { + let appGreDir = Services.dirsvc.get("GreD", AUS_Ci.nsIFile); + let envGreDir = AUS_Cc["@mozilla.org/file/local;1"]. + createInstance(AUS_Ci.nsILocalFile); + let shouldSetEnv = true; + if (IS_MACOSX) { + if (env.exists("DYLD_LIBRARY_PATH")) { + gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH"); + envGreDir.initWithPath(gEnvDyldLibraryPath); + if (envGreDir.path == appGreDir.path) { + gEnvDyldLibraryPath = null; + shouldSetEnv = false; + } + } + + if (shouldSetEnv) { + logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " + + appGreDir.path); + env.set("DYLD_LIBRARY_PATH", appGreDir.path); + } + } + else { + if (env.exists("LD_LIBRARY_PATH")) { + gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH"); + envGreDir.initWithPath(gEnvLdLibraryPath); + if (envGreDir.path == appGreDir.path) { + gEnvLdLibraryPath = null; + shouldSetEnv = false; + } + } + + if (shouldSetEnv) { + logTestInfo("setting LD_LIBRARY_PATH environment variable value to " + + appGreDir.path); + env.set("LD_LIBRARY_PATH", appGreDir.path); + } + } + } + + if (env.exists("XPCOM_MEM_LEAK_LOG")) { + gEnvXPCOMMemLeakLog = env.get("XPCOM_MEM_LEAK_LOG"); + logTestInfo("removing the XPCOM_MEM_LEAK_LOG environment variable... " + + "previous value " + gEnvXPCOMMemLeakLog); + env.set("XPCOM_MEM_LEAK_LOG", ""); + } + + if (env.exists("XPCOM_DEBUG_BREAK")) { + gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK"); + logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + + "warn... previous value " + gEnvXPCOMDebugBreak); + } + else { + logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + + "warn... previously it didn't exist"); + } + + env.set("XPCOM_DEBUG_BREAK", "warn"); + + if (gEnvUpdateRootOverride) { + logTestInfo("setting the MOZ_UPDATE_ROOT_OVERRIDE environment variable to " + + gEnvUpdateRootOverride + "\n"); + env.set("MOZ_UPDATE_ROOT_OVERRIDE", gEnvUpdateRootOverride); + } + + if (gEnvAppDirOverride) { + logTestInfo("setting the MOZ_UPDATE_APPDIR_OVERRIDE environment variable to " + + gEnvAppDirOverride + "\n"); + env.set("MOZ_UPDATE_APPDIR_OVERRIDE", gEnvAppDirOverride); + } +} + +/** + * 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; + + let env = AUS_Cc["@mozilla.org/process/environment;1"]. + getService(AUS_Ci.nsIEnvironment); + + if (gEnvXPCOMMemLeakLog) { + logTestInfo("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + + gEnvXPCOMMemLeakLog); + env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog); + } + + if (gEnvXPCOMDebugBreak) { + logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " + + gEnvXPCOMDebugBreak); + env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak); + } + else { + logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable"); + env.set("XPCOM_DEBUG_BREAK", ""); + } + + if (IS_UNIX) { + if (IS_MACOSX) { + if (gEnvDyldLibraryPath) { + logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " + + "back to " + gEnvDyldLibraryPath); + env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath); + } + else { + logTestInfo("removing DYLD_LIBRARY_PATH environment variable"); + env.set("DYLD_LIBRARY_PATH", ""); + } + } + else { + if (gEnvLdLibraryPath) { + logTestInfo("setting LD_LIBRARY_PATH environment variable value back " + + "to " + gEnvLdLibraryPath); + env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath); + } + else { + logTestInfo("removing LD_LIBRARY_PATH environment variable"); + env.set("LD_LIBRARY_PATH", ""); + } + } + } + + if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) { + logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " + + "variable"); + env.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); + } + + if (gEnvUpdateRootOverride) { + logTestInfo("removing the MOZ_UPDATE_ROOT_OVERRIDE environment variable\n"); + env.set("MOZ_UPDATE_ROOT_OVERRIDE", ""); + gEnvUpdateRootOverride = null; + } + + if (gEnvAppDirOverride) { + logTestInfo("removing the MOZ_UPDATE_APPDIR_OVERRIDE environment variable\n"); + env.set("MOZ_UPDATE_APPDIR_OVERRIDE", ""); + gEnvAppDirOverride = null; + } +} diff --git a/toolkit/mozapps/update/test/unit/test_0000_bootstrap_svc.js b/toolkit/mozapps/update/test/unit/test_0000_bootstrap_svc.js new file mode 100644 index 000000000000..bc98d31a3a27 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0000_bootstrap_svc.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Bootstrap the tests using the service by installing our own version of the service */ + +const TEST_ID = "0000_svc"; + +const TEST_FILES = [ +{ + description : "the dummy file to make sure that the update worked", + fileName : "dummy", + relPathDir : "/", + originalContents : null, + compareContents : "", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +} +]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + let applyToDir = getApplyDirFile(); + + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied, null, false); +} + +function checkUpdateApplied() { + checkFilesAfterUpdateSuccess(); + do_test_finished(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0110_general_svc.js b/toolkit/mozapps/update/test/unit/test_0110_general_svc.js new file mode 100644 index 000000000000..194a3c912ebc --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0110_general_svc.js @@ -0,0 +1,296 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ehsan Akhgari (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/* General Complete MAR File Patch Apply Test */ + +const TEST_ID = "0110_svc"; +// 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 MAX_TIME_DIFFERENCE = 60000; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0767, + comparePerms : 0767 +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/complete_precomplete", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/complete_removed-files", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0777, + comparePerms : 0755 +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0767, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0777, + comparePerms : 0755 +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0677, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : 0776, + comparePerms : 0644 +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : true +}, { + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0111_general_svc.js b/toolkit/mozapps/update/test/unit/test_0111_general_svc.js new file mode 100644 index 000000000000..96e2c04c088c --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0111_general_svc.js @@ -0,0 +1,304 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ehsan Akhgari (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/* General Partial MAR File Patch Apply Test */ + +const TEST_ID = "0111_svc"; +// 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 MAX_TIME_DIFFERENCE = 60000; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0644, + comparePerms : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/complete_precomplete", + compareFile : "data/partial_precomplete", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Patched by update.manifest (patch)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0755, + comparePerms : 0755 +}, { + description : "Patched by update.manifest (patch)", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0755, + comparePerms : 0755 +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Patched by update.manifest (patch)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Added by update.manifest (add)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/partial.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "00text2", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Removed by update.manifest (remove)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/10/", + dirRemoved : true +}, { + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_PARTIAL_FILE); + + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + + // Check that trying to change channels for a partial update doesn't change + // the update channel (the channel-prefs.js file should not be updated). + let force = updatesDir.clone(); + force.append(CHANNEL_CHANGE_FILE); + force.create(AUS_Ci.nsIFile.FILE_TYPE, PERMS_FILE); + + // apply the partial mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContents(LOG_PARTIAL_SUCCESS); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0112_general_svc.js b/toolkit/mozapps/update/test/unit/test_0112_general_svc.js new file mode 100644 index 000000000000..ec08df8ac9f8 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0112_general_svc.js @@ -0,0 +1,299 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2011 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Ehsan Akhgari (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** + */ + +/* General Partial MAR File Patch Apply Failure Test */ + +const TEST_ID = "0112_svc"; +// 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 MAX_TIME_DIFFERENCE = 60000; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0767, + comparePerms : null +}, { + description : "Not added for failed update (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/complete_precomplete", + compareFile : "data/complete_precomplete", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not added for failed update (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0775 +}, { + description : "Not patched for failed update (patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not patched for failed update (patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0644, + comparePerms : 0644 +}, { + description : "Not patched for failed update (patch)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0755, + comparePerms : 0755 +}, { + description : "Not patched for failed update (patch) and causes " + + "LoadSourceFile failed", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png", + originalPerms : 0755, + comparePerms : 0755 +}, { + description : "Not added for failed update (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Not patched for failed update (patch)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not added for failed update (add)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Not added for failed update (add)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Not added for failed update (add)", + fileName : "00text2", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Not removed for failed update (remove)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ShouldNotBeDeleted\n", + compareContents : "ShouldNotBeDeleted\n", + originalFile : null, + compareFile : null, + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Not removed for failed update (remove)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ShouldNotBeDeleted\n", + compareContents : "ShouldNotBeDeleted\n", + originalFile : null, + compareFile : null, + originalPerms : 0666, + comparePerms : 0666 +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Not removed for failed update (rmdir)", + relPathDir : "a/b/1/10/", + dirRemoved : false +}, { + description : "Not removed for failed update (rmdir)", + relPathDir : "a/b/1/", + dirRemoved : false +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_PARTIAL_FILE); + + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + + // Check that trying to change channels for a failed partial update doesn't + // change the update channel (the channel-prefs.js file should not be updated). + let force = updatesDir.clone(); + force.append(CHANNEL_CHANGE_FILE); + force.create(AUS_Ci.nsIFile.FILE_TYPE, PERMS_FILE); + + // apply the partial mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_FAILED, checkUpdateApplied); +} + +function checkUpdateApplied() { + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + logTestInfo("testing update.status should be " + STATE_FAILED); + // The update status format for a failure is failed: # where # is the error + // code for the failure. + do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED); + + checkFilesAfterUpdateFailure(); + checkUpdateLogContents(LOG_PARTIAL_FAILURE); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0120_channelChange_complete_svc.js b/toolkit/mozapps/update/test/unit/test_0120_channelChange_complete_svc.js new file mode 100644 index 000000000000..abebe607bd46 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0120_channelChange_complete_svc.js @@ -0,0 +1,264 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Channel change complete MAR file patch apply test */ + +const TEST_ID = "0120_svc"; +// 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 MAX_TIME_DIFFERENCE = 60000; + +// The files are in the same order as they are applied from the mar +const TEST_FILES = [ +{ + description : "Added by update.manifest (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0767, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/complete_precomplete", + originalPerms : 0755, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/complete_removed-files", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0777, + comparePerms : 0755 +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0767, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png", + originalPerms : 0777, + comparePerms : 0755 +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0677, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png", + originalPerms : 0776, + comparePerms : 0644 +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : true +}, { + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + + // Check that trying to change channels for a complete update changes the + // update channel (the channel-prefs.js file should be updated). + let channelchange = updatesDir.clone(); + channelchange.append(CHANNEL_CHANGE_FILE); + channelchange.create(AUS_Ci.nsIFile.FILE_TYPE, PERMS_FILE); + + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContents(LOG_COMPLETE_CC_SUCCESS); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0150_appBinReplaced_xp_win_complete_svc.js b/toolkit/mozapps/update/test/unit/test_0150_appBinReplaced_xp_win_complete_svc.js new file mode 100644 index 000000000000..53bfb18d042b --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0150_appBinReplaced_xp_win_complete_svc.js @@ -0,0 +1,218 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Replace app binary complete MAR file patch apply success test */ + +const TEST_ID = "0150_svc"; +const MAR_COMPLETE_WIN_FILE = "data/complete_win.mar"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/complete_precomplete" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/complete_removed-files" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_after.exe", + compareFile : "data/partial_in_use_win_before.exe" +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add) file in use", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_after.exe", + compareFile : "data/partial_in_use_win_before.exe" +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : true +}, { + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_WIN_FILE); + + gCallbackBinFile = "exe0.exe"; + + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0151_appBinPatched_xp_win_partial_svc.js b/toolkit/mozapps/update/test/unit/test_0151_appBinPatched_xp_win_partial_svc.js new file mode 100644 index 000000000000..7d9b360adece --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0151_appBinPatched_xp_win_partial_svc.js @@ -0,0 +1,220 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Patch app binary partial MAR file patch apply success test */ + +const TEST_ID = "0151_svc"; +const MAR_IN_USE_WIN_FILE = "data/partial_win.mar"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/complete_precomplete", + compareFile : "data/partial_precomplete" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest (patch)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_before.exe", + compareFile : "data/partial_in_use_win_after.exe" +}, { + description : "Patched by update.manifest (patch) file in use", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_before.exe", + compareFile : "data/partial_in_use_win_after.exe" +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest (patch)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest (add)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest (add)", + fileName : "00text2", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/10/", + dirRemoved : true +}, { + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_IN_USE_WIN_FILE); + + gCallbackBinFile = "exe0.exe"; + + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0160_appInUse_xp_win_complete_svc.js b/toolkit/mozapps/update/test/unit/test_0160_appInUse_xp_win_complete_svc.js new file mode 100644 index 000000000000..33e60bc29734 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0160_appInUse_xp_win_complete_svc.js @@ -0,0 +1,234 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Application in use complete MAR file patch apply failure test */ + +const TEST_ID = "0160_svc"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/complete_precomplete" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/complete_removed-files" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_before.exe", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add) file in use", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_after.exe", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed for complete update (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : true +}, { + description : "Removed for complete update (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + // Launch the callback helper application so it is in use during the update + let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile); + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"]; + let callbackAppProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + callbackAppProcess.init(callbackApp); + callbackAppProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + // The update status format for a failure is failed: # where # is the error + // code for the failure. + do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContents(LOG_COMPLETE_SUCCESS); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0170_fileLocked_xp_win_complete_svc.js b/toolkit/mozapps/update/test/unit/test_0170_fileLocked_xp_win_complete_svc.js new file mode 100644 index 000000000000..f53779d51bc8 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0170_fileLocked_xp_win_complete_svc.js @@ -0,0 +1,236 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked complete MAR file patch apply failure test */ + +const TEST_ID = "0170_svc"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/partial_precomplete" +}, { + description : "Not added for failed update (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png" +}, { + description : "Not added for failed update (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png" +}, { + description : "Not added for failed update (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/partial_removed-files" +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png" +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png" +}, { + description : "Not added for failed update (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png" +}, { + description : "Not removed for failed update (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ShouldNotBeDeleted\n", + compareContents : "ShouldNotBeDeleted\n", + originalFile : null, + compareFile : null +}, { + description : "Not removed for failed update (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ShouldNotBeDeleted\n", + compareContents : "ShouldNotBeDeleted\n", + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Not removed for failed update (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : false +}, { + description : "Not removed for failed update (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : false +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + // Exclusively lock an existing file so it is in use during the update + let helperBin = do_get_file(HELPER_BIN_FILE); + let helperDestDir = getApplyDirFile("a/b/"); + helperBin.copyTo(helperDestDir, HELPER_BIN_FILE); + helperBin = getApplyDirFile("a/b/" + HELPER_BIN_FILE); + // Strip off the first two directories so the path has to be from the helper's + // working directory. + let lockFileRelPath = TEST_FILES[3].relPathDir.split("/"); + lockFileRelPath = lockFileRelPath.slice(2); + lockFileRelPath = lockFileRelPath.join("/") + "/" + TEST_FILES[3].fileName; + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20", lockFileRelPath]; + let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + lockFileProcess.init(helperBin); + lockFileProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_FAILED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_FAILED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + // The update status format for a failure is failed: # where # is the error + // code for the failure. + do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED); + + checkFilesAfterUpdateFailure(); + checkUpdateLogContains(ERR_RENAME_FILE); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0171_fileLocked_xp_win_partial_svc.js b/toolkit/mozapps/update/test/unit/test_0171_fileLocked_xp_win_partial_svc.js new file mode 100644 index 000000000000..1d76e7af8af6 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0171_fileLocked_xp_win_partial_svc.js @@ -0,0 +1,237 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File locked partial MAR file patch apply failure test */ + +const TEST_ID = "0171_svc"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/complete_precomplete", + compareFile : "data/complete_precomplete" +}, { + description : "Not added for failed update (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not patched for failed update (patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not patched for failed update (patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not added for failed update (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not patched for failed update (patch-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not patched for failed update (patch)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not patched for failed update (patch) and causes " + + "LoadSourceFile failed", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/partial.png" +}, { + description : "Not added for failed update (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Not patched for failed update (patch)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/complete.png" +}, { + description : "Not added for failed update (add)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not added for failed update (add)", + fileName : "00text2", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Not removed for failed update (remove)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ShouldNotBeDeleted\n", + compareContents : "ShouldNotBeDeleted\n", + originalFile : null, + compareFile : null +}, { + description : "Not removed for failed update (remove)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ShouldNotBeDeleted\n", + compareContents : "ShouldNotBeDeleted\n", + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Not removed for failed update (rmdir)", + relPathDir : "a/b/1/10/", + dirRemoved : false +}, { + description : "Not removed for failed update (rmdir)", + relPathDir : "a/b/1/", + dirRemoved : false +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_PARTIAL_FILE); + + // Exclusively lock an existing file so it is in use during the update + let helperBin = do_get_file(HELPER_BIN_FILE); + let helperDestDir = getApplyDirFile("a/b/"); + helperBin.copyTo(helperDestDir, HELPER_BIN_FILE); + helperBin = getApplyDirFile("a/b/" + HELPER_BIN_FILE); + // Strip off the first two directories so the path has to be from the helper's + // working directory. + let lockFileRelPath = TEST_FILES[3].relPathDir.split("/"); + lockFileRelPath = lockFileRelPath.slice(2); + lockFileRelPath = lockFileRelPath.join("/") + "/" + TEST_FILES[3].fileName; + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20", lockFileRelPath]; + let lockFileProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + lockFileProcess.init(helperBin); + lockFileProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_FAILED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_FAILED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + // The update status format for a failure is failed: # where # is the error + // code for the failure. + do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED); + + checkFilesAfterUpdateFailure(); + checkUpdateLogContains(ERR_UNABLE_OPEN_DEST); + + logTestInfo("testing tobedeleted directory doesn't exist"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_false(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0180_fileInUse_xp_win_complete_svc.js b/toolkit/mozapps/update/test/unit/test_0180_fileInUse_xp_win_complete_svc.js new file mode 100644 index 000000000000..ff4b0bcb64cb --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0180_fileInUse_xp_win_complete_svc.js @@ -0,0 +1,233 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use complete MAR file patch apply success test */ + +const TEST_ID = "0180_svc"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/complete_precomplete" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/complete_removed-files" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : HELPER_BIN_FILE, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add) file in use", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : HELPER_BIN_FILE, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : true +}, { + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + // Launch an existing file so it is in use during the update + let fileInUseBin = getApplyDirFile(TEST_FILES[14].relPathDir + + TEST_FILES[14].fileName); + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"]; + let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + fileInUseProcess.init(fileInUseBin); + fileInUseProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + + logTestInfo("testing tobedeleted directory exists"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_true(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0181_fileInUse_xp_win_partial_svc.js b/toolkit/mozapps/update/test/unit/test_0181_fileInUse_xp_win_partial_svc.js new file mode 100644 index 000000000000..eea4729219e2 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0181_fileInUse_xp_win_partial_svc.js @@ -0,0 +1,236 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use partial MAR file patch apply success test */ + +const TEST_ID = "0181_svc"; +const MAR_IN_USE_WIN_FILE = "data/partial_win.mar"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/complete_precomplete", + compareFile : "data/partial_precomplete" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Patched by update.manifest (patch)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_before.exe", + compareFile : "data/partial_in_use_win_after.exe" +}, { + description : "Patched by update.manifest (patch) file in use", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_in_use_win_before.exe", + compareFile : "data/partial_in_use_win_after.exe" +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Patched by update.manifest (patch)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest (add)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/partial.png" +}, { + description : "Added by update.manifest (add)", + fileName : "00text2", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/10/", + dirRemoved : true +}, { + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_IN_USE_WIN_FILE); + + // Launch an existing file so it is in use during the update + let fileInUseBin = getApplyDirFile(TEST_FILES[12].relPathDir + + TEST_FILES[12].fileName); + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"]; + let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + fileInUseProcess.init(fileInUseBin); + fileInUseProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + + logTestInfo("testing tobedeleted directory exists"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_true(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0182_rmrfdirFileInUse_xp_win_complete_svc.js b/toolkit/mozapps/update/test/unit/test_0182_rmrfdirFileInUse_xp_win_complete_svc.js new file mode 100644 index 000000000000..1765b538de9b --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0182_rmrfdirFileInUse_xp_win_complete_svc.js @@ -0,0 +1,243 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir complete MAR file patch apply success test */ + +const TEST_ID = "0182_svc"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/partial_precomplete", + compareFile : "data/complete_precomplete" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "removed-files", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/partial_removed-files", + compareFile : "data/complete_removed-files" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/partial.png", + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : HELPER_BIN_FILE, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add) file in use", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : HELPER_BIN_FILE, + compareFile : "data/complete.png" +}, { + description : "Added by update.manifest (add)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromComplete\n", + compareContents : "FromComplete\n", + originalFile : null, + compareFile : null +}, { + description : "Added by update.manifest (add)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/complete.png" +}, { + description : "Removed by precomplete (remove)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}, { + description : "Removed by precomplete (remove)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/20/", + dirRemoved : true +}, { + description : "Removed by precomplete (rmdir)", + relPathDir : "a/b/2/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_COMPLETE_FILE); + + let fileInUseBin = getApplyDirFile(TEST_DIRS[4].relPathDir + + TEST_DIRS[4].subDirs[0] + + TEST_DIRS[4].subDirFiles[0]); + // Remove the empty file created for the test so the helper application can + // replace it. + fileInUseBin.remove(false); + + let helperBin = do_get_file(HELPER_BIN_FILE); + let fileInUseDir = getApplyDirFile(TEST_DIRS[4].relPathDir + + TEST_DIRS[4].subDirs[0]); + helperBin.copyTo(fileInUseDir, TEST_DIRS[4].subDirFiles[0]); + + // Launch an existing file so it is in use during the update + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"]; + let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + fileInUseProcess.init(fileInUseBin); + fileInUseProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + + logTestInfo("testing tobedeleted directory exists"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_true(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0183_rmrfdirFileInUse_xp_win_partial_svc.js b/toolkit/mozapps/update/test/unit/test_0183_rmrfdirFileInUse_xp_win_partial_svc.js new file mode 100644 index 000000000000..b952b9e647ad --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0183_rmrfdirFileInUse_xp_win_partial_svc.js @@ -0,0 +1,284 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* File in use inside removed dir partial MAR file patch apply success test */ + +const TEST_ID = "0183_svc"; +const MAR_IN_USE_WIN_FILE = "data/partial.mar"; + +// The files are listed in the same order as they are applied from the mar's +// update.manifest. Complete updates have remove file and rmdir directory +// operations located in the precomplete file performed first. +const TEST_FILES = [ +{ + description : "Only added by update.manifest for complete updates " + + "when there is a channel change (add-cc)", + fileName : "channel-prefs.js", + relPathDir : "a/b/defaults/pref/", + originalContents : "ShouldNotBeReplaced\n", + compareContents : "ShouldNotBeReplaced\n", + originalFile : null, + compareFile : null, + originalPerms : 0644, + comparePerms : null +}, { + description : "Added by update.manifest (add)", + fileName : "precomplete", + relPathDir : "", + originalContents : null, + compareContents : null, + originalFile : "data/complete_precomplete", + compareFile : "data/partial_precomplete", + originalPerms : 0666, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "searchpluginstext0", + relPathDir : "a/b/searchplugins/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0775, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng1.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Patched by update.manifest if the file exists " + + "(patch-if)", + fileName : "searchpluginspng0.png", + relPathDir : "a/b/searchplugins/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions1text0", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png1.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions1png0.png", + relPathDir : "a/b/extensions/extensions1/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Added by update.manifest if the parent directory " + + "exists (add-if)", + fileName : "extensions0text0", + relPathDir : "a/b/extensions/extensions0/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png1.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Patched by update.manifest if the parent directory " + + "exists (patch-if)", + fileName : "extensions0png0.png", + relPathDir : "a/b/extensions/extensions0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Patched by update.manifest (patch)", + fileName : "exe0.exe", + relPathDir : "a/b/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0755, + comparePerms : null +}, { + description : "Patched by update.manifest (patch)", + fileName : "0exe0.exe", + relPathDir : "a/b/0/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0755, + comparePerms : null +}, { + description : "Added by update.manifest (add)", + fileName : "00text0", + relPathDir : "a/b/0/00/", + originalContents : "ToBeReplacedWithFromPartial\n", + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : 0644, + comparePerms : null +}, { + description : "Patched by update.manifest (patch)", + fileName : "00png0.png", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : null, + originalFile : "data/complete.png", + compareFile : "data/partial.png", + originalPerms : 0666, + comparePerms : 0666 +}, { + description : "Added by update.manifest (add)", + fileName : "20text0", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "20png0.png", + relPathDir : "a/b/2/20/", + originalContents : null, + compareContents : null, + originalFile : null, + compareFile : "data/partial.png", + originalPerms : null, + comparePerms : 0644 +}, { + description : "Added by update.manifest (add)", + fileName : "00text2", + relPathDir : "a/b/0/00/", + originalContents : null, + compareContents : "FromPartial\n", + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : 0644 +}, { + description : "Removed by update.manifest (remove)", + fileName : "10text0", + relPathDir : "a/b/1/10/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}, { + description : "Removed by update.manifest (remove)", + fileName : "00text1", + relPathDir : "a/b/0/00/", + originalContents : "ToBeDeleted\n", + compareContents : null, + originalFile : null, + compareFile : null, + originalPerms : null, + comparePerms : null +}]; + +ADDITIONAL_TEST_DIRS = [ +{ + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/10/", + dirRemoved : true +}, { + description : "Removed by update.manifest (rmdir)", + relPathDir : "a/b/1/", + dirRemoved : true +}]; + +function run_test() { + do_test_pending(); + do_register_cleanup(cleanupUpdaterTest); + + setupUpdaterTest(MAR_IN_USE_WIN_FILE); + + let fileInUseBin = getApplyDirFile(TEST_DIRS[2].relPathDir + + TEST_DIRS[2].files[0]); + // Remove the empty file created for the test so the helper application can + // replace it. + fileInUseBin.remove(false); + + let helperBin = do_get_file(HELPER_BIN_FILE); + let fileInUseDir = getApplyDirFile(TEST_DIRS[2].relPathDir); + helperBin.copyTo(fileInUseDir, TEST_DIRS[2].files[0]); + + // Launch an existing file so it is in use during the update + let args = [getApplyDirPath() + "a/b/", "input", "output", "-s", "20"]; + let fileInUseProcess = AUS_Cc["@mozilla.org/process/util;1"]. + createInstance(AUS_Ci.nsIProcess); + fileInUseProcess.init(fileInUseBin); + fileInUseProcess.run(false, args, args.length); + + do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep); +} + +function doUpdate() { + // apply the complete mar + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateApplied); +} + +function checkUpdateApplied() { + setupHelperFinish(); +} + +function checkUpdate() { + logTestInfo("testing update.status should be " + STATE_SUCCEEDED); + let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX); + do_check_eq(readStatusFile(updatesDir), STATE_SUCCEEDED); + + checkFilesAfterUpdateSuccess(); + checkUpdateLogContains(ERR_BACKUP_DISCARD); + + logTestInfo("testing tobedeleted directory exists"); + let toBeDeletedDir = getApplyDirFile("tobedeleted", true); + do_check_true(toBeDeletedDir.exists()); + + checkCallbackServiceLog(); +} diff --git a/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update.js b/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update.js index b288cc219b9f..5790bddacef6 100644 --- a/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update.js +++ b/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update.js @@ -9,10 +9,6 @@ * manifest file (e.g. updatev2.manifest). */ -// Use a copy of the main application executable for the test to avoid main -// executable in use errors. -const FILE_WIN_TEST_EXE = "aus_test_app.exe"; - // Backup the updater.ini and use a custom one to prevent the updater from // launching a post update executable. const FILE_UPDATER_INI_BAK = "updater.ini.bak"; @@ -27,85 +23,6 @@ const APP_TIMER_TIMEOUT = 15000; let gAppTimer; let gProcess; -// Environment related globals -let gShouldResetEnv = undefined; -let gAddedEnvXRENoWindowsCrashDialog = false; -let gEnvXPCOMDebugBreak; -let gEnvXPCOMMemLeakLog; -let gEnvDyldLibraryPath; -let gEnvLdLibraryPath; - -// A shell script is used to get the OS version due to nsSystemInfo not -// returning the actual OS version. It is possible to get the actual OS version -// using ctypes but it would be more complicated than using a shell script. -XPCOMUtils.defineLazyGetter(this, "gIsLessThanMacOSX_10_6", function test_gMacVer() { - if (!IS_MACOSX) { - return false; - } - - let [versionScript, versionFile] = getVersionScriptAndFile(); - // Precreate the script with executable permissions - versionScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); - let scriptContents = "#! /bin/sh\nsw_vers -productVersion >> " + versionFile.path; - writeFile(versionScript, scriptContents); - logTestInfo("created " + versionScript.path + " shell script containing:\n" + - scriptContents); - - let versionScriptPath = versionScript.path; - if (/ /.test(versionScriptPath)) { - versionScriptPath = '"' + versionScriptPath + '"'; - } - - - let launchBin = getLaunchBin(); - let args = [versionScriptPath]; - let process = AUS_Cc["@mozilla.org/process/util;1"]. - createInstance(AUS_Ci.nsIProcess); - process.init(launchBin); - process.run(true, args, args.length); - if (process.exitValue != 0) { - do_throw("Version script exited with " + process.exitValue + "... unable " + - "to get Mac OS X version!"); - } - - let version = readFile(versionFile).split("\n")[0]; - logTestInfo("executing on Mac OS X verssion " + version); - - return (Services.vc.compare(version, "10.6") < 0) -}); - -/** - * Checks for the existence of a platform specific application binary that can - * be used for the test and gets its path if it is found. - * - * Note: The application shell scripts for launching the application work on all - * platforms that provide a launch shell script except for Mac OS X 10.5 which - * is why this test uses the binaries to launch the application. - */ -XPCOMUtils.defineLazyGetter(this, "gAppBinPath", function test_gAppBinPath() { - let processDir = getCurrentProcessDir(); - let appBin = processDir.clone(); - appBin.append(APP_BIN_NAME + APP_BIN_SUFFIX); - if (appBin.exists()) { - if (IS_WIN) { - let appBinCopy = processDir.clone(); - appBinCopy.append(FILE_WIN_TEST_EXE); - if (appBinCopy.exists()) { - appBinCopy.remove(false); - } - appBin.copyTo(processDir, FILE_WIN_TEST_EXE); - appBin = processDir.clone(); - appBin.append(FILE_WIN_TEST_EXE); - } - let appBinPath = appBin.path; - if (/ /.test(appBinPath)) { - appBinPath = '"' + appBinPath + '"'; - } - return appBinPath; - } - return null; -}); - function run_test() { do_test_pending(); do_register_cleanup(end_test); @@ -292,199 +209,6 @@ let gTimerCallback = { QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback]) }; -/** - * 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; - - let env = AUS_Cc["@mozilla.org/process/environment;1"]. - getService(AUS_Ci.nsIEnvironment); - if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { - gAddedEnvXRENoWindowsCrashDialog = true; - logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + - "variable to 1... previously it didn't exist"); - env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1"); - } - - if (IS_UNIX) { - let appGreDir = Services.dirsvc.get("GreD", AUS_Ci.nsIFile); - let envGreDir = AUS_Cc["@mozilla.org/file/local;1"]. - createInstance(AUS_Ci.nsILocalFile); - let shouldSetEnv = true; - if (IS_MACOSX) { - if (env.exists("DYLD_LIBRARY_PATH")) { - gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH"); - envGreDir.initWithPath(gEnvDyldLibraryPath); - if (envGreDir.path == appGreDir.path) { - gEnvDyldLibraryPath = null; - shouldSetEnv = false; - } - } - - if (shouldSetEnv) { - logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " + - appGreDir.path); - env.set("DYLD_LIBRARY_PATH", appGreDir.path); - } - } - else { - if (env.exists("LD_LIBRARY_PATH")) { - gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH"); - envGreDir.initWithPath(gEnvLdLibraryPath); - if (envGreDir.path == appGreDir.path) { - gEnvLdLibraryPath = null; - shouldSetEnv = false; - } - } - - if (shouldSetEnv) { - logTestInfo("setting LD_LIBRARY_PATH environment variable value to " + - appGreDir.path); - env.set("LD_LIBRARY_PATH", appGreDir.path); - } - } - } - - if (env.exists("XPCOM_MEM_LEAK_LOG")) { - gEnvXPCOMMemLeakLog = env.get("XPCOM_MEM_LEAK_LOG"); - logTestInfo("removing the XPCOM_MEM_LEAK_LOG environment variable... " + - "previous value " + gEnvXPCOMMemLeakLog); - env.set("XPCOM_MEM_LEAK_LOG", ""); - } - - if (env.exists("XPCOM_DEBUG_BREAK")) { - gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK"); - logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + - "warn... previous value " + gEnvXPCOMDebugBreak); - } - else { - logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " + - "warn... previously it didn't exist"); - } - - env.set("XPCOM_DEBUG_BREAK", "warn"); -} - -/** - * 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; - - let env = AUS_Cc["@mozilla.org/process/environment;1"]. - getService(AUS_Ci.nsIEnvironment); - - if (gEnvXPCOMMemLeakLog) { - logTestInfo("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + - gEnvXPCOMMemLeakLog); - env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog); - } - - if (gEnvXPCOMDebugBreak) { - logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " + - gEnvXPCOMDebugBreak); - env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak); - } - else { - logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable"); - env.set("XPCOM_DEBUG_BREAK", ""); - } - - if (IS_UNIX) { - if (IS_MACOSX) { - if (gEnvDyldLibraryPath) { - logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " + - "back to " + gEnvDyldLibraryPath); - env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath); - } - else { - logTestInfo("removing DYLD_LIBRARY_PATH environment variable"); - env.set("DYLD_LIBRARY_PATH", ""); - } - } - else { - if (gEnvLdLibraryPath) { - logTestInfo("setting LD_LIBRARY_PATH environment variable value back " + - "to " + gEnvLdLibraryPath); - env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath); - } - else { - logTestInfo("removing LD_LIBRARY_PATH environment variable"); - env.set("LD_LIBRARY_PATH", ""); - } - } - } - - if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) { - logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " + - "variable"); - env.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); - } -} - -/** - * Returns the platform specific arguments used by nsIProcess when launching - * the application. - * - * @return an array of arguments to be passed to nsIProcess. - * - * Notes: - * 1. Mozilla universal binaries that contain both i386 and x86_64 on Mac OS X - * 10.5.x must be launched using the i386 architecture. - * 2. 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. - * -process-updates makes the application exits after being relaunched by the - * updater. - * 1> pipes stdout to a file. - * appConsoleLogPath is the file path to pipe the output from the shell. - * Otherwise the output from the application will end up in the xpchsell log. - * 2>&1 pipes stderr to sdout. - */ -function getProcessArgs() { - // Pipe the output from the launched application to a file so the output from - // its console isn't present in the xpcshell log. - let appConsoleLogPath = getAppConsoleLogPath(); - - let args; - if (IS_UNIX) { - let launchScript = getLaunchScript(); - // Precreate the script with executable permissions - launchScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY); - - let scriptContents = "#! /bin/sh\n"; - // On Mac OS X versions prior to 10.6 the i386 acrhitecture must be used. - if (gIsLessThanMacOSX_10_6) { - scriptContents += "arch -arch i386 "; - } - scriptContents += gAppBinPath + " -no-remote -process-updates 1> " + - appConsoleLogPath + " 2>&1"; - writeFile(launchScript, scriptContents); - logTestInfo("created " + launchScript.path + " containing:\n" + - scriptContents); - args = [launchScript.path]; - } - else { - args = ["/D", "/Q", "/C", gAppBinPath, "-no-remote", "-process-updates", - "1>", appConsoleLogPath, "2>&1"]; - } - return args; -} - /** * Gets the directory where the update adds / removes the files contained in the * update. @@ -501,64 +225,6 @@ function getUpdateTestDir() { return updateTestDir; } -/** - * Gets a file path for piping the console output from the application so it - * doesn't appear in the xpcshell log file. - * - * @return path to the file for piping the console output from the application. - */ -function getAppConsoleLogPath() { - let appConsoleLog = do_get_file("/", true); - appConsoleLog.append("app_console_log"); - if (appConsoleLog.exists()) { - appConsoleLog.remove(false); - } - let appConsoleLogPath = appConsoleLog.path; - if (/ /.test(appConsoleLogPath)) { - appConsoleLogPath = '"' + appConsoleLogPath + '"'; - } - return appConsoleLogPath; -} - -/** - * Gets the nsIFile references for the shell script to retrieve the Mac OS X - * version and the nsIFile to pipe the output of the shell script. If either of - * these files exist they will be removed by this function. - * - * @return array containing two nsIFile references. The first array member is - * the nsIFile for the shell script to launch to get the Mac OS X - * version and the second array member is the nsIFile for the piped - * output from the shell script. - */ -function getVersionScriptAndFile() { - let versionScript = do_get_file("/", true); - let versionFile = versionScript.clone(); - versionScript.append("get_version.sh"); - if (versionScript.exists()) { - versionScript.remove(false); - } - versionFile.append("version.out"); - if (versionFile.exists()) { - versionFile.remove(false); - } - return [versionScript, versionFile]; -} - -/** - * 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("/", true); - launchScript.append("launch.sh"); - if (launchScript.exists()) { - launchScript.remove(false); - } - return launchScript; -} - /** * Checks if the update has finished and if it has finished performs checks for * the test. diff --git a/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update_svc.js b/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update_svc.js new file mode 100644 index 000000000000..2dd22fa8cd96 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/test_0200_app_launch_apply_update_svc.js @@ -0,0 +1,250 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* Test applying an update by staging an update and launching an application */ + +/** + * The MAR file used for this test should not contain a version 2 update + * manifest file (e.g. updatev2.manifest). + */ + +// Backup the updater.ini and use a custom one to prevent the updater from +// launching a post update executable. +const FILE_UPDATER_INI_BAK = "updater.ini.bak"; + +// Number of milliseconds for each do_timeout call. +const CHECK_TIMEOUT_MILLI = 1000; + +// Maximum number of milliseconds the process that is launched can run before +// the test will try to kill it. +const APP_TIMER_TIMEOUT = 15000; + +function run_test() { + do_test_pending(); + do_register_cleanup(end_test); + + removeUpdateDirsAndFiles(); + + if (!gAppBinPath) { + do_throw("Main application binary not found... expected: " + + APP_BIN_NAME + APP_BIN_SUFFIX); + return; + } + + let channel = Services.prefs.getCharPref(PREF_APP_UPDATE_CHANNEL); + let patches = getLocalPatchString(null, null, null, null, null, "true", + STATE_PENDING); + let updates = getLocalUpdateString(patches, null, null, null, null, null, + null, null, null, null, null, null, + null, "true", channel); + writeUpdatesToXMLFile(getLocalUpdatesXMLString(updates), true); + + // Read the application.ini and use its application version + let processDir = getCurrentProcessDir(); + let file = processDir.clone(); + file.append("application.ini"); + let ini = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"]. + getService(AUS_Ci.nsIINIParserFactory). + createINIParser(file); + let version = ini.getString("App", "Version"); + writeVersionFile(version); + + // This is the directory where the update files will be located + let updateTestDir = getUpdateTestDir(); + try { + removeDirRecursive(updateTestDir); + } + catch (e) { + logTestInfo("unable to remove directory - path: " + updateTestDir.path + + ", exception: " + e); + } + + // Add the directory where the update files will be added and add files that + // will be removed. + if (!updateTestDir.exists()) { + updateTestDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY); + } + logTestInfo("update test directory path: " + updateTestDir.path); + + file = updateTestDir.clone(); + file.append("UpdateTestRemoveFile"); + writeFile(file, "ToBeRemoved"); + + file = updateTestDir.clone(); + file.append("UpdateTestAddFile"); + writeFile(file, "ToBeReplaced"); + + file = updateTestDir.clone(); + file.append("removed-files"); + writeFile(file, "ToBeReplaced"); + + let updatesPatchDir = getUpdatesDir(); + updatesPatchDir.append("0"); + let mar = do_get_file("data/simple.mar"); + mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE); + + // Backup the updater.ini + let updaterIni = processDir.clone(); + updaterIni.append(FILE_UPDATER_INI); + updaterIni.moveTo(processDir, FILE_UPDATER_INI_BAK); + // Create a new updater.ini to avoid applications that provide a post update + // executable. + let updaterIniContents = "[Strings]\n" + + "Title=Update Test\n" + + "Info=Application Update XPCShell Test - " + + "test_0200_general.js\n"; + updaterIni = processDir.clone(); + updaterIni.append(FILE_UPDATER_INI); + writeFile(updaterIni, updaterIniContents); + + let updatesRootDir = processDir.clone(); + updatesRootDir.append("updates"); + updatesRootDir.append("0"); + getApplyDirPath = function() { + return processDir.path; + } + getApplyDirFile = function (aRelPath, allowNonexistent) { + let base = AUS_Cc["@mozilla.org/file/local;1"]. + createInstance(AUS_Ci.nsILocalFile); + base.initWithPath(getApplyDirPath()); + let path = (aRelPath ? aRelPath : ""); + let bits = path.split("/"); + for (let i = 0; i < bits.length; i++) { + if (bits[i]) { + if (bits[i] == "..") + base = base.parent; + else + base.append(bits[i]); + } + } + + if (!allowNonexistent && !base.exists()) { + _passed = false; + var stack = Components.stack.caller; + _dump("TEST-UNEXPECTED-FAIL | " + stack.filename + " | [" + + stack.name + " : " + stack.lineNumber + "] " + base.path + + " does not exist\n"); + } + + return base; + } + runUpdateUsingService(STATE_PENDING_SVC, STATE_SUCCEEDED, checkUpdateFinished, updatesRootDir); +} + +function end_test() { + resetEnvironment(); + + let processDir = getCurrentProcessDir(); + // Restore the backed up updater.ini + let updaterIni = processDir.clone(); + updaterIni.append(FILE_UPDATER_INI_BAK); + updaterIni.moveTo(processDir, FILE_UPDATER_INI); + + // Remove the copy of the application executable used for the test on + // Windows if it exists. + let appBinCopy = processDir.clone(); + appBinCopy.append(FILE_WIN_TEST_EXE); + if (appBinCopy.exists()) { + appBinCopy.remove(false); + } + + // Remove the files added by the update. + let updateTestDir = getUpdateTestDir(); + try { + logTestInfo("removing update test directory " + updateTestDir.path); + removeDirRecursive(updateTestDir); + } + catch (e) { + logTestInfo("unable to remove directory - path: " + updateTestDir.path + + ", exception: " + e); + } + + // This will delete the app console log file if it exists. + getAppConsoleLogPath(); + + cleanUp(); +} + +/** + * Gets the directory where the update adds / removes the files contained in the + * update. + * + * @return nsIFile for the directory where the update adds / removes the files + * contained in the update mar. + */ +function getUpdateTestDir() { + let updateTestDir = getCurrentProcessDir(); + updateTestDir.append("update_test"); + return updateTestDir; +} + +/** + * Checks if the update has finished and if it has finished performs checks for + * the test. + */ +function checkUpdateFinished() { + // Don't proceed until the update.log has been created. + let log = getUpdatesDir(); + log.append("0"); + log.append(FILE_UPDATE_LOG); + if (!log.exists()) { + do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished); + return; + } + + // Log the contents of the update.log so it is simpler to diagnose a test + // failure. For example, on Windows if the application binary is in use the + // updater will not apply the update. + let contents = readFile(log); + logTestInfo("contents of " + log.path + ":\n" + + contents.replace(/\r\n/g, "\n")); + + if (contents.indexOf("NS_main: file in use") != -1) { + do_throw("the application can't be in use when running this test"); + } + + standardInit(); + + let update = gUpdateManager.getUpdateAt(0); + do_check_eq(update.state, STATE_SUCCEEDED); + + let updateTestDir = getUpdateTestDir(); + + let file = updateTestDir.clone(); + file.append("UpdateTestRemoveFile"); + do_check_false(file.exists()); + + file = updateTestDir.clone(); + file.append("UpdateTestAddFile"); + do_check_true(file.exists()); + do_check_eq(readFileBytes(file), "UpdateTestAddFile\n"); + + file = updateTestDir.clone(); + file.append("removed-files"); + do_check_true(file.exists()); + do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n"); + + let updatesDir = getUpdatesDir(); + let log = updatesDir.clone(); + log.append("0"); + log.append(FILE_UPDATE_LOG); + logTestInfo("testing " + log.path + " shouldn't exist"); + do_check_false(log.exists()); + + log = updatesDir.clone(); + log.append(FILE_LAST_LOG); + logTestInfo("testing " + log.path + " should exist"); + do_check_true(log.exists()); + + log = updatesDir.clone(); + log.append(FILE_BACKUP_LOG); + logTestInfo("testing " + log.path + " shouldn't exist"); + do_check_false(log.exists()); + + updatesDir.append("0"); + logTestInfo("testing " + updatesDir.path + " should exist"); + do_check_true(updatesDir.exists()); + + do_timeout(CHECK_TIMEOUT_MILLI, do_test_finished); +} diff --git a/toolkit/mozapps/update/test/unit/xpcshell.ini b/toolkit/mozapps/update/test/unit/xpcshell.ini index 398ef1ee7714..0ea8785ffa69 100644 --- a/toolkit/mozapps/update/test/unit/xpcshell.ini +++ b/toolkit/mozapps/update/test/unit/xpcshell.ini @@ -28,3 +28,6 @@ run-if = os == 'win' run-if = os == 'linux' || os == 'mac' [test_bug497578.js] [test_bug595059.js] +; Tests using the maintenance service +[include:xpcshell_updater_windows_svc.ini] +run-if = os == 'win' diff --git a/toolkit/mozapps/update/test/unit/xpcshell_updater_windows_svc.ini b/toolkit/mozapps/update/test/unit/xpcshell_updater_windows_svc.ini new file mode 100644 index 000000000000..cc249214d8a6 --- /dev/null +++ b/toolkit/mozapps/update/test/unit/xpcshell_updater_windows_svc.ini @@ -0,0 +1,15 @@ +[test_0000_bootstrap_svc.js] +[test_0110_general_svc.js] +[test_0111_general_svc.js] +[test_0112_general_svc.js] +[test_0120_channelChange_complete_svc.js] +[test_0150_appBinReplaced_xp_win_complete_svc.js] +[test_0151_appBinPatched_xp_win_partial_svc.js] +[test_0160_appInUse_xp_win_complete_svc.js] +[test_0170_fileLocked_xp_win_complete_svc.js] +[test_0171_fileLocked_xp_win_partial_svc.js] +[test_0180_fileInUse_xp_win_complete_svc.js] +[test_0181_fileInUse_xp_win_partial_svc.js] +[test_0182_rmrfdirFileInUse_xp_win_complete_svc.js] +[test_0183_rmrfdirFileInUse_xp_win_partial_svc.js] +[test_0200_app_launch_apply_update_svc.js] diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 24a682a501bd..a3500093fdcd 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -3152,6 +3152,20 @@ XRE_main(int argc, char* argv[], const nsXREAppData* aAppData) appData.version); if (EnvHasValue("MOZ_PROCESS_UPDATES")) { SaveToEnv("MOZ_PROCESS_UPDATES="); + + // If the caller has asked us to log our arguments, do so. This is used + // to make sure that the maintenance service successfully launches the + // callback application. + const char *logFile = nsnull; + if (ARG_FOUND == CheckArg("dump-args", false, &logFile)) { + FILE* logFP = fopen(logFile, "wb"); + if (logFP) { + for (i = 1; i < gRestartArgc; ++i) { + fprintf(logFP, "%s\n", gRestartArgv[i]); + } + fclose(logFP); + } + } return 0; } #endif diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index 8497c098e06c..ca06e228a8f7 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -558,6 +558,33 @@ ProcessUpdates(nsIFile *greDir, nsIFile *appDir, nsIFile *updRootDir, rv = updatesDir->AppendNative(NS_LITERAL_CSTRING("0")); if (NS_FAILED(rv)) return rv; + + const char *processingUpdates = PR_GetEnv("MOZ_PROCESS_UPDATES"); + if (processingUpdates && *processingUpdates) { + // Enable the tests to request us to use a different update root directory + const char *updRootOverride = PR_GetEnv("MOZ_UPDATE_ROOT_OVERRIDE"); + if (updRootOverride && *updRootOverride) { + nsCOMPtr overrideDir; + nsCAutoString path(updRootOverride); + rv = NS_NewNativeLocalFile(path, false, getter_AddRefs(overrideDir)); + if (NS_FAILED(rv)) { + return rv; + } + updatesDir = do_QueryInterface(overrideDir); + } + // Enable the tests to request us to use a different app directory + const char *appDirOverride = PR_GetEnv("MOZ_UPDATE_APPDIR_OVERRIDE"); + if (appDirOverride && *appDirOverride) { + nsCOMPtr overrideDir; + nsCAutoString path(appDirOverride); + rv = NS_NewNativeLocalFile(path, false, getter_AddRefs(overrideDir)); + if (NS_FAILED(rv)) { + return rv; + } + NS_RELEASE(appDir); + NS_ADDREF(appDir = overrideDir); + } + } nsCOMPtr statusFile; bool isPendingService; diff --git a/xpcom/io/SpecialSystemDirectory.cpp b/xpcom/io/SpecialSystemDirectory.cpp index 1e85ca4ca7bd..88e6a17e01ea 100644 --- a/xpcom/io/SpecialSystemDirectory.cpp +++ b/xpcom/io/SpecialSystemDirectory.cpp @@ -772,6 +772,10 @@ GetSpecialSystemDirectory(SystemDirectories aSystemSystemDirectory, { return GetWindowsFolder(CSIDL_COMMON_DESKTOPDIRECTORY, aFile); } + case Win_Common_AppData: + { + return GetWindowsFolder(CSIDL_COMMON_APPDATA, aFile); + } case Win_Printhood: { return GetWindowsFolder(CSIDL_PRINTHOOD, aFile); diff --git a/xpcom/io/SpecialSystemDirectory.h b/xpcom/io/SpecialSystemDirectory.h index 47f3da3185ff..de87280dabd9 100644 --- a/xpcom/io/SpecialSystemDirectory.h +++ b/xpcom/io/SpecialSystemDirectory.h @@ -109,6 +109,7 @@ enum SystemDirectories { Win_LocalAppdata = 228, Win_ProgramFiles = 229, Win_Downloads = 230, + Win_Common_AppData = 231, Unix_LocalDirectory = 301, Unix_LibDirectory = 302, diff --git a/xpcom/io/nsDirectoryService.cpp b/xpcom/io/nsDirectoryService.cpp index c303abbfb3e3..2b42637e4c1a 100644 --- a/xpcom/io/nsDirectoryService.cpp +++ b/xpcom/io/nsDirectoryService.cpp @@ -857,6 +857,10 @@ nsDirectoryService::GetFile(const char *prop, bool *persistent, nsIFile **_retva { rv = GetSpecialSystemDirectory(Win_Common_Desktopdirectory, getter_AddRefs(localFile)); } + else if (inAtom == nsDirectoryService::sCommon_AppData) + { + rv = GetSpecialSystemDirectory(Win_Common_AppData, getter_AddRefs(localFile)); + } else if (inAtom == nsDirectoryService::sAppdata) { rv = GetSpecialSystemDirectory(Win_Appdata, getter_AddRefs(localFile)); diff --git a/xpcom/io/nsDirectoryServiceAtomList.h b/xpcom/io/nsDirectoryServiceAtomList.h index 828b3ab6836c..4a25e438810d 100644 --- a/xpcom/io/nsDirectoryServiceAtomList.h +++ b/xpcom/io/nsDirectoryServiceAtomList.h @@ -100,6 +100,7 @@ DIR_ATOM(sCommon_Startmenu, NS_WIN_COMMON_STARTMENU_DIR) DIR_ATOM(sCommon_Programs, NS_WIN_COMMON_PROGRAMS_DIR) DIR_ATOM(sCommon_Startup, NS_WIN_COMMON_STARTUP_DIR) DIR_ATOM(sCommon_Desktopdirectory, NS_WIN_COMMON_DESKTOP_DIRECTORY) +DIR_ATOM(sCommon_AppData, NS_WIN_COMMON_APPDATA_DIR) DIR_ATOM(sAppdata, NS_WIN_APPDATA_DIR) DIR_ATOM(sLocalAppdata, NS_WIN_LOCAL_APPDATA_DIR) DIR_ATOM(sPrinthood, NS_WIN_PRINTHOOD) diff --git a/xpcom/io/nsDirectoryServiceDefs.h b/xpcom/io/nsDirectoryServiceDefs.h index 797cd80abaad..0b3526b82d1e 100644 --- a/xpcom/io/nsDirectoryServiceDefs.h +++ b/xpcom/io/nsDirectoryServiceDefs.h @@ -149,6 +149,7 @@ #define NS_WIN_COMMON_PROGRAMS_DIR "CmPrgs" #define NS_WIN_COMMON_STARTUP_DIR "CmStrt" #define NS_WIN_COMMON_DESKTOP_DIRECTORY "CmDeskP" + #define NS_WIN_COMMON_APPDATA_DIR "CmAppData" #define NS_WIN_APPDATA_DIR "AppData" #define NS_WIN_LOCAL_APPDATA_DIR "LocalAppData" #define NS_WIN_PRINTHOOD "PrntHd"