Bug 1249447 - Prevent using CPOW and wait for indexedDB setup/clear with tasks. r=mratcliffe, a=test-only

This commit is contained in:
Alexandre Poirot 2016-03-18 02:44:22 -07:00
parent 27172ac8df
commit d73b3cdfd6
9 changed files with 320 additions and 283 deletions

View File

@ -13,10 +13,6 @@ document.cookie = "sc1=foobar;";
localStorage.setItem("iframe-s-ls1", "foobar");
sessionStorage.setItem("iframe-s-ss1", "foobar-2");
function success(event) {
setupIDB.next(event);
}
let idbGenerator = function*() {
let request = indexedDB.open("idb-s1", 1);
request.onerror = function() {

View File

@ -20,6 +20,7 @@ support-files =
timeline-iframe-child.html
timeline-iframe-parent.html
director-script-target.html
storage-helpers.js
[browser_animation_emitMutations.js]
[browser_animation_getFrames.js]

View File

@ -5,7 +5,7 @@
"use strict";
const {StorageFront} = require("devtools/server/actors/storage");
var gFront, gWindow;
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/server/tests/browser/storage-helpers.js", this);
const beforeReload = {
cookies: {
@ -30,51 +30,14 @@ const beforeReload = {
}
};
function finishTests(client) {
// Cleanup so that indexed db created from this test do not interfere next
// ones.
/**
* This method iterates over iframes in a window and clears the indexed db
* created by this test.
*/
let clearIDB = (w, i, c) => {
if (w[i] && w[i].clear) {
w[i].clearIterator = w[i].clear(() => clearIDB(w, i + 1, c));
w[i].clearIterator.next();
} else if (w[i] && w[i + 1]) {
clearIDB(w, i + 1, c);
} else {
c();
}
};
let closeConnection = () => {
// Forcing GC/CC to get rid of docshells and windows created by this test.
forceCollections();
client.close(() => {
forceCollections();
DebuggerServer.destroy();
forceCollections();
gFront = gWindow = null;
finish();
});
};
gWindow.clearIterator = gWindow.clear(() => {
clearIDB(gWindow, 0, closeConnection);
});
gWindow.clearIterator.next();
}
function testStores(data, client) {
function* testStores(data, front) {
testWindowsBeforeReload(data);
// FIXME: Bug 1183581 - browser_storage_dynamic_windows.js IsSafeToRunScript
// errors when testing reload in E10S mode
// testReload().then(() =>
testAddIframe().then(() =>
testRemoveIframe()).then(() =>
finishTests(client));
// yield testReload(front);
yield testAddIframe(front);
yield testRemoveIframe(front);
}
function testWindowsBeforeReload(data) {
@ -124,7 +87,7 @@ function markOutMatched(toBeEmptied, data, deleted) {
}
}
// function testReload() {
// function testReload(front) {
// info("Testing if reload works properly");
// let shouldBeEmptyFirst = Cu.cloneInto(beforeReload, {});
@ -158,17 +121,17 @@ function markOutMatched(toBeEmptied, data, deleted) {
// };
// let endTestReloaded = () => {
// gFront.off("stores-update", onStoresUpdate);
// front.off("stores-update", onStoresUpdate);
// resolve();
// };
// gFront.on("stores-update", onStoresUpdate);
// front.on("stores-update", onStoresUpdate);
// content.location.reload();
// });
// }
function testAddIframe() {
function testAddIframe(front) {
info("Testing if new iframe addition works properly");
return new Promise(resolve => {
let shouldBeEmpty = {
@ -226,11 +189,11 @@ function testAddIframe() {
};
let endTestReloaded = () => {
gFront.off("stores-update", onStoresUpdate);
front.off("stores-update", onStoresUpdate);
resolve();
};
gFront.on("stores-update", onStoresUpdate);
front.on("stores-update", onStoresUpdate);
let iframe = content.document.createElement("iframe");
iframe.src = ALT_DOMAIN_SECURED + "storage-secured-iframe.html";
@ -238,7 +201,7 @@ function testAddIframe() {
});
}
function testRemoveIframe() {
function testRemoveIframe(front) {
info("Testing if iframe removal works properly");
return new Promise(resolve => {
let shouldBeEmpty = {
@ -286,11 +249,11 @@ function testRemoveIframe() {
};
let endTestReloaded = () => {
gFront.off("stores-update", onStoresUpdate);
front.off("stores-update", onStoresUpdate);
resolve();
};
gFront.on("stores-update", onStoresUpdate);
front.on("stores-update", onStoresUpdate);
for (let iframe of content.document.querySelectorAll("iframe")) {
if (iframe.src.startsWith("http:")) {
@ -301,38 +264,22 @@ function testRemoveIframe() {
});
}
function test() {
addTab(MAIN_DOMAIN + "storage-dynamic-windows.html").then(function(browser) {
let doc = browser.contentDocument;
initDebuggerServer();
add_task(function*() {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-dynamic-windows.html");
let createConnection = () => {
let client = new DebuggerClient(DebuggerServer.connectPipe());
connectDebuggerClient(client).then(form => {
gFront = StorageFront(client, form);
gFront.listStores().then(data => testStores(data, client));
});
};
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let front = StorageFront(client, form);
let data = yield front.listStores();
yield testStores(data, front);
/**
* This method iterates over iframes in a window and setups the indexed db
* required for this test.
*/
let setupIDBInFrames = (w, i, c) => {
if (w[i] && w[i].idbGenerator) {
w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c));
w[i].setupIDB.next();
} else if (w[i] && w[i + 1]) {
setupIDBInFrames(w, i + 1, c);
} else {
c();
}
};
// Setup the indexed db in main window.
gWindow = doc.defaultView.wrappedJSObject;
gWindow.setupIDB = gWindow.idbGenerator(() => {
setupIDBInFrames(gWindow, 0, createConnection);
});
gWindow.setupIDB.next();
});
}
yield clearStorage();
// Forcing GC/CC to get rid of docshells and windows created by this test.
forceCollections();
yield client.close();
forceCollections();
DebuggerServer.destroy();
forceCollections();
});

View File

@ -5,7 +5,7 @@
"use strict";
const {StorageFront} = require("devtools/server/actors/storage");
var gWindow = null;
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/server/tests/browser/storage-helpers.js", this);
const storeMap = {
cookies: {
@ -319,53 +319,21 @@ const IDBValues = {
}
function finishTests(client) {
// Cleanup so that indexed db created from this test do not interfere next ones
/**
* This method iterates over iframes in a window and clears the indexed db
* created by this test.
*/
let clearIDB = (w, i, c) => {
if (w[i] && w[i].clear) {
w[i].clearIterator = w[i].clear(() => clearIDB(w, i + 1, c));
w[i].clearIterator.next();
}
else if (w[i] && w[i + 1]) {
clearIDB(w, i + 1, c);
}
else {
c();
}
};
let closeConnection = () => {
// Forcing GC/CC to get rid of docshells and windows created by this test.
forceCollections();
client.close(() => {
forceCollections();
DebuggerServer.destroy();
forceCollections();
gWindow = null;
finish();
});
}
gWindow.clearIterator = gWindow.clear(() => {
clearIDB(gWindow, 0, closeConnection);
});
gWindow.clearIterator.next();
}
function testStores(data) {
return Task.spawn(function*() {
ok(data.cookies, "Cookies storage actor is present");
ok(data.localStorage, "Local Storage storage actor is present");
ok(data.sessionStorage, "Session Storage storage actor is present");
ok(data.indexedDB, "Indexed DB storage actor is present");
yield testCookies(data.cookies);
yield testLocalStorage(data.localStorage);
yield testSessionStorage(data.sessionStorage);
yield testIndexedDB(data.indexedDB);
});
function* testStores(data) {
ok(data.cookies, "Cookies storage actor is present");
ok(data.localStorage, "Local Storage storage actor is present");
ok(data.sessionStorage, "Session Storage storage actor is present");
ok(data.indexedDB, "Indexed DB storage actor is present");
yield testCookies(data.cookies);
yield testLocalStorage(data.localStorage);
yield testSessionStorage(data.sessionStorage);
yield testIndexedDB(data.indexedDB);
}
function testCookies(cookiesActor) {
@ -635,41 +603,22 @@ var testIDBEntries = Task.async(function*(index, hosts, indexedDBActor) {
yield testObjectStores(++index, hosts, indexedDBActor);
});
function test() {
addTab(MAIN_DOMAIN + "storage-listings.html").then(function(browser) {
let doc = browser.contentDocument;
initDebuggerServer();
add_task(function*() {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html");
let createConnection = () => {
let client = new DebuggerClient(DebuggerServer.connectPipe());
connectDebuggerClient(client).then(form => {
let front = StorageFront(client, form);
front.listStores().then(data => testStores(data))
.then(() => finishTests(client));
});
};
initDebuggerServer();
let client = new DebuggerClient(DebuggerServer.connectPipe());
let form = yield connectDebuggerClient(client);
let front = StorageFront(client, form);
let data = yield front.listStores();
yield testStores(data);
/**
* This method iterates over iframes in a window and setups the indexed db
* required for this test.
*/
let setupIDBInFrames = (w, i, c) => {
if (w[i] && w[i].idbGenerator) {
w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c));
w[i].setupIDB.next();
}
else if (w[i] && w[i + 1]) {
setupIDBInFrames(w, i + 1, c);
}
else {
c();
}
};
// Setup the indexed db in main window.
gWindow = doc.defaultView.wrappedJSObject;
gWindow.setupIDB = gWindow.idbGenerator(() => {
setupIDBInFrames(gWindow, 0, createConnection);
});
gWindow.setupIDB.next();
});
}
yield clearStorage();
// Forcing GC/CC to get rid of docshells and windows created by this test.
forceCollections();
yield client.close();
forceCollections();
DebuggerServer.destroy();
forceCollections();
});

View File

@ -26,72 +26,91 @@ localStorage.setItem("ls2", "foobar-2");
// ... and finally some session storage items too
sessionStorage.setItem("ss1", "foobar-3");
function success(event) {
setupIDB.next(event);
}
window.idbGenerator = function*(callback) {
let idbGenerator = function*() {
let request = indexedDB.open("idb1", 1);
request.onupgradeneeded = success;
request.onsuccess = success;
request.onerror = function() {
throw new Error("error opening db connection");
};
let event = yield undefined;
let db = event.target.result;
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
let db = yield new Promise(done => {
request.onupgradeneeded = event => {
let db = event.target.result;
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
store1.transaction.oncomplete = () => {
done(db);
};
};
});
store1.add({id: 1, name: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
yield undefined;
// Prevents AbortError
yield new Promise(done => {
request.onsuccess = done;
});
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
let store1 = transaction.objectStore("obj1");
let store2 = transaction.objectStore("obj2");
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
store2.add({
id2: 1,
name: "foo",
email: "foo@bar.com",
extra: "baz"}).onsuccess = success;
yield undefined;
extra: "baz"
});
// Prevents AbortError during close()
yield new Promise(success => {
transaction.oncomplete = success;
});
yield undefined;
db.close();
request = indexedDB.open("idb2", 1);
request.onupgradeneeded = success;
request.onsuccess = success;
event = yield undefined;
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
yield undefined;
let db2 = yield new Promise(done => {
request.onupgradeneeded = event => {
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = () => {
done(db2);
}
};
});
// Prevents AbortError during close()
yield new Promise(done => {
request.onsuccess = done;
});
db2.close();
console.log("added cookies and stuff from main page");
callback();
};
function successClear(event) {
clearIterator.next(event);
function deleteDB(dbName) {
return new Promise(resolve => {
dump("removing database " + dbName + " from " + document.location + "\n");
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
});
}
window.clear = function*(callback) {
window.setup = function*() {
yield idbGenerator();
};
window.clear = function*() {
document.cookie = "c1=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
document.cookie = "c3=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
document.cookie = "cs2=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
localStorage.clear();
indexedDB.deleteDatabase("idb1").onsuccess = successClear;
yield undefined;
indexedDB.deleteDatabase("idb2").onsuccess = successClear;
yield undefined;
yield deleteDB("idb1");
yield deleteDB("idb2");
dump("removed cookies, localStorage and indexedDB data from " +
document.location + "\n");
callback();
};
</script>
</body>

View File

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* This generator function opens the given url in a new tab, then sets up the
* page by waiting for all cookies, indexedDB items etc. to be created.
*
* @param url {String} The url to be opened in the new tab
*
* @return {Promise} A promise that resolves after storage inspector is ready
*/
function* openTabAndSetupStorage(url) {
let content = yield addTab(url);
// Setup the async storages in main window and for all its iframes
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
/**
* Get all windows including frames recursively.
*
* @param {Window} [baseWindow]
* The base window at which to start looking for child windows
* (optional).
* @return {Set}
* A set of windows.
*/
function getAllWindows(baseWindow) {
let windows = new Set();
let _getAllWindows = function(win) {
windows.add(win.wrappedJSObject);
for (let i = 0; i < win.length; i++) {
_getAllWindows(win[i]);
}
};
_getAllWindows(baseWindow);
return windows;
}
let windows = getAllWindows(content);
for (let win of windows) {
if (win.setup) {
yield win.setup();
}
}
});
}
function* clearStorage() {
yield ContentTask.spawn(gBrowser.selectedBrowser, null, function*() {
/**
* Get all windows including frames recursively.
*
* @param {Window} [baseWindow]
* The base window at which to start looking for child windows
* (optional).
* @return {Set}
* A set of windows.
*/
function getAllWindows(baseWindow) {
let windows = new Set();
let _getAllWindows = function(win) {
windows.add(win.wrappedJSObject);
for (let i = 0; i < win.length; i++) {
_getAllWindows(win[i]);
}
};
_getAllWindows(baseWindow);
return windows;
}
let windows = getAllWindows(content);
for (let win of windows) {
if (win.clear) {
yield win.clear();
}
}
});
}

View File

@ -28,60 +28,80 @@ localStorage.setItem("ls2", "foobar-2");
sessionStorage.setItem("ss1", "foobar-3");
console.log("added cookies and stuff from main page");
function success(event) {
setupIDB.next(event);
}
window.idbGenerator = function*(callback) {
let idbGenerator = function*() {
let request = indexedDB.open("idb1", 1);
request.onupgradeneeded = success;
request.onsuccess = success;
request.onerror = function() {
throw new Error("error opening db connection");
};
let event = yield undefined;
let db = event.target.result;
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
let db = yield new Promise(done => {
request.onupgradeneeded = event => {
let db = event.target.result;
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
store1.transaction.oncomplete = () => {
done(db);
};
};
});
store1.add({id: 1, name: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
yield undefined;
// Prevents AbortError
yield new Promise(done => {
request.onsuccess = done;
});
let transaction = db.transaction(["obj1", "obj2"], "readwrite");
let store1 = transaction.objectStore("obj1");
let store2 = transaction.objectStore("obj2");
store1.add({id: 1, name: "foo", email: "foo@bar.com"});
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"});
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"});
store2.add({
id2: 1,
name: "foo",
email: "foo@bar.com",
extra: "baz"}).onsuccess = success;
yield undefined;
extra: "baz"
});
// Prevents AbortError during close()
yield new Promise(success => {
transaction.oncomplete = success;
});
yield undefined;
db.close();
request = indexedDB.open("idb2", 1);
request.onupgradeneeded = success;
request.onsuccess = success;
event = yield undefined;
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
yield undefined;
let db2 = yield new Promise(done => {
request.onupgradeneeded = event => {
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = () => {
done(db2);
}
};
});
// Prevents AbortError during close()
yield new Promise(done => {
request.onsuccess = done;
});
db2.close();
dump("added cookies and stuff from main page\n");
callback();
};
function successClear(event) {
clearIterator.next(event);
function deleteDB(dbName) {
return new Promise(resolve => {
dump("removing database " + dbName + " from " + document.location + "\n");
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
});
}
window.clear = function*(callback) {
window.setup = function*() {
yield idbGenerator();
};
window.clear = function*() {
document.cookie = "c1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/browser";
document.cookie =
"c3=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; secure=true";
@ -92,14 +112,11 @@ window.clear = function*(callback) {
localStorage.clear();
sessionStorage.clear();
indexedDB.deleteDatabase("idb1").onsuccess = successClear;
yield undefined;
indexedDB.deleteDatabase("idb2").onsuccess = successClear;
yield undefined;
yield deleteDB("idb1");
yield deleteDB("idb2");
dump("removed cookies, localStorage, sessionStorage and indexedDB data " +
"from " + document.location + "\n");
callback();
};
</script>
</body>

View File

@ -13,57 +13,81 @@ document.cookie = "sc1=foobar;";
localStorage.setItem("iframe-s-ls1", "foobar");
sessionStorage.setItem("iframe-s-ss1", "foobar-2");
function success(event) {
setupIDB.next(event);
}
window.idbGenerator = function*(callback) {
let idbGenerator = function*() {
let request = indexedDB.open("idb-s1", 1);
request.onupgradeneeded = success;
request.onsuccess = success;
request.onerror = function(e) {
request.onerror = function() {
throw new Error("error opening db connection");
};
let event = yield undefined;
let db = event.target.result;
let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
let db = yield new Promise(done => {
request.onupgradeneeded = event => {
let db = event.target.result;
let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
store1.transaction.oncomplete = () => {
done(db);
};
};
});
yield new Promise(done => {
request.onsuccess = done;
});
let transaction = db.transaction(["obj-s1"], "readwrite");
let store1 = transaction.objectStore("obj-s1");
store1.add({id: 6, name: "foo", email: "foo@bar.com"});
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"});
yield new Promise(success => {
transaction.oncomplete = success;
});
store1.add({id: 6, name: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
yield undefined;
yield undefined;
db.close();
request = indexedDB.open("idb-s2", 1);
request.onupgradeneeded = success;
request.onsuccess = success;
event = yield undefined;
let db2 = yield new Promise(done => {
request.onupgradeneeded = event => {
let db2 = event.target.result;
let store3 =
db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = () => {
done(db2);
};
};
});
yield new Promise(done => {
request.onsuccess = done;
});
transaction = db2.transaction(["obj-s2"], "readwrite");
let store3 = transaction.objectStore("obj-s2");
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"});
yield new Promise(success => {
transaction.oncomplete = success;
});
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
store3.createIndex("name2", "name2", { unique: true });
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
yield undefined;
db2.close();
console.log("added cookies and stuff from secured iframe");
callback();
dump("added cookies and stuff from secured iframe\n");
}
function successClear(event) {
clearIterator.next(event);
function deleteDB(dbName) {
return new Promise(resolve => {
dump("removing database " + dbName + " from " + document.location + "\n");
indexedDB.deleteDatabase(dbName).onsuccess = resolve;
});
}
window.clear = function*(callback) {
window.setup = function*() {
yield idbGenerator();
};
window.clear = function*() {
document.cookie = "sc1=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
localStorage.clear();
indexedDB.deleteDatabase("idb-s1").onsuccess = successClear;
yield undefined;
indexedDB.deleteDatabase("idb-s2").onsuccess = successClear;
yield undefined;
yield deleteDB("idb-s1");
yield deleteDB("idb-s2");
console.log("removed cookies and stuff from secured iframe");
callback();
}
</script>
</body>

View File

@ -15,12 +15,11 @@ sessionStorage.setItem("iframe-u-ss1", "foobar1");
sessionStorage.setItem("iframe-u-ss2", "foobar2");
console.log("added cookies and stuff from unsecured iframe");
window.clear = function*(callback) {
window.clear = function*() {
document.cookie = "uc1=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
localStorage.clear();
sessionStorage.clear();
console.log("removed cookies and stuff from unsecured iframe");
callback();
}
</script>
</body>