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(); + }); +}