Sat, 03 Jan 2015 20:18:00 +0100
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 | } |