Bug 637020 - Invalidate windows after they have been restored to ensure their data is collected the first time we save; f=smacleod r=yoric
authorTim Taubert <ttaubert@mozilla.com>
Thu, 08 Aug 2013 01:47:26 +0200
changeset 154586 b4dd81559271785c8972e60314a71a34b8df3f56
parent 154585 6ac17afa560c74c1f074e763cfcb0ed6f99e0c32
child 154587 760c16523e4da865f5611b5c67eeb842b13db232
push id2961
push userlsblakk@mozilla.com
push dateMon, 28 Oct 2013 21:59:28 +0000
treeherdermozilla-beta@73ef4f13486f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersyoric
bugs637020
milestone26.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 637020 - Invalidate windows after they have been restored to ensure their data is collected the first time we save; f=smacleod r=yoric
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
@@ -3002,16 +3002,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);
+}