Merge mozilla-central into mozilla-inbound

This commit is contained in:
Ehsan Akhgari 2012-06-14 09:37:35 -04:00
commit e01228d7c1
45 changed files with 5031 additions and 47 deletions

View File

@ -1,6 +1,7 @@
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
. $topsrcdir/build/unix/mozconfig.linux

View File

@ -1,6 +1,7 @@
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
. $topsrcdir/build/unix/mozconfig.linux

View File

@ -2,6 +2,7 @@
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j12"

View File

@ -4,6 +4,7 @@ ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-accessibility
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
# Enable parallel compiling
mk_add_options MOZ_MAKE_FLAGS="-j12"

View File

@ -1,6 +1,7 @@
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -4,6 +4,7 @@ ac_add_options --host=x86_64-pc-mingw32
ac_add_options --enable-debug
ac_add_options --enable-trace-malloc
ac_add_options --enable-signmar
ENABLE_MARIONETTE=1
# Needed to enable breakpad in application.ini
export MOZILLA_OFFICIAL=1

View File

@ -156,3 +156,7 @@ installer:: removed-files
ifdef INSTALLER_DIR
$(MAKE) -C $(INSTALLER_DIR)
endif
ifdef ENABLE_MARIONETTE
DEFINES += -DENABLE_MARIONETTE=1
endif

View File

@ -466,6 +466,12 @@
@BINPATH@/components/ContactManager.js
@BINPATH@/components/ContactManager.manifest
#ifdef ENABLE_MARIONETTE
@BINPATH@/chrome/marionette@JAREXT@
@BINPATH@/chrome/marionette.manifest
@BINPATH@/components/MarionetteComponents.manifest
@BINPATH@/components/marionettecomponent.js
#endif
; Modules
@BINPATH@/modules/*

View File

@ -769,18 +769,22 @@ function cleanUpUpdatesDir(aBackgroundUpdate) {
}
}
f.moveTo(dir, FILE_LAST_LOG);
continue;
if (aBackgroundUpdate) {
// We're not going to delete any files, so we can just
// bail out of the loop right now.
break;
} else {
continue;
}
}
catch (e) {
LOG("cleanUpUpdatesDir - failed to move file " + f.path + " to " +
dir.path + " and rename it to " + FILE_LAST_LOG);
}
} else if (f.leafName == FILE_UPDATE_STATUS && aBackgroundUpdate) {
// Leave the update.status file alone when a background update
// has been performed. We don't remove this file here because
// after the application directory gets replaced by the staged
// update, this will end up being the update.status file which
// represents the status of the update performed.
} else if (aBackgroundUpdate) {
// Don't delete any files when an update has been staged, as
// we need to keep them around in case we would have to fall
// back to applying the update on application restart.
continue;
}
// Now, recursively remove this file. The recursive removal is really
@ -1010,8 +1014,9 @@ function handleUpdateFailure(update, errorCode) {
* Fall back to downloading a complete update in case an update has failed.
*
* @param update the update object that has failed to apply.
* @param postStaging true if we have just attempted to stage an update.
*/
function handleFallbackToCompleteUpdate(update) {
function handleFallbackToCompleteUpdate(update, postStaging) {
cleanupActiveUpdate();
update.statusText = gUpdateBundle.GetStringFromName("patchApplyFailure");
@ -1024,7 +1029,7 @@ function handleFallbackToCompleteUpdate(update) {
"failed, downloading complete patch");
var status = Cc["@mozilla.org/updates/update-service;1"].
getService(Ci.nsIApplicationUpdateService).
downloadUpdate(update, true);
downloadUpdate(update, !postStaging);
if (status == STATE_NONE)
cleanupActiveUpdate();
}
@ -1617,7 +1622,7 @@ UpdateService.prototype = {
}
// Something went wrong with the patch application process.
handleFallbackToCompleteUpdate(update);
handleFallbackToCompleteUpdate(update, false);
prompter.showUpdateError(update);
}
@ -2432,7 +2437,7 @@ UpdateManager.prototype = {
if (update.state == STATE_FAILED && ary[1]) {
updateSucceeded = false;
if (!handleUpdateFailure(update, ary[1])) {
handleFallbackToCompleteUpdate(update);
handleFallbackToCompleteUpdate(update, true);
}
}
if (update.state == STATE_APPLIED && shouldUseService()) {

View File

@ -48,6 +48,7 @@
# define NS_ttoi atoi
# define NS_tstat stat
# define NS_tgetcwd getcwd
# define NS_tfputs fputs
# define LOG_S "%s"
#endif
@ -171,6 +172,9 @@ int NS_main(int argc, NS_tchar **argv)
"Usage: WORKINGDIR INFILE OUTFILE -s SECONDS [FILETOLOCK]\n" \
" or: WORKINGDIR LOGFILE [ARG2 ARG3...]\n" \
" or: signature-check filepath\n" \
" or: setup-symlink dir1 dir2 file symlink\n" \
" or: remove-symlink dir1 dir2 file symlink\n" \
" or: check-symlink symlink\n" \
"\n" \
" WORKINGDIR \tThe relative path to the working directory to use.\n" \
" INFILE \tThe relative path from the working directory for the file to\n" \
@ -205,6 +209,68 @@ int NS_main(int argc, NS_tchar **argv)
#endif
}
if (!NS_tstrcmp(argv[1], NS_T("setup-symlink"))) {
#ifdef XP_UNIX
NS_tchar path[MAXPATHLEN];
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
mkdir(path, 0755);
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]);
mkdir(path, 0755);
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]);
FILE * file = NS_tfopen(path, NS_T("w"));
if (file) {
NS_tfputs(NS_T("test"), file);
fclose(file);
}
symlink(path, argv[5]);
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
if (argc > 6 && !NS_tstrcmp(argv[6], NS_T("change-perm"))) {
chmod(path, 0644);
}
return 0;
#else
// Not implemented on non-Unix platforms
return 1;
#endif
}
if (!NS_tstrcmp(argv[1], NS_T("remove-symlink"))) {
#ifdef XP_UNIX
NS_tchar path[MAXPATHLEN];
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
chmod(path, 0755);
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3], argv[4]);
unlink(path);
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s/%s"), NS_T("/tmp"), argv[2], argv[3]);
rmdir(path);
NS_tsnprintf(path, sizeof(path)/sizeof(path[0]),
NS_T("%s/%s"), NS_T("/tmp"), argv[2]);
rmdir(path);
return 0;
#else
// Not implemented on non-Unix platforms
return 1;
#endif
}
if (!NS_tstrcmp(argv[1], NS_T("check-symlink"))) {
#ifdef XP_UNIX
struct stat ss;
lstat(argv[2], &ss);
return S_ISLNK(ss.st_mode) ? 0 : 1;
#else
// Not implemented on non-Unix platforms
return 1;
#endif
}
if (!NS_tstrcmp(argv[1], NS_T("wait-for-service-stop"))) {
#ifdef XP_WIN
const int maxWaitSeconds = NS_ttoi(argv[3]);

View File

@ -100,6 +100,7 @@ var gCallbackBinFile = "callback_app" + BIN_SUFFIX;
var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"];
var gBackgroundUpdate = false;
var gSwitchApp = false;
var gDisableReplaceFallback = false;
// Time to wait for the test helper process before continuing the test
const TEST_HELPER_TIMEOUT = 1000;
@ -513,10 +514,21 @@ function runUpdate() {
}
logTestInfo("Running the updater: " + updateBin.path + " " + args.join(" "));
let env = AUS_Cc["@mozilla.org/process/environment;1"].
getService(AUS_Ci.nsIEnvironment);
if (gDisableReplaceFallback) {
env.set("MOZ_NO_REPLACE_FALLBACK", "1");
}
let process = AUS_Cc["@mozilla.org/process/util;1"].
createInstance(AUS_Ci.nsIProcess);
process.init(updateBin);
process.run(true, args, args.length);
if (gDisableReplaceFallback) {
env.set("MOZ_NO_REPLACE_FALLBACK", "");
}
return process.exitValue;
}

