summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_clear_cached_resources.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/extensions/test/xpcshell/test_ext_clear_cached_resources.js')
-rw-r--r--toolkit/components/extensions/test/xpcshell/test_ext_clear_cached_resources.js417
1 files changed, 417 insertions, 0 deletions
diff --git a/toolkit/components/extensions/test/xpcshell/test_ext_clear_cached_resources.js b/toolkit/components/extensions/test/xpcshell/test_ext_clear_cached_resources.js
new file mode 100644
index 0000000000..e4f9f1d40b
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_clear_cached_resources.js
@@ -0,0 +1,417 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+Services.prefs.setBoolPref("extensions.blocklist.enabled", false);
+
+AddonTestUtils.init(this);
+AddonTestUtils.overrideCertDB();
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "1",
+ "43"
+);
+
+const { AddonManager } = ChromeUtils.importESModule(
+ "resource://gre/modules/AddonManager.sys.mjs"
+);
+
+const LEAVE_UUID_PREF = "extensions.webextensions.keepUuidOnUninstall";
+
+const BASE64_R_PIXEL =
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4z8DwHwAFAAH/F1FwBgAAAABJRU5ErkJggg==";
+const BASE64_G_PIXEL =
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2Ng+M/wHwAEAQH/7yMK/gAAAABJRU5ErkJggg==";
+const BASE64_B_PIXEL =
+ "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2NgYPj/HwADAgH/eL9GtQAAAABJRU5ErkJggg==";
+
+const toArrayBuffer = b64data =>
+ Uint8Array.from(atob(b64data), c => c.charCodeAt(0));
+const IMAGE_RED = toArrayBuffer(BASE64_R_PIXEL).buffer;
+const IMAGE_GREEN = toArrayBuffer(BASE64_G_PIXEL).buffer;
+const IMAGE_BLUE = toArrayBuffer(BASE64_B_PIXEL).buffer;
+
+const RGB_RED = "rgb(255, 0, 0)";
+const RGB_GREEN = "rgb(0, 255, 0)";
+const RGB_BLUE = "rgb(0, 0, 255)";
+
+const CSS_RED_BG = `body { background-color: ${RGB_RED}; }`;
+const CSS_GREEN_BG = `body { background-color: ${RGB_GREEN}; }`;
+const CSS_BLUE_BG = `body { background-color: ${RGB_BLUE}; }`;
+
+const ADDON_ID = "test-cached-resources@test";
+
+const manifest = {
+ version: "1",
+ browser_specific_settings: { gecko: { id: ADDON_ID } },
+};
+
+const files = {
+ "extpage.html": `<!DOCTYPE html>
+ <html>
+ <head>
+ <link rel="stylesheet" href="extpage.css">
+ </head>
+ <body>
+ <img id="test-image" src="image.png">
+ </body>
+ </html>
+ `,
+ "other_extpage.html": `<!DOCTYPE html>
+ <html>
+ <body>
+ </body>
+ </html>
+ `,
+ "extpage.css": CSS_RED_BG,
+ "image.png": IMAGE_RED,
+};
+
+const getBackgroundColor = () => {
+ return this.content.getComputedStyle(this.content.document.body)
+ .backgroundColor;
+};
+
+const hasCachedImage = imgUrl => {
+ const { document } = this.content;
+
+ const imageCache = Cc["@mozilla.org/image/tools;1"]
+ .getService(Ci.imgITools)
+ .getImgCacheForDocument(document);
+
+ const imgCacheProps = imageCache.findEntryProperties(
+ Services.io.newURI(imgUrl),
+ document
+ );
+
+ // return true if the image was in the cache.
+ return !!imgCacheProps;
+};
+
+const getImageColor = () => {
+ const { document } = this.content;
+ const img = document.querySelector("img#test-image");
+ const canvas = document.createElement("canvas");
+ canvas.width = 1;
+ canvas.height = 1;
+ const ctx = canvas.getContext("2d");
+ ctx.drawImage(img, 0, 0); // Draw without scaling.
+ const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;
+ if (a < 1) {
+ return `rgba(${r}, ${g}, ${b}, ${a})`;
+ }
+ return `rgb(${r}, ${g}, ${b})`;
+};
+
+async function assertBackgroundColor(page, color, message) {
+ equal(
+ await page.spawn([], getBackgroundColor),
+ color,
+ `Got the expected ${message}`
+ );
+}
+
+async function assertImageColor(page, color, message) {
+ equal(await page.spawn([], getImageColor), color, message);
+}
+
+async function assertImageCached(page, imageUrl, message) {
+ ok(await page.spawn([imageUrl], hasCachedImage), message);
+}
+
+// This test verifies that cached css are cleared across addon upgrades and downgrades
+// for permanently installed addon (See Bug 1746841).
+add_task(async function test_cached_resources_cleared_across_addon_updates() {
+ await AddonTestUtils.promiseStartupManager();
+
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "permanent",
+ manifest,
+ files,
+ });
+
+ await extension.startup();
+ equal(
+ extension.version,
+ "1",
+ "Got the expected version for the initial extension"
+ );
+
+ const url = extension.extension.baseURI.resolve("extpage.html");
+ let page = await ExtensionTestUtils.loadContentPage(url);
+ await assertBackgroundColor(
+ page,
+ RGB_RED,
+ "background color (initial extension version)"
+ );
+ await assertImageColor(page, RGB_RED, "image (initial extension version)");
+
+ info("Verify extension page css and image after addon upgrade");
+
+ await extension.upgrade({
+ useAddonManager: "permanent",
+ manifest: {
+ ...manifest,
+ version: "2",
+ },
+ files: {
+ ...files,
+ "extpage.css": CSS_GREEN_BG,
+ "image.png": IMAGE_GREEN,
+ },
+ });
+ equal(
+ extension.version,
+ "2",
+ "Got the expected version for the upgraded extension"
+ );
+
+ await page.loadURL(url);
+
+ await assertBackgroundColor(
+ page,
+ RGB_GREEN,
+ "background color (upgraded extension version)"
+ );
+ await assertImageColor(page, RGB_GREEN, "image (upgraded extension version)");
+
+ info("Verify extension page css and image after addon downgrade");
+
+ await extension.upgrade({
+ useAddonManager: "permanent",
+ manifest,
+ files,
+ });
+ equal(
+ extension.version,
+ "1",
+ "Got the expected version for the downgraded extension"
+ );
+
+ await page.loadURL(url);
+
+ await assertBackgroundColor(
+ page,
+ RGB_RED,
+ "background color (downgraded extension version)"
+ );
+ await assertImageColor(
+ page,
+ RGB_RED,
+ "image color (downgraded extension version)"
+ );
+
+ await page.close();
+ await extension.unload();
+ await AddonTestUtils.promiseShutdownManager();
+});
+
+// This test verifies that cached css are cleared if we are installing a new
+// extension and we did not clear the cache for a previous one with the same uuid
+// when it was uninstalled (See Bug 1746841).
+add_task(async function test_cached_resources_cleared_on_addon_install() {
+ // Make sure the test addon installed without an AddonManager addon wrapper
+ // and the ones installed right after that using the AddonManager will share
+ // the same uuid (and so also the same moz-extension resource urls).
+ Services.prefs.setBoolPref(LEAVE_UUID_PREF, true);
+ registerCleanupFunction(() => Services.prefs.clearUserPref(LEAVE_UUID_PREF));
+
+ await AddonTestUtils.promiseStartupManager();
+
+ const nonAOMExtension = ExtensionTestUtils.loadExtension({
+ manifest,
+ files: {
+ ...files,
+ // Override css with a different color from the one expected
+ // later in this test case.
+ "extpage.css": CSS_BLUE_BG,
+ "image.png": IMAGE_BLUE,
+ },
+ });
+
+ await nonAOMExtension.startup();
+ equal(
+ await AddonManager.getAddonByID(ADDON_ID),
+ null,
+ "No AOM addon wrapper found as expected"
+ );
+ let url = nonAOMExtension.extension.baseURI.resolve("extpage.html");
+ let page = await ExtensionTestUtils.loadContentPage(url);
+ await assertBackgroundColor(
+ page,
+ RGB_BLUE,
+ "background color (addon installed without uninstall observer)"
+ );
+ await assertImageColor(
+ page,
+ RGB_BLUE,
+ "image (addon uninstalled without clearing cache)"
+ );
+
+ // NOTE: unloading a test extension that does not have an AddonManager addon wrapper
+ // does not trigger the uninstall observer, and this is what this test needs to make
+ // sure that if the cached resources were not cleared on uninstall, then we will still
+ // clear it when a newly installed addon is installed even if the two extensions
+ // are sharing the same addon uuid (and so also the same moz-extension resource urls).
+ await nonAOMExtension.unload();
+
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "permanent",
+ manifest,
+ files,
+ });
+
+ await extension.startup();
+ await page.loadURL(url);
+
+ await assertBackgroundColor(
+ page,
+ RGB_RED,
+ "background color (newly installed addon, same addon id)"
+ );
+ await assertImageColor(
+ page,
+ RGB_RED,
+ "image (newly installed addon, same addon id)"
+ );
+
+ await page.close();
+ await extension.unload();
+ await AddonTestUtils.promiseShutdownManager();
+});
+
+// This test verifies that reloading a temporarily installed addon after
+// changing a css file cached in a previous run clears the previously
+// cached css and uses the new one changed on disk (See Bug 1746841).
+add_task(
+ async function test_cached_resources_cleared_on_temporary_addon_reload() {
+ await AddonTestUtils.promiseStartupManager();
+
+ const xpi = AddonTestUtils.createTempWebExtensionFile({
+ manifest,
+ files,
+ });
+
+ // This temporary directory is going to be removed from the
+ // cleanup function, but also make it unique as we do for the
+ // other temporary files (e.g. like getTemporaryFile as defined
+ // in XPInstall.jsm).
+ const random = Math.round(Math.random() * 36 ** 3).toString(36);
+ const tmpDirName = `xpcshelltest_unpacked_addons_${random}`;
+ let tmpExtPath = FileUtils.getDir("TmpD", [tmpDirName], true);
+ registerCleanupFunction(() => {
+ tmpExtPath.remove(true);
+ });
+
+ // Unpacking the xpi file into the temporary directory.
+ const extDir = await AddonTestUtils.manuallyInstall(
+ xpi,
+ tmpExtPath,
+ null,
+ /* unpacked */ true
+ );
+
+ let extension = ExtensionTestUtils.expectExtension(ADDON_ID);
+ await AddonManager.installTemporaryAddon(extDir);
+ await extension.awaitStartup();
+
+ equal(
+ extension.version,
+ "1",
+ "Got the expected version for the initial extension"
+ );
+
+ const url = extension.extension.baseURI.resolve("extpage.html");
+ let page = await ExtensionTestUtils.loadContentPage(url);
+ await assertBackgroundColor(
+ page,
+ RGB_RED,
+ "background color (initial extension version)"
+ );
+ await assertImageColor(page, RGB_RED, "image (initial extension version)");
+
+ info("Verify updated extension page css and image after addon reload");
+
+ const targetCSSFile = extDir.clone();
+ targetCSSFile.append("extpage.css");
+ ok(
+ targetCSSFile.exists(),
+ `Found the ${targetCSSFile.path} target file on disk`
+ );
+ await IOUtils.writeUTF8(targetCSSFile.path, CSS_GREEN_BG);
+
+ const targetPNGFile = extDir.clone();
+ targetPNGFile.append("image.png");
+ ok(
+ targetPNGFile.exists(),
+ `Found the ${targetPNGFile.path} target file on disk`
+ );
+ await IOUtils.write(targetPNGFile.path, toArrayBuffer(BASE64_G_PIXEL));
+
+ const addon = await AddonManager.getAddonByID(ADDON_ID);
+ ok(addon, "Got an AddonWrapper for the test extension");
+ await addon.reload();
+
+ await page.loadURL(url);
+
+ await assertBackgroundColor(
+ page,
+ RGB_GREEN,
+ "background (updated files on disk)"
+ );
+ await assertImageColor(page, RGB_GREEN, "image (updated files on disk)");
+
+ await page.close();
+ await addon.uninstall();
+ await AddonTestUtils.promiseShutdownManager();
+ }
+);
+
+// This test verifies that cached images are not cleared between
+// permanently installed addon reloads.
+add_task(async function test_cached_image_kept_on_permanent_addon_restarts() {
+ await AddonTestUtils.promiseStartupManager();
+ const extension = ExtensionTestUtils.loadExtension({
+ useAddonManager: "permanent",
+ manifest,
+ files,
+ });
+
+ await extension.startup();
+
+ equal(
+ extension.version,
+ "1",
+ "Got the expected version for the initial extension"
+ );
+
+ const imageUrl = extension.extension.baseURI.resolve("image.png");
+ const url = extension.extension.baseURI.resolve("extpage.html");
+
+ let page = await ExtensionTestUtils.loadContentPage(url);
+ await assertBackgroundColor(
+ page,
+ RGB_RED,
+ "background color (first startup)"
+ );
+ await assertImageColor(page, RGB_RED, "image (first startup)");
+ await assertImageCached(page, imageUrl, "image cached (first startup)");
+
+ info("Reload the AddonManager to simulate browser restart");
+ extension.setRestarting();
+ await AddonTestUtils.promiseRestartManager();
+ await extension.awaitStartup();
+
+ await page.loadURL(extension.extension.baseURI.resolve("other_extpage.html"));
+ await assertImageCached(
+ page,
+ imageUrl,
+ "image still cached after AddonManager restart"
+ );
+
+ await page.close();
+ await extension.unload();
+ await AddonTestUtils.promiseShutdownManager();
+});