Bug 1446833: Part 4 - Make sure directory service overrides actually take effect. r?rhelmer
The directory service caches certain directory entries, or has them set by
other callers using `.set()`. When we try to override those directories with
custom providers, the cached value still takes precedence.
It might make more sense to just store the directory entry values directly in
the directory service's hash, but this patch just takes the less obtrusive
path of clearing cached values for keys that we override.
This patch also fixes the few instances where add-on manager tests leave files
in the global temporary directory which are now caught by the shutdown
assertions.
MozReview-Commit-ID: Jq92TngLO1L
--- a/testing/xpcshell/head.js
+++ b/testing/xpcshell/head.js
@@ -1102,16 +1102,26 @@ function do_get_profile(notifyProfileAft
}
return null;
},
QueryInterface: _XPCOMUtils.generateQI(["nsIDirectoryServiceProvider"]),
};
_Services.dirsvc.QueryInterface(Ci.nsIDirectoryService)
.registerProvider(provider);
+ try {
+ _Services.dirsvc.undefine("TmpD");
+ } catch (e) {
+ // This throws if the key is not already registers, but that
+ // doesn't matter.
+ if (e.result != Cr.NS_ERROR_FAILURE) {
+ throw e;
+ }
+ }
+
// We need to update the crash events directory when the profile changes.
if (runningInParent &&
"@mozilla.org/toolkit/crash-reporter;1" in Cc) {
let crashReporter =
Cc["@mozilla.org/toolkit/crash-reporter;1"]
.getService(Ci.nsICrashReporter);
crashReporter.UpdateCrashEventsDir();
}
--- a/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
+++ b/toolkit/mozapps/extensions/internal/AddonTestUtils.jsm
@@ -26,16 +26,19 @@ const {OS} = ChromeUtils.import("resourc
ChromeUtils.defineModuleGetter(this, "Extension",
"resource://gre/modules/Extension.jsm");
XPCOMUtils.defineLazyGetter(this, "Management", () => {
let {Management} = ChromeUtils.import("resource://gre/modules/Extension.jsm", {});
return Management;
});
+ChromeUtils.defineModuleGetter(this, "FileTestUtils",
+ "resource://testing-common/FileTestUtils.jsm");
+
XPCOMUtils.defineLazyServiceGetter(this, "aomStartup",
"@mozilla.org/addons/addon-manager-startup;1",
"amIAddonManagerStartup");
XPCOMUtils.defineLazyServiceGetter(this, "rdfService",
"@mozilla.org/rdf/rdf-service;1", "nsIRDFService");
XPCOMUtils.defineLazyServiceGetter(this, "uuidGen",
"@mozilla.org/uuid-generator;1", "nsIUUIDGenerator");
@@ -290,22 +293,37 @@ var AddonTestUtils = {
if (file.exists()) {
throw new Error(`Test cleanup: path ${file.path} exists when it should not`);
}
}
testScope.registerCleanupFunction(() => {
this.cleanupTempXPIs();
+ let ignoreEntries = new Set();
+ {
+ // FileTestUtils lazily creates a directory to hold the temporary files
+ // it creates. If that directory exists, ignore it.
+ let {value} = Object.getOwnPropertyDescriptor(FileTestUtils,
+ "_globalTemporaryDirectory");
+ if (value) {
+ ignoreEntries.add(value.leafName);
+ }
+ }
+
// Check that the temporary directory is empty
var dirEntries = this.tempDir.directoryEntries
.QueryInterface(Ci.nsIDirectoryEnumerator);
var entries = [];
- while (dirEntries.hasMoreElements())
- entries.push(dirEntries.nextFile.leafName);
+ while (dirEntries.hasMoreElements()) {
+ let {leafName} = dirEntries.nextFile;
+ if (!ignoreEntries.has(leafName)) {
+ entries.push(leafName);
+ }
+ }
if (entries.length)
throw new Error(`Found unexpected files in temporary directory: ${entries.join(", ")}`);
dirEntries.close();
try {
appDirForAddons.remove(true);
} catch (ex) {
@@ -1049,16 +1067,26 @@ var AddonTestUtils = {
if (prop == key)
return dir.clone();
return null;
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider]),
};
Services.dirsvc.registerProvider(dirProvider);
+
+ try {
+ Services.dirsvc.undefine(key);
+ } catch (e) {
+ // This throws if the key is not already registers, but that
+ // doesn't matter.
+ if (e.result != Cr.NS_ERROR_FAILURE) {
+ throw e;
+ }
+ }
},
/**
* Returns a promise that resolves when the given add-on event is fired. The
* resolved value is an array of arguments passed for the event.
*
* @param {string} event
* The name of the AddonListener event handler method for which
--- a/toolkit/mozapps/extensions/internal/XPIInstall.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIInstall.jsm
@@ -1388,16 +1388,28 @@ class AddonInstall {
// Installation is already running
return;
default:
throw new Error("Cannot start installing from this state");
}
}
/**
+ * Called during XPIProvider shutdown so that we can do any necessary
+ * pre-shutdown cleanup.
+ */
+ onShutdown() {
+ switch (this.state) {
+ case AddonManager.STATE_POSTPONED:
+ this.removeTemporaryFile();
+ break;
+ }
+ }
+
+ /**
* Cancels installation of this add-on.
*
* Note this method is overridden to handle additional state in
* the subclass DownloadAddonInstall.
*
* @throws if installation cannot be cancelled from the current state
*/
cancel() {
--- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm
@@ -2321,16 +2321,22 @@ var XPIProvider = {
logger.debug("shutdown");
// Stop anything we were doing asynchronously
this.cancelAll();
this.activeAddons.clear();
this.allAppGlobal = true;
+ for (let install of this.installs) {
+ if (install.onShutdown()) {
+ install.onShutdown();
+ }
+ }
+
// If there are pending operations then we must update the list of active
// add-ons
if (Services.prefs.getBoolPref(PREF_PENDING_OPERATIONS, false)) {
AddonManagerPrivate.recordSimpleMeasure("XPIDB_pending_ops", 1);
XPIDatabase.updateActiveAddons();
Services.prefs.setBoolPref(PREF_PENDING_OPERATIONS, false);
}
new file mode 100644
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_harness.js
@@ -0,0 +1,11 @@
+"use strict";
+
+// Test that the test harness is sane.
+
+// Test that the temporary directory is actually overridden in the
+// directory service.
+add_task(async function test_TmpD_override() {
+ equal(FileUtils.getDir("TmpD", []).path,
+ AddonTestUtils.tempDir.path,
+ "Should get the correct temporary directory from the directory service");
+});
--- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install_syntax_error.js
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension_install_syntax_error.js
@@ -33,16 +33,17 @@ add_task(async function install_xpi() {
Assert.equal(install1.error, AddonManager.ERROR_CORRUPT_FILE);
// Replace xpi1 with xpi2 to have the same filename to reproduce install error
xpi2.moveTo(xpi1.parent, xpi1.leafName);
let install2 = await AddonManager.getInstallForFile(xpi2);
Assert.notEqual(install2.error, AddonManager.ERROR_CORRUPT_FILE);
+ xpi1.remove(false);
});
function run_test() {
createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1");
startupManager();
run_next_test();
}
--- a/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/mozapps/extensions/test/xpcshell/xpcshell.ini
@@ -12,16 +12,17 @@ support-files =
tags = blocklist
[test_blocklist_gfx.js]
tags = blocklist
[test_cache_certdb.js]
run-if = addon_signing
[test_cacheflush.js]
[test_gmpProvider.js]
skip-if = appname != "firefox"
+[test_harness.js]
[test_invalid_install_rdf.js]
[test_isReady.js]
[test_pluginInfoURL.js]
tags = blocklist
[test_provider_markSafe.js]
[test_provider_shutdown.js]
[test_provider_unsafe_access_shutdown.js]
[test_provider_unsafe_access_startup.js]