View File

@ -14,7 +14,7 @@ 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 = [
var TEST_FILES = [
{
description : "Should never change",
fileName : "channel-prefs.js",
@ -234,6 +234,39 @@ ADDITIONAL_TEST_DIRS = [
dirRemoved : true
}];
function runHelperProcess(args) {
let helperBin = do_get_file(HELPER_BIN_FILE);
let process = AUS_Cc["@mozilla.org/process/util;1"].
createInstance(AUS_Ci.nsIProcess);
process.init(helperBin);
logTestInfo("Running " + helperBin.path + " " + args.join(" "));
process.run(true, args, args.length);
do_check_eq(process.exitValue, 0);
}
function createSymlink() {
let args = ["setup-symlink", "moz-foo", "moz-bar", "target",
getApplyDirFile().path + "/a/b/link"];
runHelperProcess(args);
args = ["setup-symlink", "moz-foo2", "moz-bar2", "target2",
getApplyDirFile().path + "/a/b/link2", "change-perm"];
runHelperProcess(args);
}
function removeSymlink() {
let args = ["remove-symlink", "moz-foo", "moz-bar", "target",
getApplyDirFile().path + "/a/b/link"];
runHelperProcess(args);
args = ["remove-symlink", "moz-foo2", "moz-bar2", "target2",
getApplyDirFile().path + "/a/b/link2"];
runHelperProcess(args);
}
function checkSymlink() {
let args = ["check-symlink", getApplyDirFile().path + "/a/b/link"];
runHelperProcess(args);
}
function run_test() {
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
@ -253,10 +286,31 @@ function run_test() {
applyToDir.lastModifiedTime = yesterday;
}
if (IS_UNIX) {
removeSymlink();
createSymlink();
do_register_cleanup(removeSymlink);
TEST_FILES.push({
description : "Readable symlink",
fileName : "link",
relPathDir : "a/b/",
originalContents : "test",
compareContents : "test",
originalFile : null,
compareFile : null,
originalPerms : 0664,
comparePerms : 0664
});
}
// apply the complete mar
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for success when " +
"applying a complete mar");
let updateLog = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX, true);
updateLog.append(FILE_UPDATE_LOG);
let updateLogContents = readFileBytes(updateLog);
logTestInfo(updateLogContents);
do_check_eq(exitValue, 0);
logTestInfo("testing update.status should be " + STATE_APPLIED);
@ -308,8 +362,10 @@ function run_test() {
}
checkFilesAfterUpdateSuccess();
// Sorting on Linux is different so skip this check for now.
if (!IS_UNIX) {
if (IS_UNIX) {
checkSymlink();
} else {
// Sorting on Linux is different so skip this check for now.
checkUpdateLogContents(LOG_COMPLETE_SWITCH_SUCCESS);
}

View File

@ -215,6 +215,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -0,0 +1,239 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* Application in use complete MAR file background patch apply failure fallback test */
const TEST_ID = "0162";
// 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 : "Should never change",
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);
gBackgroundUpdate = true;
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", "40"];
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
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for success when " +
"applying a complete mar");
do_check_eq(exitValue, 0);
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory doesn't exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -223,6 +223,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -224,6 +224,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -0,0 +1,247 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File locked complete MAR file background patch apply failure fallback test */
const TEST_ID = "0174";
// 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 : "Should never change",
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);
gBackgroundUpdate = true;
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", "40", 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
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"applying a complete mar");
do_check_eq(exitValue, 1);
logTestInfo("testing update.status should be " + STATE_FAILED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory doesn't exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,248 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File locked partial MAR file background patch apply failure fallback test */
const TEST_ID = "0175";
// 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 : "Should never change",
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);
gBackgroundUpdate = true;
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", "40", 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
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"applying a complete mar");
do_check_eq(exitValue, 1);
logTestInfo("testing update.status should be " + STATE_FAILED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory doesn't exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -222,6 +222,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -225,6 +225,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -231,6 +231,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -272,6 +272,7 @@ function doUpdate() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -0,0 +1,246 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use complete MAR file background patch apply failure fallback test */
const TEST_ID = "0188";
// 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 : "Should never change",
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/partial_precomplete"
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginspng0.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "data/partial.png",
compareFile : "data/partial.png"
}, {
description : "Added by update.manifest (add)",
fileName : "removed-files",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "data/partial_removed-files",
compareFile : "data/partial_removed-files"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/extensions/extensions1/",
originalContents : null,
compareContents : null,
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/partial.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 : null
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : HELPER_BIN_FILE,
compareFile : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\n",
originalFile : null,
compareFile : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
originalFile : null,
compareFile : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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);
gBackgroundUpdate = true;
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", "40"];
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
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for success when " +
"applying a complete mar");
do_check_eq(exitValue, 0);
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,249 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use partial MAR file background patch apply failure fallback test */
const TEST_ID = "0189";
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 : "Should never change",
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/complete_precomplete"
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.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/complete.png"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/extensions/extensions1/",
originalContents : null,
compareContents : null,
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/complete.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/complete.png"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.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/complete.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_before.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_before.exe"
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.png"
}, {
description : "Added by update.manifest (add)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text2",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
originalFile : null,
compareFile : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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);
gBackgroundUpdate = true;
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", "40"];
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
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for success when " +
"applying a complete mar");
do_check_eq(exitValue, 0);
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,255 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use inside removed dir complete MAR file background patch apply failure fallback test */
const TEST_ID = "0190";
// 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 : "Should never change",
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/partial_precomplete"
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginspng0.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "data/partial.png",
compareFile : "data/partial.png"
}, {
description : "Added by update.manifest (add)",
fileName : "removed-files",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "data/partial_removed-files",
compareFile : "data/partial_removed-files"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/extensions/extensions1/",
originalContents : null,
compareContents : null,
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/partial.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 : null
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : HELPER_BIN_FILE,
compareFile : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\n",
originalFile : null,
compareFile : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
originalFile : null,
compareFile : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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);
gBackgroundUpdate = true;
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", "40"];
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() {
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for success when " +
"applying a complete mar");
do_check_eq(exitValue, 0);
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,296 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use inside removed dir partial MAR file background patch apply failure fallback test */
const TEST_ID = "0191";
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 : "Should never change",
fileName : "channel-prefs.js",
relPathDir : "a/b/defaults/pref/",
originalContents : "ShouldNotBeReplaced\n",
compareContents : "ShouldNotBeReplaced\n",
originalFile : null,
compareFile : null,
originalPerms : 0644,
comparePerms : 0644
}, {
description : "Added by update.manifest (add)",
fileName : "precomplete",
relPathDir : "",
originalContents : null,
compareContents : null,
originalFile : "data/complete_precomplete",
compareFile : "data/complete_precomplete",
originalPerms : 0666,
comparePerms : 0666
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : 0775,
comparePerms : 0775
}, {
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/complete.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/complete.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 : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 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/complete.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/complete.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 : "ToBeReplacedWithFromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 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/complete.png",
originalPerms : null,
comparePerms : null
}, {
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/complete.png",
originalPerms : null,
comparePerms : null
}, {
description : "Patched by update.manifest (patch)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "data/complete.png",
compareFile : "data/complete.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/complete.png",
originalPerms : 0755,
comparePerms : 0755
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.png",
originalPerms : 0666,
comparePerms : 0666
}, {
description : "Added by update.manifest (add)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Added by update.manifest (add)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text2",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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 : "ToBeDeleted\n",
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);
gBackgroundUpdate = true;
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", "40"];
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() {
let exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for success when " +
"applying a complete mar");
do_check_eq(exitValue, 0);
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,584 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Test applying an update by applying an update in the background and
* launching an application
*/
/**
* This test is identical to test_0201_app_launch_apply_update.js, except
* that it locks the application directory when the test is launched to
* make the updater fall back to apply the update regularly.
*/
/**
* The MAR file used for this test should not contain a version 2 update
* manifest file (e.g. updatev2.manifest).
*/
const TEST_ID = "0203";
// 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;
Components.utils.import("resource://gre/modules/ctypes.jsm");
let gAppTimer;
let gProcess;
let gActiveUpdate;
// Override getUpdatesRootDir on Mac because we need to apply the update
// inside the bundle directory.
function symlinkUpdateFilesIntoBundleDirectory() {
if (!shouldAdjustPathsOnMac()) {
return;
}
// Symlink active-update.xml and updates/ inside the dist/bin directory
// to point to the bundle directory.
// This is necessary because in order to test the code which actually ships
// with Firefox, we need to perform the update inside the bundle directory,
// whereas xpcshell runs from dist/bin/, and the updater service code looks
// at the current process directory to find things like these two files.
Components.utils.import("resource://gre/modules/ctypes.jsm");
let libc = ctypes.open("/usr/lib/libc.dylib");
// We need these two low level APIs because their functionality is not
// provided in nsIFile APIs.
let symlink = libc.declare("symlink", ctypes.default_abi, ctypes.int,
ctypes.char.ptr, ctypes.char.ptr);
let unlink = libc.declare("unlink", ctypes.default_abi, ctypes.int,
ctypes.char.ptr);
// Symlink active-update.xml
let dest = getAppDir();
dest.append("active-update.xml");
if (!dest.exists()) {
dest.create(dest.NORMAL_FILE_TYPE, 0644);
}
do_check_true(dest.exists());
let source = getUpdatesRootDir();
source.append("active-update.xml");
unlink(source.path);
let ret = symlink(dest.path, source.path);
do_check_eq(ret, 0);
do_check_true(source.exists());
// Symlink updates/
let dest2 = getAppDir();
dest2.append("updates");
if (dest2.exists()) {
dest2.remove(true);
}
dest2.create(dest.DIRECTORY_TYPE, 0755);
do_check_true(dest2.exists());
let source2 = getUpdatesRootDir();
source2.append("updates");
if (source2.exists()) {
source2.remove(true);
}
ret = symlink(dest2.path, source2.path);
do_check_eq(ret, 0);
do_check_true(source2.exists());
// Cleanup the symlinks when the test is finished.
do_register_cleanup(function() {
let ret = unlink(source.path);
do_check_false(source.exists());
let ret = unlink(source2.path);
do_check_false(source2.exists());
});
// Now, make sure that getUpdatesRootDir returns the application bundle
// directory, to make the various stuff in the test framework to work
// correctly.
getUpdatesRootDir = getAppDir;
}
function run_test() {
do_test_pending();
do_register_cleanup(end_test);
removeUpdateDirsAndFiles();
symlinkUpdateFilesIntoBundleDirectory();
if (IS_WIN) {
adjustPathsOnWindows();
}
if (!gAppBinPath) {
do_throw("Main application binary not found... expected: " +
APP_BIN_NAME + APP_BIN_SUFFIX);
return;
}
// Don't attempt to show a prompt when the update is finished.
Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
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 = getAppDir();
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);
writeStatusFile(STATE_PENDING);
// 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);
}
let updatesPatchDir = getUpdatesDir();
updatesPatchDir.append("0");
let mar = do_get_file("data/simple.mar");
mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
reloadUpdateManagerData();
gActiveUpdate = gUpdateManager.activeUpdate;
do_check_true(!!gActiveUpdate);
let updateSettingsIni = processDir.clone();
updateSettingsIni.append(UPDATE_SETTINGS_INI_FILE);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
// Initiate a background update.
AUS_Cc["@mozilla.org/updates/update-processor;1"].
createInstance(AUS_Ci.nsIUpdateProcessor).
processUpdate(gActiveUpdate);
checkUpdateApplied();
}
function switchApp() {
let launchBin = getLaunchBin();
let args = getProcessArgs();
logTestInfo("launching " + launchBin.path + " " + args.join(" "));
// Lock the installation directory
const LPCWSTR = ctypes.jschar.ptr;
const DWORD = ctypes.uint32_t;
const LPVOID = ctypes.voidptr_t;
const GENERIC_READ = 0x80000000;
const FILE_SHARE_READ = 1;
const FILE_SHARE_WRITE = 2;
const OPEN_EXISTING = 3;
const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
const INVALID_HANDLE_VALUE = LPVOID(0xffffffff);
let kernel32 = ctypes.open("kernel32");
let CreateFile = kernel32.declare("CreateFileW", ctypes.default_abi,
LPVOID, LPCWSTR, DWORD, DWORD,
LPVOID, DWORD, DWORD, LPVOID);
logTestInfo(gWindowsBinDir.path);
let handle = CreateFile(gWindowsBinDir.path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0),
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0));
do_check_neq(handle.toString(), INVALID_HANDLE_VALUE.toString());
kernel32.close();
gProcess = AUS_Cc["@mozilla.org/process/util;1"].
createInstance(AUS_Ci.nsIProcess);
gProcess.init(launchBin);
gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
AUS_Ci.nsITimer.TYPE_ONE_SHOT);
setEnvironment();
gProcess.runAsync(args, args.length, gProcessObserver);
resetEnvironment();
}
function end_test() {
if (gProcess.isRunning) {
logTestInfo("attempt to kill process");
gProcess.kill();
}
if (gAppTimer) {
logTestInfo("cancelling timer");
gAppTimer.cancel();
gAppTimer = null;
}
resetEnvironment();
// 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);
}
if (IS_UNIX) {
// This will delete the launch script if it exists.
getLaunchScript();
if (IS_MACOSX) {
// This will delete the version script and version file if they exist.
getVersionScriptAndFile();
}
}
cleanUp();
}
/**
* The observer for the call to nsIProcess:runAsync.
*/
let gProcessObserver = {
observe: function PO_observe(subject, topic, data) {
logTestInfo("topic " + topic + ", process exitValue " + gProcess.exitValue);
if (gAppTimer) {
gAppTimer.cancel();
gAppTimer = null;
}
if (topic != "process-finished" || gProcess.exitValue != 0) {
do_throw("Failed to launch application");
}
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
},
QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
};
/**
* The timer callback to kill the process if it takes too long.
*/
let gTimerCallback = {
notify: function TC_notify(aTimer) {
gAppTimer = null;
if (gProcess.isRunning) {
gProcess.kill();
}
do_throw("launch application timer expired");
},
QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback])
};
function shouldAdjustPathsOnMac() {
// When running xpcshell tests locally, xpcshell and firefox-bin do not live
// in the same directory.
let dir = getCurrentProcessDir();
return (IS_MACOSX && dir.leafName != "MacOS");
}
/**
* This function copies the entire process directory over to a new one which we
* can write to, so that we can test under Windows which holds locks on opened
* files.
*/
function adjustPathsOnWindows() {
// We copy the entire GRE directory into another location so that xpcshell
// running doesn't prevent the updater from moving stuff around.
let tmpDir = do_get_profile();
tmpDir.append("ExecutableDir.tmp");
tmpDir.createUnique(tmpDir.DIRECTORY_TYPE, 0755);
let procDir = getCurrentProcessDir();
procDir.copyTo(tmpDir, "bin");
let newDir = tmpDir.clone();
newDir.append("bin");
gWindowsBinDir = newDir;
logTestInfo("Using this new bin directory: " + gWindowsBinDir.path);
// Note that this directory will be deleted as part of the xpcshell teardown,
// so we don't need to remove it explicitly.
// We need to make NS_GRE_DIR point to the new bindir, since
// nsUpdateProcessor::ProcessUpdate uses NS_GRE_DIR to construct the
// destination path name which would be passed to updater.exe.
let dirProvider = {
getFile: function DP_getFile(prop, persistent) {
persistent.value = true;
if (prop == NS_GRE_DIR)
return getAppDir();
return null;
},
QueryInterface: function(iid) {
if (iid.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
iid.equals(AUS_Ci.nsISupports))
return this;
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
}
};
let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR);
ds.registerProvider(dirProvider);
do_register_cleanup(function() {
ds.unregisterProvider(dirProvider);
});
}
/**
* 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 = getAppDir();
if (IS_MACOSX) {
updateTestDir = updateTestDir.parent.parent;
}
updateTestDir.append("update_test");
return updateTestDir;
}
/**
* Checks if the update has finished being applied in the background.
*/
function checkUpdateApplied() {
// Don't proceed until the update has been applied.
if (gUpdateManager.activeUpdate.state != STATE_APPLIED_PLATFORM) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateApplied);
return;
}
let updatedDir = getAppDir();
if (IS_MACOSX) {
updatedDir = updatedDir.parent.parent;
}
updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
logTestInfo("testing " + updatedDir.path + " should exist");
do_check_true(updatedDir.exists());
let log;
if (IS_WIN) {
log = getUpdatesDir();
} else {
log = updatedDir.clone();
if (IS_MACOSX) {
log.append("Contents");
log.append("MacOS");
}
log.append("updates");
}
log.append(FILE_LAST_LOG);
if (!log.exists()) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateApplied);
return;
}
// Don't proceed until the update status is no longer pending or applying.
let status = readStatusFile();
do_check_eq(status, STATE_APPLIED_PLATFORM);
// On Windows, make sure not to use the maintenance service for switching
// the app.
if (IS_WIN) {
writeStatusFile(STATE_APPLIED);
status = readStatusFile();
do_check_eq(status, STATE_APPLIED);
}
// Log the contents of the update.log so it is simpler to diagnose a test
// failure.
let contents = readFile(log);
logTestInfo("contents of " + log.path + ":\n" +
contents.replace(/\r\n/g, "\n"));
let updateTestDir = getUpdateTestDir();
logTestInfo("testing " + updateTestDir.path + " shouldn't exist");
do_check_false(updateTestDir.exists());
updateTestDir = updatedDir.clone();
updateTestDir.append("update_test");
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
let updatesDir = getUpdatesDir();
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);
if (IS_WIN) {
// On Windows this file lives outside of the app directory, so it should exist.
logTestInfo("testing " + log.path + " should exist");
do_check_true(log.exists());
} else {
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
}
log = updatesDir.clone();
log.append(FILE_BACKUP_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
updatesDir = updatedDir.clone();
if (IS_MACOSX) {
updatesDir.append("Contents");
updatesDir.append("MacOS");
}
updatesDir.append("updates");
log = updatesDir.clone();
log.append("0");
log.append(FILE_UPDATE_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
if (!IS_WIN) {
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 + " shouldn't exist");
do_check_false(updatesDir.exists());
// Now, switch the updated version of the app
do_timeout(CHECK_TIMEOUT_MILLI, switchApp);
}
/**
* Checks if the update has finished and if it has finished performs checks for
* the test.
*/
function checkUpdateFinished() {
// Don't proceed until the update status is no longer applied.
try {
let status = readStatusFile();
if (status != STATE_SUCCEEDED) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
return;
}
} catch (e) {
// Ignore exceptions if the status file is not found
}
try {
// This will delete the app console log file if it exists.
getAppConsoleLogPath();
} catch (e) {
if (e.result == Components.results.NS_ERROR_FILE_IS_LOCKED) {
// This might happen on Windows in case the callback application has not
// finished its job yet. So, we'll wait some more.
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
return;
} else {
do_throw("getAppConsoleLogPath threw: " + e);
}
}
// At this point we need to see if the application was switched successfully.
let updatedDir = getAppDir();
if (IS_MACOSX) {
updatedDir = updatedDir.parent.parent;
}
updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
logTestInfo("testing " + updatedDir.path + " shouldn't exist");
if (updatedDir.exists()) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
return;
}
let updateTestDir = getUpdateTestDir();
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
let updatesDir = getUpdatesDir();
log = updatesDir.clone();
log.append("0");
log.append(FILE_UPDATE_LOG);
if (IS_WIN) {
// On Windows, this log file is written to the AppData directory, and will
// therefore exist.
logTestInfo("testing " + log.path + " should exist");
do_check_true(log.exists());
} else {
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");
if (IS_WIN) {
// On Windows, this log file is written to the AppData directory, and will
// therefore exist.
logTestInfo("testing " + updatesDir.path + " should exist");
do_check_true(updatesDir.exists());
} else {
logTestInfo("testing " + updatesDir.path + " shouldn't exist");
do_check_false(updatesDir.exists());
}
removeCallbackCopy();
}

