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

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 4
michael@0 5 const INSTALL_LOCALE = "@AB_CD@";
michael@0 6 const MOZ_APP_NAME = "@MOZ_APP_NAME@";
michael@0 7 const BIN_SUFFIX = "@BIN_SUFFIX@";
michael@0 8
michael@0 9 #ifdef XP_WIN
michael@0 10 // MOZ_APP_VENDOR is optional.
michael@0 11 // On Windows, if MOZ_APP_VENDOR is not defined the updates directory will be
michael@0 12 // located under %LOCALAPPDATA%\@MOZ_APP_BASENAME@\updates\TaskBarID
michael@0 13 #ifdef MOZ_APP_VENDOR
michael@0 14 const MOZ_APP_VENDOR = "@MOZ_APP_VENDOR@";
michael@0 15 #else
michael@0 16 const MOZ_APP_VENDOR = "";
michael@0 17 #endif
michael@0 18
michael@0 19 // MOZ_APP_BASENAME is not optional for tests.
michael@0 20 const MOZ_APP_BASENAME = "@MOZ_APP_BASENAME@";
michael@0 21 #endif // XP_WIN
michael@0 22
michael@0 23 const APP_INFO_NAME = "XPCShell";
michael@0 24 const APP_INFO_VENDOR = "Mozilla";
michael@0 25
michael@0 26 #ifdef XP_UNIX
michael@0 27 const APP_BIN_SUFFIX = "-bin";
michael@0 28 #else
michael@0 29 const APP_BIN_SUFFIX = "@BIN_SUFFIX@";
michael@0 30 #endif
michael@0 31
michael@0 32 #ifdef XP_WIN
michael@0 33 const IS_WIN = true;
michael@0 34 #else
michael@0 35 const IS_WIN = false;
michael@0 36 #endif
michael@0 37
michael@0 38 #ifdef XP_MACOSX
michael@0 39 const IS_MACOSX = true;
michael@0 40 #ifdef MOZ_SHARK
michael@0 41 const IS_SHARK = true;
michael@0 42 #else
michael@0 43 const IS_SHARK = false;
michael@0 44 #endif
michael@0 45 #else
michael@0 46 const IS_MACOSX = false;
michael@0 47 #endif
michael@0 48
michael@0 49 #ifdef XP_UNIX
michael@0 50 const IS_UNIX = true;
michael@0 51 #else
michael@0 52 const IS_UNIX = false;
michael@0 53 #endif
michael@0 54
michael@0 55 #ifdef ANDROID
michael@0 56 const IS_ANDROID = true;
michael@0 57 #else
michael@0 58 const IS_ANDROID = false;
michael@0 59 #endif
michael@0 60
michael@0 61 #ifdef MOZ_WIDGET_GONK
michael@0 62 const IS_TOOLKIT_GONK = true;
michael@0 63 #else
michael@0 64 const IS_TOOLKIT_GONK = false;
michael@0 65 #endif
michael@0 66
michael@0 67 const USE_EXECV = IS_UNIX && !IS_MACOSX;
michael@0 68
michael@0 69 #ifdef MOZ_VERIFY_MAR_SIGNATURE
michael@0 70 const IS_MAR_CHECKS_ENABLED = true;
michael@0 71 #else
michael@0 72 const IS_MAR_CHECKS_ENABLED = false;
michael@0 73 #endif
michael@0 74
michael@0 75 const URL_HOST = "http://localhost";
michael@0 76
michael@0 77 const FILE_APP_BIN = MOZ_APP_NAME + APP_BIN_SUFFIX;
michael@0 78 const FILE_COMPLETE_EXE = "complete.exe";
michael@0 79 const FILE_COMPLETE_MAR = "complete.mar";
michael@0 80 const FILE_HELPER_BIN = "TestAUSHelper" + BIN_SUFFIX;
michael@0 81 const FILE_MAINTENANCE_SERVICE_BIN = "maintenanceservice.exe";
michael@0 82 const FILE_MAINTENANCE_SERVICE_INSTALLER_BIN = "maintenanceservice_installer.exe";
michael@0 83 const FILE_OLD_VERSION_MAR = "old_version.mar";
michael@0 84 const FILE_PARTIAL_EXE = "partial.exe";
michael@0 85 const FILE_PARTIAL_MAR = "partial.mar";
michael@0 86 const FILE_UPDATER_BIN = "updater" + BIN_SUFFIX;
michael@0 87 const FILE_UPDATER_INI_BAK = "updater.ini.bak";
michael@0 88 const FILE_WRONG_CHANNEL_MAR = "wrong_product_channel.mar";
michael@0 89
michael@0 90 const LOG_COMPLETE_SUCCESS = "complete_log_success";
michael@0 91 const LOG_PARTIAL_SUCCESS = "partial_log_success";
michael@0 92 const LOG_PARTIAL_FAILURE = "partial_log_failure";
michael@0 93
michael@0 94 const LOG_SWITCH_SUCCESS = "rename_file: proceeding to rename the directory\n" +
michael@0 95 "rename_file: proceeding to rename the directory\n" +
michael@0 96 "Now, remove the tmpDir\n" +
michael@0 97 "succeeded\n" +
michael@0 98 "calling QuitProgressUI";
michael@0 99
michael@0 100 const ERR_RENAME_FILE = "rename_file: failed to rename file";
michael@0 101 const ERR_UNABLE_OPEN_DEST = "unable to open destination file";
michael@0 102 const ERR_BACKUP_DISCARD = "backup_discard: unable to remove";
michael@0 103
michael@0 104 const LOG_SVC_SUCCESSFUL_LAUNCH = "Process was started... waiting on result.";
michael@0 105
michael@0 106 // All we care about is that the last modified time has changed so that Mac OS
michael@0 107 // X Launch Services invalidates its cache so the test allows up to one minute
michael@0 108 // difference in the last modified time.
michael@0 109 const MAC_MAX_TIME_DIFFERENCE = 60000;
michael@0 110
michael@0 111 // Time to wait for the test helper process before continuing the test
michael@0 112 const TEST_HELPER_TIMEOUT = 100;
michael@0 113
michael@0 114 // Time to wait for a check in the test before continuing the test
michael@0 115 const TEST_CHECK_TIMEOUT = 100;
michael@0 116
michael@0 117 // How many of TEST_CHECK_TIMEOUT to wait before we abort the test.
michael@0 118 const MAX_TIMEOUT_RUNS = 2000;
michael@0 119
michael@0 120 // Time in seconds the helper application should sleep.the helper's input and output files
michael@0 121 const HELPER_SLEEP_TIMEOUT = 180;
michael@0 122
michael@0 123 // Maximum number of milliseconds the process that is launched can run before
michael@0 124 // the test will try to kill it.
michael@0 125 const APP_TIMER_TIMEOUT = 120000;
michael@0 126
michael@0 127 #ifdef XP_WIN
michael@0 128 const PIPE_TO_NULL = ">nul";
michael@0 129 #else
michael@0 130 const PIPE_TO_NULL = "> /dev/null 2>&1";
michael@0 131 #endif
michael@0 132
michael@0 133 // This default value will be overridden when using the http server.
michael@0 134 var gURLData = URL_HOST + "/";
michael@0 135
michael@0 136 var gTestID;
michael@0 137
michael@0 138 var gTestserver;
michael@0 139
michael@0 140 var gRegisteredServiceCleanup;
michael@0 141
michael@0 142 var gXHR;
michael@0 143 var gXHRCallback;
michael@0 144
michael@0 145 var gUpdatePrompt;
michael@0 146 var gUpdatePromptCallback;
michael@0 147
michael@0 148 var gCheckFunc;
michael@0 149 var gResponseBody;
michael@0 150 var gResponseStatusCode = 200;
michael@0 151 var gRequestURL;
michael@0 152 var gUpdateCount;
michael@0 153 var gUpdates;
michael@0 154 var gStatusCode;
michael@0 155 var gStatusText;
michael@0 156 var gStatusResult;
michael@0 157
michael@0 158 var gProcess;
michael@0 159 var gAppTimer;
michael@0 160 var gHandle;
michael@0 161
michael@0 162 var gGREDirOrig;
michael@0 163 var gAppDirOrig;
michael@0 164
michael@0 165 var gServiceLaunchedCallbackLog = null;
michael@0 166 var gServiceLaunchedCallbackArgs = null;
michael@0 167
michael@0 168 // Variables are used instead of contants so tests can override these values if
michael@0 169 // necessary.
michael@0 170 var gCallbackBinFile = "callback_app" + BIN_SUFFIX;
michael@0 171 var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"];
michael@0 172 var gStageUpdate = false;
michael@0 173 var gSwitchApp = false;
michael@0 174 var gDisableReplaceFallback = false;
michael@0 175 var gUseTestAppDir = true;
michael@0 176
michael@0 177 var gTimeoutRuns = 0;
michael@0 178
michael@0 179 // Environment related globals
michael@0 180 var gShouldResetEnv = undefined;
michael@0 181 var gAddedEnvXRENoWindowsCrashDialog = false;
michael@0 182 var gEnvXPCOMDebugBreak;
michael@0 183 var gEnvXPCOMMemLeakLog;
michael@0 184 var gEnvDyldLibraryPath;
michael@0 185 var gEnvLdLibraryPath;
michael@0 186
michael@0 187 // Set to true to log additional information for debugging. To log additional
michael@0 188 // information for an individual test set DEBUG_AUS_TEST to true in the test's
michael@0 189 // run_test function.
michael@0 190 var DEBUG_AUS_TEST = true;
michael@0 191 // Never set DEBUG_TEST_LOG to true except when running tests locally or on the
michael@0 192 // try server since this will force a test that failed a parallel run to fail
michael@0 193 // when the same test runs non-parallel so the log from parallel test run can
michael@0 194 // be displayed in the log.
michael@0 195 var DEBUG_TEST_LOG = false;
michael@0 196 // Set to false to keep the log file from the failed parallel test run.
michael@0 197 var gDeleteLogFile = true;
michael@0 198 var gRealDump;
michael@0 199 var gTestLogText = "";
michael@0 200 var gPassed;
michael@0 201
michael@0 202 #include ../shared.js
michael@0 203
michael@0 204 var gTestFiles = [];
michael@0 205 var gTestDirs = [];
michael@0 206
michael@0 207 // Common files for both successful and failed updates.
michael@0 208 var gTestFilesCommon = [
michael@0 209 {
michael@0 210 description : "Should never change",
michael@0 211 fileName : FILE_UPDATE_SETTINGS_INI,
michael@0 212 relPathDir : "a/b/",
michael@0 213 originalContents : "ShouldNotBeReplaced\n",
michael@0 214 compareContents : "ShouldNotBeReplaced\n",
michael@0 215 originalFile : null,
michael@0 216 compareFile : null,
michael@0 217 originalPerms : 0o767,
michael@0 218 comparePerms : 0o767
michael@0 219 }, {
michael@0 220 description : "Should never change",
michael@0 221 fileName : "channel-prefs.js",
michael@0 222 relPathDir : "a/b/defaults/pref/",
michael@0 223 originalContents : "ShouldNotBeReplaced\n",
michael@0 224 compareContents : "ShouldNotBeReplaced\n",
michael@0 225 originalFile : null,
michael@0 226 compareFile : null,
michael@0 227 originalPerms : 0o767,
michael@0 228 comparePerms : 0o767
michael@0 229 }];
michael@0 230
michael@0 231 // Files for a complete successful update. This can be used for a complete
michael@0 232 // failed update by calling setTestFilesAndDirsForFailure.
michael@0 233 var gTestFilesCompleteSuccess = [
michael@0 234 {
michael@0 235 description : "Added by update.manifest (add)",
michael@0 236 fileName : "precomplete",
michael@0 237 relPathDir : "",
michael@0 238 originalContents : null,
michael@0 239 compareContents : null,
michael@0 240 originalFile : "partial_precomplete",
michael@0 241 compareFile : "complete_precomplete",
michael@0 242 originalPerms : 0o666,
michael@0 243 comparePerms : 0o644
michael@0 244 }, {
michael@0 245 description : "Added by update.manifest (add)",
michael@0 246 fileName : "searchpluginstext0",
michael@0 247 relPathDir : "a/b/searchplugins/",
michael@0 248 originalContents : "ToBeReplacedWithFromComplete\n",
michael@0 249 compareContents : "FromComplete\n",
michael@0 250 originalFile : null,
michael@0 251 compareFile : null,
michael@0 252 originalPerms : 0o775,
michael@0 253 comparePerms : 0o644
michael@0 254 }, {
michael@0 255 description : "Added by update.manifest (add)",
michael@0 256 fileName : "searchpluginspng1.png",
michael@0 257 relPathDir : "a/b/searchplugins/",
michael@0 258 originalContents : null,
michael@0 259 compareContents : null,
michael@0 260 originalFile : null,
michael@0 261 compareFile : "complete.png",
michael@0 262 originalPerms : null,
michael@0 263 comparePerms : 0o644
michael@0 264 }, {
michael@0 265 description : "Added by update.manifest (add)",
michael@0 266 fileName : "searchpluginspng0.png",
michael@0 267 relPathDir : "a/b/searchplugins/",
michael@0 268 originalContents : null,
michael@0 269 compareContents : null,
michael@0 270 originalFile : "partial.png",
michael@0 271 compareFile : "complete.png",
michael@0 272 originalPerms : 0o666,
michael@0 273 comparePerms : 0o644
michael@0 274 }, {
michael@0 275 description : "Added by update.manifest (add)",
michael@0 276 fileName : "removed-files",
michael@0 277 relPathDir : "a/b/",
michael@0 278 originalContents : null,
michael@0 279 compareContents : null,
michael@0 280 originalFile : "partial_removed-files",
michael@0 281 compareFile : "complete_removed-files",
michael@0 282 originalPerms : 0o666,
michael@0 283 comparePerms : 0o644
michael@0 284 }, {
michael@0 285 description : "Added by update.manifest if the parent directory " +
michael@0 286 "exists (add-if)",
michael@0 287 fileName : "extensions1text0",
michael@0 288 relPathDir : "a/b/distribution/extensions/extensions1/",
michael@0 289 originalContents : null,
michael@0 290 compareContents : "FromComplete\n",
michael@0 291 originalFile : null,
michael@0 292 compareFile : null,
michael@0 293 originalPerms : null,
michael@0 294 comparePerms : 0o644
michael@0 295 }, {
michael@0 296 description : "Added by update.manifest if the parent directory " +
michael@0 297 "exists (add-if)",
michael@0 298 fileName : "extensions1png1.png",
michael@0 299 relPathDir : "a/b/distribution/extensions/extensions1/",
michael@0 300 originalContents : null,
michael@0 301 compareContents : null,
michael@0 302 originalFile : "partial.png",
michael@0 303 compareFile : "complete.png",
michael@0 304 originalPerms : 0o666,
michael@0 305 comparePerms : 0o644
michael@0 306 }, {
michael@0 307 description : "Added by update.manifest if the parent directory " +
michael@0 308 "exists (add-if)",
michael@0 309 fileName : "extensions1png0.png",
michael@0 310 relPathDir : "a/b/distribution/extensions/extensions1/",
michael@0 311 originalContents : null,
michael@0 312 compareContents : null,
michael@0 313 originalFile : null,
michael@0 314 compareFile : "complete.png",
michael@0 315 originalPerms : null,
michael@0 316 comparePerms : 0o644
michael@0 317 }, {
michael@0 318 description : "Added by update.manifest if the parent directory " +
michael@0 319 "exists (add-if)",
michael@0 320 fileName : "extensions0text0",
michael@0 321 relPathDir : "a/b/distribution/extensions/extensions0/",
michael@0 322 originalContents : "ToBeReplacedWithFromComplete\n",
michael@0 323 compareContents : "FromComplete\n",
michael@0 324 originalFile : null,
michael@0 325 compareFile : null,
michael@0 326 originalPerms : null,
michael@0 327 comparePerms : 0o644
michael@0 328 }, {
michael@0 329 description : "Added by update.manifest if the parent directory " +
michael@0 330 "exists (add-if)",
michael@0 331 fileName : "extensions0png1.png",
michael@0 332 relPathDir : "a/b/distribution/extensions/extensions0/",
michael@0 333 originalContents : null,
michael@0 334 compareContents : null,
michael@0 335 originalFile : null,
michael@0 336 compareFile : "complete.png",
michael@0 337 originalPerms : null,
michael@0 338 comparePerms : 0o644
michael@0 339 }, {
michael@0 340 description : "Added by update.manifest if the parent directory " +
michael@0 341 "exists (add-if)",
michael@0 342 fileName : "extensions0png0.png",
michael@0 343 relPathDir : "a/b/distribution/extensions/extensions0/",
michael@0 344 originalContents : null,
michael@0 345 compareContents : null,
michael@0 346 originalFile : null,
michael@0 347 compareFile : "complete.png",
michael@0 348 originalPerms : null,
michael@0 349 comparePerms : 0o644
michael@0 350 }, {
michael@0 351 description : "Added by update.manifest (add)",
michael@0 352 fileName : "exe0.exe",
michael@0 353 relPathDir : "a/b/",
michael@0 354 originalContents : null,
michael@0 355 compareContents : null,
michael@0 356 originalFile : FILE_HELPER_BIN,
michael@0 357 compareFile : FILE_COMPLETE_EXE,
michael@0 358 originalPerms : 0o777,
michael@0 359 comparePerms : 0o755
michael@0 360 }, {
michael@0 361 description : "Added by update.manifest (add)",
michael@0 362 fileName : "10text0",
michael@0 363 relPathDir : "a/b/1/10/",
michael@0 364 originalContents : "ToBeReplacedWithFromComplete\n",
michael@0 365 compareContents : "FromComplete\n",
michael@0 366 originalFile : null,
michael@0 367 compareFile : null,
michael@0 368 originalPerms : 0o767,
michael@0 369 comparePerms : 0o644
michael@0 370 }, {
michael@0 371 description : "Added by update.manifest (add)",
michael@0 372 fileName : "0exe0.exe",
michael@0 373 relPathDir : "a/b/0/",
michael@0 374 originalContents : null,
michael@0 375 compareContents : null,
michael@0 376 originalFile : FILE_HELPER_BIN,
michael@0 377 compareFile : FILE_COMPLETE_EXE,
michael@0 378 originalPerms : 0o777,
michael@0 379 comparePerms : 0o755
michael@0 380 }, {
michael@0 381 description : "Added by update.manifest (add)",
michael@0 382 fileName : "00text1",
michael@0 383 relPathDir : "a/b/0/00/",
michael@0 384 originalContents : "ToBeReplacedWithFromComplete\n",
michael@0 385 compareContents : "FromComplete\n",
michael@0 386 originalFile : null,
michael@0 387 compareFile : null,
michael@0 388 originalPerms : 0o677,
michael@0 389 comparePerms : 0o644
michael@0 390 }, {
michael@0 391 description : "Added by update.manifest (add)",
michael@0 392 fileName : "00text0",
michael@0 393 relPathDir : "a/b/0/00/",
michael@0 394 originalContents : "ToBeReplacedWithFromComplete\n",
michael@0 395 compareContents : "FromComplete\n",
michael@0 396 originalFile : null,
michael@0 397 compareFile : null,
michael@0 398 originalPerms : 0o775,
michael@0 399 comparePerms : 0o644
michael@0 400 }, {
michael@0 401 description : "Added by update.manifest (add)",
michael@0 402 fileName : "00png0.png",
michael@0 403 relPathDir : "a/b/0/00/",
michael@0 404 originalContents : null,
michael@0 405 compareContents : null,
michael@0 406 originalFile : null,
michael@0 407 compareFile : "complete.png",
michael@0 408 originalPerms : 0o776,
michael@0 409 comparePerms : 0o644
michael@0 410 }, {
michael@0 411 description : "Removed by precomplete (remove)",
michael@0 412 fileName : "20text0",
michael@0 413 relPathDir : "a/b/2/20/",
michael@0 414 originalContents : "ToBeDeleted\n",
michael@0 415 compareContents : null,
michael@0 416 originalFile : null,
michael@0 417 compareFile : null,
michael@0 418 originalPerms : null,
michael@0 419 comparePerms : null
michael@0 420 }, {
michael@0 421 description : "Removed by precomplete (remove)",
michael@0 422 fileName : "20png0.png",
michael@0 423 relPathDir : "a/b/2/20/",
michael@0 424 originalContents : "ToBeDeleted\n",
michael@0 425 compareContents : null,
michael@0 426 originalFile : null,
michael@0 427 compareFile : null,
michael@0 428 originalPerms : null,
michael@0 429 comparePerms : null
michael@0 430 }];
michael@0 431
michael@0 432 // Concatenate the common files to the end of the array.
michael@0 433 gTestFilesCompleteSuccess = gTestFilesCompleteSuccess.concat(gTestFilesCommon);
michael@0 434
michael@0 435 // Files for a partial successful update. This can be used for a partial failed
michael@0 436 // update by calling setTestFilesAndDirsForFailure.
michael@0 437 var gTestFilesPartialSuccess = [
michael@0 438 {
michael@0 439 description : "Added by update.manifest (add)",
michael@0 440 fileName : "precomplete",
michael@0 441 relPathDir : "",
michael@0 442 originalContents : null,
michael@0 443 compareContents : null,
michael@0 444 originalFile : "complete_precomplete",
michael@0 445 compareFile : "partial_precomplete",
michael@0 446 originalPerms : 0o666,
michael@0 447 comparePerms : 0o644
michael@0 448 }, {
michael@0 449 description : "Added by update.manifest (add)",
michael@0 450 fileName : "searchpluginstext0",
michael@0 451 relPathDir : "a/b/searchplugins/",
michael@0 452 originalContents : "ToBeReplacedWithFromPartial\n",
michael@0 453 compareContents : "FromPartial\n",
michael@0 454 originalFile : null,
michael@0 455 compareFile : null,
michael@0 456 originalPerms : 0o775,
michael@0 457 comparePerms : 0o644
michael@0 458 }, {
michael@0 459 description : "Patched by update.manifest if the file exists " +
michael@0 460 "(patch-if)",
michael@0 461 fileName : "searchpluginspng1.png",
michael@0 462 relPathDir : "a/b/searchplugins/",
michael@0 463 originalContents : null,
michael@0 464 compareContents : null,
michael@0 465 originalFile : "complete.png",
michael@0 466 compareFile : "partial.png",
michael@0 467 originalPerms : 0o666,
michael@0 468 comparePerms : 0o666
michael@0 469 }, {
michael@0 470 description : "Patched by update.manifest if the file exists " +
michael@0 471 "(patch-if)",
michael@0 472 fileName : "searchpluginspng0.png",
michael@0 473 relPathDir : "a/b/searchplugins/",
michael@0 474 originalContents : null,
michael@0 475 compareContents : null,
michael@0 476 originalFile : "complete.png",
michael@0 477 compareFile : "partial.png",
michael@0 478 originalPerms : 0o666,
michael@0 479 comparePerms : 0o666
michael@0 480 }, {
michael@0 481 description : "Added by update.manifest if the parent directory " +
michael@0 482 "exists (add-if)",
michael@0 483 fileName : "extensions1text0",
michael@0 484 relPathDir : "a/b/distribution/extensions/extensions1/",
michael@0 485 originalContents : null,
michael@0 486 compareContents : "FromPartial\n",
michael@0 487 originalFile : null,
michael@0 488 compareFile : null,
michael@0 489 originalPerms : null,
michael@0 490 comparePerms : 0o644
michael@0 491 }, {
michael@0 492 description : "Patched by update.manifest if the parent directory " +
michael@0 493 "exists (patch-if)",
michael@0 494 fileName : "extensions1png1.png",
michael@0 495 relPathDir : "a/b/distribution/extensions/extensions1/",
michael@0 496 originalContents : null,
michael@0 497 compareContents : null,
michael@0 498 originalFile : "complete.png",
michael@0 499 compareFile : "partial.png",
michael@0 500 originalPerms : 0o666,
michael@0 501 comparePerms : 0o666
michael@0 502 }, {
michael@0 503 description : "Patched by update.manifest if the parent directory " +
michael@0 504 "exists (patch-if)",
michael@0 505 fileName : "extensions1png0.png",
michael@0 506 relPathDir : "a/b/distribution/extensions/extensions1/",
michael@0 507 originalContents : null,
michael@0 508 compareContents : null,
michael@0 509 originalFile : "complete.png",
michael@0 510 compareFile : "partial.png",
michael@0 511 originalPerms : 0o666,
michael@0 512 comparePerms : 0o666
michael@0 513 }, {
michael@0 514 description : "Added by update.manifest if the parent directory " +
michael@0 515 "exists (add-if)",
michael@0 516 fileName : "extensions0text0",
michael@0 517 relPathDir : "a/b/distribution/extensions/extensions0/",
michael@0 518 originalContents : "ToBeReplacedWithFromPartial\n",
michael@0 519 compareContents : "FromPartial\n",
michael@0 520 originalFile : null,
michael@0 521 compareFile : null,
michael@0 522 originalPerms : 0o644,
michael@0 523 comparePerms : 0o644
michael@0 524 }, {
michael@0 525 description : "Patched by update.manifest if the parent directory " +
michael@0 526 "exists (patch-if)",
michael@0 527 fileName : "extensions0png1.png",
michael@0 528 relPathDir : "a/b/distribution/extensions/extensions0/",
michael@0 529 originalContents : null,
michael@0 530 compareContents : null,
michael@0 531 originalFile : "complete.png",
michael@0 532 compareFile : "partial.png",
michael@0 533 originalPerms : 0o644,
michael@0 534 comparePerms : 0o644
michael@0 535 }, {
michael@0 536 description : "Patched by update.manifest if the parent directory " +
michael@0 537 "exists (patch-if)",
michael@0 538 fileName : "extensions0png0.png",
michael@0 539 relPathDir : "a/b/distribution/extensions/extensions0/",
michael@0 540 originalContents : null,
michael@0 541 compareContents : null,
michael@0 542 originalFile : "complete.png",
michael@0 543 compareFile : "partial.png",
michael@0 544 originalPerms : 0o644,
michael@0 545 comparePerms : 0o644
michael@0 546 }, {
michael@0 547 description : "Patched by update.manifest (patch)",
michael@0 548 fileName : "exe0.exe",
michael@0 549 relPathDir : "a/b/",
michael@0 550 originalContents : null,
michael@0 551 compareContents : null,
michael@0 552 originalFile : FILE_COMPLETE_EXE,
michael@0 553 compareFile : FILE_PARTIAL_EXE,
michael@0 554 originalPerms : 0o755,
michael@0 555 comparePerms : 0o755
michael@0 556 }, {
michael@0 557 description : "Patched by update.manifest (patch)",
michael@0 558 fileName : "0exe0.exe",
michael@0 559 relPathDir : "a/b/0/",
michael@0 560 originalContents : null,
michael@0 561 compareContents : null,
michael@0 562 originalFile : FILE_COMPLETE_EXE,
michael@0 563 compareFile : FILE_PARTIAL_EXE,
michael@0 564 originalPerms : 0o755,
michael@0 565 comparePerms : 0o755
michael@0 566 }, {
michael@0 567 description : "Added by update.manifest (add)",
michael@0 568 fileName : "00text0",
michael@0 569 relPathDir : "a/b/0/00/",
michael@0 570 originalContents : "ToBeReplacedWithFromPartial\n",
michael@0 571 compareContents : "FromPartial\n",
michael@0 572 originalFile : null,
michael@0 573 compareFile : null,
michael@0 574 originalPerms : 0o644,
michael@0 575 comparePerms : 0o644
michael@0 576 }, {
michael@0 577 description : "Patched by update.manifest (patch)",
michael@0 578 fileName : "00png0.png",
michael@0 579 relPathDir : "a/b/0/00/",
michael@0 580 originalContents : null,
michael@0 581 compareContents : null,
michael@0 582 originalFile : "complete.png",
michael@0 583 compareFile : "partial.png",
michael@0 584 originalPerms : 0o666,
michael@0 585 comparePerms : 0o666
michael@0 586 }, {
michael@0 587 description : "Added by update.manifest (add)",
michael@0 588 fileName : "20text0",
michael@0 589 relPathDir : "a/b/2/20/",
michael@0 590 originalContents : null,
michael@0 591 compareContents : "FromPartial\n",
michael@0 592 originalFile : null,
michael@0 593 compareFile : null,
michael@0 594 originalPerms : null,
michael@0 595 comparePerms : 0o644
michael@0 596 }, {
michael@0 597 description : "Added by update.manifest (add)",
michael@0 598 fileName : "20png0.png",
michael@0 599 relPathDir : "a/b/2/20/",
michael@0 600 originalContents : null,
michael@0 601 compareContents : null,
michael@0 602 originalFile : null,
michael@0 603 compareFile : "partial.png",
michael@0 604 originalPerms : null,
michael@0 605 comparePerms : 0o644
michael@0 606 }, {
michael@0 607 description : "Added by update.manifest (add)",
michael@0 608 fileName : "00text2",
michael@0 609 relPathDir : "a/b/0/00/",
michael@0 610 originalContents : null,
michael@0 611 compareContents : "FromPartial\n",
michael@0 612 originalFile : null,
michael@0 613 compareFile : null,
michael@0 614 originalPerms : null,
michael@0 615 comparePerms : 0o644
michael@0 616 }, {
michael@0 617 description : "Removed by update.manifest (remove)",
michael@0 618 fileName : "10text0",
michael@0 619 relPathDir : "a/b/1/10/",
michael@0 620 originalContents : "ToBeDeleted\n",
michael@0 621 compareContents : null,
michael@0 622 originalFile : null,
michael@0 623 compareFile : null,
michael@0 624 originalPerms : null,
michael@0 625 comparePerms : null
michael@0 626 }, {
michael@0 627 description : "Removed by update.manifest (remove)",
michael@0 628 fileName : "00text1",
michael@0 629 relPathDir : "a/b/0/00/",
michael@0 630 originalContents : "ToBeDeleted\n",
michael@0 631 compareContents : null,
michael@0 632 originalFile : null,
michael@0 633 compareFile : null,
michael@0 634 originalPerms : null,
michael@0 635 comparePerms : null
michael@0 636 }];
michael@0 637
michael@0 638 // Concatenate the common files to the end of the array.
michael@0 639 gTestFilesPartialSuccess = gTestFilesPartialSuccess.concat(gTestFilesCommon);
michael@0 640
michael@0 641 /**
michael@0 642 * The mar files used for the updater tests contain the following remove
michael@0 643 * operations.
michael@0 644 *
michael@0 645 * partial and complete test mar remove operations
michael@0 646 * -----------------------------------------------
michael@0 647 * remove "text1"
michael@0 648 * remove "text0"
michael@0 649 * rmrfdir "9/99/"
michael@0 650 * rmdir "9/99/"
michael@0 651 * rmrfdir "9/98/"
michael@0 652 * rmrfdir "9/97/"
michael@0 653 * rmrfdir "9/96/"
michael@0 654 * rmrfdir "9/95/"
michael@0 655 * rmrfdir "9/95/"
michael@0 656 * rmrfdir "9/94/"
michael@0 657 * rmdir "9/94/"
michael@0 658 * rmdir "9/93/"
michael@0 659 * rmdir "9/92/"
michael@0 660 * rmdir "9/91/"
michael@0 661 * rmdir "9/90/"
michael@0 662 * rmdir "9/90/"
michael@0 663 * rmrfdir "8/89/"
michael@0 664 * rmdir "8/89/"
michael@0 665 * rmrfdir "8/88/"
michael@0 666 * rmrfdir "8/87/"
michael@0 667 * rmrfdir "8/86/"
michael@0 668 * rmrfdir "8/85/"
michael@0 669 * rmrfdir "8/85/"
michael@0 670 * rmrfdir "8/84/"
michael@0 671 * rmdir "8/84/"
michael@0 672 * rmdir "8/83/"
michael@0 673 * rmdir "8/82/"
michael@0 674 * rmdir "8/81/"
michael@0 675 * rmdir "8/80/"
michael@0 676 * rmdir "8/80/"
michael@0 677 * rmrfdir "7/"
michael@0 678 * rmdir "6/"
michael@0 679 * remove "5/text1"
michael@0 680 * remove "5/text0"
michael@0 681 * rmrfdir "5/"
michael@0 682 * remove "4/text1"
michael@0 683 * remove "4/text0"
michael@0 684 * remove "4/exe0.exe"
michael@0 685 * rmdir "4/"
michael@0 686 * remove "3/text1"
michael@0 687 * remove "3/text0"
michael@0 688 *
michael@0 689 * partial test mar additional remove operations
michael@0 690 * ---------------------------------------------
michael@0 691 * remove "0/00/00text1"
michael@0 692 * remove "1/10/10text0"
michael@0 693 * rmdir "1/10/"
michael@0 694 * rmdir "1/"
michael@0 695 */
michael@0 696 var gTestDirsCommon = [
michael@0 697 {
michael@0 698 relPathDir : "a/b/3/",
michael@0 699 dirRemoved : false,
michael@0 700 files : ["3text0", "3text1"],
michael@0 701 filesRemoved : true
michael@0 702 }, {
michael@0 703 relPathDir : "a/b/4/",
michael@0 704 dirRemoved : true,
michael@0 705 files : ["4text0", "4text1"],
michael@0 706 filesRemoved : true
michael@0 707 }, {
michael@0 708 relPathDir : "a/b/5/",
michael@0 709 dirRemoved : true,
michael@0 710 files : ["5test.exe", "5text0", "5text1"],
michael@0 711 filesRemoved : true
michael@0 712 }, {
michael@0 713 relPathDir : "a/b/6/",
michael@0 714 dirRemoved : true
michael@0 715 }, {
michael@0 716 relPathDir : "a/b/7/",
michael@0 717 dirRemoved : true,
michael@0 718 files : ["7text0", "7text1"],
michael@0 719 subDirs : ["70/", "71/"],
michael@0 720 subDirFiles : ["7xtest.exe", "7xtext0", "7xtext1"]
michael@0 721 }, {
michael@0 722 relPathDir : "a/b/8/",
michael@0 723 dirRemoved : false
michael@0 724 }, {
michael@0 725 relPathDir : "a/b/8/80/",
michael@0 726 dirRemoved : true
michael@0 727 }, {
michael@0 728 relPathDir : "a/b/8/81/",
michael@0 729 dirRemoved : false,
michael@0 730 files : ["81text0", "81text1"]
michael@0 731 }, {
michael@0 732 relPathDir : "a/b/8/82/",
michael@0 733 dirRemoved : false,
michael@0 734 subDirs : ["820/", "821/"]
michael@0 735 }, {
michael@0 736 relPathDir : "a/b/8/83/",
michael@0 737 dirRemoved : true
michael@0 738 }, {
michael@0 739 relPathDir : "a/b/8/84/",
michael@0 740 dirRemoved : true
michael@0 741 }, {
michael@0 742 relPathDir : "a/b/8/85/",
michael@0 743 dirRemoved : true
michael@0 744 }, {
michael@0 745 relPathDir : "a/b/8/86/",
michael@0 746 dirRemoved : true,
michael@0 747 files : ["86text0", "86text1"]
michael@0 748 }, {
michael@0 749 relPathDir : "a/b/8/87/",
michael@0 750 dirRemoved : true,
michael@0 751 subDirs : ["870/", "871/"],
michael@0 752 subDirFiles : ["87xtext0", "87xtext1"]
michael@0 753 }, {
michael@0 754 relPathDir : "a/b/8/88/",
michael@0 755 dirRemoved : true
michael@0 756 }, {
michael@0 757 relPathDir : "a/b/8/89/",
michael@0 758 dirRemoved : true
michael@0 759 }, {
michael@0 760 relPathDir : "a/b/9/90/",
michael@0 761 dirRemoved : true
michael@0 762 }, {
michael@0 763 relPathDir : "a/b/9/91/",
michael@0 764 dirRemoved : false,
michael@0 765 files : ["91text0", "91text1"]
michael@0 766 }, {
michael@0 767 relPathDir : "a/b/9/92/",
michael@0 768 dirRemoved : false,
michael@0 769 subDirs : ["920/", "921/"]
michael@0 770 }, {
michael@0 771 relPathDir : "a/b/9/93/",
michael@0 772 dirRemoved : true
michael@0 773 }, {
michael@0 774 relPathDir : "a/b/9/94/",
michael@0 775 dirRemoved : true
michael@0 776 }, {
michael@0 777 relPathDir : "a/b/9/95/",
michael@0 778 dirRemoved : true
michael@0 779 }, {
michael@0 780 relPathDir : "a/b/9/96/",
michael@0 781 dirRemoved : true,
michael@0 782 files : ["96text0", "96text1"]
michael@0 783 }, {
michael@0 784 relPathDir : "a/b/9/97/",
michael@0 785 dirRemoved : true,
michael@0 786 subDirs : ["970/", "971/"],
michael@0 787 subDirFiles : ["97xtext0", "97xtext1"]
michael@0 788 }, {
michael@0 789 relPathDir : "a/b/9/98/",
michael@0 790 dirRemoved : true
michael@0 791 }, {
michael@0 792 relPathDir : "a/b/9/99/",
michael@0 793 dirRemoved : true
michael@0 794 }];
michael@0 795
michael@0 796 // Directories for a complete successful update. This array can be used for a
michael@0 797 // complete failed update by calling setTestFilesAndDirsForFailure.
michael@0 798 var gTestDirsCompleteSuccess = [
michael@0 799 {
michael@0 800 description : "Removed by precomplete (rmdir)",
michael@0 801 relPathDir : "a/b/2/20/",
michael@0 802 dirRemoved : true
michael@0 803 }, {
michael@0 804 description : "Removed by precomplete (rmdir)",
michael@0 805 relPathDir : "a/b/2/",
michael@0 806 dirRemoved : true
michael@0 807 }];
michael@0 808
michael@0 809 // Concatenate the common files to the beginning of the array.
michael@0 810 gTestDirsCompleteSuccess = gTestDirsCommon.concat(gTestDirsCompleteSuccess);
michael@0 811
michael@0 812 // Directories for a partial successful update. This array can be used for a
michael@0 813 // partial failed update by calling setTestFilesAndDirsForFailure.
michael@0 814 var gTestDirsPartialSuccess = [
michael@0 815 {
michael@0 816 description : "Removed by update.manifest (rmdir)",
michael@0 817 relPathDir : "a/b/1/10/",
michael@0 818 dirRemoved : true
michael@0 819 }, {
michael@0 820 description : "Removed by update.manifest (rmdir)",
michael@0 821 relPathDir : "a/b/1/",
michael@0 822 dirRemoved : true
michael@0 823 }];
michael@0 824
michael@0 825 // Concatenate the common files to the beginning of the array.
michael@0 826 gTestDirsPartialSuccess = gTestDirsCommon.concat(gTestDirsPartialSuccess);
michael@0 827
michael@0 828 // Extra directories to check for existence for both complete and partial
michael@0 829 // updates. Whether they exist or not is set when calling setupUpdaterTest.
michael@0 830 var gTestExtraDirs = [
michael@0 831 {
michael@0 832 relPathDir : DIR_UPDATED,
michael@0 833 dirExists : false
michael@0 834 }, {
michael@0 835 relPathDir : DIR_TOBEDELETED,
michael@0 836 dirExists : false
michael@0 837 }];
michael@0 838
michael@0 839 // This makes it possible to run most tests on xulrunner where the update
michael@0 840 // channel default preference is not set.
michael@0 841 if (MOZ_APP_NAME == "xulrunner") {
michael@0 842 try {
michael@0 843 gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
michael@0 844 } catch (e) {
michael@0 845 setUpdateChannel("test_channel");
michael@0 846 }
michael@0 847 }
michael@0 848
michael@0 849 /**
michael@0 850 * Helper function for setting up the test environment.
michael@0 851 */
michael@0 852 function setupTestCommon() {
michael@0 853 logTestInfo("start - general test setup");
michael@0 854
michael@0 855 do_test_pending();
michael@0 856
michael@0 857 if (gTestID) {
michael@0 858 do_throw("setupTestCommon should only be called once!");
michael@0 859 }
michael@0 860
michael@0 861 let caller = Components.stack.caller;
michael@0 862 gTestID = caller.filename.toString().split("/").pop().split(".")[0];
michael@0 863
michael@0 864 if (DEBUG_TEST_LOG) {
michael@0 865 let logFile = do_get_file(gTestID + ".log", true);
michael@0 866 if (logFile.exists()) {
michael@0 867 gPassed = false;
michael@0 868 logTestInfo("start - dumping previous test run log");
michael@0 869 logTestInfo("\n" + readFile(logFile) + "\n");
michael@0 870 logTestInfo("finish - dumping previous test run log");
michael@0 871 if (gDeleteLogFile) {
michael@0 872 logFile.remove(false);
michael@0 873 }
michael@0 874 do_throw("The parallel run of this test failed. Failing non-parallel " +
michael@0 875 "test so the log from the parallel run can be displayed in " +
michael@0 876 "non-parallel log.")
michael@0 877 } else {
michael@0 878 gRealDump = dump;
michael@0 879 dump = dumpOverride;
michael@0 880 }
michael@0 881 }
michael@0 882
michael@0 883 // Don't attempt to show a prompt when an update finishes.
michael@0 884 Services.prefs.setBoolPref(PREF_APP_UPDATE_SILENT, true);
michael@0 885
michael@0 886 gGREDirOrig = getGREDir();
michael@0 887 gAppDirOrig = getAppBaseDir();
michael@0 888
michael@0 889 let applyDir = getApplyDirFile(null, true).parent;
michael@0 890
michael@0 891 // Try to remove the directory used to apply updates and the updates directory
michael@0 892 // on platforms other than Windows. Since the test hasn't ran yet and the
michael@0 893 // directory shouldn't exist finished this is non-fatal for the test.
michael@0 894 if (applyDir.exists()) {
michael@0 895 logTestInfo("attempting to remove directory. Path: " + applyDir.path);
michael@0 896 try {
michael@0 897 removeDirRecursive(applyDir);
michael@0 898 } catch (e) {
michael@0 899 logTestInfo("non-fatal error removing directory. Path: " +
michael@0 900 applyDir.path + ", Exception: " + e);
michael@0 901 }
michael@0 902 }
michael@0 903
michael@0 904 // adjustGeneralPaths registers a cleanup function that calls end_test when
michael@0 905 // it is defined as a function.
michael@0 906 adjustGeneralPaths();
michael@0 907
michael@0 908 // Remove the updates directory on Windows which is located outside of the
michael@0 909 // application directory after the call to adjustGeneralPaths has set it up.
michael@0 910 // Since the test hasn't ran yet and the directory shouldn't exist finished
michael@0 911 // this is non-fatal for the test.
michael@0 912 if (IS_WIN) {
michael@0 913 let updatesDir = getMockUpdRootD();
michael@0 914 if (updatesDir.exists()) {
michael@0 915 logTestInfo("attempting to remove directory. Path: " + updatesDir.path);
michael@0 916 try {
michael@0 917 removeDirRecursive(updatesDir);
michael@0 918 } catch (e) {
michael@0 919 logTestInfo("non-fatal error removing directory. Path: " +
michael@0 920 updatesDir.path + ", Exception: " + e);
michael@0 921 }
michael@0 922 }
michael@0 923 }
michael@0 924
michael@0 925 logTestInfo("finish - general test setup");
michael@0 926 }
michael@0 927
michael@0 928 /**
michael@0 929 * Nulls out the most commonly used global vars used by tests to prevent leaks
michael@0 930 * as needed and attempts to restore the system to its original state.
michael@0 931 */
michael@0 932 function cleanupTestCommon() {
michael@0 933 logTestInfo("start - general test cleanup");
michael@0 934
michael@0 935 // Force the update manager to reload the update data to prevent it from
michael@0 936 // writing the old data to the files that have just been removed.
michael@0 937 reloadUpdateManagerData();
michael@0 938
michael@0 939 if (gChannel) {
michael@0 940 gPrefRoot.removeObserver(PREF_APP_UPDATE_CHANNEL, observer);
michael@0 941 }
michael@0 942
michael@0 943 // Call app update's observe method passing xpcom-shutdown to test that the
michael@0 944 // shutdown of app update runs without throwing or leaking. The observer
michael@0 945 // method is used directly instead of calling notifyObservers so components
michael@0 946 // outside of the scope of this test don't assert and thereby cause app update
michael@0 947 // tests to fail.
michael@0 948 gAUS.observe(null, "xpcom-shutdown", "");
michael@0 949
michael@0 950 if (gXHR) {
michael@0 951 gXHRCallback = null;
michael@0 952
michael@0 953 gXHR.responseXML = null;
michael@0 954 // null out the event handlers to prevent a mFreeCount leak of 1
michael@0 955 gXHR.onerror = null;
michael@0 956 gXHR.onload = null;
michael@0 957 gXHR.onprogress = null;
michael@0 958
michael@0 959 gXHR = null;
michael@0 960 }
michael@0 961
michael@0 962 gTestserver = null;
michael@0 963
michael@0 964 if (IS_UNIX) {
michael@0 965 // This will delete the launch script if it exists.
michael@0 966 getLaunchScript();
michael@0 967 }
michael@0 968
michael@0 969 if (IS_WIN && MOZ_APP_BASENAME) {
michael@0 970 let appDir = getApplyDirFile(null, true);
michael@0 971 let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla";
michael@0 972 const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME +
michael@0 973 "\\TaskBarIDs";
michael@0 974 let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
michael@0 975 createInstance(AUS_Ci.nsIWindowsRegKey);
michael@0 976 try {
michael@0 977 key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
michael@0 978 AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
michael@0 979 if (key.hasValue(appDir.path)) {
michael@0 980 key.removeValue(appDir.path);
michael@0 981 }
michael@0 982 } catch (e) {
michael@0 983 }
michael@0 984 try {
michael@0 985 key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH,
michael@0 986 AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
michael@0 987 if (key.hasValue(appDir.path)) {
michael@0 988 key.removeValue(appDir.path);
michael@0 989 }
michael@0 990 } catch (e) {
michael@0 991 }
michael@0 992 }
michael@0 993
michael@0 994 // The updates directory is located outside of the application directory on
michael@0 995 // Windows so it also needs to be removed.
michael@0 996 if (IS_WIN) {
michael@0 997 let updatesDir = getMockUpdRootD();
michael@0 998 // Try to remove the directory used to apply updates. Since the test has
michael@0 999 // already finished this is non-fatal for the test.
michael@0 1000 if (updatesDir.exists()) {
michael@0 1001 logTestInfo("attempting to remove directory. Path: " + updatesDir.path);
michael@0 1002 try {
michael@0 1003 removeDirRecursive(updatesDir);
michael@0 1004 } catch (e) {
michael@0 1005 logTestInfo("non-fatal error removing directory. Path: " +
michael@0 1006 updatesDir.path + ", Exception: " + e);
michael@0 1007 }
michael@0 1008 }
michael@0 1009 }
michael@0 1010
michael@0 1011 let applyDir = getApplyDirFile(null, true).parent;
michael@0 1012
michael@0 1013 // Try to remove the directory used to apply updates. Since the test has
michael@0 1014 // already finished this is non-fatal for the test.
michael@0 1015 if (applyDir.exists()) {
michael@0 1016 logTestInfo("attempting to remove directory. Path: " + applyDir.path);
michael@0 1017 try {
michael@0 1018 removeDirRecursive(applyDir);
michael@0 1019 } catch (e) {
michael@0 1020 logTestInfo("non-fatal error removing directory. Path: " +
michael@0 1021 applyDir.path + ", Exception: " + e);
michael@0 1022 }
michael@0 1023 }
michael@0 1024
michael@0 1025 resetEnvironment();
michael@0 1026
michael@0 1027 logTestInfo("finish - general test cleanup");
michael@0 1028
michael@0 1029 if (gRealDump) {
michael@0 1030 dump = gRealDump;
michael@0 1031 gRealDump = null;
michael@0 1032 }
michael@0 1033
michael@0 1034 if (DEBUG_TEST_LOG && !gPassed) {
michael@0 1035 let fos = AUS_Cc["@mozilla.org/network/file-output-stream;1"].
michael@0 1036 createInstance(AUS_Ci.nsIFileOutputStream);
michael@0 1037 let logFile = do_get_file(gTestID + ".log", true);
michael@0 1038 if (!logFile.exists()) {
michael@0 1039 logFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
michael@0 1040 }
michael@0 1041 fos.init(logFile, MODE_WRONLY | MODE_CREATE | MODE_APPEND, PERMS_FILE, 0);
michael@0 1042 fos.write(gTestLogText, gTestLogText.length);
michael@0 1043 fos.close();
michael@0 1044 }
michael@0 1045
michael@0 1046 if (DEBUG_TEST_LOG) {
michael@0 1047 gTestLogText = null;
michael@0 1048 } else {
michael@0 1049 let logFile = do_get_file(gTestID + ".log", true);
michael@0 1050 if (logFile.exists()) {
michael@0 1051 logFile.remove(false);
michael@0 1052 }
michael@0 1053 }
michael@0 1054 }
michael@0 1055
michael@0 1056 /**
michael@0 1057 * Helper function to store the log output of calls to dump in a variable so the
michael@0 1058 * values can be written to a file for a parallel run of a test and printed to
michael@0 1059 * the log file when the test runs synchronously.
michael@0 1060 */
michael@0 1061 function dumpOverride(aText) {
michael@0 1062 gTestLogText += aText;
michael@0 1063 gRealDump(aText);
michael@0 1064 }
michael@0 1065
michael@0 1066 /**
michael@0 1067 * Helper function that calls do_test_finished that tracks whether a parallel
michael@0 1068 * run of a test passed when it runs synchronously so the log output can be
michael@0 1069 * inspected.
michael@0 1070 */
michael@0 1071 function doTestFinish() {
michael@0 1072 if (gPassed === undefined) {
michael@0 1073 gPassed = true;
michael@0 1074 }
michael@0 1075 do_test_finished();
michael@0 1076 }
michael@0 1077
michael@0 1078 /**
michael@0 1079 * Sets the most commonly used preferences used by tests
michael@0 1080 */
michael@0 1081 function setDefaultPrefs() {
michael@0 1082 Services.prefs.setBoolPref(PREF_APP_UPDATE_ENABLED, true);
michael@0 1083 Services.prefs.setBoolPref(PREF_APP_UPDATE_METRO_ENABLED, true);
michael@0 1084 // Don't display UI for a successful installation. Some apps may not set this
michael@0 1085 // pref to false like Firefox does.
michael@0 1086 Services.prefs.setBoolPref(PREF_APP_UPDATE_SHOW_INSTALLED_UI, false);
michael@0 1087 // Enable Update logging
michael@0 1088 Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true);
michael@0 1089 }
michael@0 1090
michael@0 1091 /**
michael@0 1092 * Helper function for updater binary tests that sets the appropriate values
michael@0 1093 * to check for update failures.
michael@0 1094 */
michael@0 1095 function setTestFilesAndDirsForFailure() {
michael@0 1096 gTestFiles.forEach(function STFADFF_Files(aTestFile) {
michael@0 1097 aTestFile.compareContents = aTestFile.originalContents;
michael@0 1098 aTestFile.compareFile = aTestFile.originalFile;
michael@0 1099 aTestFile.comparePerms = aTestFile.originalPerms;
michael@0 1100 });
michael@0 1101
michael@0 1102 gTestDirs.forEach(function STFADFF_Dirs(aTestDir) {
michael@0 1103 aTestDir.dirRemoved = false;
michael@0 1104 if (aTestDir.filesRemoved) {
michael@0 1105 aTestDir.filesRemoved = false;
michael@0 1106 }
michael@0 1107 });
michael@0 1108 }
michael@0 1109
michael@0 1110 /**
michael@0 1111 * Initializes the most commonly used settings and creates an instance of the
michael@0 1112 * update service stub.
michael@0 1113 */
michael@0 1114 function standardInit() {
michael@0 1115 createAppInfo("xpcshell@tests.mozilla.org", APP_INFO_NAME, "1.0", "2.0");
michael@0 1116 setDefaultPrefs();
michael@0 1117 // Initialize the update service stub component
michael@0 1118 initUpdateServiceStub();
michael@0 1119 }
michael@0 1120
michael@0 1121 /**
michael@0 1122 * Custom path handler for the http server
michael@0 1123 *
michael@0 1124 * @param aMetadata
michael@0 1125 * The http metadata for the request.
michael@0 1126 * @param aResponse
michael@0 1127 * The http response for the request.
michael@0 1128 */
michael@0 1129 function pathHandler(aMetadata, aResponse) {
michael@0 1130 aResponse.setHeader("Content-Type", "text/xml", false);
michael@0 1131 aResponse.setStatusLine(aMetadata.httpVersion, gResponseStatusCode, "OK");
michael@0 1132 aResponse.bodyOutputStream.write(gResponseBody, gResponseBody.length);
michael@0 1133 }
michael@0 1134
michael@0 1135 /**
michael@0 1136 * Helper function for getting the application version from the application.ini
michael@0 1137 * file. This will look in both the GRE and the application directories for the
michael@0 1138 * application.ini file.
michael@0 1139 *
michael@0 1140 * @return The version string from the application.ini file.
michael@0 1141 * @throws If the application.ini file is not found.
michael@0 1142 */
michael@0 1143 function getAppVersion() {
michael@0 1144 // Read the application.ini and use its application version.
michael@0 1145 let iniFile = gGREDirOrig.clone();
michael@0 1146 iniFile.append("application.ini");
michael@0 1147 if (!iniFile.exists()) {
michael@0 1148 iniFile = gAppDirOrig.clone();
michael@0 1149 iniFile.append("application.ini");
michael@0 1150 }
michael@0 1151 if (!iniFile.exists()) {
michael@0 1152 do_throw("Unable to find application.ini!");
michael@0 1153 }
michael@0 1154 let iniParser = AUS_Cc["@mozilla.org/xpcom/ini-parser-factory;1"].
michael@0 1155 getService(AUS_Ci.nsIINIParserFactory).
michael@0 1156 createINIParser(iniFile);
michael@0 1157 return iniParser.getString("App", "Version");
michael@0 1158 }
michael@0 1159
michael@0 1160 /**
michael@0 1161 * Helper function for getting the relative path to the directory where the
michael@0 1162 * application binary is located (e.g. <test_file_leafname>/dir.app/).
michael@0 1163 *
michael@0 1164 * Note: The dir.app subdirectory under <test_file_leafname> is needed for
michael@0 1165 * platforms other than Mac OS X so the tests can run in parallel due to
michael@0 1166 * update staging creating a lock file named moz_update_in_progress.lock in
michael@0 1167 * the parent directory of the installation directory.
michael@0 1168 *
michael@0 1169 * @return The relative path to the directory where application binary is
michael@0 1170 * located.
michael@0 1171 */
michael@0 1172 function getApplyDirPath() {
michael@0 1173 return gTestID + "/dir.app/";
michael@0 1174 }
michael@0 1175
michael@0 1176 /**
michael@0 1177 * Helper function for getting the nsIFile for a file in the directory where the
michael@0 1178 * update will be applied.
michael@0 1179 *
michael@0 1180 * The files for the update are located two directories below the apply to
michael@0 1181 * directory since Mac OS X sets the last modified time for the root directory
michael@0 1182 * to the current time and if the update changes any files in the root directory
michael@0 1183 * then it wouldn't be possible to test (bug 600098).
michael@0 1184 *
michael@0 1185 * @param aRelPath (optional)
michael@0 1186 * The relative path to the file or directory to get from the root of
michael@0 1187 * the test's directory. If not specified the test's directory will be
michael@0 1188 * returned.
michael@0 1189 * @param aAllowNonexistent (optional)
michael@0 1190 * Whether the file must exist. If false or not specified the file must
michael@0 1191 * exist or the function will throw.
michael@0 1192 * @return The nsIFile for the file in the directory where the update will be
michael@0 1193 * applied.
michael@0 1194 */
michael@0 1195 function getApplyDirFile(aRelPath, aAllowNonexistent) {
michael@0 1196 let relpath = getApplyDirPath() + (aRelPath ? aRelPath : "");
michael@0 1197 return do_get_file(relpath, aAllowNonexistent);
michael@0 1198 }
michael@0 1199
michael@0 1200 /**
michael@0 1201 * Helper function for getting the relative path to the directory where the
michael@0 1202 * test data files are located.
michael@0 1203 *
michael@0 1204 * @return The relative path to the directory where the test data files are
michael@0 1205 * located.
michael@0 1206 */
michael@0 1207 function getTestDirPath() {
michael@0 1208 return "../data/";
michael@0 1209 }
michael@0 1210
michael@0 1211 /**
michael@0 1212 * Helper function for getting the nsIFile for a file in the test data
michael@0 1213 * directory.
michael@0 1214 *
michael@0 1215 * @param aRelPath (optional)
michael@0 1216 * The relative path to the file or directory to get from the root of
michael@0 1217 * the test's data directory. If not specified the test's data
michael@0 1218 * directory will be returned.
michael@0 1219 * @return The nsIFile for the file in the test data directory.
michael@0 1220 * @throws If the file or directory does not exist.
michael@0 1221 */
michael@0 1222 function getTestDirFile(aRelPath) {
michael@0 1223 let relpath = getTestDirPath() + (aRelPath ? aRelPath : "");
michael@0 1224 return do_get_file(relpath, false);
michael@0 1225 }
michael@0 1226
michael@0 1227 /**
michael@0 1228 * Helper function for getting the directory that was updated. This can either
michael@0 1229 * be the directory where the application binary is located or the directory
michael@0 1230 * that contains the staged update.
michael@0 1231 */
michael@0 1232 function getUpdatedDirPath() {
michael@0 1233 return getApplyDirPath() + (gStageUpdate ? DIR_UPDATED + "/" : "");
michael@0 1234 }
michael@0 1235
michael@0 1236 #ifdef XP_WIN
michael@0 1237 XPCOMUtils.defineLazyGetter(this, "gInstallDirPathHash",
michael@0 1238 function test_gInstallDirPathHash() {
michael@0 1239 // Figure out where we should check for a cached hash value
michael@0 1240 if (!MOZ_APP_BASENAME)
michael@0 1241 return null;
michael@0 1242
michael@0 1243 let vendor = MOZ_APP_VENDOR ? MOZ_APP_VENDOR : "Mozilla";
michael@0 1244 let appDir = getApplyDirFile(null, true);
michael@0 1245
michael@0 1246 const REG_PATH = "SOFTWARE\\" + vendor + "\\" + MOZ_APP_BASENAME +
michael@0 1247 "\\TaskBarIDs";
michael@0 1248 let regKey = AUS_Cc["@mozilla.org/windows-registry-key;1"].
michael@0 1249 createInstance(AUS_Ci.nsIWindowsRegKey);
michael@0 1250 try {
michael@0 1251 regKey.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
michael@0 1252 AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
michael@0 1253 regKey.writeStringValue(appDir.path, gTestID);
michael@0 1254 return gTestID;
michael@0 1255 } catch (e) {
michael@0 1256 }
michael@0 1257
michael@0 1258 try {
michael@0 1259 regKey.create(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, REG_PATH,
michael@0 1260 AUS_Ci.nsIWindowsRegKey.ACCESS_ALL);
michael@0 1261 regKey.writeStringValue(appDir.path, gTestID);
michael@0 1262 return gTestID;
michael@0 1263 } catch (e) {
michael@0 1264 logTestInfo("failed to create registry key. Registry Path: " + REG_PATH +
michael@0 1265 ", Key Name: " + appDir.path + ", Key Value: " + gTestID +
michael@0 1266 ", Exception " + e);
michael@0 1267 }
michael@0 1268 return null;
michael@0 1269 });
michael@0 1270
michael@0 1271 XPCOMUtils.defineLazyGetter(this, "gLocalAppDataDir",
michael@0 1272 function test_gLocalAppDataDir() {
michael@0 1273 const CSIDL_LOCAL_APPDATA = 0x1c;
michael@0 1274
michael@0 1275 AUS_Cu.import("resource://gre/modules/ctypes.jsm");
michael@0 1276 let lib = ctypes.open("shell32");
michael@0 1277 let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW",
michael@0 1278 ctypes.winapi_abi,
michael@0 1279 ctypes.bool, /* bool(return) */
michael@0 1280 ctypes.int32_t, /* HWND hwndOwner */
michael@0 1281 ctypes.jschar.ptr, /* LPTSTR lpszPath */
michael@0 1282 ctypes.int32_t, /* int csidl */
michael@0 1283 ctypes.bool /* BOOL fCreate */);
michael@0 1284
michael@0 1285 let aryPathLocalAppData = ctypes.jschar.array()(260);
michael@0 1286 let rv = SHGetSpecialFolderPath(0, aryPathLocalAppData, CSIDL_LOCAL_APPDATA, false);
michael@0 1287 lib.close();
michael@0 1288
michael@0 1289 let pathLocalAppData = aryPathLocalAppData.readString(); // Convert the c-string to js-string
michael@0 1290 let updatesDir = AUS_Cc["@mozilla.org/file/local;1"].
michael@0 1291 createInstance(AUS_Ci.nsILocalFile);
michael@0 1292 updatesDir.initWithPath(pathLocalAppData);
michael@0 1293 return updatesDir;
michael@0 1294 });
michael@0 1295
michael@0 1296 XPCOMUtils.defineLazyGetter(this, "gProgFilesDir",
michael@0 1297 function test_gProgFilesDir() {
michael@0 1298 const CSIDL_PROGRAM_FILES = 0x26;
michael@0 1299
michael@0 1300 AUS_Cu.import("resource://gre/modules/ctypes.jsm");
michael@0 1301 let lib = ctypes.open("shell32");
michael@0 1302 let SHGetSpecialFolderPath = lib.declare("SHGetSpecialFolderPathW",
michael@0 1303 ctypes.winapi_abi,
michael@0 1304 ctypes.bool, /* bool(return) */
michael@0 1305 ctypes.int32_t, /* HWND hwndOwner */
michael@0 1306 ctypes.jschar.ptr, /* LPTSTR lpszPath */
michael@0 1307 ctypes.int32_t, /* int csidl */
michael@0 1308 ctypes.bool /* BOOL fCreate */);
michael@0 1309
michael@0 1310 let aryPathProgFiles = ctypes.jschar.array()(260);
michael@0 1311 let rv = SHGetSpecialFolderPath(0, aryPathProgFiles, CSIDL_PROGRAM_FILES, false);
michael@0 1312 lib.close();
michael@0 1313
michael@0 1314 let pathProgFiles = aryPathProgFiles.readString(); // Convert the c-string to js-string
michael@0 1315 let progFilesDir = AUS_Cc["@mozilla.org/file/local;1"].
michael@0 1316 createInstance(AUS_Ci.nsILocalFile);
michael@0 1317 progFilesDir.initWithPath(pathProgFiles);
michael@0 1318 return progFilesDir;
michael@0 1319 });
michael@0 1320
michael@0 1321 /**
michael@0 1322 * Helper function for getting the update root directory used by the tests. This
michael@0 1323 * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir
michael@0 1324 * in nsXREDirProvider.cpp so an application will be able to find the update
michael@0 1325 * when running a test that launches the application.
michael@0 1326 */
michael@0 1327 function getMockUpdRootD() {
michael@0 1328 let localAppDataDir = gLocalAppDataDir.clone();
michael@0 1329 let progFilesDir = gProgFilesDir.clone();
michael@0 1330 let appDir = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent;
michael@0 1331
michael@0 1332 let appDirPath = appDir.path;
michael@0 1333 var relPathUpdates = "";
michael@0 1334 if (gInstallDirPathHash && (MOZ_APP_VENDOR || MOZ_APP_BASENAME)) {
michael@0 1335 relPathUpdates += (MOZ_APP_VENDOR ? MOZ_APP_VENDOR : MOZ_APP_BASENAME) +
michael@0 1336 "\\" + DIR_UPDATES + "\\" + gInstallDirPathHash;
michael@0 1337 }
michael@0 1338
michael@0 1339 if (!relPathUpdates) {
michael@0 1340 if (appDirPath.length > progFilesDir.path.length) {
michael@0 1341 if (appDirPath.substr(0, progFilesDir.path.length) == progFilesDir.path) {
michael@0 1342 if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) {
michael@0 1343 relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME;
michael@0 1344 } else {
michael@0 1345 relPathUpdates += MOZ_APP_BASENAME;
michael@0 1346 }
michael@0 1347 relPathUpdates += appDirPath.substr(progFilesDir.path.length);
michael@0 1348 }
michael@0 1349 }
michael@0 1350 }
michael@0 1351
michael@0 1352 if (!relPathUpdates) {
michael@0 1353 if (MOZ_APP_VENDOR && MOZ_APP_BASENAME) {
michael@0 1354 relPathUpdates += MOZ_APP_VENDOR + "\\" + MOZ_APP_BASENAME;
michael@0 1355 } else {
michael@0 1356 relPathUpdates += MOZ_APP_BASENAME;
michael@0 1357 }
michael@0 1358 relPathUpdates += "\\" + MOZ_APP_NAME;
michael@0 1359 }
michael@0 1360
michael@0 1361 var updatesDir = AUS_Cc["@mozilla.org/file/local;1"].
michael@0 1362 createInstance(AUS_Ci.nsILocalFile);
michael@0 1363 updatesDir.initWithPath(localAppDataDir.path + "\\" + relPathUpdates);
michael@0 1364 logTestInfo("returning UpdRootD Path: " + updatesDir.path);
michael@0 1365 return updatesDir;
michael@0 1366 }
michael@0 1367 #else
michael@0 1368 /**
michael@0 1369 * Helper function for getting the update root directory used by the tests. This
michael@0 1370 * returns the same directory as returned by nsXREDirProvider::GetUpdateRootDir
michael@0 1371 * in nsXREDirProvider.cpp so an application will be able to find the update
michael@0 1372 * when running a test that launches the application.
michael@0 1373 */
michael@0 1374 function getMockUpdRootD() {
michael@0 1375 return getApplyDirFile(DIR_BIN_REL_PATH, true);
michael@0 1376 }
michael@0 1377 #endif
michael@0 1378
michael@0 1379 /**
michael@0 1380 * Helper function for getting the nsIFile for the directory where the update
michael@0 1381 * has been applied.
michael@0 1382 *
michael@0 1383 * This will be the same as getApplyDirFile for foreground updates, but will
michael@0 1384 * point to a different file for the case of staged updates.
michael@0 1385 *
michael@0 1386 * Functions which attempt to access the files in the updated directory should
michael@0 1387 * be using this instead of getApplyDirFile.
michael@0 1388 *
michael@0 1389 * @param aRelPath (optional)
michael@0 1390 * The relative path to the file or directory to get from the root of
michael@0 1391 * the test's directory. If not specified the test's directory will be
michael@0 1392 * returned.
michael@0 1393 * @param aAllowNonexistent (optional)
michael@0 1394 * Whether the file must exist. If false or not specified the file must
michael@0 1395 * exist or the function will throw.
michael@0 1396 * @return The nsIFile for the directory where the update has been applied.
michael@0 1397 */
michael@0 1398 function getTargetDirFile(aRelPath, aAllowNonexistent) {
michael@0 1399 let relpath = getUpdatedDirPath() + (aRelPath ? aRelPath : "");
michael@0 1400 return do_get_file(relpath, aAllowNonexistent);
michael@0 1401 }
michael@0 1402
michael@0 1403 if (IS_WIN) {
michael@0 1404 const kLockFileName = "updated.update_in_progress.lock";
michael@0 1405 /**
michael@0 1406 * Helper function for locking a directory on Windows.
michael@0 1407 *
michael@0 1408 * @param aDir
michael@0 1409 * The nsIFile for the directory to lock.
michael@0 1410 */
michael@0 1411 function lockDirectory(aDir) {
michael@0 1412 var file = aDir.clone();
michael@0 1413 file.append(kLockFileName);
michael@0 1414 file.create(file.NORMAL_FILE_TYPE, 0o444);
michael@0 1415 file.QueryInterface(AUS_Ci.nsILocalFileWin);
michael@0 1416 file.fileAttributesWin |= file.WFA_READONLY;
michael@0 1417 file.fileAttributesWin &= ~file.WFA_READWRITE;
michael@0 1418 logTestInfo("testing the successful creation of the lock file");
michael@0 1419 do_check_true(file.exists());
michael@0 1420 do_check_false(file.isWritable());
michael@0 1421 }
michael@0 1422 /**
michael@0 1423 * Helper function for unlocking a directory on Windows.
michael@0 1424 *
michael@0 1425 * @param aDir
michael@0 1426 * The nsIFile for the directory to unlock.
michael@0 1427 */
michael@0 1428 function unlockDirectory(aDir) {
michael@0 1429 var file = aDir.clone();
michael@0 1430 file.append(kLockFileName);
michael@0 1431 file.QueryInterface(AUS_Ci.nsILocalFileWin);
michael@0 1432 file.fileAttributesWin |= file.WFA_READWRITE;
michael@0 1433 file.fileAttributesWin &= ~file.WFA_READONLY;
michael@0 1434 logTestInfo("removing and testing the successful removal of the lock file");
michael@0 1435 file.remove(false);
michael@0 1436 do_check_false(file.exists());
michael@0 1437 }
michael@0 1438 }
michael@0 1439
michael@0 1440 /**
michael@0 1441 * Helper function for updater tests for launching the updater binary to apply
michael@0 1442 * a mar file.
michael@0 1443 *
michael@0 1444 * @param aExpectedExitValue
michael@0 1445 * The expected exit value from the updater binary.
michael@0 1446 * @param aExpectedStatus
michael@0 1447 * The expected value of update.status when the test finishes.
michael@0 1448 * @param aCallback (optional)
michael@0 1449 * A callback function that will be called when this function finishes.
michael@0 1450 * If null no function will be called when this function finishes.
michael@0 1451 * If not specified the checkUpdateApplied function will be called when
michael@0 1452 * this function finishes.
michael@0 1453 */
michael@0 1454 function runUpdate(aExpectedExitValue, aExpectedStatus, aCallback) {
michael@0 1455 // Copy the updater binary to the updates directory.
michael@0 1456 let binDir = gGREDirOrig.clone();
michael@0 1457 let updater = binDir.clone();
michael@0 1458 updater.append("updater.app");
michael@0 1459 if (!updater.exists()) {
michael@0 1460 updater = binDir.clone();
michael@0 1461 updater.append(FILE_UPDATER_BIN);
michael@0 1462 if (!updater.exists()) {
michael@0 1463 do_throw("Unable to find updater binary!");
michael@0 1464 }
michael@0 1465 }
michael@0 1466
michael@0 1467 let updatesDir = getUpdatesPatchDir();
michael@0 1468 updater.copyToFollowingLinks(updatesDir, updater.leafName);
michael@0 1469 let updateBin = updatesDir.clone();
michael@0 1470 updateBin.append(updater.leafName);
michael@0 1471 if (updateBin.leafName == "updater.app") {
michael@0 1472 updateBin.append("Contents");
michael@0 1473 updateBin.append("MacOS");
michael@0 1474 updateBin.append("updater");
michael@0 1475 if (!updateBin.exists()) {
michael@0 1476 do_throw("Unable to find the updater executable!");
michael@0 1477 }
michael@0 1478 }
michael@0 1479
michael@0 1480 let applyToDir = getApplyDirFile(null, true);
michael@0 1481 let applyToDirPath = applyToDir.path;
michael@0 1482 if (gStageUpdate || gSwitchApp) {
michael@0 1483 applyToDirPath += "/" + DIR_UPDATED + "/";
michael@0 1484 }
michael@0 1485
michael@0 1486 if (IS_WIN) {
michael@0 1487 // Convert to native path
michael@0 1488 applyToDirPath = applyToDirPath.replace(/\//g, "\\");
michael@0 1489 }
michael@0 1490
michael@0 1491 let callbackApp = getApplyDirFile("a/b/" + gCallbackBinFile);
michael@0 1492 callbackApp.permissions = PERMS_DIRECTORY;
michael@0 1493
michael@0 1494 let args = [updatesDir.path, applyToDirPath, 0];
michael@0 1495 if (gStageUpdate) {
michael@0 1496 args[2] = -1;
michael@0 1497 } else {
michael@0 1498 if (gSwitchApp) {
michael@0 1499 args[2] = "0/replace";
michael@0 1500 }
michael@0 1501 args = args.concat([callbackApp.parent.path, callbackApp.path]);
michael@0 1502 args = args.concat(gCallbackArgs);
michael@0 1503 }
michael@0 1504 logTestInfo("running the updater: " + updateBin.path + " " + args.join(" "));
michael@0 1505
michael@0 1506 let env = AUS_Cc["@mozilla.org/process/environment;1"].
michael@0 1507 getService(AUS_Ci.nsIEnvironment);
michael@0 1508 if (gDisableReplaceFallback) {
michael@0 1509 env.set("MOZ_NO_REPLACE_FALLBACK", "1");
michael@0 1510 }
michael@0 1511
michael@0 1512 let process = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 1513 createInstance(AUS_Ci.nsIProcess);
michael@0 1514 process.init(updateBin);
michael@0 1515 process.run(true, args, args.length);
michael@0 1516
michael@0 1517 if (gDisableReplaceFallback) {
michael@0 1518 env.set("MOZ_NO_REPLACE_FALLBACK", "");
michael@0 1519 }
michael@0 1520
michael@0 1521 let status = readStatusFile();
michael@0 1522 if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) {
michael@0 1523 if (process.exitValue != aExpectedExitValue) {
michael@0 1524 logTestInfo("updater exited with unexpected value! Got: " +
michael@0 1525 process.exitValue + ", Expected: " + aExpectedExitValue);
michael@0 1526 }
michael@0 1527 if (status != aExpectedStatus) {
michael@0 1528 logTestInfo("update status is not the expected status! Got: " + status +
michael@0 1529 ", Expected: " + aExpectedStatus);
michael@0 1530 }
michael@0 1531 let updateLog = getUpdatesPatchDir();
michael@0 1532 updateLog.append(FILE_UPDATE_LOG);
michael@0 1533 logTestInfo("contents of " + updateLog.path + ":\n" +
michael@0 1534 readFileBytes(updateLog).replace(/\r\n/g, "\n"));
michael@0 1535 }
michael@0 1536 logTestInfo("testing updater binary process exitValue against expected " +
michael@0 1537 "exit value");
michael@0 1538 do_check_eq(process.exitValue, aExpectedExitValue);
michael@0 1539 logTestInfo("testing update status against expected status");
michael@0 1540 do_check_eq(status, aExpectedStatus);
michael@0 1541
michael@0 1542 if (aCallback !== null) {
michael@0 1543 if (typeof(aCallback) == typeof(Function)) {
michael@0 1544 aCallback();
michael@0 1545 } else {
michael@0 1546 checkUpdateApplied();
michael@0 1547 }
michael@0 1548 }
michael@0 1549 }
michael@0 1550 /**
michael@0 1551 * Helper function for updater tests to stage an update.
michael@0 1552 */
michael@0 1553 function stageUpdate() {
michael@0 1554 logTestInfo("start - staging update");
michael@0 1555 Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
michael@0 1556
michael@0 1557 setEnvironment();
michael@0 1558 // Stage the update.
michael@0 1559 AUS_Cc["@mozilla.org/updates/update-processor;1"].
michael@0 1560 createInstance(AUS_Ci.nsIUpdateProcessor).
michael@0 1561 processUpdate(gUpdateManager.activeUpdate);
michael@0 1562 resetEnvironment();
michael@0 1563
michael@0 1564 logTestInfo("finish - staging update");
michael@0 1565 }
michael@0 1566
michael@0 1567 /**
michael@0 1568 * Helper function to check whether the maintenance service updater tests should
michael@0 1569 * run. See bug 711660 for more details.
michael@0 1570 *
michael@0 1571 * @param aFirstTest
michael@0 1572 * Whether this is the first test within the test.
michael@0 1573 * @return true if the test should run and false if it shouldn't.
michael@0 1574 */
michael@0 1575 function shouldRunServiceTest(aFirstTest) {
michael@0 1576 // In case the machine is running an old maintenance service or if it
michael@0 1577 // is not installed, and permissions exist to install it. Then install
michael@0 1578 // the newer bin that we have.
michael@0 1579 attemptServiceInstall();
michael@0 1580
michael@0 1581 let binDir = getGREDir();
michael@0 1582 let updaterBin = binDir.clone();
michael@0 1583 updaterBin.append(FILE_UPDATER_BIN);
michael@0 1584 if (!updaterBin.exists()) {
michael@0 1585 do_throw("Unable to find updater binary!");
michael@0 1586 }
michael@0 1587
michael@0 1588 let updaterBinPath = updaterBin.path;
michael@0 1589 if (/ /.test(updaterBinPath)) {
michael@0 1590 updaterBinPath = '"' + updaterBinPath + '"';
michael@0 1591 }
michael@0 1592
michael@0 1593 const REG_PATH = "SOFTWARE\\Mozilla\\MaintenanceService\\" +
michael@0 1594 "3932ecacee736d366d6436db0f55bce4";
michael@0 1595
michael@0 1596 let key = AUS_Cc["@mozilla.org/windows-registry-key;1"].
michael@0 1597 createInstance(AUS_Ci.nsIWindowsRegKey);
michael@0 1598 try {
michael@0 1599 key.open(AUS_Ci.nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE, REG_PATH,
michael@0 1600 AUS_Ci.nsIWindowsRegKey.ACCESS_READ | key.WOW64_64);
michael@0 1601 } catch (e) {
michael@0 1602 #ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
michael@0 1603 // The build system could sign the files and not have the test registry key
michael@0 1604 // in which case we should fail the test by throwing so it can be fixed.
michael@0 1605 if (isBinarySigned(updaterBinPath)) {
michael@0 1606 do_throw("binary is signed but the test registry key does not exists!");
michael@0 1607 }
michael@0 1608 #endif
michael@0 1609
michael@0 1610 logTestInfo("this test can only run on the buildbot build system at this " +
michael@0 1611 "time.");
michael@0 1612 return false;
michael@0 1613 }
michael@0 1614
michael@0 1615 // Check to make sure the service is installed
michael@0 1616 let helperBin = getTestDirFile(FILE_HELPER_BIN);
michael@0 1617 let args = ["wait-for-service-stop", "MozillaMaintenance", "10"];
michael@0 1618 let process = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 1619 createInstance(AUS_Ci.nsIProcess);
michael@0 1620 process.init(helperBin);
michael@0 1621 logTestInfo("checking if the service exists on this machine.");
michael@0 1622 process.run(true, args, args.length);
michael@0 1623 if (process.exitValue == 0xEE) {
michael@0 1624 do_throw("test registry key exists but this test can only run on systems " +
michael@0 1625 "with the maintenance service installed.");
michael@0 1626 } else {
michael@0 1627 logTestInfo("service exists, return value: " + process.exitValue);
michael@0 1628 }
michael@0 1629
michael@0 1630 // If this is the first test in the series, then there is no reason the
michael@0 1631 // service should be anything but stopped, so be strict here and throw
michael@0 1632 // an error.
michael@0 1633 if (aFirstTest && process.exitValue != 0) {
michael@0 1634 do_throw("First test, check for service stopped state returned error " +
michael@0 1635 process.exitValue);
michael@0 1636 }
michael@0 1637
michael@0 1638 #ifndef DISABLE_UPDATER_AUTHENTICODE_CHECK
michael@0 1639 if (!isBinarySigned(updaterBinPath)) {
michael@0 1640 logTestInfo("test registry key exists but this test can only run on " +
michael@0 1641 "builds with signed binaries when " +
michael@0 1642 "DISABLE_UPDATER_AUTHENTICODE_CHECK is not defined");
michael@0 1643 do_throw("this test can only run on builds with signed binaries.");
michael@0 1644 }
michael@0 1645 #endif
michael@0 1646 return true;
michael@0 1647 }
michael@0 1648
michael@0 1649 /**
michael@0 1650 * Helper function to check whether the a binary is signed.
michael@0 1651 *
michael@0 1652 * @param aBinPath The path to the file to check if it is signed.
michael@0 1653 * @return true if the file is signed and false if it isn't.
michael@0 1654 */
michael@0 1655 function isBinarySigned(aBinPath) {
michael@0 1656 let helperBin = getTestDirFile(FILE_HELPER_BIN);
michael@0 1657 let args = ["check-signature", aBinPath];
michael@0 1658 let process = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 1659 createInstance(AUS_Ci.nsIProcess);
michael@0 1660 process.init(helperBin);
michael@0 1661 process.run(true, args, args.length);
michael@0 1662 if (process.exitValue != 0) {
michael@0 1663 logTestInfo("binary is not signed. " + FILE_HELPER_BIN + " returned " +
michael@0 1664 process.exitValue + " for file " + aBinPath);
michael@0 1665 return false;
michael@0 1666 }
michael@0 1667 return true;
michael@0 1668 }
michael@0 1669
michael@0 1670 /**
michael@0 1671 * Helper function for asynchronously setting up the application files required
michael@0 1672 * to launch the application for the updater tests by either copying or creating
michael@0 1673 * symlinks for the files. This is needed for Windows debug builds which can
michael@0 1674 * lock a file that is being copied so that the tests can run in parallel. After
michael@0 1675 * the files have been copied the setupAppFilesFinished function will be called.
michael@0 1676 */
michael@0 1677 function setupAppFilesAsync() {
michael@0 1678 gTimeoutRuns++;
michael@0 1679 try {
michael@0 1680 setupAppFiles();
michael@0 1681 } catch (e) {
michael@0 1682 if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
michael@0 1683 do_throw("Exceeded MAX_TIMEOUT_RUNS while trying to setup application " +
michael@0 1684 "files. Exception: " + e);
michael@0 1685 }
michael@0 1686 do_timeout(TEST_CHECK_TIMEOUT, setupAppFilesAsync);
michael@0 1687 return;
michael@0 1688 }
michael@0 1689
michael@0 1690 setupAppFilesFinished();
michael@0 1691 }
michael@0 1692
michael@0 1693 /**
michael@0 1694 * Helper function for setting up the application files required to launch the
michael@0 1695 * application for the updater tests by either copying or creating symlinks for
michael@0 1696 * the files.
michael@0 1697 */
michael@0 1698 function setupAppFiles() {
michael@0 1699 logTestInfo("start - copying or creating symlinks for application files " +
michael@0 1700 "for the test");
michael@0 1701
michael@0 1702 let srcDir = getCurrentProcessDir();
michael@0 1703 let destDir = getApplyDirFile(null, true);
michael@0 1704 if (!destDir.exists()) {
michael@0 1705 try {
michael@0 1706 destDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
michael@0 1707 } catch (e) {
michael@0 1708 logTestInfo("unable to create directory, Path: " + destDir.path +
michael@0 1709 ", Exception: " + e);
michael@0 1710 do_throw(e);
michael@0 1711 }
michael@0 1712 }
michael@0 1713
michael@0 1714 // Required files for the application or the test that aren't listed in the
michael@0 1715 // dependentlibs.list file.
michael@0 1716 let fileRelPaths = [FILE_APP_BIN, FILE_UPDATER_BIN,
michael@0 1717 "application.ini", "dependentlibs.list"];
michael@0 1718
michael@0 1719 // On Linux the updater.png must also be copied
michael@0 1720 if (IS_UNIX && !IS_MACOSX) {
michael@0 1721 fileRelPaths.push("icons/updater.png");
michael@0 1722 }
michael@0 1723
michael@0 1724 // Read the dependent libs file leafnames from the dependentlibs.list file
michael@0 1725 // into the array.
michael@0 1726 let deplibsFile = srcDir.clone();
michael@0 1727 deplibsFile.append("dependentlibs.list");
michael@0 1728 let istream = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
michael@0 1729 createInstance(AUS_Ci.nsIFileInputStream);
michael@0 1730 istream.init(deplibsFile, 0x01, 0o444, 0);
michael@0 1731 istream.QueryInterface(AUS_Ci.nsILineInputStream);
michael@0 1732
michael@0 1733 let hasMore;
michael@0 1734 let line = {};
michael@0 1735 do {
michael@0 1736 hasMore = istream.readLine(line);
michael@0 1737 fileRelPaths.push(line.value);
michael@0 1738 } while(hasMore);
michael@0 1739
michael@0 1740 istream.close();
michael@0 1741
michael@0 1742 fileRelPaths.forEach(function CMAF_FLN_FE(aFileRelPath) {
michael@0 1743 copyFileToTestAppDir(aFileRelPath);
michael@0 1744 });
michael@0 1745
michael@0 1746 logTestInfo("finish - copying or creating symlinks for application files " +
michael@0 1747 "for the test");
michael@0 1748 }
michael@0 1749
michael@0 1750 /**
michael@0 1751 * Copies the specified files from the dist/bin directory into the test's
michael@0 1752 * application directory.
michael@0 1753 *
michael@0 1754 * @param aFileRelPath
michael@0 1755 * The relative path of the file to copy.
michael@0 1756 */
michael@0 1757 function copyFileToTestAppDir(aFileRelPath) {
michael@0 1758 let fileRelPath = aFileRelPath;
michael@0 1759 let srcFile = gGREDirOrig.clone();
michael@0 1760 let pathParts = fileRelPath.split("/");
michael@0 1761 for (let i = 0; i < pathParts.length; i++) {
michael@0 1762 if (pathParts[i]) {
michael@0 1763 srcFile.append(pathParts[i]);
michael@0 1764 }
michael@0 1765 }
michael@0 1766
michael@0 1767 if (IS_MACOSX && !srcFile.exists()) {
michael@0 1768 logTestInfo("unable to copy file since it doesn't exist! Checking if " +
michael@0 1769 fileRelPath + ".app exists. Path: " +
michael@0 1770 srcFile.path);
michael@0 1771 srcFile = gGREDirOrig.clone();
michael@0 1772 for (let i = 0; i < pathParts.length; i++) {
michael@0 1773 if (pathParts[i]) {
michael@0 1774 srcFile.append(pathParts[i] + (pathParts.length - 1 == i ? ".app" : ""));
michael@0 1775 }
michael@0 1776 }
michael@0 1777 fileRelPath = fileRelPath + ".app";
michael@0 1778 }
michael@0 1779
michael@0 1780 if (!srcFile.exists()) {
michael@0 1781 do_throw("Unable to copy file since it doesn't exist! Path: " +
michael@0 1782 srcFile.path);
michael@0 1783 }
michael@0 1784
michael@0 1785 // Symlink libraries. Note that the XUL library on Mac OS X doesn't have a
michael@0 1786 // file extension and this will always be false on Windows.
michael@0 1787 let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" ||
michael@0 1788 fileRelPath.substr(fileRelPath.length - 3) == ".so" ||
michael@0 1789 fileRelPath.substr(fileRelPath.length - 6) == ".dylib");
michael@0 1790 let destFile = getApplyDirFile(DIR_BIN_REL_PATH + fileRelPath, true);
michael@0 1791 if (!shouldSymlink) {
michael@0 1792 if (!destFile.exists()) {
michael@0 1793 try {
michael@0 1794 srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName);
michael@0 1795 } catch (e) {
michael@0 1796 // Just in case it is partially copied
michael@0 1797 if (destFile.exists()) {
michael@0 1798 try {
michael@0 1799 destFile.remove(true);
michael@0 1800 } catch (e) {
michael@0 1801 logTestInfo("unable to remove file that failed to copy! Path: " +
michael@0 1802 destFile.path);
michael@0 1803 }
michael@0 1804 }
michael@0 1805 do_throw("Unable to copy file! Path: " + srcFile.path +
michael@0 1806 ", Exception: " + e);
michael@0 1807 }
michael@0 1808 }
michael@0 1809 } else {
michael@0 1810 try {
michael@0 1811 if (destFile.exists()) {
michael@0 1812 destFile.remove(false);
michael@0 1813 }
michael@0 1814 let ln = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile);
michael@0 1815 ln.initWithPath("/bin/ln");
michael@0 1816 let process = AUS_Cc["@mozilla.org/process/util;1"].createInstance(AUS_Ci.nsIProcess);
michael@0 1817 process.init(ln);
michael@0 1818 let args = ["-s", srcFile.path, destFile.path];
michael@0 1819 process.run(true, args, args.length);
michael@0 1820 logTestInfo("verifying symlink. Path: " + destFile.path);
michael@0 1821 do_check_true(destFile.isSymlink());
michael@0 1822 } catch (e) {
michael@0 1823 do_throw("Unable to create symlink for file! Path: " + srcFile.path +
michael@0 1824 ", Exception: " + e);
michael@0 1825 }
michael@0 1826 }
michael@0 1827 }
michael@0 1828
michael@0 1829 /**
michael@0 1830 * Attempts to upgrade the maintenance service if permissions are allowed.
michael@0 1831 * This is useful for XP where we have permission to upgrade in case an
michael@0 1832 * older service installer exists. Also if the user manually installed into
michael@0 1833 * a unprivileged location.
michael@0 1834 */
michael@0 1835 function attemptServiceInstall() {
michael@0 1836 var version = AUS_Cc["@mozilla.org/system-info;1"]
michael@0 1837 .getService(AUS_Ci.nsIPropertyBag2)
michael@0 1838 .getProperty("version");
michael@0 1839 var isVistaOrHigher = (parseFloat(version) >= 6.0);
michael@0 1840 if (isVistaOrHigher) {
michael@0 1841 return;
michael@0 1842 }
michael@0 1843
michael@0 1844 let binDir = getGREDir();
michael@0 1845 let installerFile = binDir.clone();
michael@0 1846 installerFile.append(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
michael@0 1847 if (!installerFile.exists()) {
michael@0 1848 do_throw(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN + " not found.");
michael@0 1849 }
michael@0 1850 let installerProcess = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 1851 createInstance(AUS_Ci.nsIProcess);
michael@0 1852 installerProcess.init(installerFile);
michael@0 1853 logTestInfo("starting installer process...");
michael@0 1854 installerProcess.run(true, [], 0);
michael@0 1855 }
michael@0 1856
michael@0 1857 /**
michael@0 1858 * Helper function for updater tests for launching the updater using the
michael@0 1859 * maintenance service to apply a mar file.
michael@0 1860 *
michael@0 1861 * @param aInitialStatus
michael@0 1862 * The initial value of update.status.
michael@0 1863 * @param aExpectedStatus
michael@0 1864 * The expected value of update.status when the test finishes.
michael@0 1865 * @param aCheckSvcLog
michael@0 1866 * Whether the service log should be checked (optional).
michael@0 1867 */
michael@0 1868 function runUpdateUsingService(aInitialStatus, aExpectedStatus, aCheckSvcLog) {
michael@0 1869 // Check the service logs for a successful update
michael@0 1870 function checkServiceLogs(aOriginalContents) {
michael@0 1871 let contents = readServiceLogFile();
michael@0 1872 logTestInfo("the contents of maintenanceservice.log:\n" + contents + "\n");
michael@0 1873 do_check_neq(contents, aOriginalContents);
michael@0 1874 do_check_neq(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1);
michael@0 1875 }
michael@0 1876 function readServiceLogFile() {
michael@0 1877 let file = AUS_Cc["@mozilla.org/file/directory_service;1"].
michael@0 1878 getService(AUS_Ci.nsIProperties).
michael@0 1879 get("CmAppData", AUS_Ci.nsIFile);
michael@0 1880 file.append("Mozilla");
michael@0 1881 file.append("logs");
michael@0 1882 file.append("maintenanceservice.log");
michael@0 1883 return readFile(file);
michael@0 1884 }
michael@0 1885 function waitServiceApps() {
michael@0 1886 // maintenanceservice_installer.exe is started async during updates.
michael@0 1887 waitForApplicationStop("maintenanceservice_installer.exe");
michael@0 1888 // maintenanceservice_tmp.exe is started async from the service installer.
michael@0 1889 waitForApplicationStop("maintenanceservice_tmp.exe");
michael@0 1890 // In case the SCM thinks the service is stopped, but process still exists.
michael@0 1891 waitForApplicationStop("maintenanceservice.exe");
michael@0 1892 }
michael@0 1893 function waitForServiceStop(aFailTest) {
michael@0 1894 waitServiceApps();
michael@0 1895 logTestInfo("waiting for service to stop if necessary...");
michael@0 1896 // Use the helper bin to ensure the service is stopped. If not
michael@0 1897 // stopped then wait for the service to be stopped (at most 120 seconds)
michael@0 1898 let helperBin = getTestDirFile(FILE_HELPER_BIN);
michael@0 1899 let helperBinArgs = ["wait-for-service-stop",
michael@0 1900 "MozillaMaintenance",
michael@0 1901 "120"];
michael@0 1902 let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 1903 createInstance(AUS_Ci.nsIProcess);
michael@0 1904 helperBinProcess.init(helperBin);
michael@0 1905 logTestInfo("stopping service...");
michael@0 1906 helperBinProcess.run(true, helperBinArgs, helperBinArgs.length);
michael@0 1907 if (helperBinProcess.exitValue == 0xEE) {
michael@0 1908 do_throw("The service does not exist on this machine. Return value: " +
michael@0 1909 helperBinProcess.exitValue);
michael@0 1910 } else if (helperBinProcess.exitValue != 0) {
michael@0 1911 if (aFailTest) {
michael@0 1912 do_throw("maintenance service did not stop, last state: " +
michael@0 1913 helperBinProcess.exitValue + ". Forcing test failure.");
michael@0 1914 } else {
michael@0 1915 logTestInfo("maintenance service did not stop, last state: " +
michael@0 1916 helperBinProcess.exitValue + ". May cause failures.");
michael@0 1917 }
michael@0 1918 } else {
michael@0 1919 logTestInfo("service stopped.");
michael@0 1920 }
michael@0 1921 waitServiceApps();
michael@0 1922 }
michael@0 1923 function waitForApplicationStop(aApplication) {
michael@0 1924 logTestInfo("waiting for " + aApplication + " to stop if " +
michael@0 1925 "necessary...");
michael@0 1926 // Use the helper bin to ensure the application is stopped.
michael@0 1927 // If not, then wait for it to be stopped (at most 120 seconds)
michael@0 1928 let helperBin = getTestDirFile(FILE_HELPER_BIN);
michael@0 1929 let helperBinArgs = ["wait-for-application-exit",
michael@0 1930 aApplication,
michael@0 1931 "120"];
michael@0 1932 let helperBinProcess = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 1933 createInstance(AUS_Ci.nsIProcess);
michael@0 1934 helperBinProcess.init(helperBin);
michael@0 1935 helperBinProcess.run(true, helperBinArgs, helperBinArgs.length);
michael@0 1936 if (helperBinProcess.exitValue != 0) {
michael@0 1937 do_throw(aApplication + " did not stop, last state: " +
michael@0 1938 helperBinProcess.exitValue + ". Forcing test failure.");
michael@0 1939 }
michael@0 1940 }
michael@0 1941
michael@0 1942 // Make sure the service from the previous test is already stopped.
michael@0 1943 waitForServiceStop(true);
michael@0 1944
michael@0 1945 // Prevent the cleanup function from begin run more than once
michael@0 1946 if (gRegisteredServiceCleanup === undefined) {
michael@0 1947 gRegisteredServiceCleanup = true;
michael@0 1948
michael@0 1949 do_register_cleanup(function RUUS_cleanup() {
michael@0 1950 resetEnvironment();
michael@0 1951
michael@0 1952 // This will delete the app arguments log file if it exists.
michael@0 1953 try {
michael@0 1954 getAppArgsLogPath();
michael@0 1955 } catch (e) {
michael@0 1956 logTestInfo("unable to remove file during cleanup. Exception: " + e);
michael@0 1957 }
michael@0 1958 });
michael@0 1959 }
michael@0 1960
michael@0 1961 let svcOriginalLog;
michael@0 1962 // Default to checking the service log if the parameter is not specified.
michael@0 1963 if (aCheckSvcLog === undefined || aCheckSvcLog) {
michael@0 1964 svcOriginalLog = readServiceLogFile();
michael@0 1965 }
michael@0 1966
michael@0 1967 let appArgsLogPath = getAppArgsLogPath();
michael@0 1968 gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, "");
michael@0 1969
michael@0 1970 let updatesDir = getUpdatesPatchDir();
michael@0 1971 let file = updatesDir.clone();
michael@0 1972 writeStatusFile(aInitialStatus);
michael@0 1973
michael@0 1974 // sanity check
michael@0 1975 do_check_eq(readStatusState(), aInitialStatus);
michael@0 1976
michael@0 1977 writeVersionFile(DEFAULT_UPDATE_VERSION);
michael@0 1978
michael@0 1979 gServiceLaunchedCallbackArgs = [
michael@0 1980 "-no-remote",
michael@0 1981 "-process-updates",
michael@0 1982 "-dump-args",
michael@0 1983 appArgsLogPath
michael@0 1984 ];
michael@0 1985
michael@0 1986 if (gSwitchApp) {
michael@0 1987 // We want to set the env vars again
michael@0 1988 gShouldResetEnv = undefined;
michael@0 1989 }
michael@0 1990
michael@0 1991 setEnvironment();
michael@0 1992
michael@0 1993 // There is a security check done by the service to make sure the updater
michael@0 1994 // we are executing is the same as the one in the apply-to dir.
michael@0 1995 // To make sure they match from tests we copy updater.exe to the apply-to dir.
michael@0 1996 copyFileToTestAppDir(FILE_UPDATER_BIN);
michael@0 1997
michael@0 1998 // The service will execute maintenanceservice_installer.exe and
michael@0 1999 // will copy maintenanceservice.exe out of the same directory from
michael@0 2000 // the installation directory. So we need to make sure both of those
michael@0 2001 // bins always exist in the installation directory.
michael@0 2002 copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN);
michael@0 2003 copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN);
michael@0 2004
michael@0 2005 let launchBin = getLaunchBin();
michael@0 2006 let args = getProcessArgs(["-dump-args", appArgsLogPath]);
michael@0 2007
michael@0 2008 let process = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 2009 createInstance(AUS_Ci.nsIProcess);
michael@0 2010 process.init(launchBin);
michael@0 2011 logTestInfo("launching " + launchBin.path + " " + args.join(" "));
michael@0 2012 // Firefox does not wait for the service command to finish, but
michael@0 2013 // we still launch the process sync to avoid intermittent failures with
michael@0 2014 // the log file not being written out yet.
michael@0 2015 // We will rely on watching the update.status file and waiting for the service
michael@0 2016 // to stop to know the service command is done.
michael@0 2017 process.run(true, args, args.length);
michael@0 2018
michael@0 2019 resetEnvironment();
michael@0 2020
michael@0 2021 function timerCallback(aTimer) {
michael@0 2022 // Wait for the expected status
michael@0 2023 let status = readStatusState();
michael@0 2024 // status will probably always be equal to STATE_APPLYING but there is a
michael@0 2025 // race condition where it would be possible on slower machines where status
michael@0 2026 // could be equal to STATE_PENDING_SVC.
michael@0 2027 if (status == STATE_APPLYING ||
michael@0 2028 status == STATE_PENDING_SVC) {
michael@0 2029 logTestInfo("still waiting to see the " + aExpectedStatus +
michael@0 2030 " status, got " + status + " for now...");
michael@0 2031 return;
michael@0 2032 }
michael@0 2033
michael@0 2034 // Make sure all of the logs are written out.
michael@0 2035 waitForServiceStop(false);
michael@0 2036
michael@0 2037 aTimer.cancel();
michael@0 2038 aTimer = null;
michael@0 2039
michael@0 2040 if (status != aExpectedStatus) {
michael@0 2041 logTestInfo("update status is not the expected status! Got: " + status +
michael@0 2042 ", Expected: " + aExpectedStatus);
michael@0 2043 logTestInfo("update.status contents: " + readStatusFile());
michael@0 2044 let updateLog = getUpdatesPatchDir();
michael@0 2045 updateLog.append(FILE_UPDATE_LOG);
michael@0 2046 logTestInfo("contents of " + updateLog.path + ":\n" +
michael@0 2047 readFileBytes(updateLog).replace(/\r\n/g, "\n"));
michael@0 2048 }
michael@0 2049 logTestInfo("testing update status against expected status");
michael@0 2050 do_check_eq(status, aExpectedStatus);
michael@0 2051
michael@0 2052 if (aCheckSvcLog) {
michael@0 2053 checkServiceLogs(svcOriginalLog);
michael@0 2054 }
michael@0 2055
michael@0 2056 checkUpdateFinished();
michael@0 2057 }
michael@0 2058
michael@0 2059 let timer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
michael@0 2060 timer.initWithCallback(timerCallback, 1000, timer.TYPE_REPEATING_SLACK);
michael@0 2061 }
michael@0 2062
michael@0 2063 /**
michael@0 2064 * Gets the platform specific shell binary that is launched using nsIProcess and
michael@0 2065 * in turn launches a binary used for the test (e.g. application, updater,
michael@0 2066 * etc.). A shell is used so debug console output can be redirected to a file so
michael@0 2067 * it doesn't end up in the test log.
michael@0 2068 *
michael@0 2069 * @return nsIFile for the shell binary to launch using nsIProcess.
michael@0 2070 * @throws if the shell binary doesn't exist.
michael@0 2071 */
michael@0 2072 function getLaunchBin() {
michael@0 2073 let launchBin;
michael@0 2074 if (IS_WIN) {
michael@0 2075 launchBin = Services.dirsvc.get("WinD", AUS_Ci.nsIFile);
michael@0 2076 launchBin.append("System32");
michael@0 2077 launchBin.append("cmd.exe");
michael@0 2078 } else {
michael@0 2079 launchBin = AUS_Cc["@mozilla.org/file/local;1"].
michael@0 2080 createInstance(AUS_Ci.nsILocalFile);
michael@0 2081 launchBin.initWithPath("/bin/sh");
michael@0 2082 }
michael@0 2083
michael@0 2084 if (!launchBin.exists())
michael@0 2085 do_throw(launchBin.path + " must exist to run this test!");
michael@0 2086
michael@0 2087 return launchBin;
michael@0 2088 }
michael@0 2089
michael@0 2090 /**
michael@0 2091 * Helper function that waits until the helper has completed its operations and
michael@0 2092 * is in a sleep state before performing an update by calling doUpdate.
michael@0 2093 */
michael@0 2094 function waitForHelperSleep() {
michael@0 2095 gTimeoutRuns++;
michael@0 2096 // Give the lock file process time to lock the file before updating otherwise
michael@0 2097 // this test can fail intermittently on Windows debug builds.
michael@0 2098 let output = getApplyDirFile("a/b/output", true);
michael@0 2099 if (readFile(output) != "sleeping\n") {
michael@0 2100 if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
michael@0 2101 do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " +
michael@0 2102 "finish its operation. Path: " + output.path);
michael@0 2103 }
michael@0 2104 do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
michael@0 2105 return;
michael@0 2106 }
michael@0 2107 try {
michael@0 2108 output.remove(false);
michael@0 2109 }
michael@0 2110 catch (e) {
michael@0 2111 if (gTimeoutRuns > MAX_TIMEOUT_RUNS) {
michael@0 2112 do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper " +
michael@0 2113 "message file to no longer be in use. Path: " + output.path);
michael@0 2114 }
michael@0 2115 logTestInfo("failed to remove file. Path: " + output.path);
michael@0 2116 do_timeout(TEST_HELPER_TIMEOUT, waitForHelperSleep);
michael@0 2117 return;
michael@0 2118 }
michael@0 2119 doUpdate();
michael@0 2120 }
michael@0 2121
michael@0 2122 /**
michael@0 2123 * Helper function that waits until the helper has finished its operations
michael@0 2124 * before calling waitForHelperFinishFileUnlock to verify that the helper's
michael@0 2125 * input and output directories are no longer in use.
michael@0 2126 */
michael@0 2127 function waitForHelperFinished() {
michael@0 2128 // Give the lock file process time to lock the file before updating otherwise
michael@0 2129 // this test can fail intermittently on Windows debug builds.
michael@0 2130 let output = getApplyDirFile("a/b/output", true);
michael@0 2131 if (readFile(output) != "finished\n") {
michael@0 2132 do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinished);
michael@0 2133 return;
michael@0 2134 }
michael@0 2135 // Give the lock file process time to unlock the file before deleting the
michael@0 2136 // input and output files.
michael@0 2137 waitForHelperFinishFileUnlock();
michael@0 2138 }
michael@0 2139
michael@0 2140 /**
michael@0 2141 * Helper function that waits until the helper's input and output files are no
michael@0 2142 * longer in use before calling checkUpdate.
michael@0 2143 */
michael@0 2144 function waitForHelperFinishFileUnlock() {
michael@0 2145 try {
michael@0 2146 let output = getApplyDirFile("a/b/output", true);
michael@0 2147 if (output.exists()) {
michael@0 2148 output.remove(false);
michael@0 2149 }
michael@0 2150 let input = getApplyDirFile("a/b/input", true);
michael@0 2151 if (input.exists()) {
michael@0 2152 input.remove(false);
michael@0 2153 }
michael@0 2154 } catch (e) {
michael@0 2155 // Give the lock file process time to unlock the file before deleting the
michael@0 2156 // input and output files.
michael@0 2157 do_timeout(TEST_HELPER_TIMEOUT, waitForHelperFinishFileUnlock);
michael@0 2158 return;
michael@0 2159 }
michael@0 2160 checkUpdate();
michael@0 2161 }
michael@0 2162
michael@0 2163 /**
michael@0 2164 * Helper function to tell the helper to finish and exit its sleep state.
michael@0 2165 */
michael@0 2166 function setupHelperFinish() {
michael@0 2167 let input = getApplyDirFile("a/b/input", true);
michael@0 2168 writeFile(input, "finish\n");
michael@0 2169 waitForHelperFinished();
michael@0 2170 }
michael@0 2171
michael@0 2172 /**
michael@0 2173 * Helper function for updater binary tests that creates the files and
michael@0 2174 * directories used by the test.
michael@0 2175 *
michael@0 2176 * @param aMarFile
michael@0 2177 * The mar file for the update test.
michael@0 2178 */
michael@0 2179 function setupUpdaterTest(aMarFile, aUpdatedDirExists, aToBeDeletedDirExists) {
michael@0 2180 let updatesPatchDir = getUpdatesPatchDir();
michael@0 2181 if (!updatesPatchDir.exists()) {
michael@0 2182 updatesPatchDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
michael@0 2183 }
michael@0 2184 // Copy the mar that will be applied
michael@0 2185 let mar = getTestDirFile(aMarFile);
michael@0 2186 mar.copyToFollowingLinks(updatesPatchDir, FILE_UPDATE_ARCHIVE);
michael@0 2187
michael@0 2188 createUpdateSettingsINI();
michael@0 2189
michael@0 2190 let applyToDir = getApplyDirFile(null, true);
michael@0 2191 gTestFiles.forEach(function SUT_TF_FE(aTestFile) {
michael@0 2192 if (aTestFile.originalFile || aTestFile.originalContents) {
michael@0 2193 let testDir = getApplyDirFile(aTestFile.relPathDir, true);
michael@0 2194 if (!testDir.exists())
michael@0 2195 testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
michael@0 2196
michael@0 2197 let testFile;
michael@0 2198 if (aTestFile.originalFile) {
michael@0 2199 testFile = getTestDirFile(aTestFile.originalFile);
michael@0 2200 testFile.copyToFollowingLinks(testDir, aTestFile.fileName);
michael@0 2201 testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName);
michael@0 2202 } else {
michael@0 2203 testFile = getApplyDirFile(aTestFile.relPathDir + aTestFile.fileName,
michael@0 2204 true);
michael@0 2205 writeFile(testFile, aTestFile.originalContents);
michael@0 2206 }
michael@0 2207
michael@0 2208 // Skip these tests on Windows and OS/2 since their
michael@0 2209 // implementaions of chmod doesn't really set permissions.
michael@0 2210 if (!IS_WIN && aTestFile.originalPerms) {
michael@0 2211 testFile.permissions = aTestFile.originalPerms;
michael@0 2212 // Store the actual permissions on the file for reference later after
michael@0 2213 // setting the permissions.
michael@0 2214 if (!aTestFile.comparePerms) {
michael@0 2215 aTestFile.comparePerms = testFile.permissions;
michael@0 2216 }
michael@0 2217 }
michael@0 2218 }
michael@0 2219 });
michael@0 2220
michael@0 2221 let helperBin = getTestDirFile(FILE_HELPER_BIN);
michael@0 2222 let afterApplyBinDir = getApplyDirFile("a/b/", true);
michael@0 2223 helperBin.copyToFollowingLinks(afterApplyBinDir, gCallbackBinFile);
michael@0 2224
michael@0 2225 // Add the test directory that will be updated for a successful update or left
michael@0 2226 // in the initial state for a failed update.
michael@0 2227 gTestDirs.forEach(function SUT_TD_FE(aTestDir) {
michael@0 2228 let testDir = getApplyDirFile(aTestDir.relPathDir, true);
michael@0 2229 if (!testDir.exists()) {
michael@0 2230 testDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
michael@0 2231 }
michael@0 2232
michael@0 2233 if (aTestDir.files) {
michael@0 2234 aTestDir.files.forEach(function SUT_TD_F_FE(aTestFile) {
michael@0 2235 let testFile = getApplyDirFile(aTestDir.relPathDir + aTestFile, true);
michael@0 2236 if (!testFile.exists()) {
michael@0 2237 testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
michael@0 2238 }
michael@0 2239 });
michael@0 2240 }
michael@0 2241
michael@0 2242 if (aTestDir.subDirs) {
michael@0 2243 aTestDir.subDirs.forEach(function SUT_TD_SD_FE(aSubDir) {
michael@0 2244 let testSubDir = getApplyDirFile(aTestDir.relPathDir + aSubDir, true);
michael@0 2245 if (!testSubDir.exists()) {
michael@0 2246 testSubDir.create(AUS_Ci.nsIFile.DIRECTORY_TYPE, PERMS_DIRECTORY);
michael@0 2247 }
michael@0 2248
michael@0 2249 if (aTestDir.subDirFiles) {
michael@0 2250 aTestDir.subDirFiles.forEach(function SUT_TD_SDF_FE(aTestFile) {
michael@0 2251 let testFile = getApplyDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true);
michael@0 2252 if (!testFile.exists()) {
michael@0 2253 testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
michael@0 2254 }
michael@0 2255 });
michael@0 2256 }
michael@0 2257 });
michael@0 2258 }
michael@0 2259 });
michael@0 2260
michael@0 2261 gTestExtraDirs[0].dirExists = aUpdatedDirExists;
michael@0 2262 gTestExtraDirs[1].dirExists = IS_WIN ? aToBeDeletedDirExists : false;
michael@0 2263 }
michael@0 2264
michael@0 2265 /**
michael@0 2266 * Helper function for updater binary tests that creates the update-settings.ini
michael@0 2267 * file.
michael@0 2268 */
michael@0 2269 function createUpdateSettingsINI() {
michael@0 2270 updateSettingsIni = getApplyDirFile(null, true);
michael@0 2271 if (IS_MACOSX) {
michael@0 2272 updateSettingsIni.append("Contents");
michael@0 2273 updateSettingsIni.append("MacOS");
michael@0 2274 }
michael@0 2275 updateSettingsIni.append(FILE_UPDATE_SETTINGS_INI);
michael@0 2276 writeFile(updateSettingsIni, UPDATE_SETTINGS_CONTENTS);
michael@0 2277 }
michael@0 2278
michael@0 2279 /**
michael@0 2280 * Helper function for updater binary tests for verifying the contents of the
michael@0 2281 * update log after a successful update.
michael@0 2282 *
michael@0 2283 * @param aCompareLogFile
michael@0 2284 * The log file to compare the update log with.
michael@0 2285 */
michael@0 2286 function checkUpdateLogContents(aCompareLogFile) {
michael@0 2287 let updateLog = getUpdatesPatchDir();
michael@0 2288 updateLog.append(FILE_UPDATE_LOG);
michael@0 2289 let updateLogContents = readFileBytes(updateLog);
michael@0 2290
michael@0 2291 // The channel-prefs.js is defined in gTestFilesCommon which will always be
michael@0 2292 // located to the end of gTestFiles.
michael@0 2293 if (gTestFiles.length > 1 &&
michael@0 2294 gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
michael@0 2295 !gTestFiles[gTestFiles.length - 1].originalContents) {
michael@0 2296 updateLogContents = updateLogContents.replace(/.* a\/b\/defaults\/.*/g, "");
michael@0 2297 }
michael@0 2298 if (gTestFiles.length > 2 &&
michael@0 2299 gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
michael@0 2300 !gTestFiles[gTestFiles.length - 2].originalContents) {
michael@0 2301 updateLogContents = updateLogContents.replace(/.* a\/b\/update-settings.ini.*/g, "");
michael@0 2302 }
michael@0 2303 if (gStageUpdate) {
michael@0 2304 // Skip the staged update messages
michael@0 2305 updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
michael@0 2306 } else if (gSwitchApp) {
michael@0 2307 // Skip the switch app request messages
michael@0 2308 updateLogContents = updateLogContents.replace(/Performing a staged update/, "");
michael@0 2309 updateLogContents = updateLogContents.replace(/Performing a replace request/, "");
michael@0 2310 }
michael@0 2311 // Skip the source/destination lines since they contain absolute paths.
michael@0 2312 updateLogContents = updateLogContents.replace(/SOURCE DIRECTORY.*/g, "");
michael@0 2313 updateLogContents = updateLogContents.replace(/DESTINATION DIRECTORY.*/g, "");
michael@0 2314 // Skip lines that log failed attempts to open the callback executable.
michael@0 2315 updateLogContents = updateLogContents.replace(/NS_main: callback app file .*/g, "");
michael@0 2316 if (gSwitchApp) {
michael@0 2317 // Remove the lines which contain absolute paths
michael@0 2318 updateLogContents = updateLogContents.replace(/^Begin moving.*$/mg, "");
michael@0 2319 if (IS_MACOSX) {
michael@0 2320 // Remove the entire section about moving the precomplete file as it contains
michael@0 2321 // absolute paths.
michael@0 2322 updateLogContents = updateLogContents.replace(/\n/g, "%%%EOL%%%");
michael@0 2323 updateLogContents = updateLogContents.replace(/Moving the precomplete file.*Finished moving the precomplete file/, "");
michael@0 2324 updateLogContents = updateLogContents.replace(/%%%EOL%%%/g, "\n");
michael@0 2325 }
michael@0 2326 }
michael@0 2327 updateLogContents = updateLogContents.replace(/\r/g, "");
michael@0 2328 // Replace error codes since they are different on each platform.
michael@0 2329 updateLogContents = updateLogContents.replace(/, err:.*\n/g, "\n");
michael@0 2330 // Replace to make the log parsing happy.
michael@0 2331 updateLogContents = updateLogContents.replace(/non-fatal error /g, "");
michael@0 2332 // The FindFile results when enumerating the filesystem on Windows is not
michael@0 2333 // determistic so the results matching the following need to be ignored.
michael@0 2334 updateLogContents = updateLogContents.replace(/.* a\/b\/7\/7text.*\n/g, "");
michael@0 2335 // Remove consecutive newlines
michael@0 2336 updateLogContents = updateLogContents.replace(/\n+/g, "\n");
michael@0 2337 // Remove leading and trailing newlines
michael@0 2338 updateLogContents = updateLogContents.replace(/^\n|\n$/g, "");
michael@0 2339 // The update log when running the service tests sometimes starts with data
michael@0 2340 // from the previous launch of the updater.
michael@0 2341 updateLogContents = updateLogContents.replace(/^calling QuitProgressUI\n[^\n]*\nUPDATE TYPE/g, "UPDATE TYPE");
michael@0 2342
michael@0 2343 let compareLogContents = "";
michael@0 2344 if (aCompareLogFile) {
michael@0 2345 compareLogContents = readFileBytes(getTestDirFile(aCompareLogFile));
michael@0 2346 }
michael@0 2347 if (gSwitchApp) {
michael@0 2348 compareLogContents += LOG_SWITCH_SUCCESS;
michael@0 2349 }
michael@0 2350 // The channel-prefs.js is defined in gTestFilesCommon which will always be
michael@0 2351 // located to the end of gTestFiles.
michael@0 2352 if (gTestFiles.length > 1 &&
michael@0 2353 gTestFiles[gTestFiles.length - 1].fileName == "channel-prefs.js" &&
michael@0 2354 !gTestFiles[gTestFiles.length - 1].originalContents) {
michael@0 2355 compareLogContents = compareLogContents.replace(/.* a\/b\/defaults\/.*/g, "");
michael@0 2356 }
michael@0 2357 if (gTestFiles.length > 2 &&
michael@0 2358 gTestFiles[gTestFiles.length - 2].fileName == FILE_UPDATE_SETTINGS_INI &&
michael@0 2359 !gTestFiles[gTestFiles.length - 2].originalContents) {
michael@0 2360 compareLogContents = compareLogContents.replace(/.* a\/b\/update-settings.ini.*/g, "");
michael@0 2361 }
michael@0 2362 // Remove leading and trailing newlines
michael@0 2363 compareLogContents = compareLogContents.replace(/\n+/g, "\n");
michael@0 2364 // Remove leading and trailing newlines
michael@0 2365 compareLogContents = compareLogContents.replace(/^\n|\n$/g, "");
michael@0 2366
michael@0 2367 // Don't write the contents of the file to the log to reduce log spam
michael@0 2368 // unless there is a failure.
michael@0 2369 if (compareLogContents == updateLogContents) {
michael@0 2370 logTestInfo("log contents are correct");
michael@0 2371 do_check_true(true);
michael@0 2372 } else {
michael@0 2373 logTestInfo("log contents are not correct");
michael@0 2374 do_check_eq(compareLogContents, updateLogContents);
michael@0 2375 }
michael@0 2376 }
michael@0 2377
michael@0 2378 /**
michael@0 2379 * Helper function to check if the update log contains a string.
michael@0 2380 *
michael@0 2381 * @param aCheckString
michael@0 2382 * The string to check if the update log contains.
michael@0 2383 */
michael@0 2384 function checkUpdateLogContains(aCheckString) {
michael@0 2385 let updateLog = getUpdatesPatchDir();
michael@0 2386 updateLog.append(FILE_UPDATE_LOG);
michael@0 2387 let updateLogContents = readFileBytes(updateLog);
michael@0 2388 if (updateLogContents.indexOf(aCheckString) != -1) {
michael@0 2389 logTestInfo("log file does contain: " + aCheckString);
michael@0 2390 do_check_true(true);
michael@0 2391 } else {
michael@0 2392 logTestInfo("log file does not contain: " + aCheckString);
michael@0 2393 logTestInfo("log file contents:\n" + updateLogContents);
michael@0 2394 do_check_true(false);
michael@0 2395 }
michael@0 2396 }
michael@0 2397
michael@0 2398 /**
michael@0 2399 * Helper function for updater binary tests for verifying the state of files and
michael@0 2400 * directories after a successful update.
michael@0 2401 */
michael@0 2402 function checkFilesAfterUpdateSuccess() {
michael@0 2403 logTestInfo("testing contents of files after a successful update");
michael@0 2404 gTestFiles.forEach(function CFAUS_TF_FE(aTestFile) {
michael@0 2405 let testFile = getTargetDirFile(aTestFile.relPathDir + aTestFile.fileName,
michael@0 2406 true);
michael@0 2407 logTestInfo("testing file: " + testFile.path);
michael@0 2408 if (aTestFile.compareFile || aTestFile.compareContents) {
michael@0 2409 do_check_true(testFile.exists());
michael@0 2410
michael@0 2411 // Skip these tests on Windows and OS/2 since their
michael@0 2412 // implementaions of chmod doesn't really set permissions.
michael@0 2413 if (!IS_WIN && aTestFile.comparePerms) {
michael@0 2414 // Check if the permssions as set in the complete mar file are correct.
michael@0 2415 let logPerms = "testing file permissions - ";
michael@0 2416 if (aTestFile.originalPerms) {
michael@0 2417 logPerms += "original permissions: " +
michael@0 2418 aTestFile.originalPerms.toString(8) + ", ";
michael@0 2419 }
michael@0 2420 logPerms += "compare permissions : " +
michael@0 2421 aTestFile.comparePerms.toString(8) + ", ";
michael@0 2422 logPerms += "updated permissions : " + testFile.permissions.toString(8);
michael@0 2423 logTestInfo(logPerms);
michael@0 2424 do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff);
michael@0 2425 }
michael@0 2426
michael@0 2427 let fileContents1 = readFileBytes(testFile);
michael@0 2428 let fileContents2 = aTestFile.compareFile ?
michael@0 2429 readFileBytes(getTestDirFile(aTestFile.compareFile)) :
michael@0 2430 aTestFile.compareContents;
michael@0 2431 // Don't write the contents of the file to the log to reduce log spam
michael@0 2432 // unless there is a failure.
michael@0 2433 if (fileContents1 == fileContents2) {
michael@0 2434 logTestInfo("file contents are correct");
michael@0 2435 do_check_true(true);
michael@0 2436 } else {
michael@0 2437 logTestInfo("file contents are not correct");
michael@0 2438 do_check_eq(fileContents1, fileContents2);
michael@0 2439 }
michael@0 2440 } else {
michael@0 2441 do_check_false(testFile.exists());
michael@0 2442 }
michael@0 2443 });
michael@0 2444
michael@0 2445 logTestInfo("testing operations specified in removed-files were performed " +
michael@0 2446 "after a successful update");
michael@0 2447 gTestDirs.forEach(function CFAUS_TD_FE(aTestDir) {
michael@0 2448 let testDir = getTargetDirFile(aTestDir.relPathDir, true);
michael@0 2449 logTestInfo("testing directory: " + testDir.path);
michael@0 2450 if (aTestDir.dirRemoved) {
michael@0 2451 do_check_false(testDir.exists());
michael@0 2452 } else {
michael@0 2453 do_check_true(testDir.exists());
michael@0 2454
michael@0 2455 if (aTestDir.files) {
michael@0 2456 aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) {
michael@0 2457 let testFile = getTargetDirFile(aTestDir.relPathDir + aTestFile, true);
michael@0 2458 logTestInfo("testing directory file: " + testFile.path);
michael@0 2459 if (aTestDir.filesRemoved) {
michael@0 2460 do_check_false(testFile.exists());
michael@0 2461 } else {
michael@0 2462 do_check_true(testFile.exists());
michael@0 2463 }
michael@0 2464 });
michael@0 2465 }
michael@0 2466
michael@0 2467 if (aTestDir.subDirs) {
michael@0 2468 aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) {
michael@0 2469 let testSubDir = getTargetDirFile(aTestDir.relPathDir + aSubDir, true);
michael@0 2470 logTestInfo("testing sub-directory: " + testSubDir.path);
michael@0 2471 do_check_true(testSubDir.exists());
michael@0 2472 if (aTestDir.subDirFiles) {
michael@0 2473 aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) {
michael@0 2474 let testFile = getTargetDirFile(aTestDir.relPathDir + aSubDir + aTestFile, true);
michael@0 2475 logTestInfo("testing sub-directory file: " + testFile.path);
michael@0 2476 do_check_true(testFile.exists());
michael@0 2477 });
michael@0 2478 }
michael@0 2479 });
michael@0 2480 }
michael@0 2481 }
michael@0 2482 });
michael@0 2483
michael@0 2484 checkFilesAfterUpdateCommon();
michael@0 2485 }
michael@0 2486
michael@0 2487 /**
michael@0 2488 * Helper function for updater binary tests for verifying the state of files and
michael@0 2489 * directories after a failed update.
michael@0 2490 *
michael@0 2491 * @param aGetDirectory: the function used to get the files in the target directory.
michael@0 2492 * Pass getApplyDirFile if you want to test the case of a failed switch request.
michael@0 2493 */
michael@0 2494 function checkFilesAfterUpdateFailure(aGetDirectory) {
michael@0 2495 let getdir = aGetDirectory || getTargetDirFile;
michael@0 2496 logTestInfo("testing contents of files after a failed update");
michael@0 2497 gTestFiles.forEach(function CFAUF_TF_FE(aTestFile) {
michael@0 2498 let testFile = getdir(aTestFile.relPathDir + aTestFile.fileName, true);
michael@0 2499 logTestInfo("testing file: " + testFile.path);
michael@0 2500 if (aTestFile.compareFile || aTestFile.compareContents) {
michael@0 2501 do_check_true(testFile.exists());
michael@0 2502
michael@0 2503 // Skip these tests on Windows and OS/2 since their
michael@0 2504 // implementaions of chmod doesn't really set permissions.
michael@0 2505 if (!IS_WIN && aTestFile.comparePerms) {
michael@0 2506 // Check the original permssions are retained on the file.
michael@0 2507 let logPerms = "testing file permissions - ";
michael@0 2508 if (aTestFile.originalPerms) {
michael@0 2509 logPerms += "original permissions: " +
michael@0 2510 aTestFile.originalPerms.toString(8) + ", ";
michael@0 2511 }
michael@0 2512 logPerms += "compare permissions : " +
michael@0 2513 aTestFile.comparePerms.toString(8) + ", ";
michael@0 2514 logPerms += "updated permissions : " + testFile.permissions.toString(8);
michael@0 2515 logTestInfo(logPerms);
michael@0 2516 do_check_eq(testFile.permissions & 0xfff, aTestFile.comparePerms & 0xfff);
michael@0 2517 }
michael@0 2518
michael@0 2519 let fileContents1 = readFileBytes(testFile);
michael@0 2520 let fileContents2 = aTestFile.compareFile ?
michael@0 2521 readFileBytes(getTestDirFile(aTestFile.compareFile)) :
michael@0 2522 aTestFile.compareContents;
michael@0 2523 // Don't write the contents of the file to the log to reduce log spam
michael@0 2524 // unless there is a failure.
michael@0 2525 if (fileContents1 == fileContents2) {
michael@0 2526 logTestInfo("file contents are correct");
michael@0 2527 do_check_true(true);
michael@0 2528 } else {
michael@0 2529 logTestInfo("file contents are not correct");
michael@0 2530 do_check_eq(fileContents1, fileContents2);
michael@0 2531 }
michael@0 2532 } else {
michael@0 2533 do_check_false(testFile.exists());
michael@0 2534 }
michael@0 2535 });
michael@0 2536
michael@0 2537 logTestInfo("testing operations specified in removed-files were not " +
michael@0 2538 "performed after a failed update");
michael@0 2539 gTestDirs.forEach(function CFAUF_TD_FE(aTestDir) {
michael@0 2540 let testDir = getdir(aTestDir.relPathDir, true);
michael@0 2541 logTestInfo("testing directory: " + testDir.path);
michael@0 2542 do_check_true(testDir.exists());
michael@0 2543
michael@0 2544 if (aTestDir.files) {
michael@0 2545 aTestDir.files.forEach(function CFAUS_TD_F_FE(aTestFile) {
michael@0 2546 let testFile = getdir(aTestDir.relPathDir + aTestFile, true);
michael@0 2547 logTestInfo("testing directory file: " + testFile.path);
michael@0 2548 do_check_true(testFile.exists());
michael@0 2549 });
michael@0 2550 }
michael@0 2551
michael@0 2552 if (aTestDir.subDirs) {
michael@0 2553 aTestDir.subDirs.forEach(function CFAUS_TD_SD_FE(aSubDir) {
michael@0 2554 let testSubDir = getdir(aTestDir.relPathDir + aSubDir, true);
michael@0 2555 logTestInfo("testing sub-directory: " + testSubDir.path);
michael@0 2556 do_check_true(testSubDir.exists());
michael@0 2557 if (aTestDir.subDirFiles) {
michael@0 2558 aTestDir.subDirFiles.forEach(function CFAUS_TD_SDF_FE(aTestFile) {
michael@0 2559 let testFile = getdir(aTestDir.relPathDir + aSubDir + aTestFile,
michael@0 2560 true);
michael@0 2561 logTestInfo("testing sub-directory file: " + testFile.path);
michael@0 2562 do_check_true(testFile.exists());
michael@0 2563 });
michael@0 2564 }
michael@0 2565 });
michael@0 2566 }
michael@0 2567 });
michael@0 2568
michael@0 2569 checkFilesAfterUpdateCommon();
michael@0 2570 }
michael@0 2571
michael@0 2572 /**
michael@0 2573 * Helper function for updater binary tests for verifying the state of common
michael@0 2574 * files and directories after a successful or failed update.
michael@0 2575 */
michael@0 2576 function checkFilesAfterUpdateCommon() {
michael@0 2577 logTestInfo("testing extra directories");
michael@0 2578 gTestExtraDirs.forEach(function CFAUC_TED_FE(aTestExtraDir) {
michael@0 2579 let testDir = getTargetDirFile(aTestExtraDir.relPathDir, true);
michael@0 2580 logTestInfo("testing directory: " + testDir.path);
michael@0 2581 if (aTestExtraDir.dirExists) {
michael@0 2582 do_check_true(testDir.exists());
michael@0 2583 } else {
michael@0 2584 do_check_false(testDir.exists());
michael@0 2585 }
michael@0 2586 });
michael@0 2587
michael@0 2588 logTestInfo("testing updating directory doesn't exist in the application " +
michael@0 2589 "directory");
michael@0 2590 let updatingDir = getTargetDirFile("updating", true);
michael@0 2591 do_check_false(updatingDir.exists());
michael@0 2592
michael@0 2593 if (gStageUpdate) {
michael@0 2594 logTestInfo("testing updating directory doesn't exist in the updated " +
michael@0 2595 "directory");
michael@0 2596 updatingDir = getApplyDirFile("updating", true);
michael@0 2597 do_check_false(updatingDir.exists());
michael@0 2598
michael@0 2599 // This should never exist since the update was applied to the updated
michael@0 2600 // directory and the files should never be in use.
michael@0 2601 logTestInfo("testing tobedeleted directory doesn't exist in the updated " +
michael@0 2602 "directory");
michael@0 2603 let toBeDeletedDir = getApplyDirFile(DIR_TOBEDELETED, true);
michael@0 2604 do_check_false(toBeDeletedDir.exists());
michael@0 2605 }
michael@0 2606
michael@0 2607 logTestInfo("testing patch files should not be left behind");
michael@0 2608 let updatesDir = getUpdatesPatchDir();
michael@0 2609 let entries = updatesDir.QueryInterface(AUS_Ci.nsIFile).directoryEntries;
michael@0 2610 while (entries.hasMoreElements()) {
michael@0 2611 let entry = entries.getNext().QueryInterface(AUS_Ci.nsIFile);
michael@0 2612 do_check_neq(getFileExtension(entry), "patch");
michael@0 2613 }
michael@0 2614
michael@0 2615 logTestInfo("testing backup files should not be left behind");
michael@0 2616 let applyToDir = getTargetDirFile(null, true);
michael@0 2617 checkFilesInDirRecursive(applyToDir, checkForBackupFiles);
michael@0 2618 }
michael@0 2619
michael@0 2620 /**
michael@0 2621 * Helper function for updater binary tests for verifying the contents of the
michael@0 2622 * updater callback application log which should contain the arguments passed to
michael@0 2623 * the callback application.
michael@0 2624 */
michael@0 2625 function checkCallbackAppLog() {
michael@0 2626 let appLaunchLog = getApplyDirFile("a/b/" + gCallbackArgs[1], true);
michael@0 2627 if (!appLaunchLog.exists()) {
michael@0 2628 do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog);
michael@0 2629 return;
michael@0 2630 }
michael@0 2631
michael@0 2632 let expectedLogContents = gCallbackArgs.join("\n") + "\n";
michael@0 2633 let logContents = readFile(appLaunchLog);
michael@0 2634 // It is possible for the log file contents check to occur before the log file
michael@0 2635 // contents are completely written so wait until the contents are the expected
michael@0 2636 // value. If the contents are never the expected value then the test will
michael@0 2637 // fail by timing out.
michael@0 2638 if (logContents != expectedLogContents) {
michael@0 2639 do_timeout(TEST_HELPER_TIMEOUT, checkCallbackAppLog);
michael@0 2640 return;
michael@0 2641 }
michael@0 2642
michael@0 2643 if (logContents == expectedLogContents) {
michael@0 2644 logTestInfo("callback log file contents are correct");
michael@0 2645 do_check_true(true);
michael@0 2646 } else {
michael@0 2647 logTestInfo("callback log file contents are not correct");
michael@0 2648 do_check_eq(logContents, expectedLogContents);
michael@0 2649 }
michael@0 2650
michael@0 2651 waitForFilesInUse();
michael@0 2652 }
michael@0 2653
michael@0 2654 /**
michael@0 2655 * Helper function for updater service tests for verifying the contents of the
michael@0 2656 * updater callback application log which should contain the arguments passed to
michael@0 2657 * the callback application.
michael@0 2658 */
michael@0 2659 function checkCallbackServiceLog() {
michael@0 2660 do_check_neq(gServiceLaunchedCallbackLog, null);
michael@0 2661
michael@0 2662 let expectedLogContents = gServiceLaunchedCallbackArgs.join("\n") + "\n";
michael@0 2663 let logFile = AUS_Cc["@mozilla.org/file/local;1"].createInstance(AUS_Ci.nsILocalFile);
michael@0 2664 logFile.initWithPath(gServiceLaunchedCallbackLog);
michael@0 2665 let logContents = readFile(logFile);
michael@0 2666 // It is possible for the log file contents check to occur before the log file
michael@0 2667 // contents are completely written so wait until the contents are the expected
michael@0 2668 // value. If the contents are never the expected value then the test will
michael@0 2669 // fail by timing out.
michael@0 2670 if (logContents != expectedLogContents) {
michael@0 2671 logTestInfo("callback service log not expected value, waiting longer");
michael@0 2672 do_timeout(TEST_HELPER_TIMEOUT, checkCallbackServiceLog);
michael@0 2673 return;
michael@0 2674 }
michael@0 2675
michael@0 2676 logTestInfo("testing that the callback application successfully launched " +
michael@0 2677 "and the expected command line arguments were passed to it");
michael@0 2678 do_check_eq(logContents, expectedLogContents);
michael@0 2679
michael@0 2680 waitForFilesInUse();
michael@0 2681 }
michael@0 2682
michael@0 2683 // Waits until files that are in use that break tests are no longer in use and
michael@0 2684 // then calls do_test_finished.
michael@0 2685 function waitForFilesInUse() {
michael@0 2686 if (IS_WIN) {
michael@0 2687 let appBin = getApplyDirFile(FILE_APP_BIN, true);
michael@0 2688 let maintSvcInstaller = getApplyDirFile(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, true);
michael@0 2689 let helper = getApplyDirFile("uninstall/helper.exe", true);
michael@0 2690 let updater = getUpdatesPatchDir();
michael@0 2691 updater.append(FILE_UPDATER_BIN);
michael@0 2692
michael@0 2693 let files = [appBin, updater, maintSvcInstaller, helper];
michael@0 2694
michael@0 2695 for (var i = 0; i < files.length; ++i) {
michael@0 2696 let file = files[i];
michael@0 2697 let fileBak = file.parent.clone();
michael@0 2698 if (file.exists()) {
michael@0 2699 fileBak.append(file.leafName + ".bak");
michael@0 2700 try {
michael@0 2701 if (fileBak.exists()) {
michael@0 2702 fileBak.remove(false);
michael@0 2703 }
michael@0 2704 file.copyTo(fileBak.parent, fileBak.leafName);
michael@0 2705 file.remove(false);
michael@0 2706 fileBak.moveTo(file.parent, file.leafName);
michael@0 2707 logTestInfo("file is not in use. Path: " + file.path);
michael@0 2708 } catch (e) {
michael@0 2709 logTestInfo("file in use, will try again after " + TEST_CHECK_TIMEOUT +
michael@0 2710 " ms, Path: " + file.path + ", Exception: " + e);
michael@0 2711 try {
michael@0 2712 if (fileBak.exists()) {
michael@0 2713 fileBak.remove(false);
michael@0 2714 }
michael@0 2715 } catch (e) {
michael@0 2716 logTestInfo("unable to remove file, this should never happen! " +
michael@0 2717 "Path: " + fileBak.path + ", Exception: " + e);
michael@0 2718 }
michael@0 2719 do_timeout(TEST_CHECK_TIMEOUT, waitForFilesInUse);
michael@0 2720 return;
michael@0 2721 }
michael@0 2722 }
michael@0 2723 }
michael@0 2724 }
michael@0 2725
michael@0 2726 logTestInfo("calling doTestFinish");
michael@0 2727 doTestFinish();
michael@0 2728 }
michael@0 2729
michael@0 2730 /**
michael@0 2731 * Helper function for updater binary tests for verifying there are no update
michael@0 2732 * backup files left behind after an update.
michael@0 2733 *
michael@0 2734 * @param aFile
michael@0 2735 * An nsIFile to check if it has moz-backup for its extension.
michael@0 2736 */
michael@0 2737 function checkForBackupFiles(aFile) {
michael@0 2738 do_check_neq(getFileExtension(aFile), "moz-backup");
michael@0 2739 }
michael@0 2740
michael@0 2741 /**
michael@0 2742 * Helper function for updater binary tests for recursively enumerating a
michael@0 2743 * directory and calling a callback function with the file as a parameter for
michael@0 2744 * each file found.
michael@0 2745 *
michael@0 2746 * @param aDir
michael@0 2747 * A nsIFile for the directory to be deleted
michael@0 2748 * @param aCallback
michael@0 2749 * A callback function that will be called with the file as a
michael@0 2750 * parameter for each file found.
michael@0 2751 */
michael@0 2752 function checkFilesInDirRecursive(aDir, aCallback) {
michael@0 2753 if (!aDir.exists())
michael@0 2754 do_throw("Directory must exist!");
michael@0 2755
michael@0 2756 let dirEntries = aDir.directoryEntries;
michael@0 2757 while (dirEntries.hasMoreElements()) {
michael@0 2758 let entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
michael@0 2759
michael@0 2760 if (entry.isDirectory()) {
michael@0 2761 checkFilesInDirRecursive(entry, aCallback);
michael@0 2762 } else {
michael@0 2763 aCallback(entry);
michael@0 2764 }
michael@0 2765 }
michael@0 2766 }
michael@0 2767
michael@0 2768 /**
michael@0 2769 * Sets up the bare bones XMLHttpRequest implementation below.
michael@0 2770 *
michael@0 2771 * @param aCallback
michael@0 2772 * The callback function that will call the nsIDomEventListener's
michael@0 2773 * handleEvent method.
michael@0 2774 *
michael@0 2775 * Example of the callback function
michael@0 2776 *
michael@0 2777 * function callHandleEvent() {
michael@0 2778 * gXHR.status = gExpectedStatus;
michael@0 2779 * var e = { target: gXHR };
michael@0 2780 * gXHR.onload.handleEvent(e);
michael@0 2781 * }
michael@0 2782 */
michael@0 2783 function overrideXHR(aCallback) {
michael@0 2784 gXHRCallback = aCallback;
michael@0 2785 gXHR = new xhr();
michael@0 2786 var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
michael@0 2787 registrar.registerFactory(gXHR.classID, gXHR.classDescription,
michael@0 2788 gXHR.contractID, gXHR);
michael@0 2789 }
michael@0 2790
michael@0 2791
michael@0 2792 /**
michael@0 2793 * Bare bones XMLHttpRequest implementation for testing onprogress, onerror,
michael@0 2794 * and onload nsIDomEventListener handleEvent.
michael@0 2795 */
michael@0 2796 function makeHandler(aVal) {
michael@0 2797 if (typeof aVal == "function")
michael@0 2798 return { handleEvent: aVal };
michael@0 2799 return aVal;
michael@0 2800 }
michael@0 2801 function xhr() {
michael@0 2802 }
michael@0 2803 xhr.prototype = {
michael@0 2804 overrideMimeType: function(aMimetype) { },
michael@0 2805 setRequestHeader: function(aHeader, aValue) { },
michael@0 2806 status: null,
michael@0 2807 channel: { set notificationCallbacks(aVal) { } },
michael@0 2808 _url: null,
michael@0 2809 _method: null,
michael@0 2810 open: function(aMethod, aUrl) {
michael@0 2811 gXHR.channel.originalURI = Services.io.newURI(aUrl, null, null);
michael@0 2812 gXHR._method = aMethod; gXHR._url = aUrl;
michael@0 2813 },
michael@0 2814 responseXML: null,
michael@0 2815 responseText: null,
michael@0 2816 send: function(aBody) {
michael@0 2817 do_execute_soon(gXHRCallback); // Use a timeout so the XHR completes
michael@0 2818 },
michael@0 2819 _onprogress: null,
michael@0 2820 set onprogress(aValue) { gXHR._onprogress = makeHandler(aValue); },
michael@0 2821 get onprogress() { return gXHR._onprogress; },
michael@0 2822 _onerror: null,
michael@0 2823 set onerror(aValue) { gXHR._onerror = makeHandler(aValue); },
michael@0 2824 get onerror() { return gXHR._onerror; },
michael@0 2825 _onload: null,
michael@0 2826 set onload(aValue) { gXHR._onload = makeHandler(aValue); },
michael@0 2827 get onload() { return gXHR._onload; },
michael@0 2828 addEventListener: function(aEvent, aValue, aCapturing) {
michael@0 2829 eval("gXHR._on" + aEvent + " = aValue");
michael@0 2830 },
michael@0 2831 flags: AUS_Ci.nsIClassInfo.SINGLETON,
michael@0 2832 implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
michael@0 2833 getHelperForLanguage: function(aLanguage) null,
michael@0 2834 getInterfaces: function(aCount) {
michael@0 2835 var interfaces = [AUS_Ci.nsISupports];
michael@0 2836 aCount.value = interfaces.length;
michael@0 2837 return interfaces;
michael@0 2838 },
michael@0 2839 classDescription: "XMLHttpRequest",
michael@0 2840 contractID: "@mozilla.org/xmlextras/xmlhttprequest;1",
michael@0 2841 classID: Components.ID("{c9b37f43-4278-4304-a5e0-600991ab08cb}"),
michael@0 2842 createInstance: function(aOuter, aIID) {
michael@0 2843 if (aOuter == null)
michael@0 2844 return gXHR.QueryInterface(aIID);
michael@0 2845 throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
michael@0 2846 },
michael@0 2847 QueryInterface: function(aIID) {
michael@0 2848 if (aIID.equals(AUS_Ci.nsIClassInfo) ||
michael@0 2849 aIID.equals(AUS_Ci.nsISupports))
michael@0 2850 return gXHR;
michael@0 2851 throw AUS_Cr.NS_ERROR_NO_INTERFACE;
michael@0 2852 },
michael@0 2853 get wrappedJSObject() { return this; }
michael@0 2854 };
michael@0 2855
michael@0 2856 /**
michael@0 2857 * Helper function to override the update prompt component to verify whether it
michael@0 2858 * is called or not.
michael@0 2859 *
michael@0 2860 * @param aCallback
michael@0 2861 * The callback to call if the update prompt component is called.
michael@0 2862 */
michael@0 2863 function overrideUpdatePrompt(aCallback) {
michael@0 2864 var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
michael@0 2865 gUpdatePrompt = new UpdatePrompt();
michael@0 2866 gUpdatePromptCallback = aCallback;
michael@0 2867 registrar.registerFactory(gUpdatePrompt.classID, gUpdatePrompt.classDescription,
michael@0 2868 gUpdatePrompt.contractID, gUpdatePrompt);
michael@0 2869 }
michael@0 2870
michael@0 2871 function UpdatePrompt() {
michael@0 2872 var fns = ["checkForUpdates", "showUpdateAvailable", "showUpdateDownloaded",
michael@0 2873 "showUpdateError", "showUpdateHistory", "showUpdateInstalled"];
michael@0 2874
michael@0 2875 fns.forEach(function(aPromptFn) {
michael@0 2876 UpdatePrompt.prototype[aPromptFn] = function() {
michael@0 2877 if (!gUpdatePromptCallback) {
michael@0 2878 return;
michael@0 2879 }
michael@0 2880
michael@0 2881 var callback = gUpdatePromptCallback[aPromptFn];
michael@0 2882 if (!callback) {
michael@0 2883 return;
michael@0 2884 }
michael@0 2885
michael@0 2886 callback.apply(gUpdatePromptCallback,
michael@0 2887 Array.prototype.slice.call(arguments));
michael@0 2888 }
michael@0 2889 });
michael@0 2890 }
michael@0 2891
michael@0 2892 UpdatePrompt.prototype = {
michael@0 2893 flags: AUS_Ci.nsIClassInfo.SINGLETON,
michael@0 2894 implementationLanguage: AUS_Ci.nsIProgrammingLanguage.JAVASCRIPT,
michael@0 2895 getHelperForLanguage: function(aLanguage) null,
michael@0 2896 getInterfaces: function(aCount) {
michael@0 2897 var interfaces = [AUS_Ci.nsISupports, AUS_Ci.nsIUpdatePrompt];
michael@0 2898 aCount.value = interfaces.length;
michael@0 2899 return interfaces;
michael@0 2900 },
michael@0 2901 classDescription: "UpdatePrompt",
michael@0 2902 contractID: "@mozilla.org/updates/update-prompt;1",
michael@0 2903 classID: Components.ID("{8c350a15-9b90-4622-93a1-4d320308664b}"),
michael@0 2904 createInstance: function(aOuter, aIID) {
michael@0 2905 if (aOuter == null)
michael@0 2906 return gUpdatePrompt.QueryInterface(aIID);
michael@0 2907 throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
michael@0 2908 },
michael@0 2909 QueryInterface: function(aIID) {
michael@0 2910 if (aIID.equals(AUS_Ci.nsIClassInfo) ||
michael@0 2911 aIID.equals(AUS_Ci.nsISupports) ||
michael@0 2912 aIID.equals(AUS_Ci.nsIUpdatePrompt))
michael@0 2913 return gUpdatePrompt;
michael@0 2914 throw AUS_Cr.NS_ERROR_NO_INTERFACE;
michael@0 2915 },
michael@0 2916 };
michael@0 2917
michael@0 2918 /* Update check listener */
michael@0 2919 const updateCheckListener = {
michael@0 2920 onProgress: function UCL_onProgress(aRequest, aPosition, aTotalSize) {
michael@0 2921 },
michael@0 2922
michael@0 2923 onCheckComplete: function UCL_onCheckComplete(aRequest, aUpdates, aUpdateCount) {
michael@0 2924 gRequestURL = aRequest.channel.originalURI.spec;
michael@0 2925 gUpdateCount = aUpdateCount;
michael@0 2926 gUpdates = aUpdates;
michael@0 2927 logTestInfo("url = " + gRequestURL + ", " +
michael@0 2928 "request.status = " + aRequest.status + ", " +
michael@0 2929 "update.statusText = " + aRequest.statusText + ", " +
michael@0 2930 "updateCount = " + aUpdateCount);
michael@0 2931 // Use a timeout to allow the XHR to complete
michael@0 2932 do_execute_soon(gCheckFunc);
michael@0 2933 },
michael@0 2934
michael@0 2935 onError: function UCL_onError(aRequest, aUpdate) {
michael@0 2936 gRequestURL = aRequest.channel.originalURI.spec;
michael@0 2937 gStatusCode = aRequest.status;
michael@0 2938
michael@0 2939 gStatusText = aUpdate.statusText;
michael@0 2940 logTestInfo("url = " + gRequestURL + ", " +
michael@0 2941 "request.status = " + gStatusCode + ", " +
michael@0 2942 "update.statusText = " + gStatusText);
michael@0 2943 // Use a timeout to allow the XHR to complete
michael@0 2944 do_execute_soon(gCheckFunc.bind(null, aRequest, aUpdate));
michael@0 2945 },
michael@0 2946
michael@0 2947 QueryInterface: function(aIID) {
michael@0 2948 if (!aIID.equals(AUS_Ci.nsIUpdateCheckListener) &&
michael@0 2949 !aIID.equals(AUS_Ci.nsISupports))
michael@0 2950 throw AUS_Cr.NS_ERROR_NO_INTERFACE;
michael@0 2951 return this;
michael@0 2952 }
michael@0 2953 };
michael@0 2954
michael@0 2955 /* Update download listener - nsIRequestObserver */
michael@0 2956 const downloadListener = {
michael@0 2957 onStartRequest: function DL_onStartRequest(aRequest, aContext) {
michael@0 2958 },
michael@0 2959
michael@0 2960 onProgress: function DL_onProgress(aRequest, aContext, aProgress, aMaxProgress) {
michael@0 2961 },
michael@0 2962
michael@0 2963 onStatus: function DL_onStatus(aRequest, aContext, aStatus, aStatusText) {
michael@0 2964 },
michael@0 2965
michael@0 2966 onStopRequest: function DL_onStopRequest(aRequest, aContext, aStatus) {
michael@0 2967 gStatusResult = aStatus;
michael@0 2968 // Use a timeout to allow the request to complete
michael@0 2969 do_execute_soon(gCheckFunc);
michael@0 2970 },
michael@0 2971
michael@0 2972 QueryInterface: function DL_QueryInterface(aIID) {
michael@0 2973 if (!aIID.equals(AUS_Ci.nsIRequestObserver) &&
michael@0 2974 !aIID.equals(AUS_Ci.nsIProgressEventSink) &&
michael@0 2975 !aIID.equals(AUS_Ci.nsISupports))
michael@0 2976 throw AUS_Cr.NS_ERROR_NO_INTERFACE;
michael@0 2977 return this;
michael@0 2978 }
michael@0 2979 };
michael@0 2980
michael@0 2981 /**
michael@0 2982 * Helper for starting the http server used by the tests
michael@0 2983 */
michael@0 2984 function start_httpserver() {
michael@0 2985 let dir = getTestDirFile();
michael@0 2986 logTestInfo("http server directory path: " + dir.path);
michael@0 2987
michael@0 2988 if (!dir.isDirectory()) {
michael@0 2989 do_throw("A file instead of a directory was specified for HttpServer " +
michael@0 2990 "registerDirectory! Path: " + dir.path + "\n");
michael@0 2991 }
michael@0 2992
michael@0 2993 AUS_Cu.import("resource://testing-common/httpd.js");
michael@0 2994 gTestserver = new HttpServer();
michael@0 2995 gTestserver.registerDirectory("/", dir);
michael@0 2996 gTestserver.start(-1);
michael@0 2997 let testserverPort = gTestserver.identity.primaryPort;
michael@0 2998 gURLData = URL_HOST + ":" + testserverPort + "/";
michael@0 2999 logTestInfo("http server port = " + testserverPort);
michael@0 3000 }
michael@0 3001
michael@0 3002 /**
michael@0 3003 * Helper for stopping the http server used by the tests
michael@0 3004 *
michael@0 3005 * @param aCallback
michael@0 3006 * The callback to call after stopping the http server.
michael@0 3007 */
michael@0 3008 function stop_httpserver(aCallback) {
michael@0 3009 do_check_true(!!aCallback);
michael@0 3010 gTestserver.stop(aCallback);
michael@0 3011 }
michael@0 3012
michael@0 3013 /**
michael@0 3014 * Creates an nsIXULAppInfo
michael@0 3015 *
michael@0 3016 * @param aID
michael@0 3017 * The ID of the test application
michael@0 3018 * @param aName
michael@0 3019 * A name for the test application
michael@0 3020 * @param aVersion
michael@0 3021 * The version of the application
michael@0 3022 * @param aPlatformVersion
michael@0 3023 * The gecko version of the application
michael@0 3024 */
michael@0 3025 function createAppInfo(aID, aName, aVersion, aPlatformVersion) {
michael@0 3026 const XULAPPINFO_CONTRACTID = "@mozilla.org/xre/app-info;1";
michael@0 3027 const XULAPPINFO_CID = Components.ID("{c763b610-9d49-455a-bbd2-ede71682a1ac}");
michael@0 3028 var XULAppInfo = {
michael@0 3029 vendor: APP_INFO_VENDOR,
michael@0 3030 name: aName,
michael@0 3031 ID: aID,
michael@0 3032 version: aVersion,
michael@0 3033 appBuildID: "2007010101",
michael@0 3034 platformVersion: aPlatformVersion,
michael@0 3035 platformBuildID: "2007010101",
michael@0 3036 inSafeMode: false,
michael@0 3037 logConsoleErrors: true,
michael@0 3038 OS: "XPCShell",
michael@0 3039 XPCOMABI: "noarch-spidermonkey",
michael@0 3040
michael@0 3041 QueryInterface: function QueryInterface(aIID) {
michael@0 3042 if (aIID.equals(AUS_Ci.nsIXULAppInfo) ||
michael@0 3043 aIID.equals(AUS_Ci.nsIXULRuntime) ||
michael@0 3044 #ifdef XP_WIN
michael@0 3045 aIID.equals(AUS_Ci.nsIWinAppHelper) ||
michael@0 3046 #endif
michael@0 3047 aIID.equals(AUS_Ci.nsISupports))
michael@0 3048 return this;
michael@0 3049 throw AUS_Cr.NS_ERROR_NO_INTERFACE;
michael@0 3050 }
michael@0 3051 };
michael@0 3052
michael@0 3053 var XULAppInfoFactory = {
michael@0 3054 createInstance: function (aOuter, aIID) {
michael@0 3055 if (aOuter == null)
michael@0 3056 return XULAppInfo.QueryInterface(aIID);
michael@0 3057 throw AUS_Cr.NS_ERROR_NO_AGGREGATION;
michael@0 3058 }
michael@0 3059 };
michael@0 3060
michael@0 3061 var registrar = Components.manager.QueryInterface(AUS_Ci.nsIComponentRegistrar);
michael@0 3062 registrar.registerFactory(XULAPPINFO_CID, "XULAppInfo",
michael@0 3063 XULAPPINFO_CONTRACTID, XULAppInfoFactory);
michael@0 3064 }
michael@0 3065
michael@0 3066 /**
michael@0 3067 * Returns the platform specific arguments used by nsIProcess when launching
michael@0 3068 * the application.
michael@0 3069 *
michael@0 3070 * @param aExtraArgs (optional)
michael@0 3071 * An array of extra arguments to append to the default arguments.
michael@0 3072 * @return an array of arguments to be passed to nsIProcess.
michael@0 3073 *
michael@0 3074 * Note: a shell is necessary to pipe the application's console output which
michael@0 3075 * would otherwise pollute the xpcshell log.
michael@0 3076 *
michael@0 3077 * Command line arguments used when launching the application:
michael@0 3078 * -no-remote prevents shell integration from being affected by an existing
michael@0 3079 * application process.
michael@0 3080 * -process-updates makes the application exits after being relaunched by the
michael@0 3081 * updater.
michael@0 3082 * the platform specific string defined by PIPE_TO_NULL to output both stdout
michael@0 3083 * and stderr to null. This is needed to prevent output from the application
michael@0 3084 * from ending up in the xpchsell log.
michael@0 3085 */
michael@0 3086 function getProcessArgs(aExtraArgs) {
michael@0 3087 if (!aExtraArgs) {
michael@0 3088 aExtraArgs = [];
michael@0 3089 }
michael@0 3090
michael@0 3091 let appBinPath = getApplyDirFile(DIR_BIN_REL_PATH + FILE_APP_BIN, false).path;
michael@0 3092 if (/ /.test(appBinPath)) {
michael@0 3093 appBinPath = '"' + appBinPath + '"';
michael@0 3094 }
michael@0 3095
michael@0 3096 let args;
michael@0 3097 if (IS_UNIX) {
michael@0 3098 let launchScript = getLaunchScript();
michael@0 3099 // Precreate the script with executable permissions
michael@0 3100 launchScript.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_DIRECTORY);
michael@0 3101
michael@0 3102 let scriptContents = "#! /bin/sh\n";
michael@0 3103 scriptContents += appBinPath + " -no-remote -process-updates " +
michael@0 3104 aExtraArgs.join(" ") + " " + PIPE_TO_NULL;
michael@0 3105 writeFile(launchScript, scriptContents);
michael@0 3106 logTestInfo("created " + launchScript.path + " containing:\n" +
michael@0 3107 scriptContents);
michael@0 3108 args = [launchScript.path];
michael@0 3109 } else {
michael@0 3110 args = ["/D", "/Q", "/C", appBinPath, "-no-remote", "-process-updates"].
michael@0 3111 concat(aExtraArgs).concat([PIPE_TO_NULL]);
michael@0 3112 }
michael@0 3113 return args;
michael@0 3114 }
michael@0 3115
michael@0 3116 /**
michael@0 3117 * Gets a file path for the application to dump its arguments into. This is used
michael@0 3118 * to verify that a callback application is launched.
michael@0 3119 *
michael@0 3120 * @return the file for the application to dump its arguments into.
michael@0 3121 */
michael@0 3122 function getAppArgsLogPath() {
michael@0 3123 let appArgsLog = do_get_file("/", true);
michael@0 3124 appArgsLog.append(gTestID + "_app_args_log");
michael@0 3125 if (appArgsLog.exists()) {
michael@0 3126 appArgsLog.remove(false);
michael@0 3127 }
michael@0 3128 let appArgsLogPath = appArgsLog.path;
michael@0 3129 if (/ /.test(appArgsLogPath)) {
michael@0 3130 appArgsLogPath = '"' + appArgsLogPath + '"';
michael@0 3131 }
michael@0 3132 return appArgsLogPath;
michael@0 3133 }
michael@0 3134
michael@0 3135 /**
michael@0 3136 * Gets the nsIFile reference for the shell script to launch the application. If
michael@0 3137 * the file exists it will be removed by this function.
michael@0 3138 *
michael@0 3139 * @return the nsIFile for the shell script to launch the application.
michael@0 3140 */
michael@0 3141 function getLaunchScript() {
michael@0 3142 let launchScript = do_get_file("/", true);
michael@0 3143 launchScript.append(gTestID + "_launch.sh");
michael@0 3144 if (launchScript.exists()) {
michael@0 3145 launchScript.remove(false);
michael@0 3146 }
michael@0 3147 return launchScript;
michael@0 3148 }
michael@0 3149
michael@0 3150 /**
michael@0 3151 * Makes GreD, XREExeF, and UpdRootD point to unique file system locations so
michael@0 3152 * xpcshell tests can run in parallel and to keep the environment clean.
michael@0 3153 */
michael@0 3154 function adjustGeneralPaths() {
michael@0 3155 let dirProvider = {
michael@0 3156 getFile: function AGP_DP_getFile(aProp, aPersistent) {
michael@0 3157 aPersistent.value = true;
michael@0 3158 switch (aProp) {
michael@0 3159 case NS_GRE_DIR:
michael@0 3160 if (gUseTestAppDir) {
michael@0 3161 return getApplyDirFile(DIR_BIN_REL_PATH, true);
michael@0 3162 }
michael@0 3163 break;
michael@0 3164 case XRE_EXECUTABLE_FILE:
michael@0 3165 if (gUseTestAppDir) {
michael@0 3166 return getApplyDirFile(DIR_BIN_REL_PATH + FILE_APP_BIN, true);
michael@0 3167 }
michael@0 3168 break;
michael@0 3169 case XRE_UPDATE_ROOT_DIR:
michael@0 3170 return getMockUpdRootD();
michael@0 3171 }
michael@0 3172 return null;
michael@0 3173 },
michael@0 3174 QueryInterface: function(aIID) {
michael@0 3175 if (aIID.equals(AUS_Ci.nsIDirectoryServiceProvider) ||
michael@0 3176 aIID.equals(AUS_Ci.nsISupports))
michael@0 3177 return this;
michael@0 3178 throw AUS_Cr.NS_ERROR_NO_INTERFACE;
michael@0 3179 }
michael@0 3180 };
michael@0 3181 let ds = Services.dirsvc.QueryInterface(AUS_Ci.nsIDirectoryService);
michael@0 3182 ds.QueryInterface(AUS_Ci.nsIProperties).undefine(NS_GRE_DIR);
michael@0 3183 ds.QueryInterface(AUS_Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE);
michael@0 3184 ds.registerProvider(dirProvider);
michael@0 3185 do_register_cleanup(function AGP_cleanup() {
michael@0 3186 logTestInfo("start - unregistering directory provider");
michael@0 3187
michael@0 3188 if (gAppTimer) {
michael@0 3189 logTestInfo("start - cancel app timer");
michael@0 3190 gAppTimer.cancel();
michael@0 3191 gAppTimer = null;
michael@0 3192 logTestInfo("finish - cancel app timer");
michael@0 3193 }
michael@0 3194
michael@0 3195 if (gProcess && gProcess.isRunning) {
michael@0 3196 logTestInfo("start - kill process");
michael@0 3197 try {
michael@0 3198 gProcess.kill();
michael@0 3199 } catch (e) {
michael@0 3200 logTestInfo("kill process failed. Exception: " + e);
michael@0 3201 }
michael@0 3202 gProcess = null;
michael@0 3203 logTestInfo("finish - kill process");
michael@0 3204 }
michael@0 3205
michael@0 3206 if (gHandle) {
michael@0 3207 try {
michael@0 3208 logTestInfo("start - closing handle");
michael@0 3209 let kernel32 = ctypes.open("kernel32");
michael@0 3210 let CloseHandle = kernel32.declare("CloseHandle", ctypes.default_abi,
michael@0 3211 ctypes.bool, /*return*/
michael@0 3212 ctypes.voidptr_t /*handle*/);
michael@0 3213 if (!CloseHandle(gHandle)) {
michael@0 3214 logTestInfo("call to CloseHandle failed");
michael@0 3215 }
michael@0 3216 kernel32.close();
michael@0 3217 gHandle = null;
michael@0 3218 logTestInfo("finish - closing handle");
michael@0 3219 } catch (e) {
michael@0 3220 logTestInfo("call to CloseHandle failed. Exception: " + e);
michael@0 3221 }
michael@0 3222 }
michael@0 3223
michael@0 3224 // Call end_test first before the directory provider is unregistered
michael@0 3225 if (typeof(end_test) == typeof(Function)) {
michael@0 3226 logTestInfo("calling end_test");
michael@0 3227 end_test();
michael@0 3228 }
michael@0 3229
michael@0 3230 ds.unregisterProvider(dirProvider);
michael@0 3231 cleanupTestCommon();
michael@0 3232
michael@0 3233 logTestInfo("finish - unregistering directory provider");
michael@0 3234 });
michael@0 3235 }
michael@0 3236
michael@0 3237
michael@0 3238 /**
michael@0 3239 * Helper function for launching the application to apply an update.
michael@0 3240 */
michael@0 3241 function launchAppToApplyUpdate() {
michael@0 3242 logTestInfo("start - launching application to apply update");
michael@0 3243
michael@0 3244 let appBin = getApplyDirFile(DIR_BIN_REL_PATH + FILE_APP_BIN, false);
michael@0 3245
michael@0 3246 if (typeof(customLaunchAppToApplyUpdate) == typeof(Function)) {
michael@0 3247 customLaunchAppToApplyUpdate();
michael@0 3248 }
michael@0 3249
michael@0 3250 let launchBin = getLaunchBin();
michael@0 3251 let args = getProcessArgs();
michael@0 3252 logTestInfo("launching " + launchBin.path + " " + args.join(" "));
michael@0 3253
michael@0 3254 gProcess = AUS_Cc["@mozilla.org/process/util;1"].
michael@0 3255 createInstance(AUS_Ci.nsIProcess);
michael@0 3256 gProcess.init(launchBin);
michael@0 3257
michael@0 3258 gAppTimer = AUS_Cc["@mozilla.org/timer;1"].createInstance(AUS_Ci.nsITimer);
michael@0 3259 gAppTimer.initWithCallback(gTimerCallback, APP_TIMER_TIMEOUT,
michael@0 3260 AUS_Ci.nsITimer.TYPE_ONE_SHOT);
michael@0 3261
michael@0 3262 setEnvironment();
michael@0 3263 logTestInfo("launching application");
michael@0 3264 gProcess.runAsync(args, args.length, gProcessObserver);
michael@0 3265 resetEnvironment();
michael@0 3266
michael@0 3267 logTestInfo("finish - launching application to apply update");
michael@0 3268 }
michael@0 3269
michael@0 3270 /**
michael@0 3271 * The observer for the call to nsIProcess:runAsync.
michael@0 3272 */
michael@0 3273 let gProcessObserver = {
michael@0 3274 observe: function PO_observe(aSubject, aTopic, aData) {
michael@0 3275 logTestInfo("topic: " + aTopic + ", process exitValue: " +
michael@0 3276 gProcess.exitValue);
michael@0 3277 if (gAppTimer) {
michael@0 3278 gAppTimer.cancel();
michael@0 3279 gAppTimer = null;
michael@0 3280 }
michael@0 3281 if (aTopic != "process-finished" || gProcess.exitValue != 0) {
michael@0 3282 do_throw("Failed to launch application");
michael@0 3283 }
michael@0 3284 do_timeout(TEST_CHECK_TIMEOUT, checkUpdateFinished);
michael@0 3285 },
michael@0 3286 QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
michael@0 3287 };
michael@0 3288
michael@0 3289 /**
michael@0 3290 * The timer callback to kill the process if it takes too long.
michael@0 3291 */
michael@0 3292 let gTimerCallback = {
michael@0 3293 notify: function TC_notify(aTimer) {
michael@0 3294 gAppTimer = null;
michael@0 3295 if (gProcess.isRunning) {
michael@0 3296 logTestInfo("attempt to kill process");
michael@0 3297 gProcess.kill();
michael@0 3298 }
michael@0 3299 do_throw("launch application timer expired");
michael@0 3300 },
michael@0 3301 QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsITimerCallback])
michael@0 3302 };
michael@0 3303
michael@0 3304 /**
michael@0 3305 * The update-staged observer for the call to nsIUpdateProcessor:processUpdate.
michael@0 3306 */
michael@0 3307 let gUpdateStagedObserver = {
michael@0 3308 observe: function(aSubject, aTopic, aData) {
michael@0 3309 if (aTopic == "update-staged") {
michael@0 3310 Services.obs.removeObserver(gUpdateStagedObserver, "update-staged");
michael@0 3311 checkUpdateApplied();
michael@0 3312 }
michael@0 3313 },
michael@0 3314 QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
michael@0 3315 };
michael@0 3316
michael@0 3317 /**
michael@0 3318 * Sets the environment that will be used by the application process when it is
michael@0 3319 * launched.
michael@0 3320 */
michael@0 3321 function setEnvironment() {
michael@0 3322 // Prevent setting the environment more than once.
michael@0 3323 if (gShouldResetEnv !== undefined)
michael@0 3324 return;
michael@0 3325
michael@0 3326 gShouldResetEnv = true;
michael@0 3327
michael@0 3328 let env = AUS_Cc["@mozilla.org/process/environment;1"].
michael@0 3329 getService(AUS_Ci.nsIEnvironment);
michael@0 3330 if (IS_WIN && !env.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) {
michael@0 3331 gAddedEnvXRENoWindowsCrashDialog = true;
michael@0 3332 logTestInfo("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
michael@0 3333 "variable to 1... previously it didn't exist");
michael@0 3334 env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "1");
michael@0 3335 }
michael@0 3336
michael@0 3337 if (IS_UNIX) {
michael@0 3338 let appGreDir = gGREDirOrig.clone();
michael@0 3339 let envGreDir = AUS_Cc["@mozilla.org/file/local;1"].
michael@0 3340 createInstance(AUS_Ci.nsILocalFile);
michael@0 3341 let shouldSetEnv = true;
michael@0 3342 if (IS_MACOSX) {
michael@0 3343 if (env.exists("DYLD_LIBRARY_PATH")) {
michael@0 3344 gEnvDyldLibraryPath = env.get("DYLD_LIBRARY_PATH");
michael@0 3345 envGreDir.initWithPath(gEnvDyldLibraryPath);
michael@0 3346 if (envGreDir.path == appGreDir.path) {
michael@0 3347 gEnvDyldLibraryPath = null;
michael@0 3348 shouldSetEnv = false;
michael@0 3349 }
michael@0 3350 }
michael@0 3351
michael@0 3352 if (shouldSetEnv) {
michael@0 3353 logTestInfo("setting DYLD_LIBRARY_PATH environment variable value to " +
michael@0 3354 appGreDir.path);
michael@0 3355 env.set("DYLD_LIBRARY_PATH", appGreDir.path);
michael@0 3356 }
michael@0 3357 } else {
michael@0 3358 if (env.exists("LD_LIBRARY_PATH")) {
michael@0 3359 gEnvLdLibraryPath = env.get("LD_LIBRARY_PATH");
michael@0 3360 envGreDir.initWithPath(gEnvLdLibraryPath);
michael@0 3361 if (envGreDir.path == appGreDir.path) {
michael@0 3362 gEnvLdLibraryPath = null;
michael@0 3363 shouldSetEnv = false;
michael@0 3364 }
michael@0 3365 }
michael@0 3366
michael@0 3367 if (shouldSetEnv) {
michael@0 3368 logTestInfo("setting LD_LIBRARY_PATH environment variable value to " +
michael@0 3369 appGreDir.path);
michael@0 3370 env.set("LD_LIBRARY_PATH", appGreDir.path);
michael@0 3371 }
michael@0 3372 }
michael@0 3373 }
michael@0 3374
michael@0 3375 if (env.exists("XPCOM_MEM_LEAK_LOG")) {
michael@0 3376 gEnvXPCOMMemLeakLog = env.get("XPCOM_MEM_LEAK_LOG");
michael@0 3377 logTestInfo("removing the XPCOM_MEM_LEAK_LOG environment variable... " +
michael@0 3378 "previous value " + gEnvXPCOMMemLeakLog);
michael@0 3379 env.set("XPCOM_MEM_LEAK_LOG", "");
michael@0 3380 }
michael@0 3381
michael@0 3382 if (env.exists("XPCOM_DEBUG_BREAK")) {
michael@0 3383 gEnvXPCOMDebugBreak = env.get("XPCOM_DEBUG_BREAK");
michael@0 3384 logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " +
michael@0 3385 "warn... previous value " + gEnvXPCOMDebugBreak);
michael@0 3386 } else {
michael@0 3387 logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable to " +
michael@0 3388 "warn... previously it didn't exist");
michael@0 3389 }
michael@0 3390
michael@0 3391 env.set("XPCOM_DEBUG_BREAK", "warn");
michael@0 3392
michael@0 3393 if (gStageUpdate) {
michael@0 3394 logTestInfo("setting the MOZ_UPDATE_STAGING environment variable to 1\n");
michael@0 3395 env.set("MOZ_UPDATE_STAGING", "1");
michael@0 3396 }
michael@0 3397
michael@0 3398 logTestInfo("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1");
michael@0 3399 env.set("MOZ_NO_SERVICE_FALLBACK", "1");
michael@0 3400 }
michael@0 3401
michael@0 3402 /**
michael@0 3403 * Sets the environment back to the original values after launching the
michael@0 3404 * application.
michael@0 3405 */
michael@0 3406 function resetEnvironment() {
michael@0 3407 // Prevent resetting the environment more than once.
michael@0 3408 if (gShouldResetEnv !== true)
michael@0 3409 return;
michael@0 3410
michael@0 3411 gShouldResetEnv = false;
michael@0 3412
michael@0 3413 let env = AUS_Cc["@mozilla.org/process/environment;1"].
michael@0 3414 getService(AUS_Ci.nsIEnvironment);
michael@0 3415
michael@0 3416 if (gEnvXPCOMMemLeakLog) {
michael@0 3417 logTestInfo("setting the XPCOM_MEM_LEAK_LOG environment variable back to " +
michael@0 3418 gEnvXPCOMMemLeakLog);
michael@0 3419 env.set("XPCOM_MEM_LEAK_LOG", gEnvXPCOMMemLeakLog);
michael@0 3420 }
michael@0 3421
michael@0 3422 if (gEnvXPCOMDebugBreak) {
michael@0 3423 logTestInfo("setting the XPCOM_DEBUG_BREAK environment variable back to " +
michael@0 3424 gEnvXPCOMDebugBreak);
michael@0 3425 env.set("XPCOM_DEBUG_BREAK", gEnvXPCOMDebugBreak);
michael@0 3426 } else {
michael@0 3427 logTestInfo("clearing the XPCOM_DEBUG_BREAK environment variable");
michael@0 3428 env.set("XPCOM_DEBUG_BREAK", "");
michael@0 3429 }
michael@0 3430
michael@0 3431 if (IS_UNIX) {
michael@0 3432 if (IS_MACOSX) {
michael@0 3433 if (gEnvDyldLibraryPath) {
michael@0 3434 logTestInfo("setting DYLD_LIBRARY_PATH environment variable value " +
michael@0 3435 "back to " + gEnvDyldLibraryPath);
michael@0 3436 env.set("DYLD_LIBRARY_PATH", gEnvDyldLibraryPath);
michael@0 3437 } else {
michael@0 3438 logTestInfo("removing DYLD_LIBRARY_PATH environment variable");
michael@0 3439 env.set("DYLD_LIBRARY_PATH", "");
michael@0 3440 }
michael@0 3441 } else {
michael@0 3442 if (gEnvLdLibraryPath) {
michael@0 3443 logTestInfo("setting LD_LIBRARY_PATH environment variable value back " +
michael@0 3444 "to " + gEnvLdLibraryPath);
michael@0 3445 env.set("LD_LIBRARY_PATH", gEnvLdLibraryPath);
michael@0 3446 } else {
michael@0 3447 logTestInfo("removing LD_LIBRARY_PATH environment variable");
michael@0 3448 env.set("LD_LIBRARY_PATH", "");
michael@0 3449 }
michael@0 3450 }
michael@0 3451 }
michael@0 3452
michael@0 3453 if (IS_WIN && gAddedEnvXRENoWindowsCrashDialog) {
michael@0 3454 logTestInfo("removing the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
michael@0 3455 "variable");
michael@0 3456 env.set("XRE_NO_WINDOWS_CRASH_DIALOG", "");
michael@0 3457 }
michael@0 3458
michael@0 3459 if (gStageUpdate) {
michael@0 3460 logTestInfo("removing the MOZ_UPDATE_STAGING environment variable\n");
michael@0 3461 env.set("MOZ_UPDATE_STAGING", "");
michael@0 3462 }
michael@0 3463
michael@0 3464 logTestInfo("removing MOZ_NO_SERVICE_FALLBACK environment variable");
michael@0 3465 env.set("MOZ_NO_SERVICE_FALLBACK", "");
michael@0 3466 }

mercurial