Bug 1459404 - Add regression test for GC of ExtensionPageContextChild draft
authorRob Wu <rob@robwu.nl>
Tue, 17 Jul 2018 18:22:27 +0200
changeset 819707 dc04ae29243bd4b2af6de7453dc02c9926aa9981
parent 819328 22e14aaa788bb37311248e85f6d4553f79564494
child 819708 54326fb9af596ee9fdcce00169a0e2619875a973
push id116618
push userbmo:rob@robwu.nl
push dateWed, 18 Jul 2018 11:24:01 +0000
bugs1459404
milestone63.0a1
Bug 1459404 - Add regression test for GC of ExtensionPageContextChild MozReview-Commit-ID: 65NexMbRlDh
toolkit/components/extensions/test/xpcshell/test_ext_contexts_gc.js
--- a/toolkit/components/extensions/test/xpcshell/test_ext_contexts_gc.js
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_contexts_gc.js
@@ -121,8 +121,112 @@ add_task(async function test_ContentScri
 
   await reloadTopContext(contentPage);
   await extension.awaitMessage("contentScriptLoaded");
   await assertContextReleased(contentPage, "ContentScriptContextChild should have been released");
 
   await contentPage.close();
   await extension.unload();
 });
+
+add_task(async function test_ExtensionPageContextChild_in_child_frame() {
+  let extensionData = {
+    files: {
+      "iframe.html": `
+        <!DOCTYPE html><meta charset="utf8">
+        <script src="script.js"></script>
+      `,
+      "toplevel.html": `
+        <!DOCTYPE html><meta charset="utf8">
+        <iframe src="iframe.html"></iframe>
+      `,
+      "script.js": "browser.test.sendMessage('extensionPageLoaded');",
+    },
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  await extension.startup();
+
+  let contentPage = await ExtensionTestUtils.loadContentPage(`moz-extension://${extension.uuid}/toplevel.html`, {
+    extension,
+    remote: extension.extension.remote,
+  });
+  await extension.awaitMessage("extensionPageLoaded");
+
+  await contentPage.spawn(extension.id, async extensionId => {
+    let {ExtensionPageChild} = ChromeUtils.import("resource://gre/modules/ExtensionPageChild.jsm", {});
+
+    let frame = this.content.document.querySelector("iframe[src*='iframe.html']");
+    let innerWindowID =
+      frame.contentWindow
+        .QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(Ci.nsIDOMWindowUtils)
+        .currentInnerWindowID;
+    let context = ExtensionPageChild.extensionContexts.get(innerWindowID);
+
+    Assert.ok(context, "Got extension page context for child frame");
+
+    this.contextWeakRef = Cu.getWeakReference(context);
+    frame.remove();
+  });
+
+  await assertContextReleased(contentPage, "ExtensionPageContextChild should have been released");
+
+  await contentPage.close();
+  await extension.unload();
+});
+
+add_task(async function test_ExtensionPageContextChild_in_toplevel() {
+  let extensionData = {
+    files: {
+      "toplevel.html": `
+        <!DOCTYPE html><meta charset="utf8">
+        <script src="script.js"></script>
+      `,
+      "script.js": "browser.test.sendMessage('extensionPageLoaded');",
+    },
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  await extension.startup();
+
+  let contentPage = await ExtensionTestUtils.loadContentPage(`moz-extension://${extension.uuid}/toplevel.html`, {
+    extension,
+    remote: extension.extension.remote,
+  });
+  await extension.awaitMessage("extensionPageLoaded");
+
+  await contentPage.spawn(extension.id, async extensionId => {
+    let {ExtensionPageChild} = ChromeUtils.import("resource://gre/modules/ExtensionPageChild.jsm", {});
+
+    let innerWindowID = this.content
+        .QueryInterface(Ci.nsIInterfaceRequestor)
+        .getInterface(Ci.nsIDOMWindowUtils)
+        .currentInnerWindowID;
+    let context = ExtensionPageChild.extensionContexts.get(innerWindowID);
+
+    Assert.ok(context, "Got extension page context for top-level document");
+
+    this.contextWeakRef = Cu.getWeakReference(context);
+  });
+
+  await reloadTopContext(contentPage);
+  await extension.awaitMessage("extensionPageLoaded");
+  // For some unknown reason, the context cannot forcidbly be released by the
+  // garbage collector unless we wait for a short while.
+  await contentPage.spawn(null, async () => {
+    let start = Date.now();
+    // The treshold was found after running this subtest only, 300 times
+    // in a release build (100 of xpcshell, xpcshell-e10s and xpcshell-remote).
+    // With treshold 8, almost half of the tests complete after a 17-18 ms delay.
+    // With treshold 7, over half of the tests complete after a 13-14 ms delay,
+    //  with 12 failures in 300 tests runs.
+    // Let's double that number to have a safety margin.
+    for (let i = 0; i < 15; ++i) {
+      await new Promise(resolve => this.content.setTimeout(resolve, 0));
+    }
+    info(`Going to GC after waiting for ${Date.now() - start} ms.`);
+  });
+  await assertContextReleased(contentPage, "ExtensionPageContextChild should have been released");
+
+  await contentPage.close();
+  await extension.unload();
+});