зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1286798 - Part 32: Add a test for snapshotting verification in multi-e10s setup; r=asuth
This commit is contained in:
Родитель
d87888fe25
Коммит
7941181395
|
@ -4,6 +4,7 @@ support-files =
|
|||
browser_frame_elements.html
|
||||
page_privatestorageevent.html
|
||||
page_localstorage_e10s.html
|
||||
page_localstorage_snapshotting_e10s.html
|
||||
position.html
|
||||
test-console-api.html
|
||||
test_bug1004814.html
|
||||
|
@ -16,6 +17,7 @@ support-files =
|
|||
test_largeAllocation2.html^headers^
|
||||
test_largeAllocationFormSubmit.sjs
|
||||
helper_largeAllocation.js
|
||||
helper_localStorage_e10s.js
|
||||
!/dom/tests/mochitest/geolocation/network_geolocation.sjs
|
||||
|
||||
[browser_allocateGigabyte.js]
|
||||
|
@ -56,6 +58,8 @@ skip-if = !e10s || (os == "win" && processor == "x86") || (verify && debug && (o
|
|||
[browser_localStorage_e10s.js]
|
||||
skip-if = !e10s || verify # This is a test of e10s functionality.
|
||||
[browser_localStorage_privatestorageevent.js]
|
||||
[browser_localStorage_snapshotting_e10s.js]
|
||||
skip-if = !e10s # This is a test of e10s functionality.
|
||||
[browser_persist_cookies.js]
|
||||
support-files =
|
||||
set-samesite-cookies-and-redirect.sjs
|
||||
|
|
|
@ -2,74 +2,9 @@ const HELPER_PAGE_URL =
|
|||
"http://example.com/browser/dom/tests/browser/page_localstorage_e10s.html";
|
||||
const HELPER_PAGE_ORIGIN = "http://example.com/";
|
||||
|
||||
// Simple tab wrapper abstracting our messaging mechanism;
|
||||
class KnownTab {
|
||||
constructor(name, tab) {
|
||||
this.name = name;
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.tab = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple data structure class to help us track opened tabs and their pids.
|
||||
class KnownTabs {
|
||||
constructor() {
|
||||
this.byPid = new Map();
|
||||
this.byName = new Map();
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.byPid = null;
|
||||
this.byName = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open our helper page in a tab in its own content process, asserting that it
|
||||
* really is in its own process. We initially load and wait for about:blank to
|
||||
* load, and only then loadURI to our actual page. This is to ensure that
|
||||
* LocalStorageManager has had an opportunity to be created and populate
|
||||
* mOriginsHavingData.
|
||||
*
|
||||
* (nsGlobalWindow will reliably create LocalStorageManager as a side-effect of
|
||||
* the unconditional call to nsGlobalWindow::PreloadLocalStorage. This will
|
||||
* reliably create the StorageDBChild instance, and its corresponding
|
||||
* StorageDBParent will send the set of origins when it is constructed.)
|
||||
*/
|
||||
async function openTestTabInOwnProcess(name, knownTabs) {
|
||||
let realUrl = HELPER_PAGE_URL + '?' + encodeURIComponent(name);
|
||||
// Load and wait for about:blank.
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser, opening: 'about:blank', forceNewProcess: true
|
||||
});
|
||||
let pid = tab.linkedBrowser.frameLoader.tabParent.osPid;
|
||||
ok(!knownTabs.byName.has(name), "tab needs its own name: " + name);
|
||||
ok(!knownTabs.byPid.has(pid), "tab needs to be in its own process: " + pid);
|
||||
|
||||
let knownTab = new KnownTab(name, tab);
|
||||
knownTabs.byPid.set(pid, knownTab);
|
||||
knownTabs.byName.set(name, knownTab);
|
||||
|
||||
// Now trigger the actual load of our page.
|
||||
BrowserTestUtils.loadURI(tab.linkedBrowser, realUrl);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
is(tab.linkedBrowser.frameLoader.tabParent.osPid, pid, "still same pid");
|
||||
return knownTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all the tabs we opened.
|
||||
*/
|
||||
async function cleanupTabs(knownTabs) {
|
||||
for (let knownTab of knownTabs.byName.values()) {
|
||||
BrowserTestUtils.removeTab(knownTab.tab);
|
||||
knownTab.cleanup();
|
||||
}
|
||||
knownTabs.cleanup();
|
||||
}
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper_localStorage_e10s.js",
|
||||
this);
|
||||
|
||||
/**
|
||||
* Wait for a LocalStorage flush to occur. This notification can occur as a
|
||||
|
@ -340,10 +275,13 @@ add_task(async function() {
|
|||
|
||||
// - Open tabs. Don't configure any of them yet.
|
||||
const knownTabs = new KnownTabs();
|
||||
const writerTab = await openTestTabInOwnProcess("writer", knownTabs);
|
||||
const listenerTab = await openTestTabInOwnProcess("listener", knownTabs);
|
||||
const readerTab = await openTestTabInOwnProcess("reader", knownTabs);
|
||||
const lateWriteThenListenTab = await openTestTabInOwnProcess(
|
||||
const writerTab = await openTestTabInOwnProcess(HELPER_PAGE_URL, "writer",
|
||||
knownTabs);
|
||||
const listenerTab = await openTestTabInOwnProcess(HELPER_PAGE_URL, "listener",
|
||||
knownTabs);
|
||||
const readerTab = await openTestTabInOwnProcess(HELPER_PAGE_URL, "reader",
|
||||
knownTabs);
|
||||
const lateWriteThenListenTab = await openTestTabInOwnProcess(HELPER_PAGE_URL,
|
||||
"lateWriteThenListen", knownTabs);
|
||||
|
||||
// Sanity check that preloading did not occur in the tabs.
|
||||
|
@ -484,8 +422,8 @@ add_task(async function() {
|
|||
|
||||
// - Open a fresh tab and make sure it sees the precache/preload
|
||||
info("late open preload check");
|
||||
const lateOpenSeesPreload =
|
||||
await openTestTabInOwnProcess("lateOpenSeesPreload", knownTabs);
|
||||
const lateOpenSeesPreload = await openTestTabInOwnProcess(HELPER_PAGE_URL,
|
||||
"lateOpenSeesPreload", knownTabs);
|
||||
await verifyTabPreload(lateOpenSeesPreload, true);
|
||||
|
||||
// - Clean up.
|
||||
|
|
|
@ -0,0 +1,371 @@
|
|||
const HELPER_PAGE_URL =
|
||||
"http://example.com/browser/dom/tests/browser/page_localstorage_snapshotting_e10s.html";
|
||||
const HELPER_PAGE_ORIGIN = "http://example.com/";
|
||||
|
||||
let testDir = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
|
||||
Services.scriptloader.loadSubScript(testDir + "/helper_localStorage_e10s.js",
|
||||
this);
|
||||
|
||||
function clearOrigin() {
|
||||
let principal =
|
||||
Services.scriptSecurityManager.createCodebasePrincipalFromOrigin(
|
||||
HELPER_PAGE_ORIGIN);
|
||||
let request =
|
||||
Services.qms.clearStoragesForPrincipal(principal, "default", "ls");
|
||||
let promise = new Promise(resolve => {
|
||||
request.callback = () => {
|
||||
resolve();
|
||||
};
|
||||
});
|
||||
return promise;
|
||||
}
|
||||
|
||||
async function applyMutations(knownTab, mutations) {
|
||||
await ContentTask.spawn(
|
||||
knownTab.tab.linkedBrowser,
|
||||
mutations,
|
||||
function(mutations) {
|
||||
return content.wrappedJSObject.applyMutations(Cu.cloneInto(mutations,
|
||||
content));
|
||||
});
|
||||
}
|
||||
|
||||
async function verifyState(knownTab, expectedState) {
|
||||
let actualState = await ContentTask.spawn(
|
||||
knownTab.tab.linkedBrowser,
|
||||
{},
|
||||
function() {
|
||||
return content.wrappedJSObject.getState();
|
||||
});
|
||||
|
||||
for (let [expectedKey, expectedValue] of Object.entries(expectedState)) {
|
||||
ok(actualState.hasOwnProperty(expectedKey), "key present: " + expectedKey);
|
||||
is(actualState[expectedKey], expectedValue, "value correct");
|
||||
}
|
||||
for (let actualKey of Object.keys(actualState)) {
|
||||
if (!expectedState.hasOwnProperty(actualKey)) {
|
||||
ok(false, "actual state has key it shouldn't have: " + actualKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function getKeys(knownTab) {
|
||||
let keys = await ContentTask.spawn(
|
||||
knownTab.tab.linkedBrowser,
|
||||
null,
|
||||
function() {
|
||||
return content.wrappedJSObject.getKeys();
|
||||
});
|
||||
return keys;
|
||||
}
|
||||
|
||||
async function beginExplicitSnapshot(knownTab) {
|
||||
await ContentTask.spawn(
|
||||
knownTab.tab.linkedBrowser,
|
||||
null,
|
||||
function() {
|
||||
return content.wrappedJSObject.beginExplicitSnapshot();
|
||||
});
|
||||
}
|
||||
|
||||
async function endExplicitSnapshot(knownTab) {
|
||||
await ContentTask.spawn(
|
||||
knownTab.tab.linkedBrowser,
|
||||
null,
|
||||
function() {
|
||||
return content.wrappedJSObject.endExplicitSnapshot();
|
||||
});
|
||||
}
|
||||
|
||||
// We spin up a ton of child processes.
|
||||
requestLongerTimeout(4);
|
||||
|
||||
/**
|
||||
* Verify snapshotting of our localStorage implementation in multi-e10s setup.
|
||||
*/
|
||||
add_task(async function() {
|
||||
if (!Services.lsm.nextGenLocalStorageEnabled) {
|
||||
ok(true, "Test ignored when the next gen local storage is not enabled.");
|
||||
return;
|
||||
}
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
// Enable LocalStorage's testing API so we can explicitly create
|
||||
// snapshots when needed.
|
||||
["dom.storage.testing", true],
|
||||
]
|
||||
});
|
||||
|
||||
// Ensure that there is no localstorage data by forcing the origin to be
|
||||
// cleared prior to the start of our test..
|
||||
await clearOrigin();
|
||||
|
||||
// - Open tabs. Don't configure any of them yet.
|
||||
const knownTabs = new KnownTabs();
|
||||
const writerTab1 = await openTestTabInOwnProcess(HELPER_PAGE_URL, "writer1",
|
||||
knownTabs);
|
||||
const writerTab2 = await openTestTabInOwnProcess(HELPER_PAGE_URL, "writer2",
|
||||
knownTabs);
|
||||
const readerTab1 = await openTestTabInOwnProcess(HELPER_PAGE_URL, "reader1",
|
||||
knownTabs);
|
||||
const readerTab2 = await openTestTabInOwnProcess(HELPER_PAGE_URL, "reader2",
|
||||
knownTabs);
|
||||
|
||||
const initialMutations = [
|
||||
[null, null],
|
||||
["key1", "initial1"],
|
||||
["key2", "initial2"],
|
||||
["key3", "initial3"],
|
||||
["key5", "initial5"],
|
||||
["key6", "initial6"],
|
||||
["key7", "initial7"],
|
||||
["key8", "initial8"]
|
||||
];
|
||||
|
||||
const initialState = {
|
||||
key1: "initial1",
|
||||
key2: "initial2",
|
||||
key3: "initial3",
|
||||
key5: "initial5",
|
||||
key6: "initial6",
|
||||
key7: "initial7",
|
||||
key8: "initial8"
|
||||
};
|
||||
|
||||
function getPartialPrefill()
|
||||
{
|
||||
let size = 0;
|
||||
let entries = Object.entries(initialState);
|
||||
for (let i = 0; i < entries.length / 2; i++) {
|
||||
let entry = entries[i];
|
||||
size += entry[0].length + entry[1].length;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
const prefillValues = [
|
||||
0, // no prefill
|
||||
getPartialPrefill(), // partial prefill
|
||||
-1 // full prefill
|
||||
];
|
||||
|
||||
for (let prefillValue of prefillValues) {
|
||||
info("Setting prefill value");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["dom.storage.snapshot_prefill", prefillValue]
|
||||
]
|
||||
});
|
||||
|
||||
info("Stage 1");
|
||||
|
||||
const setRemoveMutations1 = [
|
||||
["key0", "setRemove10"],
|
||||
["key1", "setRemove11"],
|
||||
["key2", null],
|
||||
["key3", "setRemove13"],
|
||||
["key4", "setRemove14"],
|
||||
["key5", "setRemove15"],
|
||||
["key6", "setRemove16"],
|
||||
["key7", "setRemove17"],
|
||||
["key8", null],
|
||||
["key9", "setRemove19"]
|
||||
];
|
||||
|
||||
const setRemoveState1 = {
|
||||
key0: "setRemove10",
|
||||
key1: "setRemove11",
|
||||
key3: "setRemove13",
|
||||
key4: "setRemove14",
|
||||
key5: "setRemove15",
|
||||
key6: "setRemove16",
|
||||
key7: "setRemove17",
|
||||
key9: "setRemove19"
|
||||
};
|
||||
|
||||
const setRemoveMutations2 = [
|
||||
["key0", "setRemove20"],
|
||||
["key1", null],
|
||||
["key2", "setRemove22"],
|
||||
["key3", "setRemove23"],
|
||||
["key4", "setRemove24"],
|
||||
["key5", "setRemove25"],
|
||||
["key6", "setRemove26"],
|
||||
["key7", null],
|
||||
["key8", "setRemove28"],
|
||||
["key9", "setRemove29"]
|
||||
];
|
||||
|
||||
const setRemoveState2 = {
|
||||
key0: "setRemove20",
|
||||
key2: "setRemove22",
|
||||
key3: "setRemove23",
|
||||
key4: "setRemove24",
|
||||
key5: "setRemove25",
|
||||
key6: "setRemove26",
|
||||
key8: "setRemove28",
|
||||
key9: "setRemove29"
|
||||
};
|
||||
|
||||
// Apply initial mutations using an explicit snapshot. The explicit
|
||||
// snapshot here ensures that the parent process have received the changes.
|
||||
await beginExplicitSnapshot(writerTab1);
|
||||
await applyMutations(writerTab1, initialMutations);
|
||||
await endExplicitSnapshot(writerTab1);
|
||||
|
||||
// Begin explicit snapshots in all tabs except readerTab2. All these tabs
|
||||
// should see the initial state regardless what other tabs are doing.
|
||||
await beginExplicitSnapshot(writerTab1);
|
||||
await beginExplicitSnapshot(writerTab2);
|
||||
await beginExplicitSnapshot(readerTab1);
|
||||
|
||||
// Apply first array of set/remove mutations in writerTab1 and end the
|
||||
// explicit snapshot. This will trigger saving of values in other active
|
||||
// snapshots.
|
||||
await applyMutations(writerTab1, setRemoveMutations1);
|
||||
await endExplicitSnapshot(writerTab1);
|
||||
|
||||
// Begin an explicit snapshot in readerTab2. writerTab1 already ended its
|
||||
// explicit snapshot, so readerTab2 should see mutations done by
|
||||
// writerTab1.
|
||||
await beginExplicitSnapshot(readerTab2);
|
||||
|
||||
// Apply second array of set/remove mutations in writerTab2 and end the
|
||||
// explicit snapshot. This will trigger saving of values in other active
|
||||
// snapshots, but only if they haven't been saved already.
|
||||
await applyMutations(writerTab2, setRemoveMutations2);
|
||||
await endExplicitSnapshot(writerTab2);
|
||||
|
||||
// Verify state in readerTab1, it should match the initial state.
|
||||
await verifyState(readerTab1, initialState);
|
||||
await endExplicitSnapshot(readerTab1);
|
||||
|
||||
// Verify state in readerTab2, it should match the state after the first
|
||||
// array of set/remove mutatations have been applied and "commited".
|
||||
await verifyState(readerTab2, setRemoveState1);
|
||||
await endExplicitSnapshot(readerTab2);
|
||||
|
||||
// Verify final state, it should match the state after the second array of
|
||||
// set/remove mutation have been applied and "commited". An explicit
|
||||
// snapshot is used.
|
||||
await beginExplicitSnapshot(readerTab1);
|
||||
await verifyState(readerTab1, setRemoveState2);
|
||||
await endExplicitSnapshot(readerTab1);
|
||||
|
||||
info("Stage 2");
|
||||
|
||||
const setRemoveClearMutations1 = [
|
||||
["key0", "setRemoveClear10"],
|
||||
["key1", null],
|
||||
[null, null]
|
||||
];
|
||||
|
||||
const setRemoveClearState1 = {
|
||||
};
|
||||
|
||||
const setRemoveClearMutations2 = [
|
||||
["key8", null],
|
||||
["key9", "setRemoveClear29"],
|
||||
[null, null]
|
||||
];
|
||||
|
||||
const setRemoveClearState2 = {
|
||||
};
|
||||
|
||||
// This is very similar to previous stage except that in addition to
|
||||
// set/remove, the clear operation is involved too.
|
||||
await beginExplicitSnapshot(writerTab1);
|
||||
await applyMutations(writerTab1, initialMutations);
|
||||
await endExplicitSnapshot(writerTab1);
|
||||
|
||||
await beginExplicitSnapshot(writerTab1);
|
||||
await beginExplicitSnapshot(writerTab2);
|
||||
await beginExplicitSnapshot(readerTab1);
|
||||
|
||||
await applyMutations(writerTab1, setRemoveClearMutations1);
|
||||
await endExplicitSnapshot(writerTab1);
|
||||
|
||||
await beginExplicitSnapshot(readerTab2);
|
||||
|
||||
await applyMutations(writerTab2, setRemoveClearMutations2);
|
||||
await endExplicitSnapshot(writerTab2);
|
||||
|
||||
await verifyState(readerTab1, initialState);
|
||||
await endExplicitSnapshot(readerTab1);
|
||||
|
||||
await verifyState(readerTab2, setRemoveClearState1);
|
||||
await endExplicitSnapshot(readerTab2);
|
||||
|
||||
await beginExplicitSnapshot(readerTab1);
|
||||
await verifyState(readerTab1, setRemoveClearState2);
|
||||
await endExplicitSnapshot(readerTab1);
|
||||
|
||||
info("Stage 3");
|
||||
|
||||
const changeOrderMutations = [
|
||||
["key1", null],
|
||||
["key2", null],
|
||||
["key3", null],
|
||||
["key5", null],
|
||||
["key6", null],
|
||||
["key7", null],
|
||||
["key8", null],
|
||||
["key8", "initial8"],
|
||||
["key7", "initial7"],
|
||||
["key6", "initial6"],
|
||||
["key5", "initial5"],
|
||||
["key3", "initial3"],
|
||||
["key2", "initial2"],
|
||||
["key1", "initial1"]
|
||||
];
|
||||
|
||||
// Apply initial mutations using an explicit snapshot. The explicit
|
||||
// snapshot here ensures that the parent process have received the changes.
|
||||
await beginExplicitSnapshot(writerTab1);
|
||||
await applyMutations(writerTab1, initialMutations);
|
||||
await endExplicitSnapshot(writerTab1);
|
||||
|
||||
// Begin explicit snapshots in all tabs except writerTab2 which is not used
|
||||
// in this stage. All these tabs should see the initial order regardless
|
||||
// what other tabs are doing.
|
||||
await beginExplicitSnapshot(readerTab1);
|
||||
await beginExplicitSnapshot(writerTab1);
|
||||
await beginExplicitSnapshot(readerTab2);
|
||||
|
||||
// Get all keys in readerTab1 and end the explicit snapshot. No mutations
|
||||
// have been applied yet.
|
||||
let tab1Keys = await getKeys(readerTab1);
|
||||
await endExplicitSnapshot(readerTab1);
|
||||
|
||||
// Apply mutations that change the order of keys and end the explicit
|
||||
// snapshot. The state is unchanged. This will trigger saving of key order
|
||||
// in other active snapshots, but only if the order hasn't been saved
|
||||
// already.
|
||||
await applyMutations(writerTab1, changeOrderMutations);
|
||||
await endExplicitSnapshot(writerTab1);
|
||||
|
||||
// Get all keys in readerTab2 and end the explicit snapshot. Change order
|
||||
// mutations have been applied, but the order should stay unchanged.
|
||||
let tab2Keys = await getKeys(readerTab2);
|
||||
await endExplicitSnapshot(readerTab2);
|
||||
|
||||
// Verify the key order is the same.
|
||||
is(tab2Keys.length, tab1Keys.length, "Correct keys length");
|
||||
for (let i = 0; i < tab2Keys.length; i++) {
|
||||
is(tab2Keys[i], tab1Keys[i], "Correct key");
|
||||
}
|
||||
|
||||
// Verify final state, it should match the initial state since applied
|
||||
// mutations only changed the key order. An explicit snapshot is used.
|
||||
await beginExplicitSnapshot(readerTab1);
|
||||
await verifyState(readerTab1, initialState);
|
||||
await endExplicitSnapshot(readerTab1);
|
||||
}
|
||||
|
||||
// - Clean up.
|
||||
await cleanupTabs(knownTabs);
|
||||
|
||||
clearOrigin();
|
||||
});
|
|
@ -0,0 +1,72 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// Simple tab wrapper abstracting our messaging mechanism;
|
||||
class KnownTab {
|
||||
constructor(name, tab) {
|
||||
this.name = name;
|
||||
this.tab = tab;
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.tab = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Simple data structure class to help us track opened tabs and their pids.
|
||||
class KnownTabs {
|
||||
constructor() {
|
||||
this.byPid = new Map();
|
||||
this.byName = new Map();
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.byPid = null;
|
||||
this.byName = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open our helper page in a tab in its own content process, asserting that it
|
||||
* really is in its own process. We initially load and wait for about:blank to
|
||||
* load, and only then loadURI to our actual page. This is to ensure that
|
||||
* LocalStorageManager has had an opportunity to be created and populate
|
||||
* mOriginsHavingData.
|
||||
*
|
||||
* (nsGlobalWindow will reliably create LocalStorageManager as a side-effect of
|
||||
* the unconditional call to nsGlobalWindow::PreloadLocalStorage. This will
|
||||
* reliably create the StorageDBChild instance, and its corresponding
|
||||
* StorageDBParent will send the set of origins when it is constructed.)
|
||||
*/
|
||||
async function openTestTabInOwnProcess(helperPageUrl, name, knownTabs) {
|
||||
let realUrl = helperPageUrl + '?' + encodeURIComponent(name);
|
||||
// Load and wait for about:blank.
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab({
|
||||
gBrowser, opening: 'about:blank', forceNewProcess: true
|
||||
});
|
||||
let pid = tab.linkedBrowser.frameLoader.tabParent.osPid;
|
||||
ok(!knownTabs.byName.has(name), "tab needs its own name: " + name);
|
||||
ok(!knownTabs.byPid.has(pid), "tab needs to be in its own process: " + pid);
|
||||
|
||||
let knownTab = new KnownTab(name, tab);
|
||||
knownTabs.byPid.set(pid, knownTab);
|
||||
knownTabs.byName.set(name, knownTab);
|
||||
|
||||
// Now trigger the actual load of our page.
|
||||
BrowserTestUtils.loadURI(tab.linkedBrowser, realUrl);
|
||||
await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
|
||||
is(tab.linkedBrowser.frameLoader.tabParent.osPid, pid, "still same pid");
|
||||
return knownTab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close all the tabs we opened.
|
||||
*/
|
||||
async function cleanupTabs(knownTabs) {
|
||||
for (let knownTab of knownTabs.byName.values()) {
|
||||
BrowserTestUtils.removeTab(knownTab.tab);
|
||||
knownTab.cleanup();
|
||||
}
|
||||
knownTabs.cleanup();
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script>
|
||||
/**
|
||||
* Helper page used by browser_localStorage_snapshotting.js.
|
||||
*
|
||||
* We expose methods to be invoked by ContentTask.spawn() calls.
|
||||
*
|
||||
**/
|
||||
var pageName = document.location.search.substring(1);
|
||||
window.addEventListener(
|
||||
"load",
|
||||
() => { document.getElementById("pageNameH").textContent = pageName; });
|
||||
|
||||
function applyMutations(mutations) {
|
||||
mutations.forEach(function([key, value]) {
|
||||
if (key !== null) {
|
||||
if (value === null) {
|
||||
localStorage.removeItem(key);
|
||||
} else {
|
||||
localStorage.setItem(key, value);
|
||||
}
|
||||
} else {
|
||||
localStorage.clear();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getState() {
|
||||
let state = {};
|
||||
let length = localStorage.length;
|
||||
for (let index = 0; index < length; index++) {
|
||||
let key = localStorage.key(index);
|
||||
state[key] = localStorage.getItem(key);
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
function getKeys() {
|
||||
return Object.keys(localStorage);
|
||||
}
|
||||
|
||||
function beginExplicitSnapshot() {
|
||||
localStorage.beginExplicitSnapshot();
|
||||
}
|
||||
|
||||
function endExplicitSnapshot() {
|
||||
localStorage.endExplicitSnapshot();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body><h2 id="pageNameH"></h2></body>
|
||||
</html>
|
Загрузка…
Ссылка в новой задаче