Bug 1249447 - Prevent using CPOW and wait for indexedDB setup/clear with tasks. r=mratcliffe
authorAlexandre Poirot <poirot.alex@gmail.com>
Fri, 18 Mar 2016 02:44:22 -0700
changeset 313244 95656a398e8f7754d358f1f0250a2e8069f5db47
parent 313243 852ac8a4ec55b93df8c9740aafaee6b84f539c3d
child 313245 c35895f48511d4ed74a9935415c5a786546fe982
push id9480
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 17:12:58 +0000
treeherdermozilla-aurora@0d6a91c76a9e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmratcliffe
bugs1249447
milestone48.0a1
Bug 1249447 - Prevent using CPOW and wait for indexedDB setup/clear with tasks. r=mratcliffe
devtools/client/storage/test/storage-secured-iframe.html
devtools/server/tests/browser/browser.ini
devtools/server/tests/browser/browser_storage_dynamic_windows.js
devtools/server/tests/browser/browser_storage_listings.js
devtools/server/tests/browser/storage-dynamic-windows.html
devtools/server/tests/browser/storage-helpers.js
devtools/server/tests/browser/storage-listings.html
devtools/server/tests/browser/storage-secured-iframe.html
devtools/server/tests/browser/storage-unsecured-iframe.html
--- a/devtools/client/storage/test/storage-secured-iframe.html
+++ b/devtools/client/storage/test/storage-secured-iframe.html
@@ -8,20 +8,16 @@ Iframe for testing multiple host detetio
 </head>
 <body>
 <script type="application/javascript;version=1.7">
 "use strict";
 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() {
     throw new Error("error opening db connection");
   };
   let db = yield new Promise(done => {
     request.onupgradeneeded = event => {
       let db = event.target.result;
--- a/devtools/server/tests/browser/browser.ini
+++ b/devtools/server/tests/browser/browser.ini
@@ -15,16 +15,17 @@ support-files =
   storage-listings.html
   storage-unsecured-iframe.html
   storage-updates.html
   storage-secured-iframe.html
   stylesheets-nested-iframes.html
   timeline-iframe-child.html
   timeline-iframe-parent.html
   director-script-target.html
+  storage-helpers.js
 
 [browser_animation_emitMutations.js]
 [browser_animation_getFrames.js]
 [browser_animation_getMultipleStates.js]
 [browser_animation_getPlayers.js]
 [browser_animation_getStateAfterFinished.js]
 [browser_animation_getSubTreeAnimations.js]
 [browser_animation_keepFinished.js]
--- a/devtools/server/tests/browser/browser_storage_dynamic_windows.js
+++ b/devtools/server/tests/browser/browser_storage_dynamic_windows.js
@@ -1,16 +1,16 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "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: {
     "test1.example.org": ["c1", "cs2", "c3", "uc1"],
     "sectest1.example.org": ["uc1", "cs2"]
   },
   localStorage: {
     "http://test1.example.org": ["ls1", "ls2"],
@@ -25,61 +25,24 @@ const beforeReload = {
       JSON.stringify(["idb1", "obj1"]),
       JSON.stringify(["idb1", "obj2"]),
       JSON.stringify(["idb2", "obj3"]),
     ],
     "http://sectest1.example.org": []
   }
 };
 
-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) {
   for (let storageType in beforeReload) {
     ok(data[storageType], storageType + " storage actor is present");
     is(Object.keys(data[storageType].hosts).length,
        Object.keys(beforeReload[storageType]).length,
        "Number of hosts for " + storageType + "match");
@@ -119,17 +82,17 @@ function markOutMatched(toBeEmptied, dat
       }
     }
     if (!Object.keys(toBeEmptied[storageType]).length) {
       delete toBeEmptied[storageType];
     }
   }
 }
 
-// function testReload() {
+// function testReload(front) {
 //   info("Testing if reload works properly");
 
 //   let shouldBeEmptyFirst = Cu.cloneInto(beforeReload,  {});
 //   let shouldBeEmptyLast = Cu.cloneInto(beforeReload,  {});
 //   return new Promise(resolve => {
 
 //     let onStoresUpdate = data => {
 //       info("in stores update of testReload");