View File

@ -6,10 +6,13 @@
[test_0153_appBinPatched_xp_win_partial.js]
[test_0160_appInUse_xp_win_complete.js]
[test_0161_appInUse_xp_win_complete.js]
[test_0162_appInUse_xp_win_complete.js]
[test_0170_fileLocked_xp_win_complete.js]
[test_0171_fileLocked_xp_win_partial.js]
[test_0172_fileLocked_xp_win_complete.js]
[test_0173_fileLocked_xp_win_partial.js]
[test_0174_fileLocked_xp_win_complete.js]
[test_0175_fileLocked_xp_win_partial.js]
[test_0180_fileInUse_xp_win_complete.js]
[test_0181_fileInUse_xp_win_partial.js]
[test_0182_rmrfdirFileInUse_xp_win_complete.js]
@ -18,5 +21,9 @@
[test_0185_fileInUse_xp_win_partial.js]
[test_0186_rmrfdirFileInUse_xp_win_complete.js]
[test_0187_rmrfdirFileInUse_xp_win_partial.js]
[test_0188_fileInUse_xp_win_complete.js]
[test_0189_fileInUse_xp_win_partial.js]
[test_0190_rmrfdirFileInUse_xp_win_complete.js]
[test_0191_rmrfdirFileInUse_xp_win_partial.js]
[test_0202_app_launch_apply_update_dirlocked.js]
skip-if = true
[test_0203_app_launch_apply_update.js]

