Bug 637020 - Invalidate windows after they have been restored to ensure their data is collected the first time we save. r=yoric, a=bajaj
authorTim Taubert <ttaubert@mozilla.com>
Thu, 08 Aug 2013 01:47:26 +0200
changeset 153680 099ac22360cad12781627a7425a4bc5d8a3cc7d5
parent 153679 d980128343a5f8e80654b77f2eba08f4a491f1fd
child 153681 cbb6544f9769b3b712b6903f1490c2c1965424ca
push id2859
push userakeybl@mozilla.com
push dateMon, 16 Sep 2013 19:14:59 +0000
treeherdermozilla-beta@87d3c51cd2bf [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric, bajaj
bugs637020
milestone25.0a2
Bug 637020 - Invalidate windows after they have been restored to ensure their data is collected the first time we save. r=yoric, a=bajaj
browser/components/sessionstore/src/SessionStore.jsm
browser/components/sessionstore/test/Makefile.in
browser/components/sessionstore/test/browser_637020.js
browser/components/sessionstore/test/browser_637020_slow.sjs
--- a/browser/components/sessionstore/src/SessionStore.jsm
+++ b/browser/components/sessionstore/src/SessionStore.jsm
@@ -3037,16 +3037,20 @@ let SessionStoreInternal = {
       }
     }
 
     if (!this._isWindowLoaded(aWindow)) {
       // from now on, the data will come from the actual window
       delete this._statesToRestore[aWindow.__SS_restoreID];
       delete aWindow.__SS_restoreID;
       delete this._windows[aWindow.__SSi]._restoring;
+
+      // It's important to set the window state to dirty so that
+      // we collect their data for the first time when saving state.
+      this._dirtyWindows[aWindow.__SSi] = true;
     }
 
     if (aTabs.length == 0) {
       // this is normally done in restoreHistory() but as we're returning early
       // here we need to take care of it.
       this._setWindowStateReady(aWindow);
       return;
     }
--- a/browser/components/sessionstore/test/Makefile.in
+++ b/browser/components/sessionstore/test/Makefile.in
@@ -117,16 +117,18 @@ MOCHITEST_BROWSER_FILES = \
 	browser_615394-SSWindowState_events.js \
 	browser_618151.js \
 	browser_623779.js \
 	browser_624727.js \
 	browser_625257.js \
 	browser_628270.js \
 	browser_635418.js \
 	browser_636279.js \
+	browser_637020.js \
+	browser_637020_slow.sjs \
 	browser_644409-scratchpads.js \
 	browser_645428.js \
 	browser_659591.js \
 	browser_662743.js \
 	browser_662743_sample.html \
 	browser_662812.js \
 	browser_665702-state_session.js \
 	browser_682507.js \
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_637020.js
@@ -0,0 +1,65 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const TEST_URL = "http://mochi.test:8888/browser/browser/components/" +
+                 "sessionstore/test/browser_637020_slow.sjs";
+
+const TEST_STATE = {
+  windows: [{
+    tabs: [
+      { entries: [{ url: "about:mozilla" }] },
+      { entries: [{ url: "about:robots" }] }
+    ]
+  }, {
+    tabs: [
+      { entries: [{ url: TEST_URL }] },
+      { entries: [{ url: TEST_URL }] }
+    ]
+  }]
+};
+
+function test() {
+  TestRunner.run();
+}
+
+/**
+ * This test ensures that windows that have just been restored will be marked
+ * as dirty, otherwise _getCurrentState() might ignore them when collecting
+ * state for the first time and we'd just save them as empty objects.
+ *
+ * The dirty state acts as a cache to not collect data from all windows all the
+ * time, so at the beginning, each window must be dirty so that we collect
+ * their state at least once.
+ */
+
+function runTests() {
+  let win;
+
+  // Wait until the new window has been opened.
+  Services.obs.addObserver(function onOpened(subject) {
+    Services.obs.removeObserver(onOpened, "domwindowopened");
+    win = subject;
+    executeSoon(next);
+  }, "domwindowopened", false);
+
+  // Set the new browser state that will
+  // restore a window with two slowly loading tabs.
+  yield SessionStore.setBrowserState(JSON.stringify(TEST_STATE));
+
+  // The window has now been opened. Check the state that is returned,
+  // this should come from the cache while the window isn't restored, yet.
+  info("the window has been opened");
+  checkWindows();
+
+  // The history has now been restored and the tabs are loading. The data must
+  // now come from the window, if it's correctly been marked as dirty before.
+  yield whenDelayedStartupFinished(win, next);
+  info("the delayed startup has finished");
+  checkWindows();
+}
+
+function checkWindows() {
+  let state = JSON.parse(SessionStore.getBrowserState());
+  is(state.windows[0].tabs.length, 2, "first window has two tabs");
+  is(state.windows[1].tabs.length, 2, "second window has two tabs");
+}
new file mode 100644
--- /dev/null
+++ b/browser/components/sessionstore/test/browser_637020_slow.sjs
@@ -0,0 +1,21 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const DELAY_MS = "2000";
+
+let timer;
+
+function handleRequest(req, resp) {
+  resp.processAsync();
+  resp.setHeader("Cache-Control", "no-cache", false);
+  resp.setHeader("Content-Type", "text/html;charset=utf-8", false);
+
+  timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+  timer.init(() => {
+    resp.write("hi");
+    resp.finish();
+  }, DELAY_MS, Ci.nsITimer.TYPE_ONE_SHOT);
+}