@@ -153,27 +116,27 @@ function markOutMatched(toBeEmptied, dat
 
 //       if (!Object.keys(shouldBeEmptyLast).length) {
 //         info("Everything to be received is received.");
 //         endTestReloaded();
 //       }
 //     };
 
 //     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 = {
       localStorage: {
         "https://sectest1.example.org": ["iframe-s-ls1"]
       },
       sessionStorage: {
         "https://sectest1.example.org": ["iframe-s-ss1"]
@@ -221,29 +184,29 @@ function testAddIframe() {
 
       if (!Object.keys(shouldBeEmpty).length) {
         info("Everything to be received is received.");
         endTestReloaded();
       }
     };
 
     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";
     content.document.querySelector("body").appendChild(iframe);
   });
 }
 
-function testRemoveIframe() {
+function testRemoveIframe(front) {
   info("Testing if iframe removal works properly");
   return new Promise(resolve => {
     let shouldBeEmpty = {
       localStorage: {
         "http://sectest1.example.org": []
       },
       sessionStorage: {
         "http://sectest1.example.org": []
@@ -281,58 +244,42 @@ function testRemoveIframe() {
 
       if (!Object.keys(shouldBeEmpty).length) {
         info("Everything to be received is received.");
         endTestReloaded();
       }
     };
 
     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:")) {
         iframe.remove();
         break;
       }
     }
   });
 }
 
-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();
+});
--- a/devtools/server/tests/browser/browser_storage_listings.js
+++ b/devtools/server/tests/browser/browser_storage_listings.js
@@ -1,16 +1,16 @@
 /* vim: set ft=javascript ts=2 et sw=2 tw=80: */
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "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: {
     "test1.example.org": [
       {
         name: "c1",
         value: "foobar",
         expires: 2000000000000,
@@ -314,63 +314,31 @@ 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) {
   is(Object.keys(cookiesActor.hosts).length, 2, "Correct number of host entries for cookies");
   return testCookiesObjects(0, cookiesActor.hosts, cookiesActor);
 }
 
 var testCookiesObjects = Task.async(function*(index, hosts, cookiesActor) {
@@ -630,46 +598,27 @@ var testIDBEntries = Task.async(function
     ), parsed[0] + "#" + parsed[1]);
   }
   if (index == Object.keys(hosts).length - 1) {
     return;
   }
   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();
+});
--- a/devtools/server/tests/browser/storage-dynamic-windows.html
+++ b/devtools/server/tests/browser/storage-dynamic-windows.html
@@ -21,78 +21,97 @@ document.cookie = "cs2=sessionCookie; pa
 document.cookie = "c3=foobar-2; expires=" +
   new Date(cookieExpiresTime2).toGMTString() + "; path=/";
 // ... and some local storage items ..
 localStorage.setItem("ls1", "foobar");
 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 = 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();
 
-  let db2 = event.target.result;
-  let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
-  store3.createIndex("name2", "name2", { unique: true });
-  yield undefined;
-  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>
 </html>
new file mode 100644
--- /dev/null
+++ b/devtools/server/tests/browser/storage-helpers.js
@@ -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();
+      }
+    }
+  });
+}
--- a/devtools/server/tests/browser/storage-listings.html
+++ b/devtools/server/tests/browser/storage-listings.html
@@ -23,84 +23,101 @@ document.cookie = "c3=foobar-2; secure=t
   new Date(cookieExpiresTime2).toGMTString() + "; path=/";
 // ... and some local storage items ..
 localStorage.setItem("ls1", "foobar");
 localStorage.setItem("ls2", "foobar-2");
 // ... and finally some session storage items too
 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 = 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();
 
-  let db2 = event.target.result;
-  let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
-  store3.createIndex("name2", "name2", { unique: true });
-
-  yield undefined;
-  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";
   document.cookie =
     "cs2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=" +
     partialHostname;
 
   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>
 </html>
--- a/devtools/server/tests/browser/storage-secured-iframe.html
+++ b/devtools/server/tests/browser/storage-secured-iframe.html
@@ -8,63 +8,87 @@ Iframe for testing multiple host detetio
 </head>
 <body>
 <script type="application/javascript;version=1.7">
 
 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;
+  });
 
-  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;
+  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;
+  });
+
   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;
+  });
 
-  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;
+  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;
+  });
+
   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>
 </html>
--- a/devtools/server/tests/browser/storage-unsecured-iframe.html
+++ b/devtools/server/tests/browser/storage-unsecured-iframe.html
@@ -10,18 +10,17 @@ Iframe for testing multiple host detetio
 <script>
 
 document.cookie = "uc1=foobar; domain=.example.org; path=/; secure=true";
 localStorage.setItem("iframe-u-ls1", "foobar");
 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>
 </html>