View File

@ -218,6 +218,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -0,0 +1,242 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* Application in use complete MAR file background patch apply failure fallback test */
const TEST_ID = "0162_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 : "Should never change",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40"];
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_APPLIED, checkUpdateApplied);
}
function checkUpdateApplied() {
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory doesn't exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -226,6 +226,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -227,6 +227,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -0,0 +1,250 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File locked complete MAR file background patch apply failure fallback test */
const TEST_ID = "0174_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 : "Should never change",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40", 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() {
logTestInfo("testing update.status should be " + STATE_FAILED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory doesn't exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,251 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File locked partial MAR file background patch apply failure fallback test */
const TEST_ID = "0175_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 : "Should never change",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40", 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() {
logTestInfo("testing update.status should be " + STATE_FAILED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir).split(": ")[0], STATE_FAILED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory doesn't exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -225,6 +225,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -228,6 +228,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -234,6 +234,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -275,6 +275,7 @@ function checkUpdateApplied() {
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
gDisableReplaceFallback = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");

View File

@ -0,0 +1,249 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use complete MAR file background patch apply failure fallback test */
const TEST_ID = "0188_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 : "Should never change",
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/partial_precomplete"
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginspng0.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "data/partial.png",
compareFile : "data/partial.png"
}, {
description : "Added by update.manifest (add)",
fileName : "removed-files",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "data/partial_removed-files",
compareFile : "data/partial_removed-files"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/extensions/extensions1/",
originalContents : null,
compareContents : null,
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/partial.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 : null
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : HELPER_BIN_FILE,
compareFile : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\n",
originalFile : null,
compareFile : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
originalFile : null,
compareFile : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40"];
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_APPLIED, checkUpdateApplied);
}
function checkUpdateApplied() {
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,252 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use partial MAR file background patch apply failure fallback test */
const TEST_ID = "0189_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 : "Should never change",
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/complete_precomplete"
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.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/complete.png"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/extensions/extensions1/",
originalContents : null,
compareContents : null,
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/complete.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/complete.png"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.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/complete.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_before.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_before.exe"
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.png"
}, {
description : "Added by update.manifest (add)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text2",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
originalFile : null,
compareFile : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40"];
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_APPLIED, checkUpdateApplied);
}
function checkUpdateApplied() {
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,258 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use inside removed dir complete MAR file background patch apply failure fallback test */
const TEST_ID = "0190_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 : "Should never change",
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/partial_precomplete"
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginspng0.png",
relPathDir : "a/b/searchplugins/",
originalContents : null,
compareContents : null,
originalFile : "data/partial.png",
compareFile : "data/partial.png"
}, {
description : "Added by update.manifest (add)",
fileName : "removed-files",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "data/partial_removed-files",
compareFile : "data/partial_removed-files"
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions1text0",
relPathDir : "a/b/extensions/extensions1/",
originalContents : null,
compareContents : null,
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/partial.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 : null
}, {
description : "Added by update.manifest if the parent directory " +
"exists (add-if)",
fileName : "extensions0text0",
relPathDir : "a/b/extensions/extensions0/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
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 : null
}, {
description : "Added by update.manifest (add)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : HELPER_BIN_FILE,
compareFile : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : HELPER_BIN_FILE
}, {
description : "Added by update.manifest (add)",
fileName : "00text1",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\n",
originalFile : null,
compareFile : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromComplete\n",
compareContents : "ToBeReplacedWithFromComplete\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 : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
originalFile : null,
compareFile : null
}, {
description : "Removed by precomplete (remove)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40"];
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() {
runUpdateUsingService(STATE_PENDING_SVC, STATE_APPLIED, checkUpdateApplied);
}
function checkUpdateApplied() {
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,299 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* File in use inside removed dir partial MAR file background patch apply failure fallback test */
const TEST_ID = "0191_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 : "Should never change",
fileName : "channel-prefs.js",
relPathDir : "a/b/defaults/pref/",
originalContents : "ShouldNotBeReplaced\n",
compareContents : "ShouldNotBeReplaced\n",
originalFile : null,
compareFile : null,
originalPerms : 0644,
comparePerms : 0644
}, {
description : "Added by update.manifest (add)",
fileName : "precomplete",
relPathDir : "",
originalContents : null,
compareContents : null,
originalFile : "data/complete_precomplete",
compareFile : "data/complete_precomplete",
originalPerms : 0666,
comparePerms : 0666
}, {
description : "Added by update.manifest (add)",
fileName : "searchpluginstext0",
relPathDir : "a/b/searchplugins/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : 0775,
comparePerms : 0775
}, {
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/complete.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/complete.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 : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 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/complete.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/complete.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 : "ToBeReplacedWithFromPartial\n",
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : 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/complete.png",
originalPerms : null,
comparePerms : null
}, {
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/complete.png",
originalPerms : null,
comparePerms : null
}, {
description : "Patched by update.manifest (patch)",
fileName : "exe0.exe",
relPathDir : "a/b/",
originalContents : null,
compareContents : null,
originalFile : "data/complete.png",
compareFile : "data/complete.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/complete.png",
originalPerms : 0755,
comparePerms : 0755
}, {
description : "Added by update.manifest (add)",
fileName : "00text0",
relPathDir : "a/b/0/00/",
originalContents : "ToBeReplacedWithFromPartial\n",
compareContents : "ToBeReplacedWithFromPartial\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/complete.png",
originalPerms : 0666,
comparePerms : 0666
}, {
description : "Added by update.manifest (add)",
fileName : "20text0",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Added by update.manifest (add)",
fileName : "20png0.png",
relPathDir : "a/b/2/20/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Added by update.manifest (add)",
fileName : "00text2",
relPathDir : "a/b/0/00/",
originalContents : null,
compareContents : null,
originalFile : null,
compareFile : null,
originalPerms : null,
comparePerms : null
}, {
description : "Removed by update.manifest (remove)",
fileName : "10text0",
relPathDir : "a/b/1/10/",
originalContents : "ToBeDeleted\n",
compareContents : "ToBeDeleted\n",
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 : "ToBeDeleted\n",
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() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(cleanupUpdaterTest);
gBackgroundUpdate = true;
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", "40"];
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() {
runUpdateUsingService(STATE_PENDING_SVC, STATE_APPLIED, checkUpdateApplied);
}
function checkUpdateApplied() {
logTestInfo("testing update.status should be " + STATE_APPLIED);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_APPLIED);
// Now switch the application and its updated version
gBackgroundUpdate = false;
gSwitchApp = true;
exitValue = runUpdate();
logTestInfo("testing updater binary process exitValue for failure when " +
"switching to the updated application");
do_check_eq(exitValue, 1);
setupHelperFinish();
}
function checkUpdate() {
logTestInfo("testing update.status should be " + STATE_PENDING);
let updatesDir = do_get_file(TEST_ID + UPDATES_DIR_SUFFIX);
do_check_eq(readStatusFile(updatesDir), STATE_PENDING);
checkFilesAfterUpdateFailure(getApplyDirFile);
checkUpdateLogContains(ERR_RENAME_FILE);
logTestInfo("testing tobedeleted directory does not exist");
let toBeDeletedDir = getApplyDirFile("tobedeleted", true);
do_check_false(toBeDeletedDir.exists());
checkCallbackAppLog();
}

View File

@ -0,0 +1,561 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Test applying an update by applying an update in the background and
* launching an application
*/
/**
* This test is identical to test_0201_app_launch_apply_update_svc.js, except
* that it locks the application directory when the test is launched to
* make the updater fall back to apply the update regularly.
*/
/**
* The MAR file used for this test should not contain a version 2 update
* manifest file (e.g. updatev2.manifest).
*/
const TEST_ID = "0203_svc";
// 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;
Components.utils.import("resource://gre/modules/ctypes.jsm");
let gAppTimer;
let gProcess;
let gActiveUpdate;
// Override getUpdatesRootDir on Mac because we need to apply the update
// inside the bundle directory.
function symlinkUpdateFilesIntoBundleDirectory() {
if (!shouldAdjustPathsOnMac()) {
return;
}
// Symlink active-update.xml and updates/ inside the dist/bin directory
// to point to the bundle directory.
// This is necessary because in order to test the code which actually ships
// with Firefox, we need to perform the update inside the bundle directory,
// whereas xpcshell runs from dist/bin/, and the updater service code looks
// at the current process directory to find things like these two files.
Components.utils.import("resource://gre/modules/ctypes.jsm");
let libc = ctypes.open("/usr/lib/libc.dylib");
// We need these two low level APIs because their functionality is not
// provided in nsIFile APIs.
let symlink = libc.declare("symlink", ctypes.default_abi, ctypes.int,
ctypes.char.ptr, ctypes.char.ptr);
let unlink = libc.declare("unlink", ctypes.default_abi, ctypes.int,
ctypes.char.ptr);
// Symlink active-update.xml
let dest = getAppDir();
dest.append("active-update.xml");
if (!dest.exists()) {
dest.create(dest.NORMAL_FILE_TYPE, 0644);
}
do_check_true(dest.exists());
let source = getUpdatesRootDir();
source.append("active-update.xml");
unlink(source.path);
let ret = symlink(dest.path, source.path);
do_check_eq(ret, 0);
do_check_true(source.exists());
// Symlink updates/
let dest2 = getAppDir();
dest2.append("updates");
if (dest2.exists()) {
dest2.remove(true);
}
dest2.create(dest.DIRECTORY_TYPE, 0755);
do_check_true(dest2.exists());
let source2 = getUpdatesRootDir();
source2.append("updates");
if (source2.exists()) {
source2.remove(true);
}
ret = symlink(dest2.path, source2.path);
do_check_eq(ret, 0);
do_check_true(source2.exists());
// Cleanup the symlinks when the test is finished.
do_register_cleanup(function() {
let ret = unlink(source.path);
do_check_false(source.exists());
let ret = unlink(source2.path);
do_check_false(source2.exists());
});
// Now, make sure that getUpdatesRootDir returns the application bundle
// directory, to make the various stuff in the test framework to work
// correctly.
getUpdatesRootDir = getAppDir;
}
function run_test() {
if (!shouldRunServiceTest()) {
return;
}
do_test_pending();
do_register_cleanup(end_test);
removeUpdateDirsAndFiles();
symlinkUpdateFilesIntoBundleDirectory();
if (IS_WIN) {
adjustPathsOnWindows();
}
if (!gAppBinPath) {
do_throw("Main application binary not found... expected: " +
APP_BIN_NAME + APP_BIN_SUFFIX);
return;
}
// Don't attempt to show a prompt when the update is finished.
Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
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 = getAppDir();
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);
writeStatusFile(STATE_PENDING_SVC);
// 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);
}
let updatesPatchDir = getUpdatesDir();
updatesPatchDir.append("0");
let mar = do_get_file("data/simple.mar");
mar.copyTo(updatesPatchDir, FILE_UPDATE_ARCHIVE);
reloadUpdateManagerData();
gActiveUpdate = gUpdateManager.activeUpdate;
do_check_true(!!gActiveUpdate);
setEnvironment();
let updateSettingsIni = processDir.clone();
updateSettingsIni.append(UPDATE_SETTINGS_INI_FILE);
writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
// Initiate a background update.
AUS_Cc["@mozilla.org/updates/update-processor;1"].
createInstance(AUS_Ci.nsIUpdateProcessor).
processUpdate(gActiveUpdate);
resetEnvironment();
checkUpdateApplied();
}
function switchApp() {
let launchBin = getLaunchBin();
let args = getProcessArgs();
logTestInfo("launching " + launchBin.path + " " + args.join(" "));
// Lock the installation directory
const LPCWSTR = ctypes.jschar.ptr;
const DWORD = ctypes.uint32_t;
const LPVOID = ctypes.voidptr_t;
const GENERIC_READ = 0x80000000;
const FILE_SHARE_READ = 1;
const FILE_SHARE_WRITE = 2;
const OPEN_EXISTING = 3;
const FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;
const INVALID_HANDLE_VALUE = LPVOID(0xffffffff);
let kernel32 = ctypes.open("kernel32");
let CreateFile = kernel32.declare("CreateFileW", ctypes.default_abi,
LPVOID, LPCWSTR, DWORD, DWORD,
LPVOID, DWORD, DWORD, LPVOID);
logTestInfo(gWindowsBinDir.path);
let handle = CreateFile(gWindowsBinDir.path, GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE, LPVOID(0),
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, LPVOID(0));
do_check_neq(handle.toString(), INVALID_HANDLE_VALUE.toString());
kernel32.close();
gProcess = AUS_Cc["@mozilla.org/process/util;1"].
createInstance(AUS_Ci.nsIProcess);
gProcess.init(launchBin);
gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
AUS_Ci.nsITimer.TYPE_ONE_SHOT);
setEnvironment();
gProcess.runAsync(args, args.length, gProcessObserver);
resetEnvironment();
}
function end_test() {
if (gProcess.isRunning) {
logTestInfo("attempt to kill process");
gProcess.kill();
}
if (gAppTimer) {
logTestInfo("cancelling timer");
gAppTimer.cancel();
gAppTimer = null;
}
resetEnvironment();
// 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);
}
if (IS_UNIX) {
// This will delete the launch script if it exists.
getLaunchScript();
if (IS_MACOSX) {
// This will delete the version script and version file if they exist.
getVersionScriptAndFile();
}
}
cleanUp();
}
/**
* The observer for the call to nsIProcess:runAsync.
*/
let gProcessObserver = {
observe: function PO_observe(subject, topic, data) {
logTestInfo("topic " + topic + ", process exitValue " + gProcess.exitValue);
if (gAppTimer) {
gAppTimer.cancel();
gAppTimer = null;
}
if (topic != "process-finished" || gProcess.exitValue != 0) {
do_throw("Failed to launch application");
}
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
},
QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
};
/**
* The timer callback to kill the process if it takes too long.
*/
let gTimerCallback = {
notify: function TC_notify(aTimer) {
gAppTimer = null;
if (gProcess.isRunning) {
gProcess.kill();
}
do_throw("launch application timer expired");
},
QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback])
};
function shouldAdjustPathsOnMac() {
// When running xpcshell tests locally, xpcshell and firefox-bin do not live
// in the same directory.
let dir = getCurrentProcessDir();
return (IS_MACOSX && dir.leafName != "MacOS");
}
/**
* This function copies the entire process directory over to a new one which we
* can write to, so that we can test under Windows which holds locks on opened
* files.
*/
function adjustPathsOnWindows() {
// We copy the entire GRE directory into another location so that xpcshell
// running doesn't prevent the updater from moving stuff around.
let tmpDir = do_get_profile();
tmpDir.append("ExecutableDir.tmp");
tmpDir.createUnique(tmpDir.DIRECTORY_TYPE, 0755);
let procDir = getCurrentProcessDir();
procDir.copyTo(tmpDir, "bin");
let newDir = tmpDir.clone();
newDir.append("bin");
gWindowsBinDir = newDir;
logTestInfo("Using this new bin directory: " + gWindowsBinDir.path);
// Note that this directory will be deleted as part of the xpcshell teardown,
// so we don't need to remove it explicitly.
// We need to make NS_GRE_DIR point to the new bindir, since
// nsUpdateProcessor::ProcessUpdate uses NS_GRE_DIR to construct the
// destination path name which would be passed to updater.exe.
let dirProvider = {
getFile: function DP_getFile(prop, persistent) {
persistent.value = true;
if (prop == NS_GRE_DIR)
return getAppDir();
return null;
},
QueryInterface: function(iid) {
if (iid.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
iid.equals(AUS_Ci.nsISupports))
return this;
throw AUS_Cr.NS_ERROR_NO_INTERFACE;
}
};
let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR);
ds.registerProvider(dirProvider);
do_register_cleanup(function() {
ds.unregisterProvider(dirProvider);
});
}
/**
* 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 = getAppDir();
if (IS_MACOSX) {
updateTestDir = updateTestDir.parent.parent;
}
updateTestDir.append("update_test");
return updateTestDir;
}
/**
* Checks if the update has finished being applied in the background.
*/
function checkUpdateApplied() {
// Don't proceed until the update has been applied.
if (gUpdateManager.activeUpdate.state != STATE_APPLIED_PLATFORM) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateApplied);
return;
}
let updatedDir = getAppDir();
if (IS_MACOSX) {
updatedDir = updatedDir.parent.parent;
}
updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
logTestInfo("testing " + updatedDir.path + " should exist");
do_check_true(updatedDir.exists());
let log = getUpdatesDir();
log.append(FILE_LAST_LOG);
if (!log.exists()) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateApplied);
return;
}
// Don't proceed until the update status is no longer pending or applying.
let status = readStatusFile();
do_check_eq(status, STATE_APPLIED_PLATFORM);
// On Windows, make sure not to use the maintenance service for switching
// the app.
if (IS_WIN) {
writeStatusFile(STATE_APPLIED);
status = readStatusFile();
do_check_eq(status, STATE_APPLIED);
}
// Log the contents of the update.log so it is simpler to diagnose a test
// failure.
let contents = readFile(log);
logTestInfo("contents of " + log.path + ":\n" +
contents.replace(/\r\n/g, "\n"));
let updateTestDir = getUpdateTestDir();
logTestInfo("testing " + updateTestDir.path + " shouldn't exist");
do_check_false(updateTestDir.exists());
updateTestDir = updatedDir.clone();
updateTestDir.append("update_test");
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
let updatesDir = getUpdatesDir();
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 = updatedDir.clone();
if (IS_MACOSX) {
updatesDir.append("Contents");
updatesDir.append("MacOS");
}
updatesDir.append("updates");
log = updatesDir.clone();
log.append("0");
log.append(FILE_UPDATE_LOG);
logTestInfo("testing " + log.path + " shouldn't exist");
do_check_false(log.exists());
updatesDir.append("0");
logTestInfo("testing " + updatesDir.path + " shouldn't exist");
do_check_false(updatesDir.exists());
// Now, switch the updated version of the app
do_timeout(CHECK_TIMEOUT_MILLI, switchApp);
}
/**
* Checks if the update has finished and if it has finished performs checks for
* the test.
*/
function checkUpdateFinished() {
// Don't proceed until the update status is no longer applied.
try {
let status = readStatusFile();
if (status != STATE_SUCCEEDED) {
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
return;
}
} catch (e) {
// Ignore exceptions if the status file is not found
}
try {
// This will delete the app console log file if it exists.
getAppConsoleLogPath();
} catch (e) {
if (e.result == Components.results.NS_ERROR_FILE_IS_LOCKED) {
// This might happen on Windows in case the callback application has not
// finished its job yet. So, we'll wait some more.
do_timeout(CHECK_TIMEOUT_MILLI, checkUpdateFinished);
return;
} else {
do_throw("getAppConsoleLogPath threw: " + e);
}
}
// At this point we need to see if the application was switched successfully.
let updatedDir = getAppDir();
if (IS_MACOSX) {
updatedDir = updatedDir.parent.parent;
}
updatedDir.append(UPDATED_DIR_SUFFIX.replace("/", ""));
logTestInfo("testing " + updatedDir.path + " shouldn't exist");
do_check_false(updatedDir.exists());
let updateTestDir = getUpdateTestDir();
let file = updateTestDir.clone();
file.append("UpdateTestRemoveFile");
logTestInfo("testing " + file.path + " shouldn't exist");
do_check_false(file.exists());
file = updateTestDir.clone();
file.append("UpdateTestAddFile");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "UpdateTestAddFile\n");
file = updateTestDir.clone();
file.append("removed-files");
logTestInfo("testing " + file.path + " should exist");
do_check_true(file.exists());
do_check_eq(readFileBytes(file), "update_test/UpdateTestRemoveFile\n");
let updatesDir = getUpdatesDir();
log = updatesDir.clone();
log.append("0");
log.append(FILE_UPDATE_LOG);
if (IS_WIN) {
// On Windows, this log file is written to the AppData directory, and will
// therefore exist.
logTestInfo("testing " + log.path + " should exist");
do_check_true(log.exists());
} else {
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");
if (IS_WIN) {
// On Windows, this log file is written to the AppData directory, and will
// therefore exist.
logTestInfo("testing " + updatesDir.path + " should exist");
do_check_true(updatesDir.exists());
} else {
logTestInfo("testing " + updatesDir.path + " shouldn't exist");
do_check_false(updatesDir.exists());
}
removeCallbackCopy();
}

