toolkit/mozapps/update/tests/shared.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 /* Shared code for xpcshell and mochitests-chrome */
michael@0 6
michael@0 7 // const Cc, Ci, and Cr are defined in netwerk/test/httpserver/httpd.js so we
michael@0 8 // need to define unique ones.
michael@0 9 const AUS_Cc = Components.classes;
michael@0 10 const AUS_Ci = Components.interfaces;
michael@0 11 const AUS_Cr = Components.results;
michael@0 12 const AUS_Cu = Components.utils;
michael@0 13 const AUS_Cm = Components.manager;
michael@0 14
michael@0 15 const PREF_APP_UPDATE_AUTO = "app.update.auto";
michael@0 16 const PREF_APP_UPDATE_BACKGROUNDERRORS = "app.update.backgroundErrors";
michael@0 17 const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors";
michael@0 18 const PREF_APP_UPDATE_CERTS_BRANCH = "app.update.certs.";
michael@0 19 const PREF_APP_UPDATE_CERT_CHECKATTRS = "app.update.cert.checkAttributes";
michael@0 20 const PREF_APP_UPDATE_CERT_ERRORS = "app.update.cert.errors";
michael@0 21 const PREF_APP_UPDATE_CERT_MAXERRORS = "app.update.cert.maxErrors";
michael@0 22 const PREF_APP_UPDATE_CERT_REQUIREBUILTIN = "app.update.cert.requireBuiltIn";
michael@0 23 const PREF_APP_UPDATE_CHANNEL = "app.update.channel";
michael@0 24 const PREF_APP_UPDATE_ENABLED = "app.update.enabled";
michael@0 25 const PREF_APP_UPDATE_METRO_ENABLED = "app.update.metro.enabled";
michael@0 26 const PREF_APP_UPDATE_IDLETIME = "app.update.idletime";
michael@0 27 const PREF_APP_UPDATE_LOG = "app.update.log";
michael@0 28 const PREF_APP_UPDATE_NEVER_BRANCH = "app.update.never.";
michael@0 29 const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported";
michael@0 30 const PREF_APP_UPDATE_PROMPTWAITTIME = "app.update.promptWaitTime";
michael@0 31 const PREF_APP_UPDATE_SERVICE_ENABLED = "app.update.service.enabled";
michael@0 32 const PREF_APP_UPDATE_SHOW_INSTALLED_UI = "app.update.showInstalledUI";
michael@0 33 const PREF_APP_UPDATE_SILENT = "app.update.silent";
michael@0 34 const PREF_APP_UPDATE_STAGING_ENABLED = "app.update.staging.enabled";
michael@0 35 const PREF_APP_UPDATE_URL = "app.update.url";
michael@0 36 const PREF_APP_UPDATE_URL_DETAILS = "app.update.url.details";
michael@0 37 const PREF_APP_UPDATE_URL_OVERRIDE = "app.update.url.override";
michael@0 38 const PREF_APP_UPDATE_SOCKET_ERRORS = "app.update.socket.maxErrors";
michael@0 39 const PREF_APP_UPDATE_RETRY_TIMEOUT = "app.update.socket.retryTimeout";
michael@0 40
michael@0 41 const PREF_APP_UPDATE_CERT_INVALID_ATTR_NAME = PREF_APP_UPDATE_CERTS_BRANCH +
michael@0 42 "1.invalidName";
michael@0 43
michael@0 44 const PREF_APP_PARTNER_BRANCH = "app.partner.";
michael@0 45 const PREF_DISTRIBUTION_ID = "distribution.id";
michael@0 46 const PREF_DISTRIBUTION_VERSION = "distribution.version";
michael@0 47
michael@0 48 const PREF_EXTENSIONS_UPDATE_URL = "extensions.update.url";
michael@0 49 const PREF_EXTENSIONS_STRICT_COMPAT = "extensions.strictCompatibility";
michael@0 50
michael@0 51 const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
michael@0 52 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
michael@0 53 const NS_GRE_DIR = "GreD";
michael@0 54 const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD";
michael@0 55 const XRE_EXECUTABLE_FILE = "XREExeF";
michael@0 56 const XRE_UPDATE_ROOT_DIR = "UpdRootD";
michael@0 57
michael@0 58 const CRC_ERROR = 4;
michael@0 59 const WRITE_ERROR = 7;
michael@0 60
michael@0 61 const DIR_PATCH = "0";
michael@0 62 const DIR_TOBEDELETED = "tobedeleted";
michael@0 63 const DIR_UPDATES = "updates";
michael@0 64 #ifdef XP_MACOSX
michael@0 65 const DIR_BIN_REL_PATH = "Contents/MacOS/";
michael@0 66 const DIR_UPDATED = "Updated.app";
michael@0 67 #else
michael@0 68 const DIR_BIN_REL_PATH = "";
michael@0 69 const DIR_UPDATED = "updated";
michael@0 70 #endif
michael@0 71
michael@0 72 const FILE_BACKUP_LOG = "backup-update.log";
michael@0 73 const FILE_LAST_LOG = "last-update.log";
michael@0 74 const FILE_UPDATER_INI = "updater.ini";
michael@0 75 const FILE_UPDATES_DB = "updates.xml";
michael@0 76 const FILE_UPDATE_ACTIVE = "active-update.xml";
michael@0 77 const FILE_UPDATE_ARCHIVE = "update.mar";
michael@0 78 const FILE_UPDATE_LOG = "update.log";
michael@0 79 const FILE_UPDATE_SETTINGS_INI = "update-settings.ini";
michael@0 80 const FILE_UPDATE_SETTINGS_INI_BAK = "update-settings.ini.bak";
michael@0 81 const FILE_UPDATE_STATUS = "update.status";
michael@0 82 const FILE_UPDATE_VERSION = "update.version";
michael@0 83
michael@0 84 const UPDATE_SETTINGS_CONTENTS = "[Settings]\n" +
michael@0 85 "ACCEPTED_MAR_CHANNEL_IDS=xpcshell-test\n"
michael@0 86
michael@0 87 const PR_RDWR = 0x04;
michael@0 88 const PR_CREATE_FILE = 0x08;
michael@0 89 const PR_APPEND = 0x10;
michael@0 90 const PR_TRUNCATE = 0x20;
michael@0 91 const PR_SYNC = 0x40;
michael@0 92 const PR_EXCL = 0x80;
michael@0 93
michael@0 94 const DEFAULT_UPDATE_VERSION = "999999.0";
michael@0 95
michael@0 96 var gChannel;
michael@0 97
michael@0 98 #include sharedUpdateXML.js
michael@0 99
michael@0 100 AUS_Cu.import("resource://gre/modules/FileUtils.jsm");
michael@0 101 AUS_Cu.import("resource://gre/modules/Services.jsm");
michael@0 102 AUS_Cu.import("resource://gre/modules/XPCOMUtils.jsm");
michael@0 103
michael@0 104 const PERMS_FILE = FileUtils.PERMS_FILE;
michael@0 105 const PERMS_DIRECTORY = FileUtils.PERMS_DIRECTORY;
michael@0 106
michael@0 107 const MODE_RDONLY = FileUtils.MODE_RDONLY;
michael@0 108 const MODE_WRONLY = FileUtils.MODE_WRONLY;
michael@0 109 const MODE_RDWR = FileUtils.MODE_RDWR;
michael@0 110 const MODE_CREATE = FileUtils.MODE_CREATE;
michael@0 111 const MODE_APPEND = FileUtils.MODE_APPEND;
michael@0 112 const MODE_TRUNCATE = FileUtils.MODE_TRUNCATE;
michael@0 113
michael@0 114 const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties";
michael@0 115 const gUpdateBundle = Services.strings.createBundle(URI_UPDATES_PROPERTIES);
michael@0 116
michael@0 117 XPCOMUtils.defineLazyGetter(this, "gAUS", function test_gAUS() {
michael@0 118 return AUS_Cc["@mozilla.org/updates/update-service;1"].
michael@0 119 getService(AUS_Ci.nsIApplicationUpdateService).
michael@0 120 QueryInterface(AUS_Ci.nsITimerCallback).
michael@0 121 QueryInterface(AUS_Ci.nsIObserver).
michael@0 122 QueryInterface(AUS_Ci.nsIUpdateCheckListener);
michael@0 123 });
michael@0 124
michael@0 125 XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager",
michael@0 126 "@mozilla.org/updates/update-manager;1",
michael@0 127 "nsIUpdateManager");
michael@0 128
michael@0 129 XPCOMUtils.defineLazyGetter(this, "gUpdateChecker", function test_gUC() {
michael@0 130 return AUS_Cc["@mozilla.org/updates/update-checker;1"].
michael@0 131 createInstance(AUS_Ci.nsIUpdateChecker);
michael@0 132 });
michael@0 133
michael@0 134 XPCOMUtils.defineLazyGetter(this, "gUP", function test_gUP() {
michael@0 135 return AUS_Cc["@mozilla.org/updates/update-prompt;1"].
michael@0 136 createInstance(AUS_Ci.nsIUpdatePrompt);
michael@0 137 });
michael@0 138
michael@0 139 XPCOMUtils.defineLazyGetter(this, "gDefaultPrefBranch", function test_gDPB() {
michael@0 140 return Services.prefs.getDefaultBranch(null);
michael@0 141 });
michael@0 142
michael@0 143 XPCOMUtils.defineLazyGetter(this, "gPrefRoot", function test_gPR() {
michael@0 144 return Services.prefs.getBranch(null);
michael@0 145 });
michael@0 146
michael@0 147 XPCOMUtils.defineLazyGetter(this, "gZipW", function test_gZipW() {
michael@0 148 return AUS_Cc["@mozilla.org/zipwriter;1"].
michael@0 149 createInstance(AUS_Ci.nsIZipWriter);
michael@0 150 });
michael@0 151
michael@0 152 /* Initializes the update service stub */
michael@0 153 function initUpdateServiceStub() {
michael@0 154 AUS_Cc["@mozilla.org/updates/update-service-stub;1"].
michael@0 155 createInstance(AUS_Ci.nsISupports);
michael@0 156 }
michael@0 157
michael@0 158 /* Reloads the update metadata from disk */
michael@0 159 function reloadUpdateManagerData() {
michael@0 160 gUpdateManager.QueryInterface(AUS_Ci.nsIObserver).
michael@0 161 observe(null, "um-reload-update-data", "");
michael@0 162 }
michael@0 163
michael@0 164 /**
michael@0 165 * Sets the app.update.channel preference.
michael@0 166 *
michael@0 167 * @param aChannel
michael@0 168 * The update channel.
michael@0 169 */
michael@0 170 function setUpdateChannel(aChannel) {
michael@0 171 gChannel = aChannel;
michael@0 172 debugDump("setting default pref " + PREF_APP_UPDATE_CHANNEL + " to " + gChannel);
michael@0 173 gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel);
michael@0 174 gPrefRoot.addObserver(PREF_APP_UPDATE_CHANNEL, observer, false);
michael@0 175 }
michael@0 176
michael@0 177 var observer = {
michael@0 178 observe: function(aSubject, aTopic, aData) {
michael@0 179 if (aTopic == "nsPref:changed" && aData == PREF_APP_UPDATE_CHANNEL) {
michael@0 180 var channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
michael@0 181 if (channel != gChannel) {
michael@0 182 debugDump("Changing channel from " + channel + " to " + gChannel);
michael@0 183 gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel);
michael@0 184 }
michael@0 185 }
michael@0 186 },
michael@0 187 QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
michael@0 188 };
michael@0 189
michael@0 190 /**
michael@0 191 * Sets the app.update.url.override preference.
michael@0 192 *
michael@0 193 * @param aURL
michael@0 194 * The update url. If not specified 'URL_HOST + "/update.xml"' will be
michael@0 195 * used.
michael@0 196 */
michael@0 197 function setUpdateURLOverride(aURL) {
michael@0 198 let url = aURL ? aURL : URL_HOST + "/update.xml";
michael@0 199 debugDump("setting " + PREF_APP_UPDATE_URL_OVERRIDE + " to " + url);
michael@0 200 Services.prefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url);
michael@0 201 }
michael@0 202
michael@0 203 /**
michael@0 204 * Returns either the active or regular update database XML file.
michael@0 205 *
michael@0 206 * @param isActiveUpdate
michael@0 207 * If true this will return the active-update.xml otherwise it will
michael@0 208 * return the updates.xml file.
michael@0 209 */
michael@0 210 function getUpdatesXMLFile(aIsActiveUpdate) {
michael@0 211 var file = getUpdatesRootDir();
michael@0 212 file.append(aIsActiveUpdate ? FILE_UPDATE_ACTIVE : FILE_UPDATES_DB);
michael@0 213 return file;
michael@0 214 }
michael@0 215
michael@0 216 /**
michael@0 217 * Writes the updates specified to either the active-update.xml or the
michael@0 218 * updates.xml.
michael@0 219 *
michael@0 220 * @param aContent
michael@0 221 * The updates represented as a string to write to the XML file.
michael@0 222 * @param isActiveUpdate
michael@0 223 * If true this will write to the active-update.xml otherwise it will
michael@0 224 * write to the updates.xml file.
michael@0 225 */
michael@0 226 function writeUpdatesToXMLFile(aContent, aIsActiveUpdate) {
michael@0 227 writeFile(getUpdatesXMLFile(aIsActiveUpdate), aContent);
michael@0 228 }
michael@0 229
michael@0 230 /**
michael@0 231 * Writes the current update operation/state to a file in the patch
michael@0 232 * directory, indicating to the patching system that operations need
michael@0 233 * to be performed.
michael@0 234 *
michael@0 235 * @param aStatus
michael@0 236 * The status value to write.
michael@0 237 */
michael@0 238 function writeStatusFile(aStatus) {
michael@0 239 let file = getUpdatesPatchDir();
michael@0 240 file.append(FILE_UPDATE_STATUS);
michael@0 241 writeFile(file, aStatus + "\n");
michael@0 242 }
michael@0 243
michael@0 244 /**
michael@0 245 * Writes the current update version to a file in the patch directory,
michael@0 246 * indicating to the patching system the version of the update.
michael@0 247 *
michael@0 248 * @param aVersion
michael@0 249 * The version value to write.
michael@0 250 */
michael@0 251 function writeVersionFile(aVersion) {
michael@0 252 let file = getUpdatesPatchDir();
michael@0 253 file.append(FILE_UPDATE_VERSION);
michael@0 254 writeFile(file, aVersion + "\n");
michael@0 255 }
michael@0 256
michael@0 257 /**
michael@0 258 * Gets the root directory for the updates directory.
michael@0 259 *
michael@0 260 * @return nsIFile for the updates root directory.
michael@0 261 */
michael@0 262 function getUpdatesRootDir() {
michael@0 263 return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, AUS_Ci.nsIFile);
michael@0 264 }
michael@0 265
michael@0 266 /**
michael@0 267 * Gets the updates directory.
michael@0 268 *
michael@0 269 * @return nsIFile for the updates directory.
michael@0 270 */
michael@0 271 function getUpdatesDir() {
michael@0 272 var dir = getUpdatesRootDir();
michael@0 273 dir.append(DIR_UPDATES);
michael@0 274 return dir;
michael@0 275 }
michael@0 276
michael@0 277 /**
michael@0 278 * Gets the directory for update patches.
michael@0 279 *
michael@0 280 * @return nsIFile for the updates directory.
michael@0 281 */
michael@0 282 function getUpdatesPatchDir() {
michael@0 283 let dir = getUpdatesDir();
michael@0 284 dir.append(DIR_PATCH);
michael@0 285 return dir;
michael@0 286 }
michael@0 287
michael@0 288 /**
michael@0 289 * Writes text to a file. This will replace existing text if the file exists
michael@0 290 * and create the file if it doesn't exist.
michael@0 291 *
michael@0 292 * @param aFile
michael@0 293 * The file to write to. Will be created if it doesn't exist.
michael@0 294 * @param aText
michael@0 295 * The text to write to the file. If there is existing text it will be
michael@0 296 * replaced.
michael@0 297 */
michael@0 298 function writeFile(aFile, aText) {
michael@0 299 var fos = AUS_Cc["@mozilla.org/network/file-output-stream;1"].
michael@0 300 createInstance(AUS_Ci.nsIFileOutputStream);
michael@0 301 if (!aFile.exists())
michael@0 302 aFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
michael@0 303 fos.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
michael@0 304 fos.write(aText, aText.length);
michael@0 305 fos.close();
michael@0 306 }
michael@0 307
michael@0 308 /**
michael@0 309 * Reads the current update operation/state in the status file in the patch
michael@0 310 * directory including the error code if it is present.
michael@0 311 *
michael@0 312 * @return The status value.
michael@0 313 */
michael@0 314 function readStatusFile() {
michael@0 315 let file = getUpdatesPatchDir();
michael@0 316 file.append(FILE_UPDATE_STATUS);
michael@0 317
michael@0 318 if (!file.exists()) {
michael@0 319 logTestInfo("update status file does not exists! Path: " + file.path);
michael@0 320 return STATE_NONE;
michael@0 321 }
michael@0 322
michael@0 323 return readFile(file).split("\n")[0];
michael@0 324 }
michael@0 325
michael@0 326 /**
michael@0 327 * Reads the current update operation/state in the status file in the patch
michael@0 328 * directory without the error code if it is present.
michael@0 329 *
michael@0 330 * @return The state value.
michael@0 331 */
michael@0 332 function readStatusState() {
michael@0 333 return readStatusFile().split(": ")[0];
michael@0 334 }
michael@0 335
michael@0 336 /**
michael@0 337 * Reads the current update operation/state in the status file in the patch
michael@0 338 * directory with the error code.
michael@0 339 *
michael@0 340 * @return The state value.
michael@0 341 */
michael@0 342 function readStatusFailedCode() {
michael@0 343 return readStatusFile().split(": ")[1];
michael@0 344 }
michael@0 345
michael@0 346 /**
michael@0 347 * Reads text from a file and returns the string.
michael@0 348 *
michael@0 349 * @param aFile
michael@0 350 * The file to read from.
michael@0 351 * @return The string of text read from the file.
michael@0 352 */
michael@0 353 function readFile(aFile) {
michael@0 354 var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
michael@0 355 createInstance(AUS_Ci.nsIFileInputStream);
michael@0 356 if (!aFile.exists())
michael@0 357 return null;
michael@0 358 fis.init(aFile, MODE_RDONLY, PERMS_FILE, 0);
michael@0 359 var sis = AUS_Cc["@mozilla.org/scriptableinputstream;1"].
michael@0 360 createInstance(AUS_Ci.nsIScriptableInputStream);
michael@0 361 sis.init(fis);
michael@0 362 var text = sis.read(sis.available());
michael@0 363 sis.close();
michael@0 364 return text;
michael@0 365 }
michael@0 366
michael@0 367 /**
michael@0 368 * Reads the binary contents of a file and returns it as a string.
michael@0 369 *
michael@0 370 * @param aFile
michael@0 371 * The file to read from.
michael@0 372 * @return The contents of the file as a string.
michael@0 373 */
michael@0 374 function readFileBytes(aFile) {
michael@0 375 var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
michael@0 376 createInstance(AUS_Ci.nsIFileInputStream);
michael@0 377 fis.init(aFile, -1, -1, false);
michael@0 378 var bis = AUS_Cc["@mozilla.org/binaryinputstream;1"].
michael@0 379 createInstance(AUS_Ci.nsIBinaryInputStream);
michael@0 380 bis.setInputStream(fis);
michael@0 381 var data = [];
michael@0 382 var count = fis.available();
michael@0 383 while (count > 0) {
michael@0 384 var bytes = bis.readByteArray(Math.min(65535, count));
michael@0 385 data.push(String.fromCharCode.apply(null, bytes));
michael@0 386 count -= bytes.length;
michael@0 387 if (bytes.length == 0)
michael@0 388 throw "Nothing read from input stream!";
michael@0 389 }
michael@0 390 data.join('');
michael@0 391 fis.close();
michael@0 392 return data.toString();
michael@0 393 }
michael@0 394
michael@0 395 /* Returns human readable status text from the updates.properties bundle */
michael@0 396 function getStatusText(aErrCode) {
michael@0 397 return getString("check_error-" + aErrCode);
michael@0 398 }
michael@0 399
michael@0 400 /* Returns a string from the updates.properties bundle */
michael@0 401 function getString(aName) {
michael@0 402 try {
michael@0 403 return gUpdateBundle.GetStringFromName(aName);
michael@0 404 } catch (e) {
michael@0 405 }
michael@0 406 return null;
michael@0 407 }
michael@0 408
michael@0 409 /**
michael@0 410 * Gets the file extension for an nsIFile.
michael@0 411 *
michael@0 412 * @param aFile
michael@0 413 * The file to get the file extension for.
michael@0 414 * @return The file extension.
michael@0 415 */
michael@0 416 function getFileExtension(aFile) {
michael@0 417 return Services.io.newFileURI(aFile).QueryInterface(AUS_Ci.nsIURL).
michael@0 418 fileExtension;
michael@0 419 }
michael@0 420
michael@0 421 /**
michael@0 422 * Removes the updates.xml file, active-update.xml file, and all files and
michael@0 423 * sub-directories in the updates directory except for the "0" sub-directory.
michael@0 424 * This prevents some tests from failing due to files being left behind when the
michael@0 425 * tests are interrupted.
michael@0 426 */
michael@0 427 function removeUpdateDirsAndFiles() {
michael@0 428 var file = getUpdatesXMLFile(true);
michael@0 429 try {
michael@0 430 if (file.exists())
michael@0 431 file.remove(false);
michael@0 432 } catch (e) {
michael@0 433 dump("Unable to remove file\nPath: " + file.path +
michael@0 434 "\nException: " + e + "\n");
michael@0 435 }
michael@0 436
michael@0 437 file = getUpdatesXMLFile(false);
michael@0 438 try {
michael@0 439 if (file.exists())
michael@0 440 file.remove(false);
michael@0 441 } catch (e) {
michael@0 442 dump("Unable to remove file\nPath: " + file.path +
michael@0 443 "\nException: " + e + "\n");
michael@0 444 }
michael@0 445
michael@0 446 // This fails sporadically on Mac OS X so wrap it in a try catch
michael@0 447 var updatesDir = getUpdatesDir();
michael@0 448 try {
michael@0 449 cleanUpdatesDir(updatesDir);
michael@0 450 } catch (e) {
michael@0 451 dump("Unable to remove files / directories from directory\nPath: " +
michael@0 452 updatesDir.path + "\nException: " + e + "\n");
michael@0 453 }
michael@0 454 }
michael@0 455
michael@0 456 /**
michael@0 457 * Removes all files and sub-directories in the updates directory except for
michael@0 458 * the "0" sub-directory.
michael@0 459 *
michael@0 460 * @param aDir
michael@0 461 * nsIFile for the directory to be deleted.
michael@0 462 */
michael@0 463 function cleanUpdatesDir(aDir) {
michael@0 464 if (!aDir.exists())
michael@0 465 return;
michael@0 466
michael@0 467 var dirEntries = aDir.directoryEntries;
michael@0 468 while (dirEntries.hasMoreElements()) {
michael@0 469 var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
michael@0 470
michael@0 471 if (entry.isDirectory()) {
michael@0 472 if (entry.leafName == DIR_PATCH && entry.parent.leafName == DIR_UPDATES) {
michael@0 473 cleanUpdatesDir(entry);
michael@0 474 entry.permissions = PERMS_DIRECTORY;
michael@0 475 } else {
michael@0 476 try {
michael@0 477 entry.remove(true);
michael@0 478 return;
michael@0 479 } catch (e) {
michael@0 480 }
michael@0 481 cleanUpdatesDir(entry);
michael@0 482 entry.permissions = PERMS_DIRECTORY;
michael@0 483 try {
michael@0 484 entry.remove(true);
michael@0 485 } catch (e) {
michael@0 486 dump("cleanUpdatesDir: unable to remove directory\nPath: " +
michael@0 487 entry.path + "\nException: " + e + "\n");
michael@0 488 throw(e);
michael@0 489 }
michael@0 490 }
michael@0 491 } else {
michael@0 492 entry.permissions = PERMS_FILE;
michael@0 493 try {
michael@0 494 entry.remove(false);
michael@0 495 } catch (e) {
michael@0 496 dump("cleanUpdatesDir: unable to remove file\nPath: " + entry.path +
michael@0 497 "\nException: " + e + "\n");
michael@0 498 throw(e);
michael@0 499 }
michael@0 500 }
michael@0 501 }
michael@0 502 }
michael@0 503
michael@0 504 /**
michael@0 505 * Deletes a directory and its children. First it tries nsIFile::Remove(true).
michael@0 506 * If that fails it will fall back to recursing, setting the appropriate
michael@0 507 * permissions, and deleting the current entry.
michael@0 508 *
michael@0 509 * @param aDir
michael@0 510 * nsIFile for the directory to be deleted.
michael@0 511 */
michael@0 512 function removeDirRecursive(aDir) {
michael@0 513 if (!aDir.exists()) {
michael@0 514 return;
michael@0 515 }
michael@0 516
michael@0 517 try {
michael@0 518 logTestInfo("attempting to remove directory. Path: " + aDir.path);
michael@0 519 aDir.remove(true);
michael@0 520 return;
michael@0 521 } catch (e) {
michael@0 522 logTestInfo("non-fatal error removing directory. Exception: " + e);
michael@0 523 }
michael@0 524
michael@0 525 var dirEntries = aDir.directoryEntries;
michael@0 526 while (dirEntries.hasMoreElements()) {
michael@0 527 var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
michael@0 528
michael@0 529 if (entry.isDirectory()) {
michael@0 530 removeDirRecursive(entry);
michael@0 531 } else {
michael@0 532 entry.permissions = PERMS_FILE;
michael@0 533 try {
michael@0 534 logTestInfo("attempting to remove file. Path: " + entry.path);
michael@0 535 entry.remove(false);
michael@0 536 } catch (e) {
michael@0 537 logTestInfo("error removing file. Exception: " + e);
michael@0 538 throw(e);
michael@0 539 }
michael@0 540 }
michael@0 541 }
michael@0 542
michael@0 543 aDir.permissions = PERMS_DIRECTORY;
michael@0 544 try {
michael@0 545 logTestInfo("attempting to remove directory. Path: " + aDir.path);
michael@0 546 aDir.remove(true);
michael@0 547 } catch (e) {
michael@0 548 logTestInfo("error removing directory. Exception: " + e);
michael@0 549 throw(e);
michael@0 550 }
michael@0 551 }
michael@0 552
michael@0 553 /**
michael@0 554 * Returns the directory for the currently running process. This is used to
michael@0 555 * clean up after the tests and to locate the active-update.xml and updates.xml
michael@0 556 * files.
michael@0 557 *
michael@0 558 * @return nsIFile for the current process directory.
michael@0 559 */
michael@0 560 function getCurrentProcessDir() {
michael@0 561 return Services.dirsvc.get(NS_XPCOM_CURRENT_PROCESS_DIR, AUS_Ci.nsIFile);
michael@0 562 }
michael@0 563
michael@0 564 /**
michael@0 565 * Gets the application base directory.
michael@0 566 *
michael@0 567 * @return nsIFile object for the application base directory.
michael@0 568 */
michael@0 569 function getAppBaseDir() {
michael@0 570 return Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent;
michael@0 571 }
michael@0 572
michael@0 573 /**
michael@0 574 * Returns the Gecko Runtime Engine directory. This is used to locate the the
michael@0 575 * updater binary (Windows and Linux) or updater package (Mac OS X). For
michael@0 576 * XULRunner applications this is different than the currently running process
michael@0 577 * directory.
michael@0 578 *
michael@0 579 * @return nsIFile for the Gecko Runtime Engine directory.
michael@0 580 */
michael@0 581 function getGREDir() {
michael@0 582 return Services.dirsvc.get(NS_GRE_DIR, AUS_Ci.nsIFile);
michael@0 583 }
michael@0 584
michael@0 585 /**
michael@0 586 * Get the "updated" directory inside the directory where we apply the
michael@0 587 * staged updates.
michael@0 588 * @return The active updates directory inside the updated directory, as a
michael@0 589 * nsIFile object.
michael@0 590 */
michael@0 591 function getUpdatedDir() {
michael@0 592 let dir = getAppBaseDir();
michael@0 593 #ifdef XP_MACOSX
michael@0 594 dir = dir.parent.parent; // the bundle directory
michael@0 595 #endif
michael@0 596 dir.append(DIR_UPDATED);
michael@0 597 logTestInfo("updated directory path: " + dir.path);
michael@0 598 return dir;
michael@0 599 }
michael@0 600
michael@0 601 /**
michael@0 602 * Logs TEST-INFO messages.
michael@0 603 *
michael@0 604 * @param aText
michael@0 605 * The text to log.
michael@0 606 * @param aCaller (optional)
michael@0 607 * An optional Components.stack.caller. If not specified
michael@0 608 * Components.stack.caller will be used.
michael@0 609 */
michael@0 610 function logTestInfo(aText, aCaller) {
michael@0 611 let caller = (aCaller ? aCaller : Components.stack.caller);
michael@0 612 let now = new Date;
michael@0 613 let hh = now.getHours();
michael@0 614 let mm = now.getMinutes();
michael@0 615 let ss = now.getSeconds();
michael@0 616 let ms = now.getMilliseconds();
michael@0 617 let time = (hh < 10 ? "0" + hh : hh) + ":" +
michael@0 618 (mm < 10 ? "0" + mm : mm) + ":" +
michael@0 619 (ss < 10 ? "0" + ss : ss) + ":" +
michael@0 620 (ms < 10 ? "00" + ms : ms < 100 ? "0" + ms : ms);
michael@0 621 dump(time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
michael@0 622 " : " + caller.lineNumber + "] " + aText + "\n");
michael@0 623 }
michael@0 624
michael@0 625 /**
michael@0 626 * Logs TEST-INFO messages when DEBUG_AUS_TEST evaluates to true.
michael@0 627 *
michael@0 628 * @param aText
michael@0 629 * The text to log.
michael@0 630 * @param aCaller (optional)
michael@0 631 * An optional Components.stack.caller. If not specified
michael@0 632 * Components.stack.caller will be used.
michael@0 633 */
michael@0 634 function debugDump(aText, aCaller) {
michael@0 635 if (DEBUG_AUS_TEST) {
michael@0 636 let caller = aCaller ? aCaller : Components.stack.caller;
michael@0 637 logTestInfo(aText, caller);
michael@0 638 }
michael@0 639 }

mercurial