diff --git a/toolkit/mozapps/extensions/XPIProvider.jsm b/toolkit/mozapps/extensions/XPIProvider.jsm
index 35965193a4cd..da247f1b83d0 100644
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -1069,8 +1069,10 @@ function recursiveRemove(aFile) {
return;
}
catch (e) {
- if (!aFile.isDirectory())
+ if (!aFile.isDirectory()) {
+ ERROR("Failed to remove file " + aFile.path, e);
throw e;
+ }
}
let entry;
@@ -1671,7 +1673,7 @@ var XPIProvider = {
}
catch (e) {
// Non-critical, just saves some perf on startup if we clean this up.
- LOG("Error removing XPI staging dir " + stagedXPIDir.path + ": " + e);
+ LOG("Error removing XPI staging dir " + stagedXPIDir.path, e);
}
}
@@ -1774,7 +1776,7 @@ var XPIProvider = {
}
catch (e) {
// Non-critical, just saves some perf on startup if we clean this up.
- LOG("Error removing staging dir " + stagingDir.path + ": " + e);
+ LOG("Error removing staging dir " + stagingDir.path, e);
}
});
return changed;
@@ -4941,6 +4943,9 @@ AddonInstall.prototype = {
break;
case AddonManager.STATE_INSTALLED:
LOG("Cancelling install of " + this.addon.id);
+ let xpi = this.installLocation.getStagingDir();
+ xpi.append(this.addon.id + ".xpi");
+ Services.obs.notifyObservers(xpi, "flush-cache-entry", null);
cleanStagingDir(this.installLocation.getStagingDir(),
[this.addon.id, this.addon.id + ".xpi",
this.addon.id + ".json"]);
diff --git a/toolkit/mozapps/extensions/test/addons/test_cacheflush1/install.rdf b/toolkit/mozapps/extensions/test/addons/test_cacheflush1/install.rdf
new file mode 100644
index 000000000000..5e64b65c1973
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_cacheflush1/install.rdf
@@ -0,0 +1,22 @@
+
+
+
+
+
+ addon1@tests.mozilla.org
+ 2.0
+
+
+ File Pointer Test
+
+
+
+ xpcshell@tests.mozilla.org
+ 1
+ 1
+
+
+
+
+
diff --git a/toolkit/mozapps/extensions/test/addons/test_cacheflush2/install.rdf b/toolkit/mozapps/extensions/test/addons/test_cacheflush2/install.rdf
new file mode 100644
index 000000000000..7728002ea34d
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/addons/test_cacheflush2/install.rdf
@@ -0,0 +1,23 @@
+
+
+
+
+
+ addon2@tests.mozilla.org
+ 2.0
+
+
+ File Pointer Test
+ true
+
+
+
+ xpcshell@tests.mozilla.org
+ 1
+ 1
+
+
+
+
+
diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js b/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
new file mode 100644
index 000000000000..9ccddef7b3b8
--- /dev/null
+++ b/toolkit/mozapps/extensions/test/xpcshell/test_cacheflush.js
@@ -0,0 +1,121 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+// This verifies that flushing the zipreader cache happens when appropriate
+
+var gExpectedFile = null;
+var gCacheFlushed = false;
+
+var CacheFlushObserver = {
+ observe: function(aSubject, aTopic, aData) {
+ if (aTopic != "flush-cache-entry")
+ return;
+
+ do_check_true(gExpectedFile != null);
+ do_check_true(aSubject instanceof AM_Ci.nsIFile);
+ do_check_eq(aSubject.path, gExpectedFile.path);
+ gCacheFlushed = true;
+ gExpectedFile = null;
+ }
+};
+
+function run_test() {
+ // This test only makes sense when leaving extensions packed
+ if (Services.prefs.getBoolPref("extensions.alwaysUnpack"))
+ return;
+
+ do_test_pending();
+ Services.obs.addObserver(CacheFlushObserver, "flush-cache-entry", false);
+ createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "2");
+
+ startupManager();
+
+ run_test_1();
+}
+
+// Tests that the cache is flushed when cancelling a pending install
+function run_test_1() {
+ AddonManager.getInstallForFile(do_get_addon("test_cacheflush1"), function(aInstall) {
+ completeAllInstalls([aInstall], function() {
+ // We should flush the staged XPI when cancelling the install
+ gExpectedFile = gProfD.clone();
+ gExpectedFile.append("extensions");
+ gExpectedFile.append("staged");
+ gExpectedFile.append("addon1@tests.mozilla.org.xpi");
+ aInstall.cancel();
+
+ do_check_true(gCacheFlushed);
+ gCacheFlushed = false;
+
+ run_test_2();
+ });
+ });
+}
+
+// Tests that the cache is flushed when uninstalling an add-on
+function run_test_2() {
+ installAllFiles([do_get_addon("test_cacheflush1")], function() {
+ // Installing will flush the staged XPI during startup
+ gExpectedFile = gProfD.clone();
+ gExpectedFile.append("extensions");
+ gExpectedFile.append("staged");
+ gExpectedFile.append("addon1@tests.mozilla.org.xpi");
+ restartManager();
+ do_check_true(gCacheFlushed);
+ gCacheFlushed = false;
+
+ AddonManager.getAddonByID("addon1@tests.mozilla.org", function(a1) {
+ // We should flush the installed XPI when uninstalling
+ gExpectedFile = gProfD.clone();
+ gExpectedFile.append("extensions");
+ gExpectedFile.append("addon1@tests.mozilla.org.xpi");
+
+ a1.uninstall();
+ do_check_false(gCacheFlushed);
+ restartManager();
+
+ run_test_3();
+ });
+ });
+}
+
+// Tests that the cache is flushed when installing a restartless add-on
+function run_test_3() {
+ AddonManager.getInstallForFile(do_get_addon("test_cacheflush2"), function(aInstall) {
+ aInstall.addListener({
+ onInstallStarted: function(aInstall) {
+ // We should flush the staged XPI when completing the install
+ gExpectedFile = gProfD.clone();
+ gExpectedFile.append("extensions");
+ gExpectedFile.append("staged");
+ gExpectedFile.append("addon2@tests.mozilla.org.xpi");
+ },
+
+ onInstallEnded: function(aInstall) {
+ do_check_true(gCacheFlushed);
+ gCacheFlushed = false;
+
+ run_test_4();
+ }
+ });
+
+ aInstall.install();
+ });
+}
+
+// Tests that the cache is flushed when uninstalling a restartless add-on
+function run_test_4() {
+ AddonManager.getAddonByID("addon2@tests.mozilla.org", function(a2) {
+ // We should flush the installed XPI when uninstalling
+ gExpectedFile = gProfD.clone();
+ gExpectedFile.append("extensions");
+ gExpectedFile.append("addon2@tests.mozilla.org.xpi");
+
+ a2.uninstall();
+ do_check_true(gCacheFlushed);
+ gCacheFlushed = false;
+
+ do_test_finished();
+ });
+}