mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 00:01:50 +00:00
Bug 1450358
P0 Factor the event listener runtime leak checking test into a reusable test framework. r=baku
This commit is contained in:
parent
6cee50b1b0
commit
5e3b64d3ec
81
dom/events/test/event_leak_utils.js
Normal file
81
dom/events/test/event_leak_utils.js
Normal file
@ -0,0 +1,81 @@
|
||||
// Any copyright is dedicated to the Public Domain.
|
||||
// http://creativecommons.org/publicdomain/zero/1.0/
|
||||
"use strict"
|
||||
|
||||
// This function runs a number of tests where:
|
||||
//
|
||||
// 1. An iframe is created
|
||||
// 2. The target callback is executed with the iframe's contentWindow as
|
||||
// an argument.
|
||||
// 3. The iframe is destroyed and GC is forced.
|
||||
// 4. Verifies that the iframe's contentWindow has been GC'd.
|
||||
//
|
||||
// Different ways of destroying the iframe are checked. Simple
|
||||
// remove(), destruction via bfcache, or replacement by document.open().
|
||||
//
|
||||
// Please pass a target callback that exercises the API under
|
||||
// test using the given window. The callback should try to leave the
|
||||
// API active to increase the liklihood of provoking an API. Any activity
|
||||
// should be canceled by the destruction of the window.
|
||||
async function checkForEventListenerLeaks(name, target) {
|
||||
// Test if we leak in the case where we do nothing special to
|
||||
// the frame before removing it from the DOM.
|
||||
await _eventListenerLeakStep(target, `${name} default`);
|
||||
|
||||
// Test the case where we navigate the frame before removing it
|
||||
// from the DOM so that the window using the target API ends up
|
||||
// in bfcache.
|
||||
await _eventListenerLeakStep(target, `${name} bfcache`, frame => {
|
||||
frame.src = "about:blank";
|
||||
return new Promise(resolve => frame.onload = resolve);
|
||||
});
|
||||
|
||||
// Test the case where we document.open() the frame before removing
|
||||
// it from the DOM so that the window using the target API ends
|
||||
// up getting replaced.
|
||||
await _eventListenerLeakStep(target, `${name} document.open()`, frame => {
|
||||
frame.contentDocument.open();
|
||||
frame.contentDocument.close();
|
||||
});
|
||||
}
|
||||
|
||||
// ----------------
|
||||
// Internal helpers
|
||||
// ----------------
|
||||
|
||||
// Utility function to create a loaded iframe.
|
||||
async function _withFrame(doc, url) {
|
||||
let frame = doc.createElement('iframe');
|
||||
frame.src = url;
|
||||
doc.body.appendChild(frame);
|
||||
await new Promise(resolve => frame.onload = resolve);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// This function defines the basic form of the test cases. We create an
|
||||
// iframe, execute the target callback to manipulate the DOM, remove the frame
|
||||
// from the DOM, and then check to see if the frame was GC'd. The caller
|
||||
// may optionally pass in a callback that will be executed with the
|
||||
// frame as an argument before removing it from the DOM.
|
||||
async function _eventListenerLeakStep(target, name, extra) {
|
||||
let frame = await _withFrame(document, "empty.html");
|
||||
|
||||
await target(frame.contentWindow);
|
||||
|
||||
let weakRef = SpecialPowers.Cu.getWeakReference(frame.contentWindow);
|
||||
ok(weakRef.get(), `should be able to create a weak reference - ${name}`);
|
||||
|
||||
if (extra) {
|
||||
await extra(frame);
|
||||
}
|
||||
|
||||
frame.remove();
|
||||
frame = null;
|
||||
|
||||
// Perform two GC'd to avoid intermittent delayed collection.
|
||||
await new Promise(resolve => SpecialPowers.exactGC(resolve));
|
||||
await new Promise(resolve => SpecialPowers.exactGC(resolve));
|
||||
|
||||
ok(!weakRef.get(), `iframe content window should be garbage collected - ${name}`);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ support-files =
|
||||
bug418986-3.js
|
||||
error_event_worker.js
|
||||
empty.js
|
||||
event_leak_utils.js
|
||||
window_bug493251.html
|
||||
window_bug659071.html
|
||||
window_wheel_default_action.html
|
||||
|
@ -233,6 +233,7 @@ support-files =
|
||||
sw_storage_not_allow.js
|
||||
update_worker.sjs
|
||||
self_update_worker.sjs
|
||||
!/dom/events/test/event_leak_utils.js
|
||||
|
||||
[test_bug1151916.html]
|
||||
[test_bug1240436.html]
|
||||
|
@ -8,26 +8,16 @@
|
||||
<title>Bug 1447871 - Test some service worker leak conditions</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="text/javascript" src="utils.js"></script>
|
||||
<script type="text/javascript" src="/tests/dom/events/test/event_leak_utils.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
const scope = new URL("empty.html?leak_tests", location).href;
|
||||
const script = new URL("empty.js", location).href;
|
||||
|
||||
// Utility function to create a loaded iframe.
|
||||
async function withFrame(doc, url) {
|
||||
let frame = doc.createElement('iframe');
|
||||
frame.src = url;
|
||||
doc.body.appendChild(frame);
|
||||
await new Promise(resolve => frame.onload = resolve);
|
||||
return frame;
|
||||
}
|
||||
|
||||
// Manipulate service worker DOM objects in the frame's context.
|
||||
// Its important here that we create a listener callback from
|
||||
// the DOM objects back to the frame's global in order to
|
||||
@ -45,31 +35,6 @@ async function useServiceWorker(contentWindow) {
|
||||
};
|
||||
}
|
||||
|
||||
// This function defines the basic form of the test cases. We create an
|
||||
// iframe, manipulate some service worker DOM objects, remove the frame
|
||||
// from the DOM and then check to see if the frame was GC'd. The caller
|
||||
// may optionally pass in a callback that will be executed with the
|
||||
// frame as an argument before removing it from the DOM.
|
||||
async function leakTest(name, callback) {
|
||||
let frame = await withFrame(document, "empty.html");
|
||||
|
||||
await useServiceWorker(frame.contentWindow);
|
||||
|
||||
let weakRef = SpecialPowers.Cu.getWeakReference(frame.contentWindow);
|
||||
ok(weakRef.get(), `should be able to create a weak reference - ${name}`);
|
||||
|
||||
if (callback) {
|
||||
await callback(frame);
|
||||
}
|
||||
|
||||
frame.remove();
|
||||
frame = null;
|
||||
|
||||
await new Promise(resolve => SpecialPowers.exactGC(resolve));
|
||||
await new Promise(resolve => SpecialPowers.exactGC(resolve));
|
||||
ok(!weakRef.get(), `iframe content window should be garbage collected - ${name}`);
|
||||
}
|
||||
|
||||
async function runTest() {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
@ -81,25 +46,7 @@ async function runTest() {
|
||||
await waitForState(reg.installing, "activated");
|
||||
|
||||
try {
|
||||
// Test if we leak in the case where we do nothing special to
|
||||
// the frame before removing it from the DOM.
|
||||
await leakTest("default");
|
||||
|
||||
// Test the case where we navigate the frame before removing it
|
||||
// from the DOM so that the service worker using window ends up
|
||||
// in bfcache.
|
||||
await leakTest("bfcache", frame => {
|
||||
frame.src = "about:blank";
|
||||
return new Promise(resolve => frame.onload = resolve);
|
||||
});
|
||||
|
||||
// Test the case where we document.open() the frame before removing
|
||||
// it from the DOM so that the service worker using window ends
|
||||
// up getting replaced.
|
||||
await leakTest("document.open()", frame => {
|
||||
frame.contentDocument.open();
|
||||
frame.contentDocument.close();
|
||||
});
|
||||
await checkForEventListenerLeaks("ServiceWorker", useServiceWorker);
|
||||
} catch (e) {
|
||||
ok(false, e);
|
||||
} finally {
|
||||
|
Loading…
Reference in New Issue
Block a user