View File

@ -19,10 +19,13 @@ tail =
[test_0153_appBinPatched_xp_win_partial_svc.js]
[test_0160_appInUse_xp_win_complete_svc.js]
[test_0161_appInUse_xp_win_complete_svc.js]
[test_0162_appInUse_xp_win_complete_svc.js]
[test_0170_fileLocked_xp_win_complete_svc.js]
[test_0171_fileLocked_xp_win_partial_svc.js]
[test_0172_fileLocked_xp_win_complete_svc.js]
[test_0173_fileLocked_xp_win_partial_svc.js]
[test_0174_fileLocked_xp_win_complete_svc.js]
[test_0175_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]
@ -31,6 +34,11 @@ tail =
[test_0185_fileInUse_xp_win_partial_svc.js]
[test_0186_rmrfdirFileInUse_xp_win_complete_svc.js]
[test_0187_rmrfdirFileInUse_xp_win_partial_svc.js]
[test_0188_fileInUse_xp_win_complete_svc.js]
[test_0189_fileInUse_xp_win_partial_svc.js]
[test_0190_rmrfdirFileInUse_xp_win_complete_svc.js]
[test_0191_rmrfdirFileInUse_xp_win_partial_svc.js]
[test_0200_app_launch_apply_update_svc.js]
[test_0201_app_launch_apply_update_svc.js]
[test_0202_app_launch_apply_update_dirlocked_svc.js]
[test_0203_app_launch_apply_update_svc.js]

