toolkit/mozapps/update/tests/shared.js

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/mozapps/update/tests/shared.js	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,639 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +/* Shared code for xpcshell and mochitests-chrome */
     1.9 +
    1.10 +// const Cc, Ci, and Cr are defined in netwerk/test/httpserver/httpd.js so we
    1.11 +// need to define unique ones.
    1.12 +const AUS_Cc = Components.classes;
    1.13 +const AUS_Ci = Components.interfaces;
    1.14 +const AUS_Cr = Components.results;
    1.15 +const AUS_Cu = Components.utils;
    1.16 +const AUS_Cm = Components.manager;
    1.17 +
    1.18 +const PREF_APP_UPDATE_AUTO                = "app.update.auto";
    1.19 +const PREF_APP_UPDATE_BACKGROUNDERRORS    = "app.update.backgroundErrors";
    1.20 +const PREF_APP_UPDATE_BACKGROUNDMAXERRORS = "app.update.backgroundMaxErrors";
    1.21 +const PREF_APP_UPDATE_CERTS_BRANCH        = "app.update.certs.";
    1.22 +const PREF_APP_UPDATE_CERT_CHECKATTRS     = "app.update.cert.checkAttributes";
    1.23 +const PREF_APP_UPDATE_CERT_ERRORS         = "app.update.cert.errors";
    1.24 +const PREF_APP_UPDATE_CERT_MAXERRORS      = "app.update.cert.maxErrors";
    1.25 +const PREF_APP_UPDATE_CERT_REQUIREBUILTIN = "app.update.cert.requireBuiltIn";
    1.26 +const PREF_APP_UPDATE_CHANNEL             = "app.update.channel";
    1.27 +const PREF_APP_UPDATE_ENABLED             = "app.update.enabled";
    1.28 +const PREF_APP_UPDATE_METRO_ENABLED       = "app.update.metro.enabled";
    1.29 +const PREF_APP_UPDATE_IDLETIME            = "app.update.idletime";
    1.30 +const PREF_APP_UPDATE_LOG                 = "app.update.log";
    1.31 +const PREF_APP_UPDATE_NEVER_BRANCH        = "app.update.never.";
    1.32 +const PREF_APP_UPDATE_NOTIFIEDUNSUPPORTED = "app.update.notifiedUnsupported";
    1.33 +const PREF_APP_UPDATE_PROMPTWAITTIME      = "app.update.promptWaitTime";
    1.34 +const PREF_APP_UPDATE_SERVICE_ENABLED     = "app.update.service.enabled";
    1.35 +const PREF_APP_UPDATE_SHOW_INSTALLED_UI   = "app.update.showInstalledUI";
    1.36 +const PREF_APP_UPDATE_SILENT              = "app.update.silent";
    1.37 +const PREF_APP_UPDATE_STAGING_ENABLED     = "app.update.staging.enabled";
    1.38 +const PREF_APP_UPDATE_URL                 = "app.update.url";
    1.39 +const PREF_APP_UPDATE_URL_DETAILS         = "app.update.url.details";
    1.40 +const PREF_APP_UPDATE_URL_OVERRIDE        = "app.update.url.override";
    1.41 +const PREF_APP_UPDATE_SOCKET_ERRORS       = "app.update.socket.maxErrors";
    1.42 +const PREF_APP_UPDATE_RETRY_TIMEOUT       = "app.update.socket.retryTimeout";
    1.43 +
    1.44 +const PREF_APP_UPDATE_CERT_INVALID_ATTR_NAME = PREF_APP_UPDATE_CERTS_BRANCH +
    1.45 +                                               "1.invalidName";
    1.46 +
    1.47 +const PREF_APP_PARTNER_BRANCH             = "app.partner.";
    1.48 +const PREF_DISTRIBUTION_ID                = "distribution.id";
    1.49 +const PREF_DISTRIBUTION_VERSION           = "distribution.version";
    1.50 +
    1.51 +const PREF_EXTENSIONS_UPDATE_URL          = "extensions.update.url";
    1.52 +const PREF_EXTENSIONS_STRICT_COMPAT       = "extensions.strictCompatibility";
    1.53 +
    1.54 +const NS_APP_PROFILE_DIR_STARTUP   = "ProfDS";
    1.55 +const NS_APP_USER_PROFILE_50_DIR   = "ProfD";
    1.56 +const NS_GRE_DIR                   = "GreD";
    1.57 +const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD";
    1.58 +const XRE_EXECUTABLE_FILE          = "XREExeF";
    1.59 +const XRE_UPDATE_ROOT_DIR          = "UpdRootD";
    1.60 +
    1.61 +const CRC_ERROR   = 4;
    1.62 +const WRITE_ERROR = 7;
    1.63 +
    1.64 +const DIR_PATCH        = "0";
    1.65 +const DIR_TOBEDELETED  = "tobedeleted";
    1.66 +const DIR_UPDATES      = "updates";
    1.67 +#ifdef XP_MACOSX
    1.68 +const DIR_BIN_REL_PATH = "Contents/MacOS/";
    1.69 +const DIR_UPDATED      = "Updated.app";
    1.70 +#else
    1.71 +const DIR_BIN_REL_PATH = "";
    1.72 +const DIR_UPDATED      = "updated";
    1.73 +#endif
    1.74 +
    1.75 +const FILE_BACKUP_LOG                = "backup-update.log";
    1.76 +const FILE_LAST_LOG                  = "last-update.log";
    1.77 +const FILE_UPDATER_INI               = "updater.ini";
    1.78 +const FILE_UPDATES_DB                = "updates.xml";
    1.79 +const FILE_UPDATE_ACTIVE             = "active-update.xml";
    1.80 +const FILE_UPDATE_ARCHIVE            = "update.mar";
    1.81 +const FILE_UPDATE_LOG                = "update.log";
    1.82 +const FILE_UPDATE_SETTINGS_INI       = "update-settings.ini";
    1.83 +const FILE_UPDATE_SETTINGS_INI_BAK   = "update-settings.ini.bak";
    1.84 +const FILE_UPDATE_STATUS             = "update.status";
    1.85 +const FILE_UPDATE_VERSION            = "update.version";
    1.86 +
    1.87 +const UPDATE_SETTINGS_CONTENTS = "[Settings]\n" +
    1.88 +                                 "ACCEPTED_MAR_CHANNEL_IDS=xpcshell-test\n"
    1.89 +
    1.90 +const PR_RDWR        = 0x04;
    1.91 +const PR_CREATE_FILE = 0x08;
    1.92 +const PR_APPEND      = 0x10;
    1.93 +const PR_TRUNCATE    = 0x20;
    1.94 +const PR_SYNC        = 0x40;
    1.95 +const PR_EXCL        = 0x80;
    1.96 +
    1.97 +const DEFAULT_UPDATE_VERSION = "999999.0";
    1.98 +
    1.99 +var gChannel;
   1.100 +
   1.101 +#include sharedUpdateXML.js
   1.102 +
   1.103 +AUS_Cu.import("resource://gre/modules/FileUtils.jsm");
   1.104 +AUS_Cu.import("resource://gre/modules/Services.jsm");
   1.105 +AUS_Cu.import("resource://gre/modules/XPCOMUtils.jsm");
   1.106 +
   1.107 +const PERMS_FILE      = FileUtils.PERMS_FILE;
   1.108 +const PERMS_DIRECTORY = FileUtils.PERMS_DIRECTORY;
   1.109 +
   1.110 +const MODE_RDONLY   = FileUtils.MODE_RDONLY;
   1.111 +const MODE_WRONLY   = FileUtils.MODE_WRONLY;
   1.112 +const MODE_RDWR     = FileUtils.MODE_RDWR;
   1.113 +const MODE_CREATE   = FileUtils.MODE_CREATE;
   1.114 +const MODE_APPEND   = FileUtils.MODE_APPEND;
   1.115 +const MODE_TRUNCATE = FileUtils.MODE_TRUNCATE;
   1.116 +
   1.117 +const URI_UPDATES_PROPERTIES = "chrome://mozapps/locale/update/updates.properties";
   1.118 +const gUpdateBundle = Services.strings.createBundle(URI_UPDATES_PROPERTIES);
   1.119 +
   1.120 +XPCOMUtils.defineLazyGetter(this, "gAUS", function test_gAUS() {
   1.121 +  return AUS_Cc["@mozilla.org/updates/update-service;1"].
   1.122 +         getService(AUS_Ci.nsIApplicationUpdateService).
   1.123 +         QueryInterface(AUS_Ci.nsITimerCallback).
   1.124 +         QueryInterface(AUS_Ci.nsIObserver).
   1.125 +         QueryInterface(AUS_Ci.nsIUpdateCheckListener);
   1.126 +});
   1.127 +
   1.128 +XPCOMUtils.defineLazyServiceGetter(this, "gUpdateManager",
   1.129 +                                   "@mozilla.org/updates/update-manager;1",
   1.130 +                                   "nsIUpdateManager");
   1.131 +
   1.132 +XPCOMUtils.defineLazyGetter(this, "gUpdateChecker", function test_gUC() {
   1.133 +  return AUS_Cc["@mozilla.org/updates/update-checker;1"].
   1.134 +         createInstance(AUS_Ci.nsIUpdateChecker);
   1.135 +});
   1.136 +
   1.137 +XPCOMUtils.defineLazyGetter(this, "gUP", function test_gUP() {
   1.138 +  return AUS_Cc["@mozilla.org/updates/update-prompt;1"].
   1.139 +         createInstance(AUS_Ci.nsIUpdatePrompt);
   1.140 +});
   1.141 +
   1.142 +XPCOMUtils.defineLazyGetter(this, "gDefaultPrefBranch", function test_gDPB() {
   1.143 +  return Services.prefs.getDefaultBranch(null);
   1.144 +});
   1.145 +
   1.146 +XPCOMUtils.defineLazyGetter(this, "gPrefRoot", function test_gPR() {
   1.147 +  return Services.prefs.getBranch(null);
   1.148 +});
   1.149 +
   1.150 +XPCOMUtils.defineLazyGetter(this, "gZipW", function test_gZipW() {
   1.151 +  return AUS_Cc["@mozilla.org/zipwriter;1"].
   1.152 +         createInstance(AUS_Ci.nsIZipWriter);
   1.153 +});
   1.154 +
   1.155 +/* Initializes the update service stub */
   1.156 +function initUpdateServiceStub() {
   1.157 +  AUS_Cc["@mozilla.org/updates/update-service-stub;1"].
   1.158 +  createInstance(AUS_Ci.nsISupports);
   1.159 +}
   1.160 +
   1.161 +/* Reloads the update metadata from disk */
   1.162 +function reloadUpdateManagerData() {
   1.163 +  gUpdateManager.QueryInterface(AUS_Ci.nsIObserver).
   1.164 +  observe(null, "um-reload-update-data", "");
   1.165 +}
   1.166 +
   1.167 +/**
   1.168 + * Sets the app.update.channel preference.
   1.169 + *
   1.170 + * @param  aChannel
   1.171 + *         The update channel.
   1.172 + */
   1.173 +function setUpdateChannel(aChannel) {
   1.174 +  gChannel = aChannel;
   1.175 +  debugDump("setting default pref " + PREF_APP_UPDATE_CHANNEL + " to " + gChannel);
   1.176 +  gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel);
   1.177 +  gPrefRoot.addObserver(PREF_APP_UPDATE_CHANNEL, observer, false);
   1.178 +}
   1.179 +
   1.180 +var observer = {
   1.181 +  observe: function(aSubject, aTopic, aData) {
   1.182 +    if (aTopic == "nsPref:changed" && aData == PREF_APP_UPDATE_CHANNEL) {
   1.183 +      var channel = gDefaultPrefBranch.getCharPref(PREF_APP_UPDATE_CHANNEL);
   1.184 +      if (channel != gChannel) {
   1.185 +        debugDump("Changing channel from " + channel + " to " + gChannel);
   1.186 +        gDefaultPrefBranch.setCharPref(PREF_APP_UPDATE_CHANNEL, gChannel);
   1.187 +      }
   1.188 +    }
   1.189 +  },
   1.190 +  QueryInterface: XPCOMUtils.generateQI([AUS_Ci.nsIObserver])
   1.191 +};
   1.192 +
   1.193 +/**
   1.194 + * Sets the app.update.url.override preference.
   1.195 + *
   1.196 + * @param  aURL
   1.197 + *         The update url. If not specified 'URL_HOST + "/update.xml"' will be
   1.198 + *         used.
   1.199 + */
   1.200 +function setUpdateURLOverride(aURL) {
   1.201 +  let url = aURL ? aURL : URL_HOST + "/update.xml";
   1.202 +  debugDump("setting " + PREF_APP_UPDATE_URL_OVERRIDE + " to " + url);
   1.203 +  Services.prefs.setCharPref(PREF_APP_UPDATE_URL_OVERRIDE, url);
   1.204 +}
   1.205 +
   1.206 +/**
   1.207 + * Returns either the active or regular update database XML file.
   1.208 + *
   1.209 + * @param  isActiveUpdate
   1.210 + *         If true this will return the active-update.xml otherwise it will
   1.211 + *         return the updates.xml file.
   1.212 + */
   1.213 +function getUpdatesXMLFile(aIsActiveUpdate) {
   1.214 +  var file = getUpdatesRootDir();
   1.215 +  file.append(aIsActiveUpdate ? FILE_UPDATE_ACTIVE : FILE_UPDATES_DB);
   1.216 +  return file;
   1.217 +}
   1.218 +
   1.219 +/**
   1.220 + * Writes the updates specified to either the active-update.xml or the
   1.221 + * updates.xml.
   1.222 + *
   1.223 + * @param  aContent
   1.224 + *         The updates represented as a string to write to the XML file.
   1.225 + * @param  isActiveUpdate
   1.226 + *         If true this will write to the active-update.xml otherwise it will
   1.227 + *         write to the updates.xml file.
   1.228 + */
   1.229 +function writeUpdatesToXMLFile(aContent, aIsActiveUpdate) {
   1.230 +  writeFile(getUpdatesXMLFile(aIsActiveUpdate), aContent);
   1.231 +}
   1.232 +
   1.233 +/**
   1.234 + * Writes the current update operation/state to a file in the patch
   1.235 + * directory, indicating to the patching system that operations need
   1.236 + * to be performed.
   1.237 + *
   1.238 + * @param  aStatus
   1.239 + *         The status value to write.
   1.240 + */
   1.241 +function writeStatusFile(aStatus) {
   1.242 +  let file = getUpdatesPatchDir();
   1.243 +  file.append(FILE_UPDATE_STATUS);
   1.244 +  writeFile(file, aStatus + "\n");
   1.245 +}
   1.246 +
   1.247 +/**
   1.248 + * Writes the current update version to a file in the patch directory,
   1.249 + * indicating to the patching system the version of the update.
   1.250 + *
   1.251 + * @param  aVersion
   1.252 + *         The version value to write.
   1.253 + */
   1.254 +function writeVersionFile(aVersion) {
   1.255 +  let file = getUpdatesPatchDir();
   1.256 +  file.append(FILE_UPDATE_VERSION);
   1.257 +  writeFile(file, aVersion + "\n");
   1.258 +}
   1.259 +
   1.260 +/**
   1.261 + * Gets the root directory for the updates directory.
   1.262 + *
   1.263 + * @return nsIFile for the updates root directory.
   1.264 + */
   1.265 +function getUpdatesRootDir() {
   1.266 +  return Services.dirsvc.get(XRE_UPDATE_ROOT_DIR, AUS_Ci.nsIFile);
   1.267 +}
   1.268 +
   1.269 +/**
   1.270 + * Gets the updates directory.
   1.271 + *
   1.272 + * @return nsIFile for the updates directory.
   1.273 + */
   1.274 +function getUpdatesDir() {
   1.275 +  var dir = getUpdatesRootDir();
   1.276 +  dir.append(DIR_UPDATES);
   1.277 +  return dir;
   1.278 +}
   1.279 +
   1.280 +/**
   1.281 + * Gets the directory for update patches.
   1.282 + *
   1.283 + * @return nsIFile for the updates directory.
   1.284 + */
   1.285 +function getUpdatesPatchDir() {
   1.286 +  let dir = getUpdatesDir();
   1.287 +  dir.append(DIR_PATCH);
   1.288 +  return dir;
   1.289 +}
   1.290 +
   1.291 +/**
   1.292 + * Writes text to a file. This will replace existing text if the file exists
   1.293 + * and create the file if it doesn't exist.
   1.294 + *
   1.295 + * @param  aFile
   1.296 + *         The file to write to. Will be created if it doesn't exist.
   1.297 + * @param  aText
   1.298 + *         The text to write to the file. If there is existing text it will be
   1.299 + *         replaced.
   1.300 + */
   1.301 +function writeFile(aFile, aText) {
   1.302 +  var fos = AUS_Cc["@mozilla.org/network/file-output-stream;1"].
   1.303 +            createInstance(AUS_Ci.nsIFileOutputStream);
   1.304 +  if (!aFile.exists())
   1.305 +    aFile.create(AUS_Ci.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
   1.306 +  fos.init(aFile, MODE_WRONLY | MODE_CREATE | MODE_TRUNCATE, PERMS_FILE, 0);
   1.307 +  fos.write(aText, aText.length);
   1.308 +  fos.close();
   1.309 +}
   1.310 +
   1.311 +/**
   1.312 + * Reads the current update operation/state in the status file in the patch
   1.313 + * directory including the error code if it is present.
   1.314 + *
   1.315 + * @return The status value.
   1.316 + */
   1.317 +function readStatusFile() {
   1.318 +  let file = getUpdatesPatchDir();
   1.319 +  file.append(FILE_UPDATE_STATUS);
   1.320 +
   1.321 +  if (!file.exists()) {
   1.322 +    logTestInfo("update status file does not exists! Path: " + file.path);
   1.323 +    return STATE_NONE;
   1.324 +  }
   1.325 +
   1.326 +  return readFile(file).split("\n")[0];
   1.327 +}
   1.328 +
   1.329 +/**
   1.330 + * Reads the current update operation/state in the status file in the patch
   1.331 + * directory without the error code if it is present.
   1.332 + *
   1.333 + * @return The state value.
   1.334 + */
   1.335 +function readStatusState() {
   1.336 +  return readStatusFile().split(": ")[0];
   1.337 +}
   1.338 +
   1.339 +/**
   1.340 + * Reads the current update operation/state in the status file in the patch
   1.341 + * directory with the error code.
   1.342 + *
   1.343 + * @return The state value.
   1.344 + */
   1.345 +function readStatusFailedCode() {
   1.346 +  return readStatusFile().split(": ")[1];
   1.347 +}
   1.348 +
   1.349 +/**
   1.350 + * Reads text from a file and returns the string.
   1.351 + *
   1.352 + * @param  aFile
   1.353 + *         The file to read from.
   1.354 + * @return The string of text read from the file.
   1.355 + */
   1.356 +function readFile(aFile) {
   1.357 +  var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
   1.358 +            createInstance(AUS_Ci.nsIFileInputStream);
   1.359 +  if (!aFile.exists())
   1.360 +    return null;
   1.361 +  fis.init(aFile, MODE_RDONLY, PERMS_FILE, 0);
   1.362 +  var sis = AUS_Cc["@mozilla.org/scriptableinputstream;1"].
   1.363 +            createInstance(AUS_Ci.nsIScriptableInputStream);
   1.364 +  sis.init(fis);
   1.365 +  var text = sis.read(sis.available());
   1.366 +  sis.close();
   1.367 +  return text;
   1.368 +}
   1.369 +
   1.370 +/**
   1.371 + * Reads the binary contents of a file and returns it as a string.
   1.372 + *
   1.373 + * @param  aFile
   1.374 + *         The file to read from.
   1.375 + * @return The contents of the file as a string.
   1.376 + */
   1.377 +function readFileBytes(aFile) {
   1.378 +  var fis = AUS_Cc["@mozilla.org/network/file-input-stream;1"].
   1.379 +            createInstance(AUS_Ci.nsIFileInputStream);
   1.380 +  fis.init(aFile, -1, -1, false);
   1.381 +  var bis = AUS_Cc["@mozilla.org/binaryinputstream;1"].
   1.382 +            createInstance(AUS_Ci.nsIBinaryInputStream);
   1.383 +  bis.setInputStream(fis);
   1.384 +  var data = [];
   1.385 +  var count = fis.available();
   1.386 +  while (count > 0) {
   1.387 +    var bytes = bis.readByteArray(Math.min(65535, count));
   1.388 +    data.push(String.fromCharCode.apply(null, bytes));
   1.389 +    count -= bytes.length;
   1.390 +    if (bytes.length == 0)
   1.391 +      throw "Nothing read from input stream!";
   1.392 +  }
   1.393 +  data.join('');
   1.394 +  fis.close();
   1.395 +  return data.toString();
   1.396 +}
   1.397 +
   1.398 +/* Returns human readable status text from the updates.properties bundle */
   1.399 +function getStatusText(aErrCode) {
   1.400 +  return getString("check_error-" + aErrCode);
   1.401 +}
   1.402 +
   1.403 +/* Returns a string from the updates.properties bundle */
   1.404 +function getString(aName) {
   1.405 +  try {
   1.406 +    return gUpdateBundle.GetStringFromName(aName);
   1.407 +  } catch (e) {
   1.408 +  }
   1.409 +  return null;
   1.410 +}
   1.411 +
   1.412 +/**
   1.413 + * Gets the file extension for an nsIFile.
   1.414 + *
   1.415 + * @param  aFile
   1.416 + *         The file to get the file extension for.
   1.417 + * @return The file extension.
   1.418 + */
   1.419 +function getFileExtension(aFile) {
   1.420 +  return Services.io.newFileURI(aFile).QueryInterface(AUS_Ci.nsIURL).
   1.421 +         fileExtension;
   1.422 +}
   1.423 +
   1.424 +/**
   1.425 + * Removes the updates.xml file, active-update.xml file, and all files and
   1.426 + * sub-directories in the updates directory except for the "0" sub-directory.
   1.427 + * This prevents some tests from failing due to files being left behind when the
   1.428 + * tests are interrupted.
   1.429 + */
   1.430 +function removeUpdateDirsAndFiles() {
   1.431 +  var file = getUpdatesXMLFile(true);
   1.432 +  try {
   1.433 +    if (file.exists())
   1.434 +      file.remove(false);
   1.435 +  } catch (e) {
   1.436 +    dump("Unable to remove file\nPath: " + file.path +
   1.437 +         "\nException: " + e + "\n");
   1.438 +  }
   1.439 +
   1.440 +  file = getUpdatesXMLFile(false);
   1.441 +  try {
   1.442 +    if (file.exists())
   1.443 +      file.remove(false);
   1.444 +  } catch (e) {
   1.445 +    dump("Unable to remove file\nPath: " + file.path +
   1.446 +         "\nException: " + e + "\n");
   1.447 +  }
   1.448 +
   1.449 +  // This fails sporadically on Mac OS X so wrap it in a try catch
   1.450 +  var updatesDir = getUpdatesDir();
   1.451 +  try {
   1.452 +    cleanUpdatesDir(updatesDir);
   1.453 +  } catch (e) {
   1.454 +    dump("Unable to remove files / directories from directory\nPath: " +
   1.455 +         updatesDir.path + "\nException: " + e + "\n");
   1.456 +  }
   1.457 +}
   1.458 +
   1.459 +/**
   1.460 + * Removes all files and sub-directories in the updates directory except for
   1.461 + * the "0" sub-directory.
   1.462 + *
   1.463 + * @param  aDir
   1.464 + *         nsIFile for the directory to be deleted.
   1.465 + */
   1.466 +function cleanUpdatesDir(aDir) {
   1.467 +  if (!aDir.exists())
   1.468 +    return;
   1.469 +
   1.470 +  var dirEntries = aDir.directoryEntries;
   1.471 +  while (dirEntries.hasMoreElements()) {
   1.472 +    var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
   1.473 +
   1.474 +    if (entry.isDirectory()) {
   1.475 +      if (entry.leafName == DIR_PATCH && entry.parent.leafName == DIR_UPDATES) {
   1.476 +        cleanUpdatesDir(entry);
   1.477 +        entry.permissions = PERMS_DIRECTORY;
   1.478 +      } else {
   1.479 +        try {
   1.480 +          entry.remove(true);
   1.481 +          return;
   1.482 +        } catch (e) {
   1.483 +        }
   1.484 +        cleanUpdatesDir(entry);
   1.485 +        entry.permissions = PERMS_DIRECTORY;
   1.486 +        try {
   1.487 +          entry.remove(true);
   1.488 +        } catch (e) {
   1.489 +          dump("cleanUpdatesDir: unable to remove directory\nPath: " +
   1.490 +               entry.path + "\nException: " + e + "\n");
   1.491 +          throw(e);
   1.492 +        }
   1.493 +      }
   1.494 +    } else {
   1.495 +      entry.permissions = PERMS_FILE;
   1.496 +      try {
   1.497 +        entry.remove(false);
   1.498 +      } catch (e) {
   1.499 +        dump("cleanUpdatesDir: unable to remove file\nPath: " + entry.path +
   1.500 +             "\nException: " + e + "\n");
   1.501 +        throw(e);
   1.502 +      }
   1.503 +    }
   1.504 +  }
   1.505 +}
   1.506 +
   1.507 +/**
   1.508 + * Deletes a directory and its children. First it tries nsIFile::Remove(true).
   1.509 + * If that fails it will fall back to recursing, setting the appropriate
   1.510 + * permissions, and deleting the current entry.
   1.511 + *
   1.512 + * @param  aDir
   1.513 + *         nsIFile for the directory to be deleted.
   1.514 + */
   1.515 +function removeDirRecursive(aDir) {
   1.516 +  if (!aDir.exists()) {
   1.517 +    return;
   1.518 +  }
   1.519 +
   1.520 +  try {
   1.521 +    logTestInfo("attempting to remove directory. Path: " + aDir.path);
   1.522 +    aDir.remove(true);
   1.523 +    return;
   1.524 +  } catch (e) {
   1.525 +    logTestInfo("non-fatal error removing directory. Exception: " + e);
   1.526 +  }
   1.527 +
   1.528 +  var dirEntries = aDir.directoryEntries;
   1.529 +  while (dirEntries.hasMoreElements()) {
   1.530 +    var entry = dirEntries.getNext().QueryInterface(AUS_Ci.nsIFile);
   1.531 +
   1.532 +    if (entry.isDirectory()) {
   1.533 +      removeDirRecursive(entry);
   1.534 +    } else {
   1.535 +      entry.permissions = PERMS_FILE;
   1.536 +      try {
   1.537 +        logTestInfo("attempting to remove file. Path: " + entry.path);
   1.538 +        entry.remove(false);
   1.539 +      } catch (e) {
   1.540 +        logTestInfo("error removing file. Exception: " + e);
   1.541 +        throw(e);
   1.542 +      }
   1.543 +    }
   1.544 +  }
   1.545 +
   1.546 +  aDir.permissions = PERMS_DIRECTORY;
   1.547 +  try {
   1.548 +    logTestInfo("attempting to remove directory. Path: " + aDir.path);
   1.549 +    aDir.remove(true);
   1.550 +  } catch (e) {
   1.551 +    logTestInfo("error removing directory. Exception: " + e);
   1.552 +    throw(e);
   1.553 +  }
   1.554 +}
   1.555 +
   1.556 +/**
   1.557 + * Returns the directory for the currently running process. This is used to
   1.558 + * clean up after the tests and to locate the active-update.xml and updates.xml
   1.559 + * files.
   1.560 + *
   1.561 + * @return nsIFile for the current process directory.
   1.562 + */
   1.563 +function getCurrentProcessDir() {
   1.564 +  return Services.dirsvc.get(NS_XPCOM_CURRENT_PROCESS_DIR, AUS_Ci.nsIFile);
   1.565 +}
   1.566 +
   1.567 +/**
   1.568 + * Gets the application base directory.
   1.569 + *
   1.570 + * @return  nsIFile object for the application base directory.
   1.571 + */
   1.572 +function getAppBaseDir() {
   1.573 +  return Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsIFile).parent;
   1.574 +}
   1.575 +
   1.576 +/**
   1.577 + * Returns the Gecko Runtime Engine directory. This is used to locate the the
   1.578 + * updater binary (Windows and Linux) or updater package (Mac OS X). For
   1.579 + * XULRunner applications this is different than the currently running process
   1.580 + * directory.
   1.581 + *
   1.582 + * @return nsIFile for the Gecko Runtime Engine directory.
   1.583 + */
   1.584 +function getGREDir() {
   1.585 +  return Services.dirsvc.get(NS_GRE_DIR, AUS_Ci.nsIFile);
   1.586 +}
   1.587 +
   1.588 +/**
   1.589 + * Get the "updated" directory inside the directory where we apply the
   1.590 + * staged updates.
   1.591 + * @return The active updates directory inside the updated directory, as a
   1.592 + *         nsIFile object.
   1.593 + */
   1.594 +function getUpdatedDir() {
   1.595 +  let dir = getAppBaseDir();
   1.596 +#ifdef XP_MACOSX
   1.597 +  dir = dir.parent.parent; // the bundle directory
   1.598 +#endif
   1.599 +  dir.append(DIR_UPDATED);
   1.600 +  logTestInfo("updated directory path: " + dir.path);
   1.601 +  return dir;
   1.602 +}
   1.603 +
   1.604 +/**
   1.605 + * Logs TEST-INFO messages.
   1.606 + *
   1.607 + * @param  aText
   1.608 + *         The text to log.
   1.609 + * @param  aCaller (optional)
   1.610 + *         An optional Components.stack.caller. If not specified
   1.611 + *         Components.stack.caller will be used.
   1.612 + */
   1.613 +function logTestInfo(aText, aCaller) {
   1.614 +  let caller = (aCaller ? aCaller : Components.stack.caller);
   1.615 +  let now = new Date;
   1.616 +  let hh = now.getHours();
   1.617 +  let mm = now.getMinutes();
   1.618 +  let ss = now.getSeconds();
   1.619 +  let ms = now.getMilliseconds();
   1.620 +  let time = (hh < 10 ? "0" + hh : hh) + ":" +
   1.621 +             (mm < 10 ? "0" + mm : mm) + ":" +
   1.622 +             (ss < 10 ? "0" + ss : ss) + ":" +
   1.623 +             (ms < 10 ? "00" + ms : ms < 100 ? "0" + ms : ms);
   1.624 +  dump(time + " | TEST-INFO | " + caller.filename + " | [" + caller.name +
   1.625 +       " : " + caller.lineNumber + "] " + aText + "\n");
   1.626 +}
   1.627 +
   1.628 +/**
   1.629 + * Logs TEST-INFO messages when DEBUG_AUS_TEST evaluates to true.
   1.630 + *
   1.631 + * @param  aText
   1.632 + *         The text to log.
   1.633 + * @param  aCaller (optional)
   1.634 + *         An optional Components.stack.caller. If not specified
   1.635 + *         Components.stack.caller will be used.
   1.636 + */
   1.637 +function debugDump(aText, aCaller) {
   1.638 +  if (DEBUG_AUS_TEST) {
   1.639 +    let caller = aCaller ? aCaller : Components.stack.caller;
   1.640 +    logTestInfo(aText, caller);
   1.641 +  }
   1.642 +}

mercurial