toolkit/mozapps/update/tests/unit_aus_update/head_update.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/mozapps/update/tests/unit_aus_update/head_update.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,3466 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +const INSTALL_LOCALE = "@AB_CD@";
     1.9 +const MOZ_APP_NAME = "@MOZ_APP_NAME@";
    1.10 +const BIN_SUFFIX = "@BIN_SUFFIX@";
    1.11 +
    1.12 +#ifdef XP_WIN
    1.13 +// MOZ_APP_VENDOR is optional.
    1.14 +// On Windows, if MOZ_APP_VENDOR is not defined the updates directory will be
    1.15 +// located under %LOCALAPPDATA%\@MOZ_APP_BASENAME@\updates\TaskBarID
    1.16 +#ifdef MOZ_APP_VENDOR
    1.17 +const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@";
    1.18 +#else
    1.19 +const MOZ_APP_VENDOR = "";
    1.20 +#endif
    1.21 +
    1.22 +// MOZ_APP_BASENAME is not optional for tests.
    1.23 +const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@";
    1.24 +#endif // XP_WIN
    1.25 +
    1.26 +const APP_INFO_NAME = "XPCShell";
    1.27 +const APP_INFO_VENDOR = "Mozilla";
    1.28 +
    1.29 +#ifdef XP_UNIX
    1.30 +const APP_BIN_SUFFIX = "-bin";
    1.31 +#else
    1.32 +const APP_BIN_SUFFIX = "@BIN_SUFFIX@";
    1.33 +#endif
    1.34 +
    1.35 +#ifdef XP_WIN
    1.36 +const IS_WIN = true;
    1.37 +#else
    1.38 +const IS_WIN = false;
    1.39 +#endif
    1.40 +
    1.41 +#ifdef XP_MACOSX
    1.42 +const IS_MACOSX = true;
    1.43 +#ifdef MOZ_SHARK
    1.44 +const IS_SHARK = true;
    1.45 +#else
    1.46 +const IS_SHARK = false;
    1.47 +#endif
    1.48 +#else
    1.49 +const IS_MACOSX = false;
    1.50 +#endif
    1.51 +
    1.52 +#ifdef XP_UNIX
    1.53 +const IS_UNIX = true;
    1.54 +#else
    1.55 +const IS_UNIX = false;
    1.56 +#endif
    1.57 +
    1.58 +#ifdef ANDROID
    1.59 +const IS_ANDROID = true;
    1.60 +#else
    1.61 +const IS_ANDROID = false;
    1.62 +#endif
    1.63 +
    1.64 +#ifdef MOZ_WIDGET_GONK
    1.65 +const IS_TOOLKIT_GONK = true;
    1.66 +#else
    1.67 +const IS_TOOLKIT_GONK = false;
    1.68 +#endif
    1.69 +
    1.70 +const USE_EXECV = IS_UNIX && !IS_MACOSX;
    1.71 +
    1.72 +#ifdef MOZ_VERIFY_MAR_SIGNATURE
    1.73 +const IS_MAR_CHECKS_ENABLED = true;
    1.74 +#else
    1.75 +const IS_MAR_CHECKS_ENABLED = false;
    1.76 +#endif
    1.77 +
    1.78 +const URL_HOST = "http://localhost";
    1.79 +
    1.80 +const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX;
    1.81 +const FILE_COMPLETE_EXE = "complete.exe";
    1.82 +const FILE_COMPLETE_MAR = "complete.mar";
    1.83 +const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX;
    1.84 +const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe";
    1.85 +const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe";
    1.86 +const FILE_OLD_VERSION_MAR = "old_version.mar";
    1.87 +const FILE_PARTIAL_EXE = "partial.exe";
    1.88 +const FILE_PARTIAL_MAR = "partial.mar";
    1.89 +const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX;
    1.90 +const FILE_UPDATER_INI_BAK = "updater.ini.bak";
    1.91 +const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar";
    1.92 +
    1.93 +const LOG_COMPLETE_SUCCESS = "complete_log_success";
    1.94 +const LOG_PARTIAL_SUCCESS  = "partial_log_success";
    1.95 +const LOG_PARTIAL_FAILURE  = "partial_log_failure";
    1.96 +
    1.97 +const LOG_SWITCH_SUCCESS = "rename_file: proceeding to rename the directory\n" +
    1.98 +                           "rename_file: proceeding to rename the directory\n" +
    1.99 +                           "Now, remove the tmpDir\n" +
   1.100 +                           "succeeded\n" +
   1.101 +                           "calling QuitProgressUI";
   1.102 +
   1.103 +const ERR_RENAME_FILE = "rename_file: failed to rename file";
   1.104 +const ERR_UNABLE_OPEN_DEST = "unable to open destination file";
   1.105 +const ERR_BACKUP_DISCARD = "backup_discard: unable to remove";
   1.106 +
   1.107 +const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result.";
   1.108 +
   1.109 +// All we care about is that the last modified time has changed so that Mac OS
   1.110 +// X Launch Services invalidates its cache so the test allows up to one minute
   1.111 +// difference in the last modified time.
   1.112 +const MAC_MAX_TIME_DIFFERENCE = 60000;
   1.113 +
   1.114 +// Time to wait for the test helper process before continuing the test
   1.115 +const TEST_HELPER_TIMEOUT = 100;
   1.116 +
   1.117 +// Time to wait for a check in the test before continuing the test
   1.118 +const TEST_CHECK_TIMEOUT = 100;
   1.119 +
   1.120 +// How many of TEST_CHECK_TIMEOUT to wait before we abort the test.
   1.121 +const MAX_TIMEOUT_RUNS = 2000;
   1.122 +
   1.123 +// Time in seconds the helper application should sleep.the helper's input and output files
   1.124 +const HELPER_SLEEP_TIMEOUT = 180;
   1.125 +
   1.126 +// Maximum number of milliseconds the process that is launched can run before
   1.127 +// the test will try to kill it.
   1.128 +const APP_TIMER_TIMEOUT = 120000;
   1.129 +
   1.130 +#ifdef XP_WIN
   1.131 +const PIPE_TO_NULL = ">nul";
   1.132 +#else
   1.133 +const PIPE_TO_NULL = "> /dev/null 2>&1";
   1.134 +#endif
   1.135 +
   1.136 +// This default value will be overridden when using the http server.
   1.137 +var gURLData = URL_HOST + "/";
   1.138 +
   1.139 +var gTestID;
   1.140 +
   1.141 +var gTestserver;
   1.142 +
   1.143 +var gRegisteredServiceCleanup;
   1.144 +
   1.145 +var gXHR;
   1.146 +var gXHRCallback;
   1.147 +
   1.148 +var gUpdatePrompt;
   1.149 +var gUpdatePromptCallback;
   1.150 +
   1.151 +var gCheckFunc;
   1.152 +var gResponseBody;
   1.153 +var gResponseStatusCode = 200;
   1.154 +var gRequestURL;
   1.155 +var gUpdateCount;
   1.156 +var gUpdates;
   1.157 +var gStatusCode;
   1.158 +var gStatusText;
   1.159 +var gStatusResult;
   1.160 +
   1.161 +var gProcess;
   1.162 +var gAppTimer;
   1.163 +var gHandle;
   1.164 +
   1.165 +var gGREDirOrig;
   1.166 +var gAppDirOrig;
   1.167 +
   1.168 +var gServiceLaunchedCallbackLog = null;
   1.169 +var gServiceLaunchedCallbackArgs = null;
   1.170 +
   1.171 +// Variables are used instead of contants so tests can override these values if
   1.172 +// necessary.
   1.173 +var gCallbackBinFile = "callback_app" + BIN_SUFFIX;
   1.174 +var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"];
   1.175 +var gStageUpdate = false;
   1.176 +var gSwitchApp = false;
   1.177 +var gDisableReplaceFallback = false;
   1.178 +var gUseTestAppDir = true;
   1.179 +
   1.180 +var gTimeoutRuns = 0;
   1.181 +
   1.182 +// Environment related globals
   1.183 +var gShouldResetEnv = undefined;
   1.184 +var gAddedEnvXRENoWindowsCrashDialog = false;
   1.185 +var gEnvXPCOMDebugBreak;
   1.186 +var gEnvXPCOMMemLeakLog;
   1.187 +var gEnvDyldLibraryPath;
   1.188 +var gEnvLdLibraryPath;
   1.189 +
   1.190 +// Set to true to log additional information for debugging. To log additional
   1.191 +// information for an individual test set DEBUG_AUS_TEST to true in the test's
   1.192 +// run_test function.
   1.193 +var DEBUG_AUS_TEST = true;
   1.194 +// Never set DEBUG_TEST_LOG to true except when running tests locally or on the
   1.195 +// try server since this will force a test that failed a parallel run to fail
   1.196 +// when the same test runs non-parallel so the log from parallel test run can
   1.197 +// be displayed in the log.
   1.198 +var DEBUG_TEST_LOG = false;
   1.199 +// Set to false to keep the log file from the failed parallel test run.
   1.200 +var gDeleteLogFile = true;
   1.201 +var gRealDump;
   1.202 +var gTestLogText = "";
   1.203 +var gPassed;
   1.204 +
   1.205 +#include ../shared.js
   1.206 +
   1.207 +var gTestFiles = [];
   1.208 +var gTestDirs = [];
   1.209 +
   1.210 +// Common files for both successful and failed updates.
   1.211 +var gTestFilesCommon = [
   1.212 +{
   1.213 +  description      : "Should never change",
   1.214 +  fileName         : FILE_UPDATE_SETTINGS_INI,
   1.215 +  relPathDir       : "a/b/",
   1.216 +  originalContents : "ShouldNotBeReplaced\n",
   1.217 +  compareContents  : "ShouldNotBeReplaced\n",
   1.218 +  originalFile     : null,
   1.219 +  compareFile      : null,
   1.220 +  originalPerms    : 0o767,
   1.221 +  comparePerms     : 0o767
   1.222 +}, {
   1.223 +  description      : "Should never change",
   1.224 +  fileName         : "channel-prefs.js",
   1.225 +  relPathDir       : "a/b/defaults/pref/",
   1.226 +  originalContents : "ShouldNotBeReplaced\n",
   1.227 +  compareContents  : "ShouldNotBeReplaced\n",
   1.228 +  originalFile     : null,
   1.229 +  compareFile      : null,
   1.230 +  originalPerms    : 0o767,
   1.231 +  comparePerms     : 0o767
   1.232 +}];
   1.233 +
   1.234 +// Files for a complete successful update. This can be used for a complete
   1.235 +// failed update by calling setTestFilesAndDirsForFailure.
   1.236 +var gTestFilesCompleteSuccess = [
   1.237 +{
   1.238 +  description      : "Added by update.manifest (add)",
   1.239 +  fileName         : "precomplete",
   1.240 +  relPathDir       : "",
   1.241 +  originalContents : null,
   1.242 +  compareContents  : null,
   1.243 +  originalFile     : "partial_precomplete",
   1.244 +  compareFile      : "complete_precomplete",
   1.245 +  originalPerms    : 0o666,
   1.246 +  comparePerms     : 0o644
   1.247 +}, {
   1.248 +  description      : "Added by update.manifest (add)",
   1.249 +  fileName         : "searchpluginstext0",
   1.250 +  relPathDir       : "a/b/searchplugins/",
   1.251 +  originalContents : "ToBeReplacedWithFromComplete\n",
   1.252 +  compareContents  : "FromComplete\n",
   1.253 +  originalFile     : null,
   1.254 +  compareFile      : null,
   1.255 +  originalPerms    : 0o775,
   1.256 +  comparePerms     : 0o644
   1.257 +}, {
   1.258 +  description      : "Added by update.manifest (add)",
   1.259 +  fileName         : "searchpluginspng1.png",
   1.260 +  relPathDir       : "a/b/searchplugins/",
   1.261 +  originalContents : null,
   1.262 +  compareContents  : null,
   1.263 +  originalFile     : null,
   1.264 +  compareFile      : "complete.png",
   1.265 +  originalPerms    : null,
   1.266 +  comparePerms     : 0o644
   1.267 +}, {
   1.268 +  description      : "Added by update.manifest (add)",
   1.269 +  fileName         : "searchpluginspng0.png",
   1.270 +  relPathDir       : "a/b/searchplugins/",
   1.271 +  originalContents : null,
   1.272 +  compareContents  : null,
   1.273 +  originalFile     : "partial.png",
   1.274 +  compareFile      : "complete.png",
   1.275 +  originalPerms    : 0o666,
   1.276 +  comparePerms     : 0o644
   1.277 +}, {
   1.278 +  description      : "Added by update.manifest (add)",
   1.279 +  fileName         : "removed-files",
   1.280 +  relPathDir       : "a/b/",
   1.281 +  originalContents : null,
   1.282 +  compareContents  : null,
   1.283 +  originalFile     : "partial_removed-files",
   1.284 +  compareFile      : "complete_removed-files",
   1.285 +  originalPerms    : 0o666,
   1.286 +  comparePerms     : 0o644
   1.287 +}, {
   1.288 +  description      : "Added by update.manifest if the parent directory " +
   1.289 +                     "exists (add-if)",
   1.290 +  fileName         : "extensions1text0",
   1.291 +  relPathDir       : "a/b/distribution/extensions/extensions1/",
   1.292 +  originalContents : null,
   1.293 +  compareContents  : "FromComplete\n",
   1.294 +  originalFile     : null,
   1.295 +  compareFile      : null,
   1.296 +  originalPerms    : null,
   1.297 +  comparePerms     : 0o644
   1.298 +}, {
   1.299 +  description      : "Added by update.manifest if the parent directory " +
   1.300 +                     "exists (add-if)",
   1.301 +  fileName         : "extensions1png1.png",
   1.302 +  relPathDir       : "a/b/distribution/extensions/extensions1/",
   1.303 +  originalContents : null,
   1.304 +  compareContents  : null,
   1.305 +  originalFile     : "partial.png",
   1.306 +  compareFile      : "complete.png",
   1.307 +  originalPerms    : 0o666,
   1.308 +  comparePerms     : 0o644
   1.309 +}, {
   1.310 +  description      : "Added by update.manifest if the parent directory " +
   1.311 +                     "exists (add-if)",
   1.312 +  fileName         : "extensions1png0.png",
   1.313 +  relPathDir       : "a/b/distribution/extensions/extensions1/",
   1.314 +  originalContents : null,
   1.315 +  compareContents  : null,
   1.316 +  originalFile     : null,
   1.317 +  compareFile      : "complete.png",
   1.318 +  originalPerms    : null,
   1.319 +  comparePerms     : 0o644
   1.320 +}, {
   1.321 +  description      : "Added by update.manifest if the parent directory " +
   1.322 +                     "exists (add-if)",
   1.323 +  fileName         : "extensions0text0",
   1.324 +  relPathDir       : "a/b/distribution/extensions/extensions0/",
   1.325 +  originalContents : "ToBeReplacedWithFromComplete\n",
   1.326 +  compareContents  : "FromComplete\n",
   1.327 +  originalFile     : null,
   1.328 +  compareFile      : null,
   1.329 +  originalPerms    : null,
   1.330 +  comparePerms     : 0o644
   1.331 +}, {
   1.332 +  description      : "Added by update.manifest if the parent directory " +
   1.333 +                     "exists (add-if)",
   1.334 +  fileName         : "extensions0png1.png",
   1.335 +  relPathDir       : "a/b/distribution/extensions/extensions0/",
   1.336 +  originalContents : null,
   1.337 +  compareContents  : null,
   1.338 +  originalFile     : null,
   1.339 +  compareFile      : "complete.png",
   1.340 +  originalPerms    : null,
   1.341 +  comparePerms     : 0o644
   1.342 +}, {
   1.343 +  description      : "Added by update.manifest if the parent directory " +
   1.344 +                     "exists (add-if)",
   1.345 +  fileName         : "extensions0png0.png",
   1.346 +  relPathDir       : "a/b/distribution/extensions/extensions0/",
   1.347 +  originalContents : null,
   1.348 +  compareContents  : null,
   1.349 +  originalFile     : null,
   1.350 +  compareFile      : "complete.png",
   1.351 +  originalPerms    : null,
   1.352 +  comparePerms     : 0o644
   1.353 +}, {
   1.354 +  description      : "Added by update.manifest (add)",
   1.355 +  fileName         : "exe0.exe",
   1.356 +  relPathDir       : "a/b/",
   1.357 +  originalContents : null,
   1.358 +  compareContents  : null,
   1.359 +  originalFile     : FILE_HELPER_BIN,
   1.360 +  compareFile      : FILE_COMPLETE_EXE,
   1.361 +  originalPerms    : 0o777,
   1.362 +  comparePerms     : 0o755
   1.363 +}, {
   1.364 +  description      : "Added by update.manifest (add)",
   1.365 +  fileName         : "10text0",
   1.366 +  relPathDir       : "a/b/1/10/",
   1.367 +  originalContents : "ToBeReplacedWithFromComplete\n",
   1.368 +  compareContents  : "FromComplete\n",
   1.369 +  originalFile     : null,
   1.370 +  compareFile      : null,
   1.371 +  originalPerms    : 0o767,
   1.372 +  comparePerms     : 0o644
   1.373 +}, {
   1.374 +  description      : "Added by update.manifest (add)",
   1.375 +  fileName         : "0exe0.exe",
   1.376 +  relPathDir       : "a/b/0/",
   1.377 +  originalContents : null,
   1.378 +  compareContents  : null,
   1.379 +  originalFile     : FILE_HELPER_BIN,
   1.380 +  compareFile      : FILE_COMPLETE_EXE,
   1.381 +  originalPerms    : 0o777,
   1.382 +  comparePerms     : 0o755
   1.383 +}, {
   1.384 +  description      : "Added by update.manifest (add)",
   1.385 +  fileName         : "00text1",
   1.386 +  relPathDir       : "a/b/0/00/",
   1.387 +  originalContents : "ToBeReplacedWithFromComplete\n",
   1.388 +  compareContents  : "FromComplete\n",
   1.389 +  originalFile     : null,
   1.390 +  compareFile      : null,
   1.391 +  originalPerms    : 0o677,
   1.392 +  comparePerms     : 0o644
   1.393 +}, {
   1.394 +  description      : "Added by update.manifest (add)",
   1.395 +  fileName         : "00text0",
   1.396 +  relPathDir       : "a/b/0/00/",
   1.397 +  originalContents : "ToBeReplacedWithFromComplete\n",
   1.398 +  compareContents  : "FromComplete\n",
   1.399 +  originalFile     : null,
   1.400 +  compareFile      : null,
   1.401 +  originalPerms    : 0o775,
   1.402 +  comparePerms     : 0o644
   1.403 +}, {
   1.404 +  description      : "Added by update.manifest (add)",
   1.405 +  fileName         : "00png0.png",
   1.406 +  relPathDir       : "a/b/0/00/",
   1.407 +  originalContents : null,
   1.408 +  compareContents  : null,
   1.409 +  originalFile     : null,
   1.410 +  compareFile      : "complete.png",
   1.411 +  originalPerms    : 0o776,
   1.412 +  comparePerms     : 0o644
   1.413 +}, {
   1.414 +  description      : "Removed by precomplete (remove)",
   1.415 +  fileName         : "20text0",
   1.416 +  relPathDir       : "a/b/2/20/",
   1.417 +  originalContents : "ToBeDeleted\n",
   1.418 +  compareContents  : null,
   1.419 +  originalFile     : null,
   1.420 +  compareFile      : null,
   1.421 +  originalPerms    : null,
   1.422 +  comparePerms     : null
   1.423 +}, {
   1.424 +  description      : "Removed by precomplete (remove)",
   1.425 +  fileName         : "20png0.png",
   1.426 +  relPathDir       : "a/b/2/20/",
   1.427 +  originalContents : "ToBeDeleted\n",
   1.428 +  compareContents  : null,
   1.429 +  originalFile     : null,
   1.430 +  compareFile      : null,
   1.431 +  originalPerms    : null,
   1.432 +  comparePerms     : null
   1.433 +}];
   1.434 +
   1.435 +// Concatenate the common files to the end of the array.
   1.436 +gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon);
   1.437 +
   1.438 +// Files for a partial successful update. This can be used for a partial failed
   1.439 +// update by calling setTestFilesAndDirsForFailure.
   1.440 +var gTestFilesPartialSuccess = [
   1.441 +{
   1.442 +  description      : "Added by update.manifest (add)",
   1.443 +  fileName         : "precomplete",
   1.444 +  relPathDir       : "",
   1.445 +  originalContents : null,
   1.446 +  compareContents  : null,
   1.447 +  originalFile     : "complete_precomplete",
   1.448 +  compareFile      : "partial_precomplete",
   1.449 +  originalPerms    : 0o666,
   1.450 +  comparePerms     : 0o644
   1.451 +}, {
   1.452 +  description      : "Added by update.manifest (add)",
   1.453 +  fileName         : "searchpluginstext0",
   1.454 +  relPathDir       : "a/b/searchplugins/",
   1.455 +  originalContents : "ToBeReplacedWithFromPartial\n",
   1.456 +  compareContents  : "FromPartial\n",
   1.457 +  originalFile     : null,
   1.458 +  compareFile      : null,
   1.459 +  originalPerms    : 0o775,
   1.460 +  comparePerms     : 0o644
   1.461 +}, {
   1.462 +  description      : "Patched by update.manifest if the file exists " +
   1.463 +                     "(patch-if)",
   1.464 +  fileName         : "searchpluginspng1.png",
   1.465 +  relPathDir       : "a/b/searchplugins/",
   1.466 +  originalContents : null,
   1.467 +  compareContents  : null,
   1.468 +  originalFile     : "complete.png",
   1.469 +  compareFile      : "partial.png",
   1.470 +  originalPerms    : 0o666,
   1.471 +  comparePerms     : 0o666
   1.472 +}, {
   1.473 +  description      : "Patched by update.manifest if the file exists " +
   1.474 +                     "(patch-if)",
   1.475 +  fileName         : "searchpluginspng0.png",
   1.476 +  relPathDir       : "a/b/searchplugins/",
   1.477 +  originalContents : null,
   1.478 +  compareContents  : null,
   1.479 +  originalFile     : "complete.png",
   1.480 +  compareFile      : "partial.png",
   1.481 +  originalPerms    : 0o666,
   1.482 +  comparePerms     : 0o666
   1.483 +}, {
   1.484 +  description      : "Added by update.manifest if the parent directory " +
   1.485 +                     "exists (add-if)",
   1.486 +  fileName         : "extensions1text0",
   1.487 +  relPathDir       : "a/b/distribution/extensions/extensions1/",
   1.488 +  originalContents : null,
   1.489 +  compareContents  : "FromPartial\n",
   1.490 +  originalFile     : null,
   1.491 +  compareFile      : null,
   1.492 +  originalPerms    : null,
   1.493 +  comparePerms     : 0o644
   1.494 +}, {
   1.495 +  description      : "Patched by update.manifest if the parent directory " +
   1.496 +                     "exists (patch-if)",
   1.497 +  fileName         : "extensions1png1.png",
   1.498 +  relPathDir       : "a/b/distribution/extensions/extensions1/",
   1.499 +  originalContents : null,
   1.500 +  compareContents  : null,
   1.501 +  originalFile     : "complete.png",
   1.502 +  compareFile      : "partial.png",
   1.503 +  originalPerms    : 0o666,
   1.504 +  comparePerms     : 0o666
   1.505 +}, {
   1.506 +  description      : "Patched by update.manifest if the parent directory " +
   1.507 +                     "exists (patch-if)",
   1.508 +  fileName         : "extensions1png0.png",
   1.509 +  relPathDir       : "a/b/distribution/extensions/extensions1/",
   1.510 +  originalContents : null,
   1.511 +  compareContents  : null,
   1.512 +  originalFile     : "complete.png",
   1.513 +  compareFile      : "partial.png",
   1.514 +  originalPerms    : 0o666,
   1.515 +  comparePerms     : 0o666
   1.516 +}, {
   1.517 +  description      : "Added by update.manifest if the parent directory " +
   1.518 +                     "exists (add-if)",
   1.519 +  fileName         : "extensions0text0",
   1.520 +  relPathDir       : "a/b/distribution/extensions/extensions0/",
   1.521 +  originalContents : "ToBeReplacedWithFromPartial\n",
   1.522 +  compareContents  : "FromPartial\n",
   1.523 +  originalFile     : null,
   1.524 +  compareFile      : null,
   1.525 +  originalPerms    : 0o644,
   1.526 +  comparePerms     : 0o644
   1.527 +}, {
   1.528 +  description      : "Patched by update.manifest if the parent directory " +
   1.529 +                     "exists (patch-if)",
   1.530 +  fileName         : "extensions0png1.png",
   1.531 +  relPathDir       : "a/b/distribution/extensions/extensions0/",
   1.532 +  originalContents : null,
   1.533 +  compareContents  : null,
   1.534 +  originalFile     : "complete.png",
   1.535 +  compareFile      : "partial.png",
   1.536 +  originalPerms    : 0o644,
   1.537 +  comparePerms     : 0o644
   1.538 +}, {
   1.539 +  description      : "Patched by update.manifest if the parent directory " +
   1.540 +                     "exists (patch-if)",
   1.541 +  fileName         : "extensions0png0.png",
   1.542 +  relPathDir       : "a/b/distribution/extensions/extensions0/",
   1.543 +  originalContents : null,
   1.544 +  compareContents  : null,
   1.545 +  originalFile     : "complete.png",
   1.546 +  compareFile      : "partial.png",
   1.547 +  originalPerms    : 0o644,
   1.548 +  comparePerms     : 0o644
   1.549 +}, {
   1.550 +  description      : "Patched by update.manifest (patch)",
   1.551 +  fileName         : "exe0.exe",
   1.552 +  relPathDir       : "a/b/",
   1.553 +  originalContents : null,
   1.554 +  compareContents  : null,
   1.555 +  originalFile     : FILE_COMPLETE_EXE,
   1.556 +  compareFile      : FILE_PARTIAL_EXE,
   1.557 +  originalPerms    : 0o755,
   1.558 +  comparePerms     : 0o755
   1.559 +}, {
   1.560 +  description      : "Patched by update.manifest (patch)",
   1.561 +  fileName         : "0exe0.exe",
   1.562 +  relPathDir       : "a/b/0/",
   1.563 +  originalContents : null,
   1.564 +  compareContents  : null,
   1.565 +  originalFile     : FILE_COMPLETE_EXE,
   1.566 +  compareFile      : FILE_PARTIAL_EXE,
   1.567 +  originalPerms    : 0o755,
   1.568 +  comparePerms     : 0o755
   1.569 +}, {
   1.570 +  description      : "Added by update.manifest (add)",
   1.571 +  fileName         : "00text0",
   1.572 +  relPathDir       : "a/b/0/00/",
   1.573 +  originalContents : "ToBeReplacedWithFromPartial\n",
   1.574 +  compareContents  : "FromPartial\n",
   1.575 +  originalFile     : null,
   1.576 +  compareFile      : null,
   1.577 +  originalPerms    : 0o644,
   1.578 +  comparePerms     : 0o644
   1.579 +}, {
   1.580 +  description      : "Patched by update.manifest (patch)",
   1.581 +  fileName         : "00png0.png",
   1.582 +  relPathDir       : "a/b/0/00/",
   1.583 +  originalContents : null,
   1.584 +  compareContents  : null,
   1.585 +  originalFile     : "complete.png",
   1.586 +  compareFile      : "partial.png",
   1.587 +  originalPerms    : 0o666,
   1.588 +  comparePerms     : 0o666
   1.589 +}, {
   1.590 +  description      : "Added by update.manifest (add)",
   1.591 +  fileName         : "20text0",
   1.592 +  relPathDir       : "a/b/2/20/",
   1.593 +  originalContents : null,
   1.594 +  compareContents  : "FromPartial\n",
   1.595 +  originalFile     : null,
   1.596 +  compareFile      : null,
   1.597 +  originalPerms    : null,
   1.598 +  comparePerms     : 0o644
   1.599 +}, {
   1.600 +  description      : "Added by update.manifest (add)",
   1.601 +  fileName         : "20png0.png",
   1.602 +  relPathDir       : "a/b/2/20/",
   1.603 +  originalContents : null,
   1.604 +  compareContents  : null,
   1.605 +  originalFile     : null,
   1.606 +  compareFile      : "partial.png",
   1.607 +  originalPerms    : null,
   1.608 +  comparePerms     : 0o644
   1.609 +}, {
   1.610 +  description      : "Added by update.manifest (add)",
   1.611 +  fileName         : "00text2",
   1.612 +  relPathDir       : "a/b/0/00/",
   1.613 +  originalContents : null,
   1.614 +  compareContents  : "FromPartial\n",
   1.615 +  originalFile     : null,
   1.616 +  compareFile      : null,
   1.617 +  originalPerms    : null,
   1.618 +  comparePerms     : 0o644
   1.619 +}, {
   1.620 +  description      : "Removed by update.manifest (remove)",
   1.621 +  fileName         : "10text0",
   1.622 +  relPathDir       : "a/b/1/10/",
   1.623 +  originalContents : "ToBeDeleted\n",
   1.624 +  compareContents  : null,
   1.625 +  originalFile     : null,
   1.626 +  compareFile      : null,
   1.627 +  originalPerms    : null,
   1.628 +  comparePerms     : null
   1.629 +}, {
   1.630 +  description      : "Removed by update.manifest (remove)",
   1.631 +  fileName         : "00text1",
   1.632 +  relPathDir       : "a/b/0/00/",
   1.633 +  originalContents : "ToBeDeleted\n",
   1.634 +  compareContents  : null,
   1.635 +  originalFile     : null,
   1.636 +  compareFile      : null,
   1.637 +  originalPerms    : null,
   1.638 +  comparePerms     : null
   1.639 +}];
   1.640 +
   1.641 +// Concatenate the common files to the end of the array.
   1.642 +gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon);
   1.643 +
   1.644 +/**
   1.645 + * The mar files used for the updater tests contain the following remove
   1.646 + * operations.
   1.647 + *
   1.648 + * partial and complete test mar remove operations
   1.649 + * -----------------------------------------------
   1.650 + * remove "text1"
   1.651 + * remove "text0"
   1.652 + * rmrfdir "9/99/"
   1.653 + * rmdir "9/99/"
   1.654 + * rmrfdir "9/98/"
   1.655 + * rmrfdir "9/97/"
   1.656 + * rmrfdir "9/96/"
   1.657 + * rmrfdir "9/95/"
   1.658 + * rmrfdir "9/95/"
   1.659 + * rmrfdir "9/94/"
   1.660 + * rmdir "9/94/"
   1.661 + * rmdir "9/93/"
   1.662 + * rmdir "9/92/"
   1.663 + * rmdir "9/91/"
   1.664 + * rmdir "9/90/"
   1.665 + * rmdir "9/90/"
   1.666 + * rmrfdir "8/89/"
   1.667 + * rmdir "8/89/"
   1.668 + * rmrfdir "8/88/"
   1.669 + * rmrfdir "8/87/"
   1.670 + * rmrfdir "8/86/"
   1.671 + * rmrfdir "8/85/"
   1.672 + * rmrfdir "8/85/"
   1.673 + * rmrfdir "8/84/"
   1.674 + * rmdir "8/84/"
   1.675 + * rmdir "8/83/"
   1.676 + * rmdir "8/82/"
   1.677 + * rmdir "8/81/"
   1.678 + * rmdir "8/80/"
   1.679 + * rmdir "8/80/"
   1.680 + * rmrfdir "7/"
   1.681 + * rmdir "6/"
   1.682 + * remove "5/text1"
   1.683 + * remove "5/text0"
   1.684 + * rmrfdir "5/"
   1.685 + * remove "4/text1"
   1.686 + * remove "4/text0"
   1.687 + * remove "4/exe0.exe"
   1.688 + * rmdir "4/"
   1.689 + * remove "3/text1"
   1.690 + * remove "3/text0"
   1.691 + *
   1.692 + * partial test mar additional remove operations
   1.693 + * ---------------------------------------------
   1.694 + * remove "0/00/00text1"
   1.695 + * remove "1/10/10text0"
   1.696 + * rmdir "1/10/"
   1.697 + * rmdir "1/"
   1.698 + */
   1.699 +var gTestDirsCommon = [
   1.700 +{
   1.701 +  relPathDir   : "a/b/3/",
   1.702 +  dirRemoved   : false,
   1.703 +  files        : ["3text0", "3text1"],
   1.704 +  filesRemoved : true
   1.705 +}, {
   1.706 +  relPathDir   : "a/b/4/",
   1.707 +  dirRemoved   : true,
   1.708 +  files        : ["4text0", "4text1"],
   1.709 +  filesRemoved : true
   1.710 +}, {
   1.711 +  relPathDir   : "a/b/5/",
   1.712 +  dirRemoved   : true,
   1.713 +  files        : ["5test.exe", "5text0", "5text1"],
   1.714 +  filesRemoved : true
   1.715 +}, {
   1.716 +  relPathDir   : "a/b/6/",
   1.717 +  dirRemoved   : true
   1.718 +}, {
   1.719 +  relPathDir   : "a/b/7/",
   1.720 +  dirRemoved   : true,
   1.721 +  files        : ["7text0", "7text1"],
   1.722 +  subDirs      : ["70/", "71/"],
   1.723 +  subDirFiles  : ["7xtest.exe", "7xtext0", "7xtext1"]
   1.724 +}, {
   1.725 +  relPathDir   : "a/b/8/",
   1.726 +  dirRemoved   : false
   1.727 +}, {
   1.728 +  relPathDir   : "a/b/8/80/",
   1.729 +  dirRemoved   : true
   1.730 +}, {
   1.731 +  relPathDir   : "a/b/8/81/",
   1.732 +  dirRemoved   : false,
   1.733 +  files        : ["81text0", "81text1"]
   1.734 +}, {
   1.735 +  relPathDir   : "a/b/8/82/",
   1.736 +  dirRemoved   : false,
   1.737 +  subDirs      : ["820/", "821/"]
   1.738 +}, {
   1.739 +  relPathDir   : "a/b/8/83/",
   1.740 +  dirRemoved   : true
   1.741 +}, {
   1.742 +  relPathDir   : "a/b/8/84/",
   1.743 +  dirRemoved   : true
   1.744 +}, {
   1.745 +  relPathDir   : "a/b/8/85/",
   1.746 +  dirRemoved   : true
   1.747 +}, {
   1.748 +  relPathDir   : "a/b/8/86/",
   1.749 +  dirRemoved   : true,
   1.750 +  files        : ["86text0", "86text1"]
   1.751 +}, {
   1.752 +  relPathDir   : "a/b/8/87/",
   1.753 +  dirRemoved   : true,
   1.754 +  subDirs      : ["870/", "871/"],
   1.755 +  subDirFiles  : ["87xtext0", "87xtext1"]
   1.756 +}, {
   1.757 +  relPathDir   : "a/b/8/88/",
   1.758 +  dirRemoved   : true
   1.759 +}, {
   1.760 +  relPathDir   : "a/b/8/89/",
   1.761 +  dirRemoved   : true
   1.762 +}, {
   1.763 +  relPathDir   : "a/b/9/90/",
   1.764 +  dirRemoved   : true
   1.765 +}, {
   1.766 +  relPathDir   : "a/b/9/91/",
   1.767 +  dirRemoved   : false,
   1.768 +  files        : ["91text0", "91text1"]
   1.769 +}, {
   1.770 +  relPathDir   : "a/b/9/92/",
   1.771 +  dirRemoved   : false,
   1.772 +  subDirs      : ["920/", "921/"]
   1.773 +}, {
   1.774 +  relPathDir   : "a/b/9/93/",
   1.775 +  dirRemoved   : true
   1.776 +}, {
   1.777 +  relPathDir   : "a/b/9/94/",
   1.778 +  dirRemoved   : true
   1.779 +}, {
   1.780 +  relPathDir   : "a/b/9/95/",
   1.781 +  dirRemoved   : true
   1.782 +}, {
   1.783 +  relPathDir   : "a/b/9/96/",
   1.784 +  dirRemoved   : true,
   1.785 +  files        : ["96text0", "96text1"]
   1.786 +}, {
   1.787 +  relPathDir   : "a/b/9/97/",
   1.788 +  dirRemoved   : true,
   1.789 +  subDirs      : ["970/", "971/"],
   1.790 +  subDirFiles  : ["97xtext0", "97xtext1"]
   1.791 +}, {
   1.792 +  relPathDir   : "a/b/9/98/",
   1.793 +  dirRemoved   : true
   1.794 +}, {
   1.795 +  relPathDir   : "a/b/9/99/",
   1.796 +  dirRemoved   : true
   1.797 +}];
   1.798 +
   1.799 +// Directories for a complete successful update. This array can be used for a
   1.800 +// complete failed update by calling setTestFilesAndDirsForFailure.
   1.801 +var gTestDirsCompleteSuccess = [
   1.802 +{
   1.803 +  description  : "Removed by precomplete (rmdir)",
   1.804 +  relPathDir   : "a/b/2/20/",
   1.805 +  dirRemoved   : true
   1.806 +}, {
   1.807 +  description  : "Removed by precomplete (rmdir)",
   1.808 +  relPathDir   : "a/b/2/",
   1.809 +  dirRemoved   : true
   1.810 +}];
   1.811 +
   1.812 +// Concatenate the common files to the beginning of the array.
   1.813 +gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess);
   1.814 +
   1.815 +// Directories for a partial successful update. This array can be used for a
   1.816 +// partial failed update by calling setTestFilesAndDirsForFailure.
   1.817 +var gTestDirsPartialSuccess = [
   1.818 +{
   1.819 +  description  : "Removed by update.manifest (rmdir)",
   1.820 +  relPathDir   : "a/b/1/10/",
   1.821 +  dirRemoved   : true
   1.822 +}, {
   1.823 +  description  : "Removed by update.manifest (rmdir)",
   1.824 +  relPathDir   : "a/b/1/",
   1.825 +  dirRemoved   : true
   1.826 +}];
   1.827 +
   1.828 +// Concatenate the common files to the beginning of the array.
   1.829 +gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess);
   1.830 +
   1.831 +// Extra directories to check for existence for both complete and partial
   1.832 +// updates. Whether they exist or not is set when calling setupUpdaterTest.
   1.833 +var gTestExtraDirs = [
   1.834 +{
   1.835 +  relPathDir   : DIR_UPDATED,
   1.836 +  dirExists    : false
   1.837 +}, {
   1.838 +  relPathDir   : DIR_TOBEDELETED,
   1.839 +  dirExists    : false
   1.840 +}];
   1.841 +
   1.842 +// This makes it possible to run most tests on xulrunner where the update
   1.843 +// channel default preference is not set.
   1.844 +if (MOZ_APP_NAME == "xulrunner") {
   1.845 +  try {
   1.846 +    gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
   1.847 +  } catch (e) {
   1.848 +    setUpdateChannel("test_channel");
   1.849 +  }
   1.850 +}
   1.851 +
   1.852 +/**
   1.853 + * Helper function for setting up the test environment.
   1.854 + */
   1.855 +function setupTestCommon() {
   1.856 +  logTestInfo("start - general test setup");
   1.857 +
   1.858 +  do_test_pending();
   1.859 +
   1.860 +  if (gTestID) {
   1.861 +    do_throw("setupTestCommon should only be called once!");
   1.862 +  }
   1.863 +
   1.864 +  let caller = Components.stack.caller;
   1.865 +  gTestID = caller.filename.toString().split("/").pop().split(".")[0];
   1.866 +
   1.867 +  if (DEBUG_TEST_LOG) {
   1.868 +    let logFile = do_get_file(gTestID + ".log", true);
   1.869 +    if (logFile.exists()) {
   1.870 +      gPassed = false;
   1.871 +      logTestInfo("start - dumping previous test run log");
   1.872 +      logTestInfo("\n" + readFile(logFile) + "\n");
   1.873 +      logTestInfo("finish - dumping previous test run log");
   1.874 +      if (gDeleteLogFile) {
   1.875 +        logFile.remove(false);
   1.876 +      }
   1.877 +      do_throw("The parallel run of this test failed. Failing non-parallel " +
   1.878 +               "test so the log from the parallel run can be displayed in " +
   1.879 +               "non-parallel log.")
   1.880 +    } else {
   1.881 +      gRealDump = dump;
   1.882 +      dump = dumpOverride;
   1.883 +    }
   1.884 +  }
   1.885 +
   1.886 +  // Don't attempt to show a prompt when an update finishes.
   1.887 +  Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
   1.888 +
   1.889 +  gGREDirOrig = getGREDir();
   1.890 +  gAppDirOrig = getAppBaseDir();
   1.891 +
   1.892 +  let applyDir = getApplyDirFile(null, true).parent;
   1.893 +
   1.894 +  // Try to remove the directory used to apply updates and the updates directory
   1.895 +  // on platforms other than Windows. Since the test hasn't ran yet and the
   1.896 +  // directory shouldn't exist finished this is non-fatal for the test.
   1.897 +  if (applyDir.exists()) {
   1.898 +    logTestInfo("attempting to remove directory. Path: " + applyDir.path);
   1.899 +    try {
   1.900 +      removeDirRecursive(applyDir);
   1.901 +    } catch (e) {
   1.902 +      logTestInfo("non-fatal error removing directory. Path: " +
   1.903 +                  applyDir.path + ", Exception: " + e);
   1.904 +    }
   1.905 +  }
   1.906 +
   1.907 +  // adjustGeneralPaths registers a cleanup function that calls end_test when
   1.908 +  // it is defined as a function.
   1.909 +  adjustGeneralPaths();
   1.910 +
   1.911 +  // Remove the updates directory on Windows which is located outside of the
   1.912 +  // application directory after the call to adjustGeneralPaths has set it up.
   1.913 +  // Since the test hasn't ran yet and the directory shouldn't exist finished
   1.914 +  // this is non-fatal for the test.
   1.915 +  if (IS_WIN) {
   1.916 +    let updatesDir = getMockUpdRootD();
   1.917 +    if (updatesDir.exists())  {
   1.918 +      logTestInfo("attempting to remove directory. Path: " + updatesDir.path);
   1.919 +      try {
   1.920 +        removeDirRecursive(updatesDir);
   1.921 +      } catch (e) {
   1.922 +        logTestInfo("non-fatal error removing directory. Path: " +
   1.923 +                    updatesDir.path + ", Exception: " + e);
   1.924 +      }
   1.925 +    }
   1.926 +  }
   1.927 +
   1.928 +  logTestInfo("finish - general test setup");
   1.929 +}
   1.930 +
   1.931 +/**
   1.932 + * Nulls out the most commonly used global vars used by tests to prevent leaks
   1.933 + * as needed and attempts to restore the system to its original state.
   1.934 + */
   1.935 +function cleanupTestCommon() {
   1.936 +  logTestInfo("start - general test cleanup");
   1.937 +
   1.938 +  // Force the update manager to reload the update data to prevent it from
   1.939 +  // writing the old data to the files that have just been removed.
   1.940 +  reloadUpdateManagerData();
   1.941 +
   1.942 +  if (gChannel) {
   1.943 +    gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
   1.944 +  }
   1.945 +
   1.946 +  // Call app update's observe method passing xpcom-shutdown to test that the
   1.947 +  // shutdown of app update runs without throwing or leaking. The observer
   1.948 +  // method is used directly instead of calling notifyObservers so components
   1.949 +  // outside of the scope of this test don't assert and thereby cause app update
   1.950 +  // tests to fail.
   1.951 +  gAUS.observe(null, "xpcom-shutdown", "");
   1.952 +
   1.953 +  if (gXHR) {
   1.954 +    gXHRCallback     = null;
   1.955 +
   1.956 +    gXHR.responseXML = null;
   1.957 +    // null out the event handlers to prevent a mFreeCount leak of 1
   1.958 +    gXHR.onerror     = null;
   1.959 +    gXHR.onload      = null;
   1.960 +    gXHR.onprogress  = null;
   1.961 +
   1.962 +    gXHR             = null;
   1.963 +  }
   1.964 +
   1.965 +  gTestserver = null;
   1.966 +
   1.967 +  if (IS_UNIX) {
   1.968 +    // This will delete the launch script if it exists.
   1.969 +    getLaunchScript();
   1.970 +  }
   1.971 +
   1.972 +  if (IS_WIN && MOZ_APP_BASENAME) {
   1.973 +    let appDir = getApplyDirFile(null, true);
   1.974 +    let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla";
   1.975 +    const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME +
   1.976 +                     "\\TaskBarIDs";
   1.977 +    let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
   1.978 +              createInstance(AUS_Ci.nsIWindowsRegKey);
   1.979 +    try {
   1.980 +      key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
   1.981 +               AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
   1.982 +      if (key.hasValue(appDir.path)) {
   1.983 +        key.removeValue(appDir.path);
   1.984 +      }
   1.985 +    } catch (e) {
   1.986 +    }
   1.987 +    try {
   1.988 +      key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH,
   1.989 +               AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
   1.990 +      if (key.hasValue(appDir.path)) {
   1.991 +        key.removeValue(appDir.path);
   1.992 +      }
   1.993 +    } catch (e) {
   1.994 +    }
   1.995 +  }
   1.996 +
   1.997 +  // The updates directory is located outside of the application directory on
   1.998 +  // Windows so it also needs to be removed.
   1.999 +  if (IS_WIN) {
  1.1000 +    let updatesDir = getMockUpdRootD();
  1.1001 +    // Try to remove the directory used to apply updates. Since the test has
  1.1002 +    // already finished this is non-fatal for the test.
  1.1003 +    if (updatesDir.exists()) {
  1.1004 +      logTestInfo("attempting to remove directory. Path: " + updatesDir.path);
  1.1005 +      try {
  1.1006 +        removeDirRecursive(updatesDir);
  1.1007 +      } catch (e) {
  1.1008 +        logTestInfo("non-fatal error removing directory. Path: " +
  1.1009 +                    updatesDir.path + ", Exception: " + e);
  1.1010 +      }
  1.1011 +    }
  1.1012 +  }
  1.1013 +
  1.1014 +  let applyDir = getApplyDirFile(null, true).parent;
  1.1015 +
  1.1016 +  // Try to remove the directory used to apply updates. Since the test has
  1.1017 +  // already finished this is non-fatal for the test.
  1.1018 +  if (applyDir.exists()) {
  1.1019 +    logTestInfo("attempting to remove directory. Path: " + applyDir.path);
  1.1020 +    try {
  1.1021 +      removeDirRecursive(applyDir);
  1.1022 +    } catch (e) {
  1.1023 +      logTestInfo("non-fatal error removing directory. Path: " +
  1.1024 +                  applyDir.path + ", Exception: " + e);
  1.1025 +    }
  1.1026 +  }
  1.1027 +
  1.1028 +  resetEnvironment();
  1.1029 +
  1.1030 +  logTestInfo("finish - general test cleanup");
  1.1031 +
  1.1032 +  if (gRealDump) {
  1.1033 +    dump = gRealDump;
  1.1034 +    gRealDump = null;
  1.1035 +  }
  1.1036 +
  1.1037 +  if (DEBUG_TEST_LOG && !gPassed) {
  1.1038 +    let fos = AUS_Cc["@mozilla.org/network/file-output-stream;1"].
  1.1039 +              createInstance(AUS_Ci.nsIFileOutputStream);
  1.1040 +    let logFile = do_get_file(gTestID + ".log", true);
  1.1041 +    if (!logFile.exists()) {
  1.1042 +      logFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
  1.1043 +    }
  1.1044 +    fos.init(logFile, MODE_WRONLY | MODE_CREATE | MODE_APPEND, PERMS_FILE, 0);
  1.1045 +    fos.write(gTestLogText, gTestLogText.length);
  1.1046 +    fos.close();
  1.1047 +  }
  1.1048 +
  1.1049 +  if (DEBUG_TEST_LOG) {
  1.1050 +    gTestLogText = null;
  1.1051 +  } else {
  1.1052 +    let logFile = do_get_file(gTestID + ".log", true);
  1.1053 +    if (logFile.exists()) {
  1.1054 +      logFile.remove(false);
  1.1055 +    }
  1.1056 +  }
  1.1057 +}
  1.1058 +
  1.1059 +/**
  1.1060 + * Helper function to store the log output of calls to dump in a variable so the
  1.1061 + * values can be written to a file for a parallel run of a test and printed to
  1.1062 + * the log file when the test runs synchronously.
  1.1063 + */
  1.1064 +function dumpOverride(aText) {
  1.1065 +  gTestLogText += aText;
  1.1066 +  gRealDump(aText);
  1.1067 +}
  1.1068 +
  1.1069 +/**
  1.1070 + * Helper function that calls do_test_finished that tracks whether a parallel
  1.1071 + * run of a test passed when it runs synchronously so the log output can be
  1.1072 + * inspected.
  1.1073 + */
  1.1074 +function doTestFinish() {
  1.1075 +  if (gPassed === undefined) {
  1.1076 +    gPassed = true;
  1.1077 +  }
  1.1078 +  do_test_finished();
  1.1079 +}
  1.1080 +
  1.1081 +/**
  1.1082 + * Sets the most commonly used preferences used by tests
  1.1083 + */
  1.1084 +function setDefaultPrefs() {
  1.1085 +  Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
  1.1086 +  Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true);
  1.1087 +  // Don't display UI for a successful installation. Some apps may not set this
  1.1088 +  // pref to false like Firefox does.
  1.1089 +  Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, false);
  1.1090 +  // Enable Update logging
  1.1091 +  Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true);
  1.1092 +}
  1.1093 +
  1.1094 +/**
  1.1095 + * Helper function for updater binary tests that sets the appropriate values
  1.1096 + * to check for update failures.
  1.1097 + */
  1.1098 +function setTestFilesAndDirsForFailure() {
  1.1099 +  gTestFiles.forEach(function STFADFF_Files(aTestFile) {
  1.1100 +    aTestFile.compareContents = aTestFile.originalContents;
  1.1101 +    aTestFile.compareFile = aTestFile.originalFile;
  1.1102 +    aTestFile.comparePerms = aTestFile.originalPerms;
  1.1103 +  });
  1.1104 +
  1.1105 +  gTestDirs.forEach(function STFADFF_Dirs(aTestDir) {
  1.1106 +    aTestDir.dirRemoved = false;
  1.1107 +    if (aTestDir.filesRemoved) {
  1.1108 +      aTestDir.filesRemoved = false;
  1.1109 +    }
  1.1110 +  });
  1.1111 +}
  1.1112 +
  1.1113 +/**
  1.1114 + * Initializes the most commonly used settings and creates an instance of the
  1.1115 + * update service stub.
  1.1116 + */
  1.1117 +function standardInit() {
  1.1118 +  createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0");
  1.1119 +  setDefaultPrefs();
  1.1120 +  // Initialize the update service stub component
  1.1121 +  initUpdateServiceStub();
  1.1122 +}
  1.1123 +
  1.1124 +/**
  1.1125 + * Custom path handler for the http server
  1.1126 + *
  1.1127 + * @param   aMetadata
  1.1128 + *          The http metadata for the request.
  1.1129 + * @param   aResponse
  1.1130 + *          The http response for the request.
  1.1131 + */
  1.1132 +function pathHandler(aMetadata, aResponse) {
  1.1133 +  aResponse.setHeader("Content-Type", "text/xml", false);
  1.1134 +  aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK");
  1.1135 +  aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length);
  1.1136 +}
  1.1137 +
  1.1138 +/**
  1.1139 + * Helper function for getting the application version from the application.ini
  1.1140 + * file. This will look in both the GRE and the application directories for the
  1.1141 + * application.ini file.
  1.1142 + *
  1.1143 + * @return  The version string from the application.ini file.
  1.1144 + * @throws  If the application.ini file is not found.
  1.1145 + */
  1.1146 +function getAppVersion() {
  1.1147 +  // Read the application.ini and use its application version.
  1.1148 +  let iniFile = gGREDirOrig.clone();
  1.1149 +  iniFile.append("application.ini");
  1.1150 +  if (!iniFile.exists()) {
  1.1151 +    iniFile = gAppDirOrig.clone();
  1.1152 +    iniFile.append("application.ini");
  1.1153 +  }
  1.1154 +  if (!iniFile.exists()) {
  1.1155 +    do_throw("Unable to find application.ini!");
  1.1156 +  }
  1.1157 +  let iniParser = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
  1.1158 +                  getService(AUS_Ci.nsIINIParserFactory).
  1.1159 +                  createINIParser(iniFile);
  1.1160 +  return iniParser.getString("App", "Version");
  1.1161 +}
  1.1162 +
  1.1163 +/**
  1.1164 + * Helper function for getting the relative path to the directory where the
  1.1165 + * application binary is located (e.g. <test_file_leafname>/dir.app/).
  1.1166 + *
  1.1167 + * Note: The dir.app subdirectory under <test_file_leafname> is needed for
  1.1168 + *       platforms other than Mac OS X so the tests can run in parallel due to
  1.1169 + *       update staging creating a lock file named moz_update_in_progress.lock in
  1.1170 + *       the parent directory of the installation directory.
  1.1171 + *
  1.1172 + * @return  The relative path to the directory where application binary is
  1.1173 + *          located.
  1.1174 + */
  1.1175 +function getApplyDirPath() {
  1.1176 +  return gTestID + "/dir.app/";
  1.1177 +}
  1.1178 +
  1.1179 +/**
  1.1180 + * Helper function for getting the nsIFile for a file in the directory where the
  1.1181 + * update will be applied.
  1.1182 + *
  1.1183 + * The files for the update are located two directories below the apply to
  1.1184 + * directory since Mac OS X sets the last modified time for the root directory
  1.1185 + * to the current time and if the update changes any files in the root directory
  1.1186 + * then it wouldn't be possible to test (bug 600098).
  1.1187 + *
  1.1188 + * @param   aRelPath (optional)
  1.1189 + *          The relative path to the file or directory to get from the root of
  1.1190 + *          the test's directory. If not specified the test's directory will be
  1.1191 + *          returned.
  1.1192 + * @param   aAllowNonexistent (optional)
  1.1193 + *          Whether the file must exist. If false or not specified the file must
  1.1194 + *          exist or the function will throw.
  1.1195 + * @return  The nsIFile for the file in the directory where the update will be
  1.1196 + *          applied.
  1.1197 + */
  1.1198 +function getApplyDirFile(aRelPath, aAllowNonexistent) {
  1.1199 +  let relpath = getApplyDirPath() + (aRelPath ? aRelPath : "");
  1.1200 +  return do_get_file(relpath, aAllowNonexistent);
  1.1201 +}
  1.1202 +
  1.1203 +/**
  1.1204 + * Helper function for getting the relative path to the directory where the
  1.1205 + * test data files are located.
  1.1206 + *
  1.1207 + * @return  The relative path to the directory where the test data files are
  1.1208 + *          located.
  1.1209 + */
  1.1210 +function getTestDirPath() {
  1.1211 +  return "../data/";
  1.1212 +}
  1.1213 +
  1.1214 +/**
  1.1215 + * Helper function for getting the nsIFile for a file in the test data
  1.1216 + * directory.
  1.1217 + *
  1.1218 + * @param   aRelPath (optional)
  1.1219 + *          The relative path to the file or directory to get from the root of
  1.1220 + *          the test's data directory. If not specified the test's data
  1.1221 + *          directory will be returned.
  1.1222 + * @return  The nsIFile for the file in the test data directory.
  1.1223 + * @throws  If the file or directory does not exist.
  1.1224 + */
  1.1225 +function getTestDirFile(aRelPath) {
  1.1226 +  let relpath = getTestDirPath() + (aRelPath ? aRelPath : "");
  1.1227 +  return do_get_file(relpath, false);
  1.1228 +}
  1.1229 +
  1.1230 +/**
  1.1231 + * Helper function for getting the directory that was updated. This can either
  1.1232 + * be the directory where the application binary is located or the directory
  1.1233 + * that contains the staged update.
  1.1234 + */
  1.1235 +function getUpdatedDirPath() {
  1.1236 +  return getApplyDirPath() + (gStageUpdate ? DIR_UPDATED +  "/" : "");
  1.1237 +}
  1.1238 +
  1.1239 +#ifdef XP_WIN
  1.1240 +XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash",
  1.1241 +                            function test_gInstallDirPathHash() {
  1.1242 +  // Figure out where we should check for a cached hash value
  1.1243 +  if (!MOZ_APP_BASENAME)
  1.1244 +    return null;
  1.1245 +
  1.1246 +  let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla";
  1.1247 +  let appDir = getApplyDirFile(null, true);
  1.1248 +
  1.1249 +  const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME +
  1.1250 +                   "\\TaskBarIDs";
  1.1251 +  let regKey = AUS_Cc["@mozilla.org/windows-registry-key;1"].
  1.1252 +               createInstance(AUS_Ci.nsIWindowsRegKey);
  1.1253 +  try {
  1.1254 +    regKey.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
  1.1255 +                AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
  1.1256 +    regKey.writeStringValue(appDir.path, gTestID);
  1.1257 +    return gTestID;
  1.1258 +  } catch (e) {
  1.1259 +  }
  1.1260 +
  1.1261 +  try {
  1.1262 +    regKey.create(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH,
  1.1263 +                  AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
  1.1264 +    regKey.writeStringValue(appDir.path, gTestID);
  1.1265 +    return gTestID;
  1.1266 +  } catch (e) {
  1.1267 +    logTestInfo("failed to create registry key. Registry Path: " + REG_PATH +
  1.1268 +                ", Key Name: " + appDir.path + ", Key Value: " + gTestID +
  1.1269 +                ", Exception " + e);
  1.1270 +  }
  1.1271 +  return null;
  1.1272 +});
  1.1273 +
  1.1274 +XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir",
  1.1275 +                            function test_gLocalAppDataDir() {
  1.1276 +  const CSIDL_LOCAL_APPDATA = 0x1c;
  1.1277 +
  1.1278 +  AUS_Cu.import("resource://gre/modules/ctypes.jsm");
  1.1279 +  let lib = ctypes.open("shell32");
  1.1280 +  let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW",
  1.1281 +                                           ctypes.winapi_abi,
  1.1282 +                                           ctypes.bool, /* bool(return) */
  1.1283 +                                           ctypes.int32_t, /* HWND hwndOwner */
  1.1284 +                                           ctypes.jschar.ptr, /* LPTSTR lpszPath */
  1.1285 +                                           ctypes.int32_t, /* int csidl */
  1.1286 +                                           ctypes.bool /* BOOL fCreate */);
  1.1287 +
  1.1288 +  let aryPathLocalAppData = ctypes.jschar.array()(260);
  1.1289 +  let rv = SHGetSpecialFolderPath(0, aryPathLocalAppData, CSIDL_LOCAL_APPDATA, false);
  1.1290 +  lib.close();
  1.1291 +
  1.1292 +  let pathLocalAppData = aryPathLocalAppData.readString(); // Convert the c-string to js-string
  1.1293 +  let updatesDir = AUS_Cc["@mozilla.org/file/local;1"].
  1.1294 +                   createInstance(AUS_Ci.nsILocalFile);
  1.1295 +  updatesDir.initWithPath(pathLocalAppData);
  1.1296 +  return updatesDir;
  1.1297 +});
  1.1298 +
  1.1299 +XPCOMUtils.defineLazyGetter(this, "gProgFilesDir",
  1.1300 +                            function test_gProgFilesDir() {
  1.1301 +  const CSIDL_PROGRAM_FILES = 0x26;
  1.1302 +
  1.1303 +  AUS_Cu.import("resource://gre/modules/ctypes.jsm");
  1.1304 +  let lib = ctypes.open("shell32");
  1.1305 +  let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW",
  1.1306 +                                           ctypes.winapi_abi,
  1.1307 +                                           ctypes.bool, /* bool(return) */
  1.1308 +                                           ctypes.int32_t, /* HWND hwndOwner */
  1.1309 +                                           ctypes.jschar.ptr, /* LPTSTR lpszPath */
  1.1310 +                                           ctypes.int32_t, /* int csidl */
  1.1311 +                                           ctypes.bool /* BOOL fCreate */);
  1.1312 +
  1.1313 +  let aryPathProgFiles = ctypes.jschar.array()(260);
  1.1314 +  let rv = SHGetSpecialFolderPath(0, aryPathProgFiles, CSIDL_PROGRAM_FILES, false);
  1.1315 +  lib.close();
  1.1316 +
  1.1317 +  let pathProgFiles = aryPathProgFiles.readString(); // Convert the c-string to js-string
  1.1318 +  let progFilesDir = AUS_Cc["@mozilla.org/file/local;1"].
  1.1319 +                     createInstance(AUS_Ci.nsILocalFile);
  1.1320 +  progFilesDir.initWithPath(pathProgFiles);
  1.1321 +  return progFilesDir;
  1.1322 +});
  1.1323 +
  1.1324 +/**
  1.1325 + * Helper function for getting the update root directory used by the tests. This
  1.1326 + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir
  1.1327 + * in nsXREDirProvider.cpp so an application will be able to find the update
  1.1328 + * when running a test that launches the application.
  1.1329 + */
  1.1330 +function getMockUpdRootD() {
  1.1331 +  let localAppDataDir = gLocalAppDataDir.clone();
  1.1332 +  let progFilesDir = gProgFilesDir.clone();
  1.1333 +  let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent;
  1.1334 +
  1.1335 +  let appDirPath = appDir.path;
  1.1336 +  var relPathUpdates = "";
  1.1337 +  if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) {
  1.1338 +    relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) +
  1.1339 +                      "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash;
  1.1340 +  }
  1.1341 +
  1.1342 +  if (!relPathUpdates) {
  1.1343 +    if (appDirPath.length > progFilesDir.path.length) {
  1.1344 +      if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) {
  1.1345 +        if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) {
  1.1346 +          relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME;
  1.1347 +        } else {
  1.1348 +          relPathUpdates += MOZ_APP_BASENAME;
  1.1349 +        }
  1.1350 +        relPathUpdates += appDirPath.substr(progFilesDir.path.length);
  1.1351 +      }
  1.1352 +    }
  1.1353 +  }
  1.1354 +
  1.1355 +  if (!relPathUpdates) {
  1.1356 +    if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) {
  1.1357 +      relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME;
  1.1358 +    } else {
  1.1359 +      relPathUpdates += MOZ_APP_BASENAME;
  1.1360 +    }
  1.1361 +    relPathUpdates += "\\" + MOZ_APP_NAME;
  1.1362 +  }
  1.1363 +
  1.1364 +  var updatesDir = AUS_Cc["@mozilla.org/file/local;1"].
  1.1365 +                   createInstance(AUS_Ci.nsILocalFile);
  1.1366 +  updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates);
  1.1367 +  logTestInfo("returning UpdRootD Path: " + updatesDir.path);
  1.1368 +  return updatesDir;
  1.1369 +}
  1.1370 +#else
  1.1371 +/**
  1.1372 + * Helper function for getting the update root directory used by the tests. This
  1.1373 + * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir
  1.1374 + * in nsXREDirProvider.cpp so an application will be able to find the update
  1.1375 + * when running a test that launches the application.
  1.1376 + */
  1.1377 +function getMockUpdRootD() {
  1.1378 +  return getApplyDirFile(DIR_BIN_REL_PATH, true);
  1.1379 +}
  1.1380 +#endif
  1.1381 +
  1.1382 +/**
  1.1383 + * Helper function for getting the nsIFile for the directory where the update
  1.1384 + * has been applied.
  1.1385 + *
  1.1386 + * This will be the same as getApplyDirFile for foreground updates, but will
  1.1387 + * point to a different file for the case of staged updates.
  1.1388 + *
  1.1389 + * Functions which attempt to access the files in the updated directory should
  1.1390 + * be using this instead of getApplyDirFile.
  1.1391 + *
  1.1392 + * @param   aRelPath (optional)
  1.1393 + *          The relative path to the file or directory to get from the root of
  1.1394 + *          the test's directory. If not specified the test's directory will be
  1.1395 + *          returned.
  1.1396 + * @param   aAllowNonexistent (optional)
  1.1397 + *          Whether the file must exist. If false or not specified the file must
  1.1398 + *          exist or the function will throw.
  1.1399 + * @return  The nsIFile for the directory where the update has been applied.
  1.1400 + */
  1.1401 +function getTargetDirFile(aRelPath, aAllowNonexistent) {
  1.1402 +  let relpath = getUpdatedDirPath() + (aRelPath ? aRelPath : "");
  1.1403 +  return do_get_file(relpath, aAllowNonexistent);
  1.1404 +}
  1.1405 +
  1.1406 +if (IS_WIN) {
  1.1407 +  const kLockFileName = "updated.update_in_progress.lock";
  1.1408 +  /**
  1.1409 +   * Helper function for locking a directory on Windows.
  1.1410 +   *
  1.1411 +   * @param   aDir
  1.1412 +   *          The nsIFile for the directory to lock.
  1.1413 +   */
  1.1414 +  function lockDirectory(aDir) {
  1.1415 +    var file = aDir.clone();
  1.1416 +    file.append(kLockFileName);
  1.1417 +    file.create(file.NORMAL_FILE_TYPE, 0o444);
  1.1418 +    file.QueryInterface(AUS_Ci.nsILocalFileWin);
  1.1419 +    file.fileAttributesWin |= file.WFA_READONLY;
  1.1420 +    file.fileAttributesWin &= ~file.WFA_READWRITE;
  1.1421 +    logTestInfo("testing the successful creation of the lock file");
  1.1422 +    do_check_true(file.exists());
  1.1423 +    do_check_false(file.isWritable());
  1.1424 +  }
  1.1425 +  /**
  1.1426 +   * Helper function for unlocking a directory on Windows.
  1.1427 +   *
  1.1428 +   * @param   aDir
  1.1429 +   *          The nsIFile for the directory to unlock.
  1.1430 +   */
  1.1431 +  function unlockDirectory(aDir) {
  1.1432 +    var file = aDir.clone();
  1.1433 +    file.append(kLockFileName);
  1.1434 +    file.QueryInterface(AUS_Ci.nsILocalFileWin);
  1.1435 +    file.fileAttributesWin |= file.WFA_READWRITE;
  1.1436 +    file.fileAttributesWin &= ~file.WFA_READONLY;
  1.1437 +    logTestInfo("removing and testing the successful removal of the lock file");
  1.1438 +    file.remove(false);
  1.1439 +    do_check_false(file.exists());
  1.1440 +  }
  1.1441 +}
  1.1442 +
  1.1443 +/**
  1.1444 + * Helper function for updater tests for launching the updater binary to apply
  1.1445 + * a mar file.
  1.1446 + *
  1.1447 + * @param   aExpectedExitValue
  1.1448 + *          The expected exit value from the updater binary.
  1.1449 + * @param   aExpectedStatus
  1.1450 + *          The expected value of update.status when the test finishes.
  1.1451 + * @param   aCallback (optional)
  1.1452 + *          A callback function that will be called when this function finishes.
  1.1453 + *          If null no function will be called when this function finishes.
  1.1454 + *          If not specified the checkUpdateApplied function will be called when
  1.1455 + *          this function finishes.
  1.1456 + */
  1.1457 +function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) {
  1.1458 +  // Copy the updater binary to the updates directory.
  1.1459 +  let binDir = gGREDirOrig.clone();
  1.1460 +  let updater = binDir.clone();
  1.1461 +  updater.append("updater.app");
  1.1462 +  if (!updater.exists()) {
  1.1463 +    updater = binDir.clone();
  1.1464 +    updater.append(FILE_UPDATER_BIN);
  1.1465 +    if (!updater.exists()) {
  1.1466 +      do_throw("Unable to find updater binary!");
  1.1467 +    }
  1.1468 +  }
  1.1469 +
  1.1470 +  let updatesDir = getUpdatesPatchDir();
  1.1471 +  updater.copyToFollowingLinks(updatesDir, updater.leafName);
  1.1472 +  let updateBin = updatesDir.clone();
  1.1473 +  updateBin.append(updater.leafName);
  1.1474 +  if (updateBin.leafName == "updater.app") {
  1.1475 +    updateBin.append("Contents");
  1.1476 +    updateBin.append("MacOS");
  1.1477 +    updateBin.append("updater");
  1.1478 +    if (!updateBin.exists()) {
  1.1479 +      do_throw("Unable to find the updater executable!");
  1.1480 +    }
  1.1481 +  }
  1.1482 +
  1.1483 +  let applyToDir = getApplyDirFile(null, true);
  1.1484 +  let applyToDirPath = applyToDir.path;
  1.1485 +  if (gStageUpdate || gSwitchApp) {
  1.1486 +    applyToDirPath += "/" + DIR_UPDATED + "/";
  1.1487 +  }
  1.1488 +
  1.1489 +  if (IS_WIN) {
  1.1490 +    // Convert to native path
  1.1491 +    applyToDirPath = applyToDirPath.replace(/\//g, "\\");
  1.1492 +  }
  1.1493 +
  1.1494 +  let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
  1.1495 +  callbackApp.permissions = PERMS_DIRECTORY;
  1.1496 +
  1.1497 +  let args = [updatesDir.path, applyToDirPath, 0];
  1.1498 +  if (gStageUpdate) {
  1.1499 +    args[2] = -1;
  1.1500 +  } else {
  1.1501 +    if (gSwitchApp) {
  1.1502 +      args[2] = "0/replace";
  1.1503 +    }
  1.1504 +    args = args.concat([callbackApp.parent.path, callbackApp.path]);
  1.1505 +    args = args.concat(gCallbackArgs);
  1.1506 +  }
  1.1507 +  logTestInfo("running the updater: " + updateBin.path + " " + args.join(" "));
  1.1508 +
  1.1509 +  let env = AUS_Cc["@mozilla.org/process/environment;1"].
  1.1510 +            getService(AUS_Ci.nsIEnvironment);
  1.1511 +  if (gDisableReplaceFallback) {
  1.1512 +    env.set("MOZ_NO_REPLACE_FALLBACK", "1");
  1.1513 +  }
  1.1514 +
  1.1515 +  let process = AUS_Cc["@mozilla.org/process/util;1"].
  1.1516 +                createInstance(AUS_Ci.nsIProcess);
  1.1517 +  process.init(updateBin);
  1.1518 +  process.run(true, args, args.length);
  1.1519 +
  1.1520 +  if (gDisableReplaceFallback) {
  1.1521 +    env.set("MOZ_NO_REPLACE_FALLBACK", "");
  1.1522 +  }
  1.1523 +
  1.1524 +  let status = readStatusFile();
  1.1525 +  if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) {
  1.1526 +    if (process.exitValue != aExpectedExitValue) {
  1.1527 +      logTestInfo("updater exited with unexpected value! Got: " +
  1.1528 +                  process.exitValue + ", Expected: " +  aExpectedExitValue);
  1.1529 +    }
  1.1530 +    if (status != aExpectedStatus) {
  1.1531 +      logTestInfo("update status is not the expected status! Got: " + status +
  1.1532 +                  ", Expected: " +  aExpectedStatus);
  1.1533 +    }
  1.1534 +    let updateLog = getUpdatesPatchDir();
  1.1535 +    updateLog.append(FILE_UPDATE_LOG);
  1.1536 +    logTestInfo("contents of " + updateLog.path + ":\n" +
  1.1537 +                readFileBytes(updateLog).replace(/\r\n/g, "\n"));
  1.1538 +  }
  1.1539 +  logTestInfo("testing updater binary process exitValue against expected " +
  1.1540 +              "exit value");
  1.1541 +  do_check_eq(process.exitValue, aExpectedExitValue);
  1.1542 +  logTestInfo("testing update status against expected status");
  1.1543 +  do_check_eq(status, aExpectedStatus);
  1.1544 +
  1.1545 +  if (aCallback !== null) {
  1.1546 +    if (typeof(aCallback) == typeof(Function)) {
  1.1547 +      aCallback();
  1.1548 +    } else {
  1.1549 +      checkUpdateApplied();
  1.1550 +    }
  1.1551 +  }
  1.1552 +}
  1.1553 +/**
  1.1554 + * Helper function for updater tests to stage an update.
  1.1555 + */
  1.1556 +function stageUpdate() {
  1.1557 +  logTestInfo("start - staging update");
  1.1558 +  Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
  1.1559 +
  1.1560 +  setEnvironment();
  1.1561 +  // Stage the update.
  1.1562 +  AUS_Cc["@mozilla.org/updates/update-processor;1"].
  1.1563 +    createInstance(AUS_Ci.nsIUpdateProcessor).
  1.1564 +    processUpdate(gUpdateManager.activeUpdate);
  1.1565 +  resetEnvironment();
  1.1566 +
  1.1567 +  logTestInfo("finish - staging update");
  1.1568 +}
  1.1569 +
  1.1570 +/**
  1.1571 + * Helper function to check whether the maintenance service updater tests should
  1.1572 + * run. See bug 711660 for more details.
  1.1573 + *
  1.1574 + * @param  aFirstTest
  1.1575 + *         Whether this is the first test within the test.
  1.1576 + * @return true if the test should run and false if it shouldn't.
  1.1577 + */
  1.1578 +function shouldRunServiceTest(aFirstTest) {
  1.1579 +  // In case the machine is running an old maintenance service or if it
  1.1580 +  // is not installed, and permissions exist to install it.  Then install
  1.1581 +  // the newer bin that we have.
  1.1582 +  attemptServiceInstall();
  1.1583 +
  1.1584 +  let binDir = getGREDir();
  1.1585 +  let updaterBin = binDir.clone();
  1.1586 +  updaterBin.append(FILE_UPDATER_BIN);
  1.1587 +  if (!updaterBin.exists()) {
  1.1588 +    do_throw("Unable to find updater binary!");
  1.1589 +  }
  1.1590 +
  1.1591 +  let updaterBinPath = updaterBin.path;
  1.1592 +  if (/ /.test(updaterBinPath)) {
  1.1593 +    updaterBinPath = '"' + updaterBinPath + '"';
  1.1594 +  }
  1.1595 +
  1.1596 +  const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" +
  1.1597 +                   "3932ecacee736d366d6436db0f55bce4";
  1.1598 +
  1.1599 +  let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
  1.1600 +            createInstance(AUS_Ci.nsIWindowsRegKey);
  1.1601 +  try {
  1.1602 +    key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
  1.1603 +             AUS_Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64);
  1.1604 +  } catch (e) {
  1.1605 +#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
  1.1606 +    // The build system could sign the files and not have the test registry key
  1.1607 +    // in which case we should fail the test by throwing so it can be fixed.
  1.1608 +    if (isBinarySigned(updaterBinPath)) {
  1.1609 +      do_throw("binary is signed but the test registry key does not exists!");
  1.1610 +    }
  1.1611 +#endif
  1.1612 +
  1.1613 +    logTestInfo("this test can only run on the buildbot build system at this " +
  1.1614 +                "time.");
  1.1615 +    return false;
  1.1616 +  }
  1.1617 +
  1.1618 +  // Check to make sure the service is installed
  1.1619 +  let helperBin = getTestDirFile(FILE_HELPER_BIN);
  1.1620 +  let args = ["wait-for-service-stop", "MozillaMaintenance", "10"];
  1.1621 +  let process = AUS_Cc["@mozilla.org/process/util;1"].
  1.1622 +                createInstance(AUS_Ci.nsIProcess);
  1.1623 +  process.init(helperBin);
  1.1624 +  logTestInfo("checking if the service exists on this machine.");
  1.1625 +  process.run(true, args, args.length);
  1.1626 +  if (process.exitValue == 0xEE) {
  1.1627 +    do_throw("test registry key exists but this test can only run on systems " +
  1.1628 +             "with the maintenance service installed.");
  1.1629 +  } else {
  1.1630 +    logTestInfo("service exists, return value: " + process.exitValue);
  1.1631 +  }
  1.1632 +
  1.1633 +  // If this is the first test in the series, then there is no reason the
  1.1634 +  // service should be anything but stopped, so be strict here and throw
  1.1635 +  // an error.
  1.1636 +  if (aFirstTest && process.exitValue != 0) {
  1.1637 +    do_throw("First test, check for service stopped state returned error " +
  1.1638 +             process.exitValue);
  1.1639 +  }
  1.1640 +
  1.1641 +#ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
  1.1642 +  if (!isBinarySigned(updaterBinPath)) {
  1.1643 +    logTestInfo("test registry key exists but this test can only run on " +
  1.1644 +                "builds with signed binaries when " +
  1.1645 +                "DISABLE_UPDATER_AUTHENTICODE_CHECK is not defined");
  1.1646 +    do_throw("this test can only run on builds with signed binaries.");
  1.1647 +  }
  1.1648 +#endif
  1.1649 +  return true;
  1.1650 +}
  1.1651 +
  1.1652 +/**
  1.1653 + * Helper function to check whether the a binary is signed.
  1.1654 + *
  1.1655 + * @param  aBinPath The path to the file to check if it is signed.
  1.1656 + * @return true if the file is signed and false if it isn't.
  1.1657 + */
  1.1658 +function isBinarySigned(aBinPath) {
  1.1659 +  let helperBin = getTestDirFile(FILE_HELPER_BIN);
  1.1660 +  let args = ["check-signature", aBinPath];
  1.1661 +  let process = AUS_Cc["@mozilla.org/process/util;1"].
  1.1662 +                createInstance(AUS_Ci.nsIProcess);
  1.1663 +  process.init(helperBin);
  1.1664 +  process.run(true, args, args.length);
  1.1665 +  if (process.exitValue != 0) {
  1.1666 +    logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " +
  1.1667 +                process.exitValue + " for file " + aBinPath);
  1.1668 +    return false;
  1.1669 +  }
  1.1670 +  return true;
  1.1671 +}
  1.1672 +
  1.1673 +/**
  1.1674 + * Helper function for asynchronously setting up the application files required
  1.1675 + * to launch the application for the updater tests by either copying or creating
  1.1676 + * symlinks for the files. This is needed for Windows debug builds which can
  1.1677 + * lock a file that is being copied so that the tests can run in parallel. After
  1.1678 + * the files have been copied the setupAppFilesFinished function will be called.
  1.1679 + */
  1.1680 +function setupAppFilesAsync() {
  1.1681 +  gTimeoutRuns++;
  1.1682 +  try {
  1.1683 +    setupAppFiles();
  1.1684 +  } catch (e) {
  1.1685 +    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
  1.1686 +      do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " +
  1.1687 +               "files. Exception: " + e);
  1.1688 +    }
  1.1689 +    do_timeout(TEST_CHECK_TIMEOUT, setupAppFilesAsync);
  1.1690 +    return;
  1.1691 +  }
  1.1692 +
  1.1693 +  setupAppFilesFinished();
  1.1694 +}
  1.1695 +
  1.1696 +/**
  1.1697 + * Helper function for setting up the application files required to launch the
  1.1698 + * application for the updater tests by either copying or creating symlinks for
  1.1699 + * the files.
  1.1700 + */
  1.1701 +function setupAppFiles() {
  1.1702 +  logTestInfo("start - copying or creating symlinks for application files " +
  1.1703 +              "for the test");
  1.1704 +
  1.1705 +  let srcDir = getCurrentProcessDir();
  1.1706 +  let destDir = getApplyDirFile(null, true);
  1.1707 +  if (!destDir.exists()) {
  1.1708 +    try {
  1.1709 +      destDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
  1.1710 +    } catch (e) {
  1.1711 +      logTestInfo("unable to create directory, Path: " + destDir.path +
  1.1712 +                  ", Exception: " + e);
  1.1713 +      do_throw(e);
  1.1714 +    }
  1.1715 +  }
  1.1716 +
  1.1717 +  // Required files for the application or the test that aren't listed in the
  1.1718 +  // dependentlibs.list file.
  1.1719 +  let fileRelPaths = [FILE_APP_BIN, FILE_UPDATER_BIN,
  1.1720 +                      "application.ini", "dependentlibs.list"];
  1.1721 +
  1.1722 +  // On Linux the updater.png must also be copied
  1.1723 +  if (IS_UNIX && !IS_MACOSX) {
  1.1724 +    fileRelPaths.push("icons/updater.png");
  1.1725 +  }
  1.1726 +
  1.1727 +  // Read the dependent libs file leafnames from the dependentlibs.list file
  1.1728 +  // into the array.
  1.1729 +  let deplibsFile = srcDir.clone();
  1.1730 +  deplibsFile.append("dependentlibs.list");
  1.1731 +  let istream = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
  1.1732 +                createInstance(AUS_Ci.nsIFileInputStream);
  1.1733 +  istream.init(deplibsFile, 0x01, 0o444, 0);
  1.1734 +  istream.QueryInterface(AUS_Ci.nsILineInputStream);
  1.1735 +
  1.1736 +  let hasMore;
  1.1737 +  let line = {};
  1.1738 +  do {
  1.1739 +    hasMore = istream.readLine(line);
  1.1740 +    fileRelPaths.push(line.value);
  1.1741 +  } while(hasMore);
  1.1742 +
  1.1743 +  istream.close();
  1.1744 +
  1.1745 +  fileRelPaths.forEach(function CMAF_FLN_FE(aFileRelPath) {
  1.1746 +    copyFileToTestAppDir(aFileRelPath);
  1.1747 +  });
  1.1748 +
  1.1749 +  logTestInfo("finish - copying or creating symlinks for application files " +
  1.1750 +              "for the test");
  1.1751 +}
  1.1752 +
  1.1753 +/**
  1.1754 + * Copies the specified files from the dist/bin directory into the test's
  1.1755 + * application directory.
  1.1756 + *
  1.1757 + * @param  aFileRelPath
  1.1758 + *         The relative path of the file to copy.
  1.1759 + */
  1.1760 +function copyFileToTestAppDir(aFileRelPath) {
  1.1761 +  let fileRelPath = aFileRelPath;
  1.1762 +  let srcFile = gGREDirOrig.clone();
  1.1763 +  let pathParts = fileRelPath.split("/");
  1.1764 +  for (let i = 0; i < pathParts.length; i++) {
  1.1765 +    if (pathParts[i]) {
  1.1766 +      srcFile.append(pathParts[i]);
  1.1767 +    }
  1.1768 +  }
  1.1769 +
  1.1770 +  if (IS_MACOSX && !srcFile.exists()) {
  1.1771 +    logTestInfo("unable to copy file since it doesn't exist! Checking if " +
  1.1772 +                 fileRelPath + ".app exists. Path: " +
  1.1773 +                 srcFile.path);
  1.1774 +    srcFile = gGREDirOrig.clone();
  1.1775 +    for (let i = 0; i < pathParts.length; i++) {
  1.1776 +      if (pathParts[i]) {
  1.1777 +        srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : ""));
  1.1778 +      }
  1.1779 +    }
  1.1780 +    fileRelPath = fileRelPath + ".app";
  1.1781 +  }
  1.1782 +
  1.1783 +  if (!srcFile.exists()) {
  1.1784 +    do_throw("Unable to copy file since it doesn't exist! Path: " +
  1.1785 +             srcFile.path);
  1.1786 +  }
  1.1787 +
  1.1788 +  // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a
  1.1789 +  // file extension and this will always be false on Windows.
  1.1790 +  let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" ||
  1.1791 +                       fileRelPath.substr(fileRelPath.length - 3) == ".so" ||
  1.1792 +                       fileRelPath.substr(fileRelPath.length - 6) == ".dylib");
  1.1793 +  let destFile = getApplyDirFile(DIR_BIN_REL_PATH + fileRelPath, true);
  1.1794 +  if (!shouldSymlink) {
  1.1795 +    if (!destFile.exists()) {
  1.1796 +      try {
  1.1797 +        srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName);
  1.1798 +      } catch (e) {
  1.1799 +        // Just in case it is partially copied
  1.1800 +        if (destFile.exists()) {
  1.1801 +          try {
  1.1802 +            destFile.remove(true);
  1.1803 +          } catch (e) {
  1.1804 +            logTestInfo("unable to remove file that failed to copy! Path: " +
  1.1805 +                        destFile.path);
  1.1806 +          }
  1.1807 +        }
  1.1808 +        do_throw("Unable to copy file! Path: " + srcFile.path +
  1.1809 +                 ", Exception: " + e);
  1.1810 +      }
  1.1811 +    }
  1.1812 +  } else {
  1.1813 +    try {
  1.1814 +      if (destFile.exists()) {
  1.1815 +        destFile.remove(false);
  1.1816 +      }
  1.1817 +      let ln = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile);
  1.1818 +      ln.initWithPath("/bin/ln");
  1.1819 +      let process = AUS_Cc["@mozilla.org/process/util;1"].createInstance(AUS_Ci.nsIProcess);
  1.1820 +      process.init(ln);
  1.1821 +      let args = ["-s", srcFile.path, destFile.path];
  1.1822 +      process.run(true, args, args.length);
  1.1823 +      logTestInfo("verifying symlink. Path: " + destFile.path);
  1.1824 +      do_check_true(destFile.isSymlink());
  1.1825 +    } catch (e) {
  1.1826 +      do_throw("Unable to create symlink for file! Path: " + srcFile.path +
  1.1827 +               ", Exception: " + e);
  1.1828 +    }
  1.1829 +  }
  1.1830 +}
  1.1831 +
  1.1832 +/**
  1.1833 + * Attempts to upgrade the maintenance service if permissions are allowed.
  1.1834 + * This is useful for XP where we have permission to upgrade in case an
  1.1835 + * older service installer exists.  Also if the user manually installed into
  1.1836 + * a unprivileged location.
  1.1837 + */
  1.1838 +function attemptServiceInstall() {
  1.1839 +  var version = AUS_Cc["@mozilla.org/system-info;1"]
  1.1840 +                .getService(AUS_Ci.nsIPropertyBag2)
  1.1841 +                .getProperty("version");
  1.1842 +  var isVistaOrHigher = (parseFloat(version) >= 6.0);
  1.1843 +  if (isVistaOrHigher) {
  1.1844 +    return;
  1.1845 +  }
  1.1846 +
  1.1847 +  let binDir = getGREDir();
  1.1848 +  let installerFile = binDir.clone();
  1.1849 +  installerFile.append(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
  1.1850 +  if (!installerFile.exists()) {
  1.1851 +    do_throw(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN + " not found.");
  1.1852 +  }
  1.1853 +  let installerProcess = AUS_Cc["@mozilla.org/process/util;1"].
  1.1854 +                         createInstance(AUS_Ci.nsIProcess);
  1.1855 +  installerProcess.init(installerFile);
  1.1856 +  logTestInfo("starting installer process...");
  1.1857 +  installerProcess.run(true, [], 0);
  1.1858 +}
  1.1859 +
  1.1860 +/**
  1.1861 + * Helper function for updater tests for launching the updater using the
  1.1862 + * maintenance service to apply a mar file.
  1.1863 + *
  1.1864 + * @param aInitialStatus
  1.1865 + *        The initial value of update.status.
  1.1866 + * @param aExpectedStatus
  1.1867 + *        The expected value of update.status when the test finishes.
  1.1868 + * @param aCheckSvcLog
  1.1869 + *        Whether the service log should be checked (optional).
  1.1870 + */
  1.1871 +function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) {
  1.1872 +  // Check the service logs for a successful update
  1.1873 +  function checkServiceLogs(aOriginalContents) {
  1.1874 +    let contents = readServiceLogFile();
  1.1875 +    logTestInfo("the contents of maintenanceservice.log:\n" + contents + "\n");
  1.1876 +    do_check_neq(contents, aOriginalContents);
  1.1877 +    do_check_neq(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1);
  1.1878 +  }
  1.1879 +  function readServiceLogFile() {
  1.1880 +    let file = AUS_Cc["@mozilla.org/file/directory_service;1"].
  1.1881 +               getService(AUS_Ci.nsIProperties).
  1.1882 +               get("CmAppData", AUS_Ci.nsIFile);
  1.1883 +    file.append("Mozilla");
  1.1884 +    file.append("logs");
  1.1885 +    file.append("maintenanceservice.log");
  1.1886 +    return readFile(file);
  1.1887 +  }
  1.1888 +  function waitServiceApps() {
  1.1889 +    // maintenanceservice_installer.exe is started async during updates.
  1.1890 +    waitForApplicationStop("maintenanceservice_installer.exe");
  1.1891 +    // maintenanceservice_tmp.exe is started async from the service installer.
  1.1892 +    waitForApplicationStop("maintenanceservice_tmp.exe");
  1.1893 +    // In case the SCM thinks the service is stopped, but process still exists.
  1.1894 +    waitForApplicationStop("maintenanceservice.exe");
  1.1895 +  }
  1.1896 +  function waitForServiceStop(aFailTest) {
  1.1897 +    waitServiceApps();
  1.1898 +    logTestInfo("waiting for service to stop if necessary...");
  1.1899 +    // Use the helper bin to ensure the service is stopped. If not
  1.1900 +    // stopped then wait for the service to be stopped (at most 120 seconds)
  1.1901 +    let helperBin = getTestDirFile(FILE_HELPER_BIN);
  1.1902 +    let helperBinArgs = ["wait-for-service-stop",
  1.1903 +                         "MozillaMaintenance",
  1.1904 +                         "120"];
  1.1905 +    let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"].
  1.1906 +                           createInstance(AUS_Ci.nsIProcess);
  1.1907 +    helperBinProcess.init(helperBin);
  1.1908 +    logTestInfo("stopping service...");
  1.1909 +    helperBinProcess.run(true, helperBinArgs, helperBinArgs.length);
  1.1910 +    if (helperBinProcess.exitValue == 0xEE) {
  1.1911 +      do_throw("The service does not exist on this machine.  Return value: " +
  1.1912 +               helperBinProcess.exitValue);
  1.1913 +    } else if (helperBinProcess.exitValue != 0) {
  1.1914 +      if (aFailTest) {
  1.1915 +        do_throw("maintenance service did not stop, last state: " +
  1.1916 +                 helperBinProcess.exitValue + ". Forcing test failure.");
  1.1917 +      } else {
  1.1918 +        logTestInfo("maintenance service did not stop, last state: " +
  1.1919 +                    helperBinProcess.exitValue + ".  May cause failures.");
  1.1920 +      }
  1.1921 +    } else {
  1.1922 +      logTestInfo("service stopped.");
  1.1923 +    }
  1.1924 +    waitServiceApps();
  1.1925 +  }
  1.1926 +  function waitForApplicationStop(aApplication) {
  1.1927 +    logTestInfo("waiting for " + aApplication + " to stop if " +
  1.1928 +                "necessary...");
  1.1929 +    // Use the helper bin to ensure the application is stopped.
  1.1930 +    // If not, then wait for it to be stopped (at most 120 seconds)
  1.1931 +    let helperBin = getTestDirFile(FILE_HELPER_BIN);
  1.1932 +    let helperBinArgs = ["wait-for-application-exit",
  1.1933 +                         aApplication,
  1.1934 +                         "120"];
  1.1935 +    let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"].
  1.1936 +                           createInstance(AUS_Ci.nsIProcess);
  1.1937 +    helperBinProcess.init(helperBin);
  1.1938 +    helperBinProcess.run(true, helperBinArgs, helperBinArgs.length);
  1.1939 +    if (helperBinProcess.exitValue != 0) {
  1.1940 +      do_throw(aApplication + " did not stop, last state: " +
  1.1941 +               helperBinProcess.exitValue + ". Forcing test failure.");
  1.1942 +    }
  1.1943 +  }
  1.1944 +
  1.1945 +  // Make sure the service from the previous test is already stopped.
  1.1946 +  waitForServiceStop(true);
  1.1947 +
  1.1948 +  // Prevent the cleanup function from begin run more than once
  1.1949 +  if (gRegisteredServiceCleanup === undefined) {
  1.1950 +    gRegisteredServiceCleanup = true;
  1.1951 +
  1.1952 +    do_register_cleanup(function RUUS_cleanup() {
  1.1953 +      resetEnvironment();
  1.1954 +
  1.1955 +      // This will delete the app arguments log file if it exists.
  1.1956 +      try {
  1.1957 +        getAppArgsLogPath();
  1.1958 +      } catch (e) {
  1.1959 +        logTestInfo("unable to remove file during cleanup. Exception: " + e);
  1.1960 +      }
  1.1961 +    });
  1.1962 +  }
  1.1963 +
  1.1964 +  let svcOriginalLog;
  1.1965 +  // Default to checking the service log if the parameter is not specified.
  1.1966 +  if (aCheckSvcLog === undefined || aCheckSvcLog) {
  1.1967 +    svcOriginalLog = readServiceLogFile();
  1.1968 +  }
  1.1969 +
  1.1970 +  let appArgsLogPath = getAppArgsLogPath();
  1.1971 +  gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, "");
  1.1972 +
  1.1973 +  let updatesDir = getUpdatesPatchDir();
  1.1974 +  let file = updatesDir.clone();
  1.1975 +  writeStatusFile(aInitialStatus);
  1.1976 +
  1.1977 +  // sanity check
  1.1978 +  do_check_eq(readStatusState(), aInitialStatus);
  1.1979 +
  1.1980 +  writeVersionFile(DEFAULT_UPDATE_VERSION);
  1.1981 +
  1.1982 +  gServiceLaunchedCallbackArgs = [
  1.1983 +    "-no-remote",
  1.1984 +    "-process-updates",
  1.1985 +    "-dump-args",
  1.1986 +    appArgsLogPath
  1.1987 +  ];
  1.1988 +
  1.1989 +  if (gSwitchApp) {
  1.1990 +    // We want to set the env vars again
  1.1991 +    gShouldResetEnv = undefined;
  1.1992 +  }
  1.1993 +
  1.1994 +  setEnvironment();
  1.1995 +
  1.1996 +  // There is a security check done by the service to make sure the updater
  1.1997 +  // we are executing is the same as the one in the apply-to dir.
  1.1998 +  // To make sure they match from tests we copy updater.exe to the apply-to dir.
  1.1999 +  copyFileToTestAppDir(FILE_UPDATER_BIN);
  1.2000 +
  1.2001 +  // The service will execute maintenanceservice_installer.exe and
  1.2002 +  // will copy maintenanceservice.exe out of the same directory from
  1.2003 +  // the installation directory.  So we need to make sure both of those
  1.2004 +  // bins always exist in the installation directory.
  1.2005 +  copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN);
  1.2006 +  copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
  1.2007 +
  1.2008 +  let launchBin = getLaunchBin();
  1.2009 +  let args = getProcessArgs(["-dump-args", appArgsLogPath]);
  1.2010 +
  1.2011 +  let process = AUS_Cc["@mozilla.org/process/util;1"].
  1.2012 +                   createInstance(AUS_Ci.nsIProcess);
  1.2013 +  process.init(launchBin);
  1.2014 +  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
  1.2015 +  // Firefox does not wait for the service command to finish, but
  1.2016 +  // we still launch the process sync to avoid intermittent failures with
  1.2017 +  // the log file not being written out yet.
  1.2018 +  // We will rely on watching the update.status file and waiting for the service
  1.2019 +  // to stop to know the service command is done.
  1.2020 +  process.run(true, args, args.length);
  1.2021 +
  1.2022 +  resetEnvironment();
  1.2023 +
  1.2024 +  function timerCallback(aTimer) {
  1.2025 +    // Wait for the expected status
  1.2026 +    let status = readStatusState();
  1.2027 +    // status will probably always be equal to STATE_APPLYING but there is a
  1.2028 +    // race condition where it would be possible on slower machines where status
  1.2029 +    // could be equal to STATE_PENDING_SVC.
  1.2030 +    if (status == STATE_APPLYING ||
  1.2031 +        status == STATE_PENDING_SVC) {
  1.2032 +      logTestInfo("still waiting to see the " + aExpectedStatus +
  1.2033 +                  " status, got " + status + " for now...");
  1.2034 +      return;
  1.2035 +    }
  1.2036 +
  1.2037 +    // Make sure all of the logs are written out.
  1.2038 +    waitForServiceStop(false);
  1.2039 +
  1.2040 +    aTimer.cancel();
  1.2041 +    aTimer = null;
  1.2042 +
  1.2043 +    if (status != aExpectedStatus) {
  1.2044 +      logTestInfo("update status is not the expected status! Got: " + status +
  1.2045 +                  ", Expected: " +  aExpectedStatus);
  1.2046 +      logTestInfo("update.status contents: " + readStatusFile());
  1.2047 +      let updateLog = getUpdatesPatchDir();
  1.2048 +      updateLog.append(FILE_UPDATE_LOG);
  1.2049 +      logTestInfo("contents of " + updateLog.path + ":\n" +
  1.2050 +                  readFileBytes(updateLog).replace(/\r\n/g, "\n"));
  1.2051 +    }
  1.2052 +    logTestInfo("testing update status against expected status");
  1.2053 +    do_check_eq(status, aExpectedStatus);
  1.2054 +
  1.2055 +    if (aCheckSvcLog) {
  1.2056 +      checkServiceLogs(svcOriginalLog);
  1.2057 +    }
  1.2058 +
  1.2059 +    checkUpdateFinished();
  1.2060 +  }
  1.2061 +
  1.2062 +  let timer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
  1.2063 +  timer.initWithCallback(timerCallback, 1000, timer.TYPE_REPEATING_SLACK);
  1.2064 +}
  1.2065 +
  1.2066 +/**
  1.2067 + * Gets the platform specific shell binary that is launched using nsIProcess and
  1.2068 + * in turn launches a binary used for the test (e.g. application, updater,
  1.2069 + * etc.). A shell is used so debug console output can be redirected to a file so
  1.2070 + * it doesn't end up in the test log.
  1.2071 + *
  1.2072 + * @return  nsIFile for the shell binary to launch using nsIProcess.
  1.2073 + * @throws  if the shell binary doesn't exist.
  1.2074 + */
  1.2075 +function getLaunchBin() {
  1.2076 +  let launchBin;
  1.2077 +  if (IS_WIN) {
  1.2078 +    launchBin = Services.dirsvc.get("WinD", AUS_Ci.nsIFile);
  1.2079 +    launchBin.append("System32");
  1.2080 +    launchBin.append("cmd.exe");
  1.2081 +  } else {
  1.2082 +    launchBin = AUS_Cc["@mozilla.org/file/local;1"].
  1.2083 +                createInstance(AUS_Ci.nsILocalFile);
  1.2084 +    launchBin.initWithPath("/bin/sh");
  1.2085 +  }
  1.2086 +
  1.2087 +  if (!launchBin.exists())
  1.2088 +    do_throw(launchBin.path + " must exist to run this test!");
  1.2089 +
  1.2090 +  return launchBin;
  1.2091 +}
  1.2092 +
  1.2093 +/**
  1.2094 + * Helper function that waits until the helper has completed its operations and
  1.2095 + * is in a sleep state before performing an update by calling doUpdate.
  1.2096 + */
  1.2097 +function waitForHelperSleep() {
  1.2098 +  gTimeoutRuns++;
  1.2099 +  // Give the lock file process time to lock the file before updating otherwise
  1.2100 +  // this test can fail intermittently on Windows debug builds.
  1.2101 +  let output = getApplyDirFile("a/b/output", true);
  1.2102 +  if (readFile(output) != "sleeping\n") {
  1.2103 +    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
  1.2104 +      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " +
  1.2105 +               "finish its operation. Path: " + output.path);
  1.2106 +    }
  1.2107 +    do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
  1.2108 +    return;
  1.2109 +  }
  1.2110 +  try {
  1.2111 +    output.remove(false);
  1.2112 +  }
  1.2113 +  catch (e) {
  1.2114 +    if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
  1.2115 +      do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper " +
  1.2116 +               "message file to no longer be in use. Path: " + output.path);
  1.2117 +    }
  1.2118 +    logTestInfo("failed to remove file. Path: " + output.path);
  1.2119 +    do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
  1.2120 +    return;
  1.2121 +  }
  1.2122 +  doUpdate();
  1.2123 +}
  1.2124 +
  1.2125 +/**
  1.2126 + * Helper function that waits until the helper has finished its operations
  1.2127 + * before calling waitForHelperFinishFileUnlock to verify that the helper's
  1.2128 + * input and output directories are no longer in use.
  1.2129 + */
  1.2130 +function waitForHelperFinished() {
  1.2131 +  // Give the lock file process time to lock the file before updating otherwise
  1.2132 +  // this test can fail intermittently on Windows debug builds.
  1.2133 +  let output = getApplyDirFile("a/b/output", true);
  1.2134 +  if (readFile(output) != "finished\n") {
  1.2135 +    do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinished);
  1.2136 +    return;
  1.2137 +  }
  1.2138 +  // Give the lock file process time to unlock the file before deleting the
  1.2139 +  // input and output files.
  1.2140 +  waitForHelperFinishFileUnlock();
  1.2141 +}
  1.2142 +
  1.2143 +/**
  1.2144 + * Helper function that waits until the helper's input and output files are no
  1.2145 + * longer in use before calling checkUpdate.
  1.2146 + */
  1.2147 +function waitForHelperFinishFileUnlock() {
  1.2148 +  try {
  1.2149 +    let output = getApplyDirFile("a/b/output", true);
  1.2150 +    if (output.exists()) {
  1.2151 +      output.remove(false);
  1.2152 +    }
  1.2153 +    let input = getApplyDirFile("a/b/input", true);
  1.2154 +    if (input.exists()) {
  1.2155 +      input.remove(false);
  1.2156 +    }
  1.2157 +  } catch (e) {
  1.2158 +    // Give the lock file process time to unlock the file before deleting the
  1.2159 +    // input and output files.
  1.2160 +    do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinishFileUnlock);
  1.2161 +    return;
  1.2162 +  }
  1.2163 +  checkUpdate();
  1.2164 +}
  1.2165 +
  1.2166 +/**
  1.2167 + * Helper function to tell the helper to finish and exit its sleep state.
  1.2168 + */
  1.2169 +function setupHelperFinish() {
  1.2170 +  let input = getApplyDirFile("a/b/input", true);
  1.2171 +  writeFile(input, "finish\n");
  1.2172 +  waitForHelperFinished();
  1.2173 +}
  1.2174 +
  1.2175 +/**
  1.2176 + * Helper function for updater binary tests that creates the files and
  1.2177 + * directories used by the test.
  1.2178 + *
  1.2179 + * @param   aMarFile
  1.2180 + *          The mar file for the update test.
  1.2181 + */
  1.2182 +function setupUpdaterTest(aMarFile, aUpdatedDirExists, aToBeDeletedDirExists) {
  1.2183 +  let updatesPatchDir = getUpdatesPatchDir();
  1.2184 +  if (!updatesPatchDir.exists()) {
  1.2185 +    updatesPatchDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
  1.2186 +  }
  1.2187 +  // Copy the mar that will be applied
  1.2188 +  let mar = getTestDirFile(aMarFile);
  1.2189 +  mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_ARCHIVE);
  1.2190 +
  1.2191 +  createUpdateSettingsINI();
  1.2192 +
  1.2193 +  let applyToDir = getApplyDirFile(null, true);
  1.2194 +  gTestFiles.forEach(function SUT_TF_FE(aTestFile) {
  1.2195 +    if (aTestFile.originalFile || aTestFile.originalContents) {
  1.2196 +      let testDir = getApplyDirFile(aTestFile.relPathDir, true);
  1.2197 +      if (!testDir.exists())
  1.2198 +        testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
  1.2199 +
  1.2200 +      let testFile;
  1.2201 +      if (aTestFile.originalFile) {
  1.2202 +        testFile = getTestDirFile(aTestFile.originalFile);
  1.2203 +        testFile.copyToFollowingLinks(testDir, aTestFile.fileName);
  1.2204 +        testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName);
  1.2205 +      } else {
  1.2206 +        testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName,
  1.2207 +                                   true);
  1.2208 +        writeFile(testFile, aTestFile.originalContents);
  1.2209 +      }
  1.2210 +
  1.2211 +      // Skip these tests on Windows and OS/2 since their
  1.2212 +      // implementaions of chmod doesn't really set permissions.
  1.2213 +      if (!IS_WIN && aTestFile.originalPerms) {
  1.2214 +        testFile.permissions = aTestFile.originalPerms;
  1.2215 +        // Store the actual permissions on the file for reference later after
  1.2216 +        // setting the permissions.
  1.2217 +        if (!aTestFile.comparePerms) {
  1.2218 +          aTestFile.comparePerms = testFile.permissions;
  1.2219 +        }
  1.2220 +      }
  1.2221 +    }
  1.2222 +  });
  1.2223 +
  1.2224 +  let helperBin = getTestDirFile(FILE_HELPER_BIN);
  1.2225 +  let afterApplyBinDir = getApplyDirFile("a/b/", true);
  1.2226 +  helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile);
  1.2227 +
  1.2228 +  // Add the test directory that will be updated for a successful update or left
  1.2229 +  // in the initial state for a failed update.
  1.2230 +  gTestDirs.forEach(function SUT_TD_FE(aTestDir) {
  1.2231 +    let testDir = getApplyDirFile(aTestDir.relPathDir, true);
  1.2232 +    if (!testDir.exists()) {
  1.2233 +      testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
  1.2234 +    }
  1.2235 +
  1.2236 +    if (aTestDir.files) {
  1.2237 +      aTestDir.files.forEach(function SUT_TD_F_FE(aTestFile) {
  1.2238 +        let testFile = getApplyDirFile(aTestDir.relPathDir + aTestFile, true);
  1.2239 +        if (!testFile.exists()) {
  1.2240 +          testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
  1.2241 +        }
  1.2242 +      });
  1.2243 +    }
  1.2244 +
  1.2245 +    if (aTestDir.subDirs) {
  1.2246 +      aTestDir.subDirs.forEach(function SUT_TD_SD_FE(aSubDir) {
  1.2247 +        let testSubDir = getApplyDirFile(aTestDir.relPathDir + aSubDir, true);
  1.2248 +        if (!testSubDir.exists()) {
  1.2249 +          testSubDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
  1.2250 +        }
  1.2251 +
  1.2252 +        if (aTestDir.subDirFiles) {
  1.2253 +          aTestDir.subDirFiles.forEach(function SUT_TD_SDF_FE(aTestFile) {
  1.2254 +            let testFile = getApplyDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true);
  1.2255 +            if (!testFile.exists()) {
  1.2256 +              testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
  1.2257 +            }
  1.2258 +          });
  1.2259 +        }
  1.2260 +      });
  1.2261 +    }
  1.2262 +  });
  1.2263 +
  1.2264 +  gTestExtraDirs[0].dirExists = aUpdatedDirExists;
  1.2265 +  gTestExtraDirs[1].dirExists = IS_WIN ? aToBeDeletedDirExists : false;
  1.2266 +}
  1.2267 +
  1.2268 +/**
  1.2269 + * Helper function for updater binary tests that creates the update-settings.ini
  1.2270 + * file.
  1.2271 + */
  1.2272 +function createUpdateSettingsINI() {
  1.2273 +  updateSettingsIni = getApplyDirFile(null, true);
  1.2274 +  if (IS_MACOSX) {
  1.2275 +    updateSettingsIni.append("Contents");
  1.2276 +    updateSettingsIni.append("MacOS");
  1.2277 +  }
  1.2278 +  updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
  1.2279 +  writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
  1.2280 +}
  1.2281 +
  1.2282 +/**
  1.2283 + * Helper function for updater binary tests for verifying the contents of the
  1.2284 + * update log after a successful update.
  1.2285 + *
  1.2286 + * @param   aCompareLogFile
  1.2287 + *          The log file to compare the update log with.
  1.2288 + */
  1.2289 +function checkUpdateLogContents(aCompareLogFile) {
  1.2290 +  let updateLog = getUpdatesPatchDir();
  1.2291 +  updateLog.append(FILE_UPDATE_LOG);
  1.2292 +  let updateLogContents = readFileBytes(updateLog);
  1.2293 +
  1.2294 +  // The channel-prefs.js is defined in gTestFilesCommon which will always be
  1.2295 +  // located to the end of gTestFiles.
  1.2296 +  if (gTestFiles.length > 1 &&
  1.2297 +	  gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
  1.2298 +	  !gTestFiles[gTestFiles.length - 1].originalContents) {
  1.2299 +    updateLogContents = updateLogContents.replace(/.* a\/b\/defaults\/.*/g, "");
  1.2300 +  }
  1.2301 +  if (gTestFiles.length > 2 &&
  1.2302 +	  gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
  1.2303 +	  !gTestFiles[gTestFiles.length - 2].originalContents) {
  1.2304 +    updateLogContents = updateLogContents.replace(/.* a\/b\/update-settings.ini.*/g, "");
  1.2305 +  }
  1.2306 +  if (gStageUpdate) {
  1.2307 +    // Skip the staged update messages
  1.2308 +    updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
  1.2309 +  } else if (gSwitchApp) {
  1.2310 +    // Skip the switch app request messages
  1.2311 +    updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
  1.2312 +    updateLogContents = updateLogContents.replace(/Performing a replace request/, "");
  1.2313 +  }
  1.2314 +  // Skip the source/destination lines since they contain absolute paths.
  1.2315 +  updateLogContents = updateLogContents.replace(/SOURCE DIRECTORY.*/g, "");
  1.2316 +  updateLogContents = updateLogContents.replace(/DESTINATION DIRECTORY.*/g, "");
  1.2317 +  // Skip lines that log failed attempts to open the callback executable.
  1.2318 +  updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, "");
  1.2319 +  if (gSwitchApp) {
  1.2320 +    // Remove the lines which contain absolute paths
  1.2321 +    updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, "");
  1.2322 +    if (IS_MACOSX) {
  1.2323 +      // Remove the entire section about moving the precomplete file as it contains
  1.2324 +      // absolute paths.
  1.2325 +      updateLogContents = updateLogContents.replace(/\n/g, "%%%EOL%%%");
  1.2326 +      updateLogContents = updateLogContents.replace(/Moving the precomplete file.*Finished moving the precomplete file/, "");
  1.2327 +      updateLogContents = updateLogContents.replace(/%%%EOL%%%/g, "\n");
  1.2328 +    }
  1.2329 +  }
  1.2330 +  updateLogContents = updateLogContents.replace(/\r/g, "");
  1.2331 +  // Replace error codes since they are different on each platform.
  1.2332 +  updateLogContents = updateLogContents.replace(/, err:.*\n/g, "\n");
  1.2333 +  // Replace to make the log parsing happy.
  1.2334 +  updateLogContents = updateLogContents.replace(/non-fatal error /g, "");
  1.2335 +  // The FindFile results when enumerating the filesystem on Windows is not
  1.2336 +  // determistic so the results matching the following need to be ignored.
  1.2337 +  updateLogContents = updateLogContents.replace(/.* a\/b\/7\/7text.*\n/g, "");
  1.2338 +  // Remove consecutive newlines
  1.2339 +  updateLogContents = updateLogContents.replace(/\n+/g, "\n");
  1.2340 +  // Remove leading and trailing newlines
  1.2341 +  updateLogContents = updateLogContents.replace(/^\n|\n$/g, "");
  1.2342 +  // The update log when running the service tests sometimes starts with data
  1.2343 +  // from the previous launch of the updater.
  1.2344 +  updateLogContents = updateLogContents.replace(/^calling QuitProgressUI\n[^\n]*\nUPDATE TYPE/g, "UPDATE TYPE");
  1.2345 +
  1.2346 +  let compareLogContents = "";
  1.2347 +  if (aCompareLogFile) {
  1.2348 +    compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile));
  1.2349 +  }
  1.2350 +  if (gSwitchApp) {
  1.2351 +    compareLogContents += LOG_SWITCH_SUCCESS;
  1.2352 +  }
  1.2353 +  // The channel-prefs.js is defined in gTestFilesCommon which will always be
  1.2354 +  // located to the end of gTestFiles.
  1.2355 +  if (gTestFiles.length > 1 &&
  1.2356 +	  gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
  1.2357 +	  !gTestFiles[gTestFiles.length - 1].originalContents) {
  1.2358 +    compareLogContents = compareLogContents.replace(/.* a\/b\/defaults\/.*/g, "");
  1.2359 +  }
  1.2360 +  if (gTestFiles.length > 2 &&
  1.2361 +	  gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
  1.2362 +	  !gTestFiles[gTestFiles.length - 2].originalContents) {
  1.2363 +    compareLogContents = compareLogContents.replace(/.* a\/b\/update-settings.ini.*/g, "");
  1.2364 +  }
  1.2365 +  // Remove leading and trailing newlines
  1.2366 +  compareLogContents = compareLogContents.replace(/\n+/g, "\n");
  1.2367 +  // Remove leading and trailing newlines
  1.2368 +  compareLogContents = compareLogContents.replace(/^\n|\n$/g, "");
  1.2369 +
  1.2370 +  // Don't write the contents of the file to the log to reduce log spam
  1.2371 +  // unless there is a failure.
  1.2372 +  if (compareLogContents == updateLogContents) {
  1.2373 +    logTestInfo("log contents are correct");
  1.2374 +    do_check_true(true);
  1.2375 +  } else {
  1.2376 +    logTestInfo("log contents are not correct");
  1.2377 +    do_check_eq(compareLogContents, updateLogContents);
  1.2378 +  }
  1.2379 +}
  1.2380 +
  1.2381 +/**
  1.2382 + * Helper function to check if the update log contains a string.
  1.2383 + *
  1.2384 + * @param   aCheckString
  1.2385 + *          The string to check if the update log contains.
  1.2386 + */
  1.2387 +function checkUpdateLogContains(aCheckString) {
  1.2388 +  let updateLog = getUpdatesPatchDir();
  1.2389 +  updateLog.append(FILE_UPDATE_LOG);
  1.2390 +  let updateLogContents = readFileBytes(updateLog);
  1.2391 +  if (updateLogContents.indexOf(aCheckString) != -1) {
  1.2392 +    logTestInfo("log file does contain: " + aCheckString);
  1.2393 +    do_check_true(true);
  1.2394 +  } else {
  1.2395 +    logTestInfo("log file does not contain: " + aCheckString);
  1.2396 +    logTestInfo("log file contents:\n" + updateLogContents);
  1.2397 +    do_check_true(false);
  1.2398 +  }
  1.2399 +}
  1.2400 +
  1.2401 +/**
  1.2402 + * Helper function for updater binary tests for verifying the state of files and
  1.2403 + * directories after a successful update.
  1.2404 + */
  1.2405 +function checkFilesAfterUpdateSuccess() {
  1.2406 +  logTestInfo("testing contents of files after a successful update");
  1.2407 +  gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) {
  1.2408 +    let testFile = getTargetDirFile(aTestFile.relPathDir + aTestFile.fileName,
  1.2409 +                                    true);
  1.2410 +    logTestInfo("testing file: " + testFile.path);
  1.2411 +    if (aTestFile.compareFile || aTestFile.compareContents) {
  1.2412 +      do_check_true(testFile.exists());
  1.2413 +
  1.2414 +      // Skip these tests on Windows and OS/2 since their
  1.2415 +      // implementaions of chmod doesn't really set permissions.
  1.2416 +      if (!IS_WIN && aTestFile.comparePerms) {
  1.2417 +        // Check if the permssions as set in the complete mar file are correct.
  1.2418 +        let logPerms = "testing file permissions - ";
  1.2419 +        if (aTestFile.originalPerms) {
  1.2420 +          logPerms += "original permissions: " +
  1.2421 +                      aTestFile.originalPerms.toString(8) + ", ";
  1.2422 +        }
  1.2423 +        logPerms += "compare permissions : " +
  1.2424 +                    aTestFile.comparePerms.toString(8) + ", ";
  1.2425 +        logPerms += "updated permissions : " + testFile.permissions.toString(8);
  1.2426 +        logTestInfo(logPerms);
  1.2427 +        do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff);
  1.2428 +      }
  1.2429 +
  1.2430 +      let fileContents1 = readFileBytes(testFile);
  1.2431 +      let fileContents2 = aTestFile.compareFile ?
  1.2432 +                          readFileBytes(getTestDirFile(aTestFile.compareFile)) :
  1.2433 +                          aTestFile.compareContents;
  1.2434 +      // Don't write the contents of the file to the log to reduce log spam
  1.2435 +      // unless there is a failure.
  1.2436 +      if (fileContents1 == fileContents2) {
  1.2437 +        logTestInfo("file contents are correct");
  1.2438 +        do_check_true(true);
  1.2439 +      } else {
  1.2440 +        logTestInfo("file contents are not correct");
  1.2441 +        do_check_eq(fileContents1, fileContents2);
  1.2442 +      }
  1.2443 +    } else {
  1.2444 +      do_check_false(testFile.exists());
  1.2445 +    }
  1.2446 +  });
  1.2447 +
  1.2448 +  logTestInfo("testing operations specified in removed-files were performed " +
  1.2449 +              "after a successful update");
  1.2450 +  gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) {
  1.2451 +    let testDir = getTargetDirFile(aTestDir.relPathDir, true);
  1.2452 +    logTestInfo("testing directory: " + testDir.path);
  1.2453 +    if (aTestDir.dirRemoved) {
  1.2454 +      do_check_false(testDir.exists());
  1.2455 +    } else {
  1.2456 +      do_check_true(testDir.exists());
  1.2457 +
  1.2458 +      if (aTestDir.files) {
  1.2459 +        aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) {
  1.2460 +          let testFile = getTargetDirFile(aTestDir.relPathDir + aTestFile, true);
  1.2461 +          logTestInfo("testing directory file: " + testFile.path);
  1.2462 +          if (aTestDir.filesRemoved) {
  1.2463 +            do_check_false(testFile.exists());
  1.2464 +          } else {
  1.2465 +            do_check_true(testFile.exists());
  1.2466 +          }
  1.2467 +        });
  1.2468 +      }
  1.2469 +
  1.2470 +      if (aTestDir.subDirs) {
  1.2471 +        aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) {
  1.2472 +          let testSubDir = getTargetDirFile(aTestDir.relPathDir + aSubDir, true);
  1.2473 +          logTestInfo("testing sub-directory: " + testSubDir.path);
  1.2474 +          do_check_true(testSubDir.exists());
  1.2475 +          if (aTestDir.subDirFiles) {
  1.2476 +            aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) {
  1.2477 +              let testFile = getTargetDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true);
  1.2478 +              logTestInfo("testing sub-directory file: " + testFile.path);
  1.2479 +              do_check_true(testFile.exists());
  1.2480 +            });
  1.2481 +          }
  1.2482 +        });
  1.2483 +      }
  1.2484 +    }
  1.2485 +  });
  1.2486 +
  1.2487 +  checkFilesAfterUpdateCommon();
  1.2488 +}
  1.2489 +
  1.2490 +/**
  1.2491 + * Helper function for updater binary tests for verifying the state of files and
  1.2492 + * directories after a failed update.
  1.2493 + *
  1.2494 + * @param aGetDirectory: the function used to get the files in the target directory.
  1.2495 + * Pass getApplyDirFile if you want to test the case of a failed switch request.
  1.2496 + */
  1.2497 +function checkFilesAfterUpdateFailure(aGetDirectory) {
  1.2498 +  let getdir = aGetDirectory || getTargetDirFile;
  1.2499 +  logTestInfo("testing contents of files after a failed update");
  1.2500 +  gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) {
  1.2501 +    let testFile = getdir(aTestFile.relPathDir + aTestFile.fileName, true);
  1.2502 +    logTestInfo("testing file: " + testFile.path);
  1.2503 +    if (aTestFile.compareFile || aTestFile.compareContents) {
  1.2504 +      do_check_true(testFile.exists());
  1.2505 +
  1.2506 +      // Skip these tests on Windows and OS/2 since their
  1.2507 +      // implementaions of chmod doesn't really set permissions.
  1.2508 +      if (!IS_WIN && aTestFile.comparePerms) {
  1.2509 +        // Check the original permssions are retained on the file.
  1.2510 +        let logPerms = "testing file permissions - ";
  1.2511 +        if (aTestFile.originalPerms) {
  1.2512 +          logPerms += "original permissions: " +
  1.2513 +                      aTestFile.originalPerms.toString(8) + ", ";
  1.2514 +        }
  1.2515 +        logPerms += "compare permissions : " +
  1.2516 +                    aTestFile.comparePerms.toString(8) + ", ";
  1.2517 +        logPerms += "updated permissions : " + testFile.permissions.toString(8);
  1.2518 +        logTestInfo(logPerms);
  1.2519 +        do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff);
  1.2520 +      }
  1.2521 +
  1.2522 +      let fileContents1 = readFileBytes(testFile);
  1.2523 +      let fileContents2 = aTestFile.compareFile ?
  1.2524 +                          readFileBytes(getTestDirFile(aTestFile.compareFile)) :
  1.2525 +                          aTestFile.compareContents;
  1.2526 +      // Don't write the contents of the file to the log to reduce log spam
  1.2527 +      // unless there is a failure.
  1.2528 +      if (fileContents1 == fileContents2) {
  1.2529 +        logTestInfo("file contents are correct");
  1.2530 +        do_check_true(true);
  1.2531 +      } else {
  1.2532 +        logTestInfo("file contents are not correct");
  1.2533 +        do_check_eq(fileContents1, fileContents2);
  1.2534 +      }
  1.2535 +    } else {
  1.2536 +      do_check_false(testFile.exists());
  1.2537 +    }
  1.2538 +  });
  1.2539 +
  1.2540 +  logTestInfo("testing operations specified in removed-files were not " +
  1.2541 +              "performed after a failed update");
  1.2542 +  gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) {
  1.2543 +    let testDir = getdir(aTestDir.relPathDir, true);
  1.2544 +    logTestInfo("testing directory: " + testDir.path);
  1.2545 +    do_check_true(testDir.exists());
  1.2546 +
  1.2547 +    if (aTestDir.files) {
  1.2548 +      aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) {
  1.2549 +        let testFile = getdir(aTestDir.relPathDir + aTestFile, true);
  1.2550 +        logTestInfo("testing directory file: " + testFile.path);
  1.2551 +        do_check_true(testFile.exists());
  1.2552 +      });
  1.2553 +    }
  1.2554 +
  1.2555 +    if (aTestDir.subDirs) {
  1.2556 +      aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) {
  1.2557 +        let testSubDir = getdir(aTestDir.relPathDir + aSubDir, true);
  1.2558 +        logTestInfo("testing sub-directory: " + testSubDir.path);
  1.2559 +        do_check_true(testSubDir.exists());
  1.2560 +        if (aTestDir.subDirFiles) {
  1.2561 +          aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) {
  1.2562 +            let testFile = getdir(aTestDir.relPathDir + aSubDir + aTestFile,
  1.2563 +                                  true);
  1.2564 +            logTestInfo("testing sub-directory file: " + testFile.path);
  1.2565 +            do_check_true(testFile.exists());
  1.2566 +          });
  1.2567 +        }
  1.2568 +      });
  1.2569 +    }
  1.2570 +  });
  1.2571 +
  1.2572 +  checkFilesAfterUpdateCommon();
  1.2573 +}
  1.2574 +
  1.2575 +/**
  1.2576 + * Helper function for updater binary tests for verifying the state of common
  1.2577 + * files and directories after a successful or failed update.
  1.2578 + */
  1.2579 +function checkFilesAfterUpdateCommon() {
  1.2580 +  logTestInfo("testing extra directories");
  1.2581 +  gTestExtraDirs.forEach(function CFAUC_TED_FE(aTestExtraDir) {
  1.2582 +    let testDir = getTargetDirFile(aTestExtraDir.relPathDir, true);
  1.2583 +    logTestInfo("testing directory: " + testDir.path);
  1.2584 +    if (aTestExtraDir.dirExists) {
  1.2585 +      do_check_true(testDir.exists());
  1.2586 +    } else {
  1.2587 +      do_check_false(testDir.exists());
  1.2588 +    }
  1.2589 +  });
  1.2590 +
  1.2591 +  logTestInfo("testing updating directory doesn't exist in the application " +
  1.2592 +	          "directory");
  1.2593 +  let updatingDir = getTargetDirFile("updating", true);
  1.2594 +  do_check_false(updatingDir.exists());
  1.2595 +
  1.2596 +  if (gStageUpdate) {
  1.2597 +    logTestInfo("testing updating directory doesn't exist in the updated " +
  1.2598 +		        "directory");
  1.2599 +    updatingDir = getApplyDirFile("updating", true);
  1.2600 +    do_check_false(updatingDir.exists());
  1.2601 +
  1.2602 +    // This should never exist since the update was applied to the updated
  1.2603 +	// directory and the files should never be in use.
  1.2604 +    logTestInfo("testing tobedeleted directory doesn't exist in the updated " +
  1.2605 +                "directory");
  1.2606 +    let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true);
  1.2607 +    do_check_false(toBeDeletedDir.exists());
  1.2608 +  }
  1.2609 +
  1.2610 +  logTestInfo("testing patch files should not be left behind");
  1.2611 +  let updatesDir = getUpdatesPatchDir();
  1.2612 +  let entries = updatesDir.QueryInterface(AUS_Ci.nsIFile).directoryEntries;
  1.2613 +  while (entries.hasMoreElements()) {
  1.2614 +    let entry = entries.getNext().QueryInterface(AUS_Ci.nsIFile);
  1.2615 +    do_check_neq(getFileExtension(entry), "patch");
  1.2616 +  }
  1.2617 +
  1.2618 +  logTestInfo("testing backup files should not be left behind");
  1.2619 +  let applyToDir = getTargetDirFile(null, true);
  1.2620 +  checkFilesInDirRecursive(applyToDir, checkForBackupFiles);
  1.2621 +}
  1.2622 +
  1.2623 +/**
  1.2624 + * Helper function for updater binary tests for verifying the contents of the
  1.2625 + * updater callback application log which should contain the arguments passed to
  1.2626 + * the callback application.
  1.2627 + */
  1.2628 +function checkCallbackAppLog() {
  1.2629 +  let appLaunchLog = getApplyDirFile("a/b/" + gCallbackArgs[1], true);
  1.2630 +  if (!appLaunchLog.exists()) {
  1.2631 +    do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog);
  1.2632 +    return;
  1.2633 +  }
  1.2634 +
  1.2635 +  let expectedLogContents = gCallbackArgs.join("\n") + "\n";
  1.2636 +  let logContents = readFile(appLaunchLog);
  1.2637 +  // It is possible for the log file contents check to occur before the log file
  1.2638 +  // contents are completely written so wait until the contents are the expected
  1.2639 +  // value. If the contents are never the expected value then the test will
  1.2640 +  // fail by timing out.
  1.2641 +  if (logContents != expectedLogContents) {
  1.2642 +    do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog);
  1.2643 +    return;
  1.2644 +  }
  1.2645 +
  1.2646 +  if (logContents == expectedLogContents) {
  1.2647 +    logTestInfo("callback log file contents are correct");
  1.2648 +    do_check_true(true);
  1.2649 +  } else {
  1.2650 +    logTestInfo("callback log file contents are not correct");
  1.2651 +    do_check_eq(logContents, expectedLogContents);
  1.2652 +  }
  1.2653 +
  1.2654 +  waitForFilesInUse();
  1.2655 +}
  1.2656 +
  1.2657 +/**
  1.2658 + * Helper function for updater service tests for verifying the contents of the
  1.2659 + * updater callback application log which should contain the arguments passed to
  1.2660 + * the callback application.
  1.2661 + */
  1.2662 +function checkCallbackServiceLog() {
  1.2663 +  do_check_neq(gServiceLaunchedCallbackLog, null);
  1.2664 +
  1.2665 +  let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n";
  1.2666 +  let logFile = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile);
  1.2667 +  logFile.initWithPath(gServiceLaunchedCallbackLog);
  1.2668 +  let logContents = readFile(logFile);
  1.2669 +  // It is possible for the log file contents check to occur before the log file
  1.2670 +  // contents are completely written so wait until the contents are the expected
  1.2671 +  // value. If the contents are never the expected value then the test will
  1.2672 +  // fail by timing out.
  1.2673 +  if (logContents != expectedLogContents) {
  1.2674 +    logTestInfo("callback service log not expected value, waiting longer");
  1.2675 +    do_timeout(TEST_HELPER_TIMEOUT, checkCallbackServiceLog);
  1.2676 +    return;
  1.2677 +  }
  1.2678 +
  1.2679 +  logTestInfo("testing that the callback application successfully launched " +
  1.2680 +              "and the expected command line arguments were passed to it");
  1.2681 +  do_check_eq(logContents, expectedLogContents);
  1.2682 +
  1.2683 +  waitForFilesInUse();
  1.2684 +}
  1.2685 +
  1.2686 +// Waits until files that are in use that break tests are no longer in use and
  1.2687 +// then calls do_test_finished.
  1.2688 +function waitForFilesInUse() {
  1.2689 +  if (IS_WIN) {
  1.2690 +    let appBin = getApplyDirFile(FILE_APP_BIN, true);
  1.2691 +    let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true);
  1.2692 +    let helper = getApplyDirFile("uninstall/helper.exe", true);
  1.2693 +    let updater = getUpdatesPatchDir();
  1.2694 +    updater.append(FILE_UPDATER_BIN);
  1.2695 +
  1.2696 +    let files = [appBin, updater, maintSvcInstaller, helper];
  1.2697 +
  1.2698 +    for (var i = 0; i < files.length; ++i) {
  1.2699 +      let file = files[i];
  1.2700 +      let fileBak = file.parent.clone();
  1.2701 +      if (file.exists()) {
  1.2702 +        fileBak.append(file.leafName + ".bak");
  1.2703 +        try {
  1.2704 +          if (fileBak.exists()) {
  1.2705 +            fileBak.remove(false);
  1.2706 +          }
  1.2707 +          file.copyTo(fileBak.parent, fileBak.leafName);
  1.2708 +          file.remove(false);
  1.2709 +          fileBak.moveTo(file.parent, file.leafName);
  1.2710 +          logTestInfo("file is not in use. Path: " + file.path);
  1.2711 +        } catch (e) {
  1.2712 +          logTestInfo("file in use, will try again after " + TEST_CHECK_TIMEOUT +
  1.2713 +                      " ms, Path: " + file.path + ", Exception: " + e);
  1.2714 +          try {
  1.2715 +            if (fileBak.exists()) {
  1.2716 +              fileBak.remove(false);
  1.2717 +            }
  1.2718 +          } catch (e) {
  1.2719 +            logTestInfo("unable to remove file, this should never happen! " +
  1.2720 +                        "Path: " + fileBak.path + ", Exception: " + e);
  1.2721 +          }
  1.2722 +          do_timeout(TEST_CHECK_TIMEOUT, waitForFilesInUse);
  1.2723 +          return;
  1.2724 +        }
  1.2725 +      }
  1.2726 +    }
  1.2727 +  }
  1.2728 +
  1.2729 +  logTestInfo("calling doTestFinish");
  1.2730 +  doTestFinish();
  1.2731 +}
  1.2732 +
  1.2733 +/**
  1.2734 + * Helper function for updater binary tests for verifying there are no update
  1.2735 + * backup files left behind after an update.
  1.2736 + *
  1.2737 + * @param   aFile
  1.2738 + *          An nsIFile to check if it has moz-backup for its extension.
  1.2739 + */
  1.2740 +function checkForBackupFiles(aFile) {
  1.2741 +  do_check_neq(getFileExtension(aFile), "moz-backup");
  1.2742 +}
  1.2743 +
  1.2744 +/**
  1.2745 + * Helper function for updater binary tests for recursively enumerating a
  1.2746 + * directory and calling a callback function with the file as a parameter for
  1.2747 + * each file found.
  1.2748 + *
  1.2749 + * @param   aDir
  1.2750 + *          A nsIFile for the directory to be deleted
  1.2751 + * @param   aCallback
  1.2752 + *          A callback function that will be called with the file as a
  1.2753 + *          parameter for each file found.
  1.2754 + */
  1.2755 +function checkFilesInDirRecursive(aDir, aCallback) {
  1.2756 +  if (!aDir.exists())
  1.2757 +    do_throw("Directory must exist!");
  1.2758 +
  1.2759 +  let dirEntries = aDir.directoryEntries;
  1.2760 +  while (dirEntries.hasMoreElements()) {
  1.2761 +    let entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
  1.2762 +
  1.2763 +    if (entry.isDirectory()) {
  1.2764 +      checkFilesInDirRecursive(entry, aCallback);
  1.2765 +    } else {
  1.2766 +      aCallback(entry);
  1.2767 +    }
  1.2768 +  }
  1.2769 +}
  1.2770 +
  1.2771 +/**
  1.2772 + * Sets up the bare bones XMLHttpRequest implementation below.
  1.2773 + *
  1.2774 + * @param   aCallback
  1.2775 + *          The callback function that will call the nsIDomEventListener's
  1.2776 + *          handleEvent method.
  1.2777 + *
  1.2778 + *          Example of the callback function
  1.2779 + *
  1.2780 + *            function callHandleEvent() {
  1.2781 + *              gXHR.status = gExpectedStatus;
  1.2782 + *              var e = { target: gXHR };
  1.2783 + *              gXHR.onload.handleEvent(e);
  1.2784 + *            }
  1.2785 + */
  1.2786 +function overrideXHR(aCallback) {
  1.2787 +  gXHRCallback = aCallback;
  1.2788 +  gXHR = new xhr();
  1.2789 +  var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
  1.2790 +  registrar.registerFactory(gXHR.classID, gXHR.classDescription,
  1.2791 +                            gXHR.contractID, gXHR);
  1.2792 +}
  1.2793 +
  1.2794 +
  1.2795 +/**
  1.2796 + * Bare bones XMLHttpRequest implementation for testing onprogress, onerror,
  1.2797 + * and onload nsIDomEventListener handleEvent.
  1.2798 + */
  1.2799 +function makeHandler(aVal) {
  1.2800 +  if (typeof aVal == "function")
  1.2801 +    return { handleEvent: aVal };
  1.2802 +  return aVal;
  1.2803 +}
  1.2804 +function xhr() {
  1.2805 +}
  1.2806 +xhr.prototype = {
  1.2807 +  overrideMimeType: function(aMimetype) { },
  1.2808 +  setRequestHeader: function(aHeader, aValue) { },
  1.2809 +  status: null,
  1.2810 +  channel: { set notificationCallbacks(aVal) { } },
  1.2811 +  _url: null,
  1.2812 +  _method: null,
  1.2813 +  open: function(aMethod, aUrl) {
  1.2814 +    gXHR.channel.originalURI = Services.io.newURI(aUrl, null, null);
  1.2815 +    gXHR._method = aMethod; gXHR._url = aUrl;
  1.2816 +  },
  1.2817 +  responseXML: null,
  1.2818 +  responseText: null,
  1.2819 +  send: function(aBody) {
  1.2820 +    do_execute_soon(gXHRCallback); // Use a timeout so the XHR completes
  1.2821 +  },
  1.2822 +  _onprogress: null,
  1.2823 +  set onprogress(aValue) { gXHR._onprogress = makeHandler(aValue); },
  1.2824 +  get onprogress() { return gXHR._onprogress; },
  1.2825 +  _onerror: null,
  1.2826 +  set onerror(aValue) { gXHR._onerror = makeHandler(aValue); },
  1.2827 +  get onerror() { return gXHR._onerror; },
  1.2828 +  _onload: null,
  1.2829 +  set onload(aValue) { gXHR._onload = makeHandler(aValue); },
  1.2830 +  get onload() { return gXHR._onload; },
  1.2831 +  addEventListener: function(aEvent, aValue, aCapturing) {
  1.2832 +    eval("gXHR._on" + aEvent + " = aValue");
  1.2833 +  },
  1.2834 +  flags: AUS_Ci.nsIClassInfo.SINGLETON,
  1.2835 +  implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
  1.2836 +  getHelperForLanguage: function(aLanguage) null,
  1.2837 +  getInterfaces: function(aCount) {
  1.2838 +    var interfaces = [AUS_Ci.nsISupports];
  1.2839 +    aCount.value = interfaces.length;
  1.2840 +    return interfaces;
  1.2841 +  },
  1.2842 +  classDescription: "XMLHttpRequest",
  1.2843 +  contractID: "@mozilla.org/xmlextras/xmlhttprequest;1",
  1.2844 +  classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"),
  1.2845 +  createInstance: function(aOuter, aIID) {
  1.2846 +    if (aOuter == null)
  1.2847 +      return gXHR.QueryInterface(aIID);
  1.2848 +    throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
  1.2849 +  },
  1.2850 +  QueryInterface: function(aIID) {
  1.2851 +    if (aIID.equals(AUS_Ci.nsIClassInfo) ||
  1.2852 +        aIID.equals(AUS_Ci.nsISupports))
  1.2853 +      return gXHR;
  1.2854 +    throw AUS_Cr.NS_ERROR_NO_INTERFACE;
  1.2855 +  },
  1.2856 +  get wrappedJSObject() { return this; }
  1.2857 +};
  1.2858 +
  1.2859 +/**
  1.2860 + * Helper function to override the update prompt component to verify whether it
  1.2861 + * is called or not.
  1.2862 + *
  1.2863 + * @param   aCallback
  1.2864 + *          The callback to call if the update prompt component is called.
  1.2865 + */
  1.2866 +function overrideUpdatePrompt(aCallback) {
  1.2867 +  var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
  1.2868 +  gUpdatePrompt = new UpdatePrompt();
  1.2869 +  gUpdatePromptCallback = aCallback;
  1.2870 +  registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription,
  1.2871 +                            gUpdatePrompt.contractID, gUpdatePrompt);
  1.2872 +}
  1.2873 +
  1.2874 +function UpdatePrompt() {
  1.2875 +  var fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded",
  1.2876 +             "showUpdateError", "showUpdateHistory", "showUpdateInstalled"];
  1.2877 +
  1.2878 +  fns.forEach(function(aPromptFn) {
  1.2879 +    UpdatePrompt.prototype[aPromptFn] = function() {
  1.2880 +      if (!gUpdatePromptCallback) {
  1.2881 +        return;
  1.2882 +      }
  1.2883 +
  1.2884 +      var callback = gUpdatePromptCallback[aPromptFn];
  1.2885 +      if (!callback) {
  1.2886 +        return;
  1.2887 +      }
  1.2888 +
  1.2889 +      callback.apply(gUpdatePromptCallback,
  1.2890 +                     Array.prototype.slice.call(arguments));
  1.2891 +    }
  1.2892 +  });
  1.2893 +}
  1.2894 +
  1.2895 +UpdatePrompt.prototype = {
  1.2896 +  flags: AUS_Ci.nsIClassInfo.SINGLETON,
  1.2897 +  implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
  1.2898 +  getHelperForLanguage: function(aLanguage) null,
  1.2899 +  getInterfaces: function(aCount) {
  1.2900 +    var interfaces = [AUS_Ci.nsISupports, AUS_Ci.nsIUpdatePrompt];
  1.2901 +    aCount.value = interfaces.length;
  1.2902 +    return interfaces;
  1.2903 +  },
  1.2904 +  classDescription: "UpdatePrompt",
  1.2905 +  contractID: "@mozilla.org/updates/update-prompt;1",
  1.2906 +  classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"),
  1.2907 +  createInstance: function(aOuter, aIID) {
  1.2908 +    if (aOuter == null)
  1.2909 +      return gUpdatePrompt.QueryInterface(aIID);
  1.2910 +    throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
  1.2911 +  },
  1.2912 +  QueryInterface: function(aIID) {
  1.2913 +    if (aIID.equals(AUS_Ci.nsIClassInfo) ||
  1.2914 +        aIID.equals(AUS_Ci.nsISupports) ||
  1.2915 +        aIID.equals(AUS_Ci.nsIUpdatePrompt))
  1.2916 +      return gUpdatePrompt;
  1.2917 +    throw AUS_Cr.NS_ERROR_NO_INTERFACE;
  1.2918 +  },
  1.2919 +};
  1.2920 +
  1.2921 +/* Update check listener */
  1.2922 +const updateCheckListener = {
  1.2923 +  onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) {
  1.2924 +  },
  1.2925 +
  1.2926 +  onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) {
  1.2927 +    gRequestURL = aRequest.channel.originalURI.spec;
  1.2928 +    gUpdateCount = aUpdateCount;
  1.2929 +    gUpdates = aUpdates;
  1.2930 +    logTestInfo("url = " + gRequestURL + ", " +
  1.2931 +                "request.status = " + aRequest.status + ", " +
  1.2932 +                "update.statusText = " + aRequest.statusText + ", " +
  1.2933 +                "updateCount = " + aUpdateCount);
  1.2934 +    // Use a timeout to allow the XHR to complete
  1.2935 +    do_execute_soon(gCheckFunc);
  1.2936 +  },
  1.2937 +
  1.2938 +  onError: function UCL_onError(aRequest, aUpdate) {
  1.2939 +    gRequestURL = aRequest.channel.originalURI.spec;
  1.2940 +    gStatusCode = aRequest.status;
  1.2941 +
  1.2942 +    gStatusText = aUpdate.statusText;
  1.2943 +    logTestInfo("url = " + gRequestURL + ", " +
  1.2944 +                "request.status = " + gStatusCode + ", " +
  1.2945 +                "update.statusText = " + gStatusText);
  1.2946 +    // Use a timeout to allow the XHR to complete
  1.2947 +    do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate));
  1.2948 +  },
  1.2949 +
  1.2950 +  QueryInterface: function(aIID) {
  1.2951 +    if (!aIID.equals(AUS_Ci.nsIUpdateCheckListener) &&
  1.2952 +        !aIID.equals(AUS_Ci.nsISupports))
  1.2953 +      throw AUS_Cr.NS_ERROR_NO_INTERFACE;
  1.2954 +    return this;
  1.2955 +  }
  1.2956 +};
  1.2957 +
  1.2958 +/* Update download listener - nsIRequestObserver */
  1.2959 +const downloadListener = {
  1.2960 +  onStartRequest: function DL_onStartRequest(aRequest, aContext) {
  1.2961 +  },
  1.2962 +
  1.2963 +  onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) {
  1.2964 +  },
  1.2965 +
  1.2966 +  onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) {
  1.2967 +  },
  1.2968 +
  1.2969 +  onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) {
  1.2970 +    gStatusResult = aStatus;
  1.2971 +    // Use a timeout to allow the request to complete
  1.2972 +    do_execute_soon(gCheckFunc);
  1.2973 +  },
  1.2974 +
  1.2975 +  QueryInterface: function DL_QueryInterface(aIID) {
  1.2976 +    if (!aIID.equals(AUS_Ci.nsIRequestObserver) &&
  1.2977 +        !aIID.equals(AUS_Ci.nsIProgressEventSink) &&
  1.2978 +        !aIID.equals(AUS_Ci.nsISupports))
  1.2979 +      throw AUS_Cr.NS_ERROR_NO_INTERFACE;
  1.2980 +    return this;
  1.2981 +  }
  1.2982 +};
  1.2983 +
  1.2984 +/**
  1.2985 + * Helper for starting the http server used by the tests
  1.2986 + */
  1.2987 +function start_httpserver() {
  1.2988 +  let dir = getTestDirFile();
  1.2989 +  logTestInfo("http server directory path: " + dir.path);
  1.2990 +
  1.2991 +  if (!dir.isDirectory()) {
  1.2992 +    do_throw("A file instead of a directory was specified for HttpServer " +
  1.2993 +             "registerDirectory! Path: " + dir.path + "\n");
  1.2994 +  }
  1.2995 +
  1.2996 +  AUS_Cu.import("resource://testing-common/httpd.js");
  1.2997 +  gTestserver = new HttpServer();
  1.2998 +  gTestserver.registerDirectory("/", dir);
  1.2999 +  gTestserver.start(-1);
  1.3000 +  let testserverPort = gTestserver.identity.primaryPort;
  1.3001 +  gURLData = URL_HOST + ":" + testserverPort + "/";
  1.3002 +  logTestInfo("http server port = " + testserverPort);
  1.3003 +}
  1.3004 +
  1.3005 +/**
  1.3006 + * Helper for stopping the http server used by the tests
  1.3007 + *
  1.3008 + * @param   aCallback
  1.3009 + *          The callback to call after stopping the http server.
  1.3010 + */
  1.3011 +function stop_httpserver(aCallback) {
  1.3012 +  do_check_true(!!aCallback);
  1.3013 +  gTestserver.stop(aCallback);
  1.3014 +}
  1.3015 +
  1.3016 +/**
  1.3017 + * Creates an nsIXULAppInfo
  1.3018 + *
  1.3019 + * @param   aID
  1.3020 + *          The ID of the test application
  1.3021 + * @param   aName
  1.3022 + *          A name for the test application
  1.3023 + * @param   aVersion
  1.3024 + *          The version of the application
  1.3025 + * @param   aPlatformVersion
  1.3026 + *          The gecko version of the application
  1.3027 + */
  1.3028 +function createAppInfo(aID, aName, aVersion, aPlatformVersion) {
  1.3029 +  const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
  1.3030 +  const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
  1.3031 +  var XULAppInfo = {
  1.3032 +    vendor: APP_INFO_VENDOR,
  1.3033 +    name: aName,
  1.3034 +    ID: aID,
  1.3035 +    version: aVersion,
  1.3036 +    appBuildID: "2007010101",
  1.3037 +    platformVersion: aPlatformVersion,
  1.3038 +    platformBuildID: "2007010101",
  1.3039 +    inSafeMode: false,
  1.3040 +    logConsoleErrors: true,
  1.3041 +    OS: "XPCShell",
  1.3042 +    XPCOMABI: "noarch-spidermonkey",
  1.3043 +
  1.3044 +    QueryInterface: function QueryInterface(aIID) {
  1.3045 +      if (aIID.equals(AUS_Ci.nsIXULAppInfo) ||
  1.3046 +          aIID.equals(AUS_Ci.nsIXULRuntime) ||
  1.3047 +#ifdef XP_WIN
  1.3048 +          aIID.equals(AUS_Ci.nsIWinAppHelper) ||
  1.3049 +#endif
  1.3050 +          aIID.equals(AUS_Ci.nsISupports))
  1.3051 +        return this;
  1.3052 +      throw AUS_Cr.NS_ERROR_NO_INTERFACE;
  1.3053 +    }
  1.3054 +  };
  1.3055 +
  1.3056 +  var XULAppInfoFactory = {
  1.3057 +    createInstance: function (aOuter, aIID) {
  1.3058 +      if (aOuter == null)
  1.3059 +        return XULAppInfo.QueryInterface(aIID);
  1.3060 +      throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
  1.3061 +    }
  1.3062 +  };
  1.3063 +
  1.3064 +  var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
  1.3065 +  registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
  1.3066 +                            XULAPPINFO_CONTRACTID, XULAppInfoFactory);
  1.3067 +}
  1.3068 +
  1.3069 +/**
  1.3070 + * Returns the platform specific arguments used by nsIProcess when launching
  1.3071 + * the application.
  1.3072 + *
  1.3073 + * @param   aExtraArgs (optional)
  1.3074 + *          An array of extra arguments to append to the default arguments.
  1.3075 + * @return  an array of arguments to be passed to nsIProcess.
  1.3076 + *
  1.3077 + * Note: a shell is necessary to pipe the application's console output which
  1.3078 + *       would otherwise pollute the xpcshell log.
  1.3079 + *
  1.3080 + * Command line arguments used when launching the application:
  1.3081 + * -no-remote prevents shell integration from being affected by an existing
  1.3082 + * application process.
  1.3083 + * -process-updates makes the application exits after being relaunched by the
  1.3084 + * updater.
  1.3085 + * the platform specific string defined by PIPE_TO_NULL to output both stdout
  1.3086 + * and stderr to null. This is needed to prevent output from the application
  1.3087 + * from ending up in the xpchsell log.
  1.3088 + */
  1.3089 +function getProcessArgs(aExtraArgs) {
  1.3090 +  if (!aExtraArgs) {
  1.3091 +    aExtraArgs = [];
  1.3092 +  }
  1.3093 +
  1.3094 +  let appBinPath = getApplyDirFile(DIR_BIN_REL_PATH + FILE_APP_BIN, false).path;
  1.3095 +  if (/ /.test(appBinPath)) {
  1.3096 +    appBinPath = '"' + appBinPath + '"';
  1.3097 +  }
  1.3098 +
  1.3099 +  let args;
  1.3100 +  if (IS_UNIX) {
  1.3101 +    let launchScript = getLaunchScript();
  1.3102 +    // Precreate the script with executable permissions
  1.3103 +    launchScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY);
  1.3104 +
  1.3105 +    let scriptContents = "#! /bin/sh\n";
  1.3106 +    scriptContents += appBinPath + " -no-remote -process-updates " +
  1.3107 +                      aExtraArgs.join(" ") + " " + PIPE_TO_NULL;
  1.3108 +    writeFile(launchScript, scriptContents);
  1.3109 +    logTestInfo("created " + launchScript.path + " containing:\n" +
  1.3110 +                scriptContents);
  1.3111 +    args = [launchScript.path];
  1.3112 +  } else {
  1.3113 +    args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-process-updates"].
  1.3114 +           concat(aExtraArgs).concat([PIPE_TO_NULL]);
  1.3115 +  }
  1.3116 +  return args;
  1.3117 +}
  1.3118 +
  1.3119 +/**
  1.3120 + * Gets a file path for the application to dump its arguments into.  This is used
  1.3121 + * to verify that a callback application is launched.
  1.3122 + *
  1.3123 + * @return  the file for the application to dump its arguments into.
  1.3124 + */
  1.3125 +function getAppArgsLogPath() {
  1.3126 +  let appArgsLog = do_get_file("/", true);
  1.3127 +  appArgsLog.append(gTestID + "_app_args_log");
  1.3128 +  if (appArgsLog.exists()) {
  1.3129 +    appArgsLog.remove(false);
  1.3130 +  }
  1.3131 +  let appArgsLogPath = appArgsLog.path;
  1.3132 +  if (/ /.test(appArgsLogPath)) {
  1.3133 +    appArgsLogPath = '"' + appArgsLogPath + '"';
  1.3134 +  }
  1.3135 +  return appArgsLogPath;
  1.3136 +}
  1.3137 +
  1.3138 +/**
  1.3139 + * Gets the nsIFile reference for the shell script to launch the application. If
  1.3140 + * the file exists it will be removed by this function.
  1.3141 + *
  1.3142 + * @return  the nsIFile for the shell script to launch the application.
  1.3143 + */
  1.3144 +function getLaunchScript() {
  1.3145 +  let launchScript = do_get_file("/", true);
  1.3146 +  launchScript.append(gTestID + "_launch.sh");
  1.3147 +  if (launchScript.exists()) {
  1.3148 +    launchScript.remove(false);
  1.3149 +  }
  1.3150 +  return launchScript;
  1.3151 +}
  1.3152 +
  1.3153 +/**
  1.3154 + * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so
  1.3155 + * xpcshell tests can run in parallel and to keep the environment clean.
  1.3156 + */
  1.3157 +function adjustGeneralPaths() {
  1.3158 +  let dirProvider = {
  1.3159 +    getFile: function AGP_DP_getFile(aProp, aPersistent) {
  1.3160 +      aPersistent.value = true;
  1.3161 +      switch (aProp) {
  1.3162 +        case NS_GRE_DIR:
  1.3163 +          if (gUseTestAppDir) {
  1.3164 +            return getApplyDirFile(DIR_BIN_REL_PATH, true);
  1.3165 +          }
  1.3166 +          break;
  1.3167 +        case XRE_EXECUTABLE_FILE:
  1.3168 +          if (gUseTestAppDir) {
  1.3169 +            return getApplyDirFile(DIR_BIN_REL_PATH + FILE_APP_BIN, true);
  1.3170 +          }
  1.3171 +          break;
  1.3172 +        case XRE_UPDATE_ROOT_DIR:
  1.3173 +          return getMockUpdRootD();
  1.3174 +      }
  1.3175 +      return null;
  1.3176 +    },
  1.3177 +    QueryInterface: function(aIID) {
  1.3178 +      if (aIID.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
  1.3179 +          aIID.equals(AUS_Ci.nsISupports))
  1.3180 +        return this;
  1.3181 +      throw AUS_Cr.NS_ERROR_NO_INTERFACE;
  1.3182 +    }
  1.3183 +  };
  1.3184 +  let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
  1.3185 +  ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR);
  1.3186 +  ds.QueryInterface(AUS_Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE);
  1.3187 +  ds.registerProvider(dirProvider);
  1.3188 +  do_register_cleanup(function AGP_cleanup() {
  1.3189 +    logTestInfo("start - unregistering directory provider");
  1.3190 +
  1.3191 +    if (gAppTimer) {
  1.3192 +      logTestInfo("start - cancel app timer");
  1.3193 +      gAppTimer.cancel();
  1.3194 +      gAppTimer = null;
  1.3195 +      logTestInfo("finish - cancel app timer");
  1.3196 +    }
  1.3197 +
  1.3198 +    if (gProcess && gProcess.isRunning) {
  1.3199 +      logTestInfo("start - kill process");
  1.3200 +      try {
  1.3201 +        gProcess.kill();
  1.3202 +      } catch (e) {
  1.3203 +        logTestInfo("kill process failed. Exception: " + e);
  1.3204 +      }
  1.3205 +      gProcess = null;
  1.3206 +      logTestInfo("finish - kill process");
  1.3207 +    }
  1.3208 +
  1.3209 +    if (gHandle) {
  1.3210 +      try {
  1.3211 +        logTestInfo("start - closing handle");
  1.3212 +        let kernel32 = ctypes.open("kernel32");
  1.3213 +        let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi,
  1.3214 +                                           ctypes.bool, /*return*/
  1.3215 +                                           ctypes.voidptr_t /*handle*/);
  1.3216 +        if (!CloseHandle(gHandle)) {
  1.3217 +          logTestInfo("call to CloseHandle failed");
  1.3218 +        }
  1.3219 +        kernel32.close();
  1.3220 +        gHandle = null;
  1.3221 +        logTestInfo("finish - closing handle");
  1.3222 +      } catch (e) {
  1.3223 +        logTestInfo("call to CloseHandle failed. Exception: " + e);
  1.3224 +      }
  1.3225 +    }
  1.3226 +
  1.3227 +    // Call end_test first before the directory provider is unregistered
  1.3228 +    if (typeof(end_test) == typeof(Function)) {
  1.3229 +      logTestInfo("calling end_test");
  1.3230 +      end_test();
  1.3231 +    }
  1.3232 +
  1.3233 +    ds.unregisterProvider(dirProvider);
  1.3234 +    cleanupTestCommon();
  1.3235 +
  1.3236 +    logTestInfo("finish - unregistering directory provider");
  1.3237 +  });
  1.3238 +}
  1.3239 +
  1.3240 +
  1.3241 +/**
  1.3242 + * Helper function for launching the application to apply an update.
  1.3243 + */
  1.3244 +function launchAppToApplyUpdate() {
  1.3245 +  logTestInfo("start - launching application to apply update");
  1.3246 +
  1.3247 +  let appBin = getApplyDirFile(DIR_BIN_REL_PATH + FILE_APP_BIN, false);
  1.3248 +
  1.3249 +  if (typeof(customLaunchAppToApplyUpdate) == typeof(Function)) {
  1.3250 +    customLaunchAppToApplyUpdate();
  1.3251 +  }
  1.3252 +
  1.3253 +  let launchBin = getLaunchBin();
  1.3254 +  let args = getProcessArgs();
  1.3255 +  logTestInfo("launching " + launchBin.path + " " + args.join(" "));
  1.3256 +
  1.3257 +  gProcess = AUS_Cc["@mozilla.org/process/util;1"].
  1.3258 +                createInstance(AUS_Ci.nsIProcess);
  1.3259 +  gProcess.init(launchBin);
  1.3260 +
  1.3261 +  gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
  1.3262 +  gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
  1.3263 +                             AUS_Ci.nsITimer.TYPE_ONE_SHOT);
  1.3264 +
  1.3265 +  setEnvironment();
  1.3266 +  logTestInfo("launching application");
  1.3267 +  gProcess.runAsync(args, args.length, gProcessObserver);
  1.3268 +  resetEnvironment();
  1.3269 +
  1.3270 +  logTestInfo("finish - launching application to apply update");
  1.3271 +}
  1.3272 +
  1.3273 +/**
  1.3274 + * The observer for the call to nsIProcess:runAsync.
  1.3275 + */
  1.3276 +let gProcessObserver = {
  1.3277 +  observe: function PO_observe(aSubject, aTopic, aData) {
  1.3278 +    logTestInfo("topic: " + aTopic + ", process exitValue: " +
  1.3279 +                gProcess.exitValue);
  1.3280 +    if (gAppTimer) {
  1.3281 +      gAppTimer.cancel();
  1.3282 +      gAppTimer = null;
  1.3283 +    }
  1.3284 +    if (aTopic != "process-finished" || gProcess.exitValue != 0) {
  1.3285 +      do_throw("Failed to launch application");
  1.3286 +    }
  1.3287 +    do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
  1.3288 +  },
  1.3289 +  QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
  1.3290 +};
  1.3291 +
  1.3292 +/**
  1.3293 + * The timer callback to kill the process if it takes too long.
  1.3294 + */
  1.3295 +let gTimerCallback = {
  1.3296 +  notify: function TC_notify(aTimer) {
  1.3297 +    gAppTimer = null;
  1.3298 +    if (gProcess.isRunning) {
  1.3299 +      logTestInfo("attempt to kill process");
  1.3300 +      gProcess.kill();
  1.3301 +    }
  1.3302 +    do_throw("launch application timer expired");
  1.3303 +  },
  1.3304 +  QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback])
  1.3305 +};
  1.3306 +
  1.3307 +/**
  1.3308 + * The update-staged observer for the call to nsIUpdateProcessor:processUpdate.
  1.3309 + */
  1.3310 +let gUpdateStagedObserver = {
  1.3311 +  observe: function(aSubject, aTopic, aData) {
  1.3312 +    if (aTopic == "update-staged") {
  1.3313 +      Services.obs.removeObserver(gUpdateStagedObserver, "update-staged");
  1.3314 +      checkUpdateApplied();
  1.3315 +    }
  1.3316 +  },
  1.3317 +  QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
  1.3318 +};
  1.3319 +
  1.3320 +/**
  1.3321 + * Sets the environment that will be used by the application process when it is
  1.3322 + * launched.
  1.3323 + */
  1.3324 +function setEnvironment() {
  1.3325 +  // Prevent setting the environment more than once.
  1.3326 +  if (gShouldResetEnv !== undefined)
  1.3327 +    return;
  1.3328 +
  1.3329 +  gShouldResetEnv = true;
  1.3330 +
  1.3331 +  let env = AUS_Cc["@mozilla.org/process/environment;1"].
  1.3332 +            getService(AUS_Ci.nsIEnvironment);
  1.3333 +  if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) {
  1.3334 +    gAddedEnvXRENoWindowsCrashDialog = true;
  1.3335 +    logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
  1.3336 +                "variable to 1... previously it didn't exist");
  1.3337 +    env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1");
  1.3338 +  }
  1.3339 +
  1.3340 +  if (IS_UNIX) {
  1.3341 +    let appGreDir = gGREDirOrig.clone();
  1.3342 +    let envGreDir = AUS_Cc["@mozilla.org/file/local;1"].
  1.3343 +                    createInstance(AUS_Ci.nsILocalFile);
  1.3344 +    let shouldSetEnv = true;
  1.3345 +    if (IS_MACOSX) {
  1.3346 +      if (env.exists("DYLD_LIBRARY_PATH")) {
  1.3347 +        gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH");
  1.3348 +        envGreDir.initWithPath(gEnvDyldLibraryPath);
  1.3349 +        if (envGreDir.path == appGreDir.path) {
  1.3350 +          gEnvDyldLibraryPath = null;
  1.3351 +          shouldSetEnv = false;
  1.3352 +        }
  1.3353 +      }
  1.3354 +
  1.3355 +      if (shouldSetEnv) {
  1.3356 +        logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " +
  1.3357 +                    appGreDir.path);
  1.3358 +        env.set("DYLD_LIBRARY_PATH", appGreDir.path);
  1.3359 +      }
  1.3360 +    } else {
  1.3361 +      if (env.exists("LD_LIBRARY_PATH")) {
  1.3362 +        gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH");
  1.3363 +        envGreDir.initWithPath(gEnvLdLibraryPath);
  1.3364 +        if (envGreDir.path == appGreDir.path) {
  1.3365 +          gEnvLdLibraryPath = null;
  1.3366 +          shouldSetEnv = false;
  1.3367 +        }
  1.3368 +      }
  1.3369 +
  1.3370 +      if (shouldSetEnv) {
  1.3371 +        logTestInfo("setting LD_LIBRARY_PATH environment variable value to " +
  1.3372 +                    appGreDir.path);
  1.3373 +        env.set("LD_LIBRARY_PATH", appGreDir.path);
  1.3374 +      }
  1.3375 +    }
  1.3376 +  }
  1.3377 +
  1.3378 +  if (env.exists("XPCOM_MEM_LEAK_LOG")) {
  1.3379 +    gEnvXPCOMMemLeakLog = env.get("XPCOM_MEM_LEAK_LOG");
  1.3380 +    logTestInfo("removing the XPCOM_MEM_LEAK_LOG environment variable... " +
  1.3381 +                "previous value " + gEnvXPCOMMemLeakLog);
  1.3382 +    env.set("XPCOM_MEM_LEAK_LOG", "");
  1.3383 +  }
  1.3384 +
  1.3385 +  if (env.exists("XPCOM_DEBUG_BREAK")) {
  1.3386 +    gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK");
  1.3387 +    logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " +
  1.3388 +                "warn... previous value " + gEnvXPCOMDebugBreak);
  1.3389 +  } else {
  1.3390 +    logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " +
  1.3391 +                "warn... previously it didn't exist");
  1.3392 +  }
  1.3393 +
  1.3394 +  env.set("XPCOM_DEBUG_BREAK", "warn");
  1.3395 +
  1.3396 +  if (gStageUpdate) {
  1.3397 +    logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1\n");
  1.3398 +    env.set("MOZ_UPDATE_STAGING", "1");
  1.3399 +  }
  1.3400 +
  1.3401 +  logTestInfo("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1");
  1.3402 +  env.set("MOZ_NO_SERVICE_FALLBACK", "1");
  1.3403 +}
  1.3404 +
  1.3405 +/**
  1.3406 + * Sets the environment back to the original values after launching the
  1.3407 + * application.
  1.3408 + */
  1.3409 +function resetEnvironment() {
  1.3410 +  // Prevent resetting the environment more than once.
  1.3411 +  if (gShouldResetEnv !== true)
  1.3412 +    return;
  1.3413 +
  1.3414 +  gShouldResetEnv = false;
  1.3415 +
  1.3416 +  let env = AUS_Cc["@mozilla.org/process/environment;1"].
  1.3417 +            getService(AUS_Ci.nsIEnvironment);
  1.3418 +
  1.3419 +  if (gEnvXPCOMMemLeakLog) {
  1.3420 +    logTestInfo("setting the XPCOM_MEM_LEAK_LOG environment variable back to " +
  1.3421 +                gEnvXPCOMMemLeakLog);
  1.3422 +    env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog);
  1.3423 +  }
  1.3424 +
  1.3425 +  if (gEnvXPCOMDebugBreak) {
  1.3426 +    logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " +
  1.3427 +                gEnvXPCOMDebugBreak);
  1.3428 +    env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak);
  1.3429 +  } else {
  1.3430 +    logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable");
  1.3431 +    env.set("XPCOM_DEBUG_BREAK", "");
  1.3432 +  }
  1.3433 +
  1.3434 +  if (IS_UNIX) {
  1.3435 +    if (IS_MACOSX) {
  1.3436 +      if (gEnvDyldLibraryPath) {
  1.3437 +        logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " +
  1.3438 +                    "back to " + gEnvDyldLibraryPath);
  1.3439 +        env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath);
  1.3440 +      } else {
  1.3441 +        logTestInfo("removing DYLD_LIBRARY_PATH environment variable");
  1.3442 +        env.set("DYLD_LIBRARY_PATH", "");
  1.3443 +      }
  1.3444 +    } else {
  1.3445 +      if (gEnvLdLibraryPath) {
  1.3446 +        logTestInfo("setting LD_LIBRARY_PATH environment variable value back " +
  1.3447 +                    "to " + gEnvLdLibraryPath);
  1.3448 +        env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath);
  1.3449 +      } else {
  1.3450 +        logTestInfo("removing LD_LIBRARY_PATH environment variable");
  1.3451 +        env.set("LD_LIBRARY_PATH", "");
  1.3452 +      }
  1.3453 +    }
  1.3454 +  }
  1.3455 +
  1.3456 +  if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) {
  1.3457 +    logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
  1.3458 +                "variable");
  1.3459 +    env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "");
  1.3460 +  }
  1.3461 +
  1.3462 +  if (gStageUpdate) {
  1.3463 +    logTestInfo("removing the MOZ_UPDATE_STAGING environment variable\n");
  1.3464 +    env.set("MOZ_UPDATE_STAGING", "");
  1.3465 +  }
  1.3466 +
  1.3467 +  logTestInfo("removing MOZ_NO_SERVICE_FALLBACK environment variable");
  1.3468 +  env.set("MOZ_NO_SERVICE_FALLBACK", "");
  1.3469 +}

mercurial