View File

@ -267,6 +267,7 @@ static ArchiveReader gArchiveReader;
static bool gSucceeded = false;
static bool sBackgroundUpdate = false;
static bool sReplaceRequest = false;
static bool sUsingService = false;
#ifdef XP_WIN
// The current working directory specified in the command line.
@ -550,6 +551,27 @@ static int ensure_parent_dir(const NS_tchar *path)
return rv;
}
#ifdef XP_UNIX
static int ensure_copy_symlink(const NS_tchar *path, const NS_tchar *dest)
{
// Copy symlinks by creating a new symlink to the same target
NS_tchar target[MAXPATHLEN + 1] = {NS_T('\0')};
int rv = readlink(path, target, MAXPATHLEN);
if (rv == -1) {
LOG(("ensure_copy_symlink: failed to read the link: " LOG_S ", err: %d\n",
path, errno));
return READ_ERROR;
}
rv = symlink(target, dest);
if (rv == -1) {
LOG(("ensure_copy_symlink: failed to create the new link: " LOG_S ", target: " LOG_S " err: %d\n",
dest, target, errno));
return READ_ERROR;
}
return 0;
}
#endif
// Copy the file named path onto a new file named dest.
static int ensure_copy(const NS_tchar *path, const NS_tchar *dest)
{
@ -564,13 +586,19 @@ static int ensure_copy(const NS_tchar *path, const NS_tchar *dest)
return 0;
#else
struct stat ss;
int rv = NS_tstat(path, &ss);
int rv = NS_tlstat(path, &ss);
if (rv) {
LOG(("ensure_copy: failed to read file status info: " LOG_S ", err: %d\n",
path, errno));
return READ_ERROR;
}
#ifdef XP_UNIX
if (S_ISLNK(ss.st_mode)) {
return ensure_copy_symlink(path, dest);
}
#endif
AutoFile infile = ensure_open(path, NS_T("rb"), ss.st_mode);
if (!infile) {
LOG(("ensure_copy: failed to open the file for reading: " LOG_S ", err: %d\n",
@ -645,12 +673,19 @@ static int ensure_copy_recursive(const NS_tchar *path, const NS_tchar *dest,
copy_recursive_skiplist<N>& skiplist)
{
struct stat sInfo;
int rv = NS_tstat(path, &sInfo);
int rv = NS_tlstat(path, &sInfo);
if (rv) {
LOG(("ensure_copy_recursive: path doesn't exist: " LOG_S ", rv: %d, err: %d\n",
path, rv, errno));
return READ_ERROR;
}
#ifdef XP_UNIX
if (S_ISLNK(sInfo.st_mode)) {
return ensure_copy_symlink(path, dest);
}
#endif
if (!S_ISDIR(sInfo.st_mode)) {
return ensure_copy(path, dest);
}
@ -1589,7 +1624,7 @@ LaunchCallbackApp(const NS_tchar *workingDir,
}
static void
WriteStatusFile(int status)
WriteStatusText(const char* text)
{
// This is how we communicate our completion status to the main application.
@ -1601,6 +1636,12 @@ WriteStatusFile(int status)
if (file == NULL)
return;
fwrite(text, strlen(text), 1, file);
}
static void
WriteStatusFile(int status)
{
const char *text;
char buf[32];
@ -1614,7 +1655,8 @@ WriteStatusFile(int status)
snprintf(buf, sizeof(buf)/sizeof(buf[0]), "failed: %d\n", status);
text = buf;
}
fwrite(text, strlen(text), 1, file);
WriteStatusText(text);
}
static bool
@ -2033,31 +2075,64 @@ UpdateThreadFunc(void *param)
}
}
if (rv) {
LOG(("failed: %d\n", rv));
}
else {
bool reportRealResults = true;
if (sReplaceRequest && rv && !getenv("MOZ_NO_REPLACE_FALLBACK")) {
// When attempting to replace the application, we should fall back
// to non-staged updates in case of a failure. We do this by
// setting the status to pending, exiting the updater, and
// launching the callback application. The callback application's
// startup path will see the pending status, and will start the
// updater application again in order to apply the update without
// staging.
// The MOZ_NO_REPLACE_FALLBACK environment variable is used to
// bypass this fallback, and is used in the updater tests.
// The only special thing which we should do here is to remove the
// staged directory as it won't be useful any more.
NS_tchar installDir[MAXPATHLEN];
if (GetInstallationDir(installDir)) {
NS_tchar stageDir[MAXPATHLEN];
NS_tsnprintf(stageDir, sizeof(stageDir)/sizeof(stageDir[0]),
#ifdef XP_MACOSX
// If the update was successful we need to update the timestamp
// on the top-level Mac OS X bundle directory so that Mac OS X's
// Launch Services picks up any major changes. Here we assume that
// the current working directory is the top-level bundle directory.
char* cwd = getcwd(NULL, 0);
if (cwd) {
if (utimes(cwd, NULL) != 0) {
LOG(("Couldn't set access/modification time on application bundle.\n"));
}
free(cwd);
NS_T("%s/Updated.app"),
#else
NS_T("%s/updated"),
#endif
installDir);
ensure_remove_recursive(stageDir);
WriteStatusText(sUsingService ? "pending-service" : "pending");
putenv("MOZ_PROCESS_UPDATES="); // We need to use -process-updates again in the tests
reportRealResults = false; // pretend success
}
}
if (reportRealResults) {
if (rv) {
LOG(("failed: %d\n", rv));
}
else {
LOG(("Couldn't get current working directory for setting "
"access/modification time on application bundle.\n"));
}
#ifdef XP_MACOSX
// If the update was successful we need to update the timestamp
// on the top-level Mac OS X bundle directory so that Mac OS X's
// Launch Services picks up any major changes. Here we assume that
// the current working directory is the top-level bundle directory.
char* cwd = getcwd(NULL, 0);
if (cwd) {
if (utimes(cwd, NULL) != 0) {
LOG(("Couldn't set access/modification time on application bundle.\n"));
}
free(cwd);
}
else {
LOG(("Couldn't get current working directory for setting "
"access/modification time on application bundle.\n"));
}
#endif
LOG(("succeeded\n"));
LOG(("succeeded\n"));
}
WriteStatusFile(rv);
}
WriteStatusFile(rv);
LOG(("calling QuitProgressUI\n"));
QuitProgressUI();
@ -2227,9 +2302,8 @@ int NS_main(int argc, NS_tchar **argv)
// argument prior to callbackIndex is the working directory.
const int callbackIndex = 5;
bool usingService = false;
#if defined(XP_WIN)
usingService = getenv("MOZ_USING_SERVICE") != NULL;
sUsingService = getenv("MOZ_USING_SERVICE") != NULL;
putenv(const_cast<char*>("MOZ_USING_SERVICE="));
// lastFallbackError keeps track of the last error for the service not being
// used, in case of an error when fallback is not enabled we write the
@ -2242,7 +2316,7 @@ int NS_main(int argc, NS_tchar **argv)
// when write access is denied to the installation directory.
HANDLE updateLockFileHandle = INVALID_HANDLE_VALUE;
NS_tchar elevatedLockFilePath[MAXPATHLEN] = {NS_T('\0')};
if (!usingService &&
if (!sUsingService &&
(argc > callbackIndex || sBackgroundUpdate || sReplaceRequest)) {
NS_tchar updateLockFilePath[MAXPATHLEN];
if (sBackgroundUpdate) {
@ -2492,7 +2566,7 @@ int NS_main(int argc, NS_tchar **argv)
if (argc > callbackIndex) {
LaunchCallbackApp(argv[4], argc - callbackIndex,
argv + callbackIndex, usingService);
argv + callbackIndex, sUsingService);
}
CloseHandle(elevatedFileHandle);
@ -2583,7 +2657,7 @@ int NS_main(int argc, NS_tchar **argv)
EXIT_WHEN_ELEVATED(elevatedLockFilePath, updateLockFileHandle, 1);
if (argc > callbackIndex) {
LaunchCallbackApp(argv[4], argc - callbackIndex,
argv + callbackIndex, usingService);
argv + callbackIndex, sUsingService);
}
return 1;
}
@ -2628,7 +2702,7 @@ int NS_main(int argc, NS_tchar **argv)
LaunchCallbackApp(argv[4],
argc - callbackIndex,
argv + callbackIndex,
usingService);
sUsingService);
}
return 1;
}
@ -2701,7 +2775,7 @@ int NS_main(int argc, NS_tchar **argv)
LaunchCallbackApp(argv[4],
argc - callbackIndex,
argv + callbackIndex,
usingService);
sUsingService);
return 1;
}
}
@ -2770,7 +2844,7 @@ int NS_main(int argc, NS_tchar **argv)
// service if the service failed to apply the update. We want to update
// the service to a newer version in that case. If we are not running
// through the service, then MOZ_USING_SERVICE will not exist.
if (!usingService) {
if (!sUsingService) {
NS_tchar installDir[MAXPATHLEN];
if (GetInstallationDir(installDir)) {
if (!LaunchWinPostProcess(installDir, gSourcePath, false, NULL)) {
@ -2791,7 +2865,7 @@ int NS_main(int argc, NS_tchar **argv)
LaunchCallbackApp(argv[4],
argc - callbackIndex,
argv + callbackIndex,
usingService);
sUsingService);
}
return gSucceeded ? 0 : 1;