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