Bug 1109875 - Add tests for async tab removal r=billm
authorTim Taubert <ttaubert@mozilla.com>
Thu, 30 Apr 2015 18:28:44 +0200
changeset 273742 e2ba32edadf3726f3bc42199c49ff55464b8c3cc
parent 273741 98edf81629bd496d06580a07af58c7734704f500
child 273743 40f06e925ae25451402f2fb770ed2e6c10dc8ce9
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbillm
bugs1109875
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1109875 - Add tests for async tab removal r=billm
browser/components/sessionstore/test/browser.ini
browser/components/sessionstore/test/browser_async_remove_tab.js
--- a/browser/components/sessionstore/test/browser.ini
+++ b/browser/components/sessionstore/test/browser.ini
@@ -60,16 +60,18 @@ support-files =
 
 
 #disabled-for-intermittent-failures--bug-766044, browser_459906_empty.html
 #disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html
 #disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html
 
 [browser_aboutPrivateBrowsing.js]
 [browser_aboutSessionRestore.js]
+[browser_async_remove_tab.js]
+run-if = e10s
 [browser_attributes.js]
 [browser_backup_recovery.js]
 [browser_broadcast.js]
 [browser_capabilities.js]
 [browser_cleaner.js]
 [browser_cookies.js]
 [browser_crashedTabs.js]
 skip-if = !e10s || !crashreporter
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_async_remove_tab.js
@@ -0,0 +1,242 @@
+"use strict";
+
+function* createTabWithRandomValue(url) {
+  let tab = gBrowser.addTab(url);
+  let browser = tab.linkedBrowser;
+  yield promiseBrowserLoaded(browser);
+
+  // Set a random value.
+  let r = `rand-${Math.random()}`;
+  ss.setTabValue(tab, "foobar", r);
+
+  // Flush to ensure there are no scheduled messages.
+  TabState.flush(browser);
+
+  return {tab, r};
+}
+
+function isValueInClosedData(rval) {
+  return ss.getClosedTabData(window).includes(rval);
+}
+
+function restoreClosedTabWithValue(rval) {
+  let closedTabData = JSON.parse(ss.getClosedTabData(window));
+  let index = closedTabData.findIndex(function (data) {
+    return (data.state.extData && data.state.extData.foobar) == rval;
+  });
+
+  if (index == -1) {
+    throw new Error("no closed tab found for given rval");
+  }
+
+  return ss.undoCloseTab(window, index);
+}
+
+function promiseNewLocationAndHistoryEntryReplaced(browser, snippet) {
+  return ContentTask.spawn(browser, snippet, function* (snippet) {
+    let webNavigation = docShell.QueryInterface(Ci.nsIWebNavigation);
+    let shistory = webNavigation.sessionHistory;
+
+    // Evaluate the snippet that the changes the location.
+    eval(snippet);
+
+    return new Promise(resolve => {
+      let listener = {
+        OnHistoryReplaceEntry() {
+          shistory.removeSHistoryListener(this);
+          resolve();
+        },
+
+        QueryInterface: XPCOMUtils.generateQI([
+          Ci.nsISHistoryListener,
+          Ci.nsISupportsWeakReference
+        ])
+      };
+
+      shistory.addSHistoryListener(listener);
+
+      /* Keep the weak shistory listener alive. */
+      addEventListener("unload", function () {
+        try {
+          shistory.removeSHistoryListener(listener);
+        } catch (e) { /* Will most likely fail. */ }
+      });
+    });
+  });
+}
+
+function promiseHistoryEntryReplacedNonRemote(browser) {
+  let {listeners} = promiseHistoryEntryReplacedNonRemote;
+
+  return new Promise(resolve => {
+    let shistory = browser.webNavigation.sessionHistory;
+
+    let listener = {
+      OnHistoryReplaceEntry() {
+        shistory.removeSHistoryListener(this);
+        resolve();
+      },
+
+      QueryInterface: XPCOMUtils.generateQI([
+        Ci.nsISHistoryListener,
+        Ci.nsISupportsWeakReference
+      ])
+    };
+
+    shistory.addSHistoryListener(listener);
+    listeners.set(browser, listener);
+  });
+}
+promiseHistoryEntryReplacedNonRemote.listeners = new WeakMap();
+
+add_task(function* dont_save_empty_tabs() {
+  let {tab, r} = yield createTabWithRandomValue("about:blank");
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // No tab state worth saving.
+  ok(!isValueInClosedData(r), "closed tab not saved");
+  yield promise;
+
+  // Still no tab state worth saving.
+  ok(!isValueInClosedData(r), "closed tab not saved");
+});
+
+add_task(function* save_worthy_tabs_remote() {
+  let {tab, r} = yield createTabWithRandomValue("https://example.com/");
+  ok(tab.linkedBrowser.isRemoteBrowser, "browser is remote");
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // Tab state deemed worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+  yield promise;
+
+  // Tab state still deemed worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+});
+
+add_task(function* save_worthy_tabs_nonremote() {
+  let {tab, r} = yield createTabWithRandomValue("about:robots");
+  ok(!tab.linkedBrowser.isRemoteBrowser, "browser is not remote");
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // Tab state deemed worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+  yield promise;
+
+  // Tab state still deemed worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+});
+
+add_task(function* save_worthy_tabs_remote_final() {
+  let {tab, r} = yield createTabWithRandomValue("about:blank");
+  let browser = tab.linkedBrowser;
+  ok(browser.isRemoteBrowser, "browser is remote");
+
+  // Replace about:blank with a new remote page.
+  let snippet = 'webNavigation.loadURI("https://example.com/", null, null, null, null)';
+  yield promiseNewLocationAndHistoryEntryReplaced(browser, snippet);
+
+  // Remotness shouldn't have changed.
+  ok(browser.isRemoteBrowser, "browser is still remote");
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // No tab state worth saving (that we know about yet).
+  ok(!isValueInClosedData(r), "closed tab not saved");
+  yield promise;
+
+  // Turns out there is a tab state worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+});
+
+add_task(function* save_worthy_tabs_nonremote_final() {
+  let {tab, r} = yield createTabWithRandomValue("about:blank");
+  let browser = tab.linkedBrowser;
+  ok(browser.isRemoteBrowser, "browser is remote");
+
+  // Replace about:blank with a non-remote entry.
+  browser.loadURI("about:robots");
+  ok(!browser.isRemoteBrowser, "browser is not remote anymore");
+
+  // Wait until the new entry replaces about:blank.
+  yield promiseHistoryEntryReplacedNonRemote(browser);
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // No tab state worth saving (that we know about yet).
+  ok(!isValueInClosedData(r), "closed tab not saved");
+  yield promise;
+
+  // Turns out there is a tab state worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+});
+
+add_task(function* dont_save_empty_tabs_final() {
+  let {tab, r} = yield createTabWithRandomValue("https://example.com/");
+  let browser = tab.linkedBrowser;
+
+  // Replace the current page with an about:blank entry.
+  let snippet = 'content.location.replace("about:blank")';
+  yield promiseNewLocationAndHistoryEntryReplaced(browser, snippet);
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // Tab state deemed worth saving (yet).
+  ok(isValueInClosedData(r), "closed tab saved");
+  yield promise;
+
+  // Turns out we don't want to save the tab state.
+  ok(!isValueInClosedData(r), "closed tab not saved");
+});
+
+add_task(function* undo_worthy_tabs() {
+  let {tab, r} = yield createTabWithRandomValue("https://example.com/");
+  ok(tab.linkedBrowser.isRemoteBrowser, "browser is remote");
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // Tab state deemed worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+
+  // Restore the closed tab before receiving its final message.
+  tab = restoreClosedTabWithValue(r);
+
+  // Wait for the final update message.
+  yield promise;
+
+  // Check we didn't add the tab back to the closed list.
+  ok(!isValueInClosedData(r), "tab no longer closed");
+
+  // Cleanup.
+  yield promiseRemoveTab(tab);
+});
+
+add_task(function* forget_worthy_tabs_remote() {
+  let {tab, r} = yield createTabWithRandomValue("https://example.com/");
+  ok(tab.linkedBrowser.isRemoteBrowser, "browser is remote");
+
+  // Remove the tab before the update arrives.
+  let promise = promiseRemoveTab(tab);
+
+  // Tab state deemed worth saving.
+  ok(isValueInClosedData(r), "closed tab saved");
+
+  // Forget the closed tab.
+  ss.forgetClosedTab(window, 0);
+
+  // Wait for the final update message.
+  yield promise;
+
+  // Check we didn't add the tab back to the closed list.
+  ok(!isValueInClosedData(r), "we forgot about the tab");
+});