Bug 1059007 - [e10s] Use TabState.flush() in session store tests (r=ttaubert)

This commit is contained in:
Bill McCloskey 2014-09-23 15:48:53 -07:00
parent dd3e00d519
commit 5acbba65ce
24 changed files with 81 additions and 77 deletions

View File

@ -39,6 +39,10 @@ this.TabState = Object.freeze({
TabStateInternal.flush(browser);
},
flushAsync: function (browser) {
TabStateInternal.flushAsync(browser);
},
flushWindow: function (window) {
TabStateInternal.flushWindow(window);
},
@ -93,6 +97,18 @@ let TabStateInternal = {
}
},
/**
* DO NOT USE - DEBUGGING / TESTING ONLY
*
* This function is used to simulate certain situations where race conditions
* can occur by sending data shortly before flushing synchronously.
*/
flushAsync: function(browser) {
if (this._syncHandlers.has(browser.permanentKey)) {
this._syncHandlers.get(browser.permanentKey).flushAsync();
}
},
/**
* Flushes queued content script data for all browsers of a given window.
*/

View File

@ -18,7 +18,7 @@ add_task(function test_set_tabstate() {
yield promiseBrowserLoaded(tab.linkedBrowser);
// get the tab's state
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let state = ss.getTabState(tab);
ok(state, "get the tab's state");

View File

@ -29,7 +29,7 @@ function test() {
whenBrowserLoaded(newWin.gBrowser.selectedBrowser, function() {
// get the sessionstore state for the window
SyncHandlers.get(newWin.gBrowser.selectedBrowser).flush();
TabState.flush(newWin.gBrowser.selectedBrowser);
let state = ss.getWindowState(newWin);
// verify our cookie got set during pageload

View File

@ -26,7 +26,7 @@ function test() {
ss.setTabState(tab, JSON.stringify(tabState));
whenTabRestored(tab, function() {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
tabState = JSON.parse(ss.getTabState(tab));
is(tabState.entries.length, max_entries, "session history filled to the limit");
is(tabState.entries[0].url, baseURL + 0, "... but not more");
@ -37,7 +37,7 @@ function test() {
}, null).then(check);
function check() {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
tabState = JSON.parse(ss.getTabState(tab));
if (tab.linkedBrowser.currentURI.spec != baseURL + "end") {
// It may take a few passes through the event loop before we

View File

@ -57,7 +57,7 @@ add_task(function test_nested_about_sessionrestore() {
function checkState(prefix, tab) {
// Flush and query tab state.
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let {formdata} = JSON.parse(ss.getTabState(tab));
ok(formdata.id["sessionData"], prefix + ": we have form data for about:sessionrestore");

View File

@ -99,7 +99,7 @@ function test() {
history.replaceState({obj3:/^a$/}, "title-obj3");
}
runInContent(browser, contentTest, null).then(function() {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let state = ss.getTabState(tab);
gBrowser.removeTab(tab);

View File

@ -72,7 +72,7 @@ function testTabRestoreData(aFormData, aExpectedValue, aCallback) {
let value = select.options[select.selectedIndex].value;
// Flush to make sure we have the latest form data.
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let restoredTabState = JSON.parse(ss.getTabState(tab));
// If aExpectedValue=null we don't expect any form data to be collected.

View File

@ -27,7 +27,7 @@ function test() {
whenChildCount(entry, 1, function () {
whenChildCount(entry, 2, function () {
whenBrowserLoaded(browser, function () {
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "tab has one history entry");
ok(!entries[0].children, "history entry has no subframes");

View File

@ -176,7 +176,7 @@ function testOnWindow(aIsPrivate, aCallback) {
function waitForTabLoad(aWin, aURL, aCallback) {
let browser = aWin.gBrowser.selectedBrowser;
whenBrowserLoaded(browser, function () {
SyncHandlers.get(browser).flush();
TabState.flush(browser);
executeSoon(aCallback);
});
browser.loadURI(aURL);

View File

@ -51,7 +51,7 @@ add_task(function* test_creation() {
info("Testing situation after a single write");
yield promiseBrowserLoaded(tab.linkedBrowser);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
yield SessionSaver.run();
ok((yield File.exists(Paths.recovery)), "After write, recovery sessionstore file exists again");
@ -63,7 +63,7 @@ add_task(function* test_creation() {
let URL2 = URL_BASE + "?second_write";
tab.linkedBrowser.loadURI(URL2);
yield promiseBrowserLoaded(tab.linkedBrowser);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
yield SessionSaver.run();
ok((yield File.exists(Paths.recovery)), "After second write, recovery sessionstore file still exists");
@ -90,7 +90,7 @@ let promiseSource = Task.async(function*(name) {
let tab = gBrowser.addTab(URL);
yield promiseBrowserLoaded(tab.linkedBrowser);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
yield SessionSaver.run();
gBrowser.removeTab(tab);

View File

@ -93,14 +93,14 @@ add_task(function flush_on_settabstate() {
let browser = tab.linkedBrowser;
// Flush to make sure our tab state is up-to-date.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let state = ss.getTabState(tab);
yield modifySessionStorage(browser, {test: "on-set-tab-state"});
// Flush all data contained in the content script but send it using
// asynchronous messages.
SyncHandlers.get(browser).flushAsync();
TabState.flushAsync(browser);
ss.setTabState(tab, state);
yield promiseTabRestored(tab);
@ -122,13 +122,13 @@ add_task(function flush_on_tabclose_racy() {
let browser = tab.linkedBrowser;
// Flush to make sure we start with an empty queue.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
yield modifySessionStorage(browser, {test: "on-tab-close-racy"});
// Flush all data contained in the content script but send it using
// asynchronous messages.
SyncHandlers.get(browser).flushAsync();
TabState.flushAsync(browser);
gBrowser.removeTab(tab);
let [{state: {storage}}] = JSON.parse(ss.getClosedTabData(window));

View File

@ -31,7 +31,7 @@ add_task(function docshell_capabilities() {
yield promiseBrowserLoaded(browser);
// Flush to make sure chrome received all data.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
// Check that we correctly save disallowed features.
let disallowedState = JSON.parse(ss.getTabState(tab));
@ -45,7 +45,7 @@ add_task(function docshell_capabilities() {
yield promiseTabRestored(tab);
// Flush to make sure chrome received all data.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
// After restoring disallowed features must be available again.
state = JSON.parse(ss.getTabState(tab));

View File

@ -24,7 +24,7 @@ function runTests() {
// Open a second tab and close the first one.
let tab = win.gBrowser.addTab("about:mozilla");
yield whenBrowserLoaded(tab.linkedBrowser);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
win.gBrowser.removeTab(win.gBrowser.tabs[0]);
// Make sure our window is still tracked by sessionstore

View File

@ -24,7 +24,7 @@ add_task(function () {
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
// Check URLs.
@ -61,7 +61,7 @@ add_task(function () {
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
// Check URLs.
@ -76,7 +76,7 @@ add_task(function () {
browser.messageManager.sendAsyncMessage("ss-test:click", {id: "lnk"});
yield promiseBrowserLoaded(browser, false /* don't ignore subframes */);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
// Check URLs.

View File

@ -181,7 +181,7 @@ add_task(function test_nested() {
yield promiseTabRestored(tab);
// Check that the input field has the right value.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({formdata} = JSON.parse(ss.getTabState(tab)));
is(JSON.stringify(formdata), JSON.stringify(FORM_DATA),
"formdata for iframe restored correctly");

View File

@ -79,7 +79,7 @@ function testTabRestoreData(aFormData, aExpectedValue, aCallback) {
ss.setTabState(tab, JSON.stringify(tabState));
yield promiseTabRestored(tab);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let restoredTabState = JSON.parse(ss.getTabState(tab));
let restoredFormData = restoredTabState.formdata;

View File

@ -49,7 +49,7 @@ add_task(function *test_history_cap() {
ss.setTabState(tab, JSON.stringify(tabState));
yield promiseTabRestored(tab);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let restoredTabState = JSON.parse(ss.getTabState(tab));
is(restoredTabState.entries.length, maxBack1 + 1 + maxFwd1,
@ -70,7 +70,7 @@ add_task(function *test_history_cap() {
ss.setTabState(tab, JSON.stringify(tabState));
yield promiseTabRestored(tab);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
restoredTabState = JSON.parse(ss.getTabState(tab));
is(restoredTabState.entries.length, maxEntries,
@ -89,7 +89,7 @@ add_task(function *test_history_cap() {
ss.setTabState(tab, JSON.stringify(tabState));
yield promiseTabRestored(tab);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
restoredTabState = JSON.parse(ss.getTabState(tab));
is(restoredTabState.entries.length, 1 + maxFwd2,
@ -108,7 +108,7 @@ add_task(function *test_history_cap() {
ss.setTabState(tab, JSON.stringify(tabState));
yield promiseTabRestored(tab);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
restoredTabState = JSON.parse(ss.getTabState(tab));
is(restoredTabState.entries.length, maxBack2 + 1,

View File

@ -25,7 +25,7 @@ add_task(function test_label_and_icon() {
yield promiseBrowserLoaded(browser);
// Retrieve the tab state.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let state = ss.getTabState(tab);
gBrowser.removeTab(tab);
browser = null;

View File

@ -30,8 +30,8 @@ add_task(function() {
yield promiseBrowserLoaded(tab2.linkedBrowser);
info("Flush to make sure chrome received all data.");
SyncHandlers.get(tab1.linkedBrowser).flush();
SyncHandlers.get(tab2.linkedBrowser).flush();
TabState.flush(tab1.linkedBrowser);
TabState.flush(tab2.linkedBrowser);
info("Checking out state");
let state = yield promiseRecoveryFileContents();
@ -81,7 +81,7 @@ add_task(function () {
let tab = win.gBrowser.addTab("about:mozilla");
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
// Check that we consider the tab as private.
let state = JSON.parse(ss.getTabState(tab));
@ -95,7 +95,7 @@ add_task(function () {
tab = win.gBrowser.addTab("about:mozilla");
browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
// Check that we consider the tab as private.
state = JSON.parse(ss.getTabState(tab));
@ -120,7 +120,7 @@ add_task(function () {
let tab = win.gBrowser.addTab("about:mozilla");
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
// Check that we consider the tab as private.
let state = JSON.parse(ss.getTabState(tab));

View File

@ -129,7 +129,7 @@ add_task(function test_scroll_old_format() {
function checkScroll(tab, expected, msg) {
let browser = tab.linkedBrowser;
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let scroll = JSON.parse(ss.getTabState(tab)).scroll || null;
is(JSON.stringify(scroll), JSON.stringify(expected), msg);

View File

@ -43,7 +43,7 @@ add_task(function test_purge() {
yield promiseBrowserLoaded(browser);
// Check that we now have two shistory entries.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 2, "there are two shistory entries");
@ -51,7 +51,7 @@ add_task(function test_purge() {
yield sendMessage(browser, "ss-test:purgeSessionHistory");
// Check that we are left with a single shistory entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 1, "there is one shistory entry");
@ -71,7 +71,7 @@ add_task(function test_hashchange() {
yield promiseBrowserLoaded(browser);
// Check that we start with a single shistory entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "there is one shistory entry");
@ -80,7 +80,7 @@ add_task(function test_hashchange() {
yield promiseContentMessage(browser, "ss-test:hashchange");
// Check that we now have two shistory entries.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 2, "there are two shistory entries");
@ -110,7 +110,7 @@ add_task(function test_pageshow() {
is(browser.currentURI.spec, URL, "correct url after going back");
// Check that loading from bfcache did invalidate shistory.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {index} = JSON.parse(ss.getTabState(tab));
is(index, 1, "first history entry is selected");
@ -133,7 +133,7 @@ add_task(function test_subframes() {
yield promiseBrowserLoaded(browser);
// Check that we have a single shistory entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "there is one shistory entry");
is(entries[0].children.length, 1, "the entry has one child");
@ -143,7 +143,7 @@ add_task(function test_subframes() {
yield promiseBrowserLoaded(browser, false /* don't ignore subframes */);
// Check shistory.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 2, "there now are two shistory entries");
is(entries[1].children.length, 1, "the second entry has one child");
@ -157,7 +157,7 @@ add_task(function test_subframes() {
yield promiseContentMessage(browser, "ss-test:hashchange");
// Check shistory.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 2, "there now are two shistory entries");
is(entries[1].children.length, 1, "the second entry has one child");
@ -176,7 +176,7 @@ add_task(function test_about_page_navigate() {
yield promiseBrowserLoaded(browser);
// Check that we have a single shistory entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "there is one shistory entry");
is(entries[0].url, "about:blank", "url is correct");
@ -185,7 +185,7 @@ add_task(function test_about_page_navigate() {
yield promiseBrowserLoaded(browser);
// Check that we have changed the history entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 1, "there is one shistory entry");
is(entries[0].url, "about:robots", "url is correct");
@ -204,7 +204,7 @@ add_task(function test_pushstate_replacestate() {
yield promiseBrowserLoaded(browser);
// Check that we have a single shistory entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
is(entries.length, 1, "there is one shistory entry");
is(entries[0].url, "http://example.com/1", "url is correct");
@ -214,7 +214,7 @@ add_task(function test_pushstate_replacestate() {
yield promiseContentMessage(browser, "ss-test:historyPushState");
// Check that we have added the history entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 2, "there is another shistory entry");
is(entries[1].url, "http://example.com/test-entry/", "url is correct");
@ -224,7 +224,7 @@ add_task(function test_pushstate_replacestate() {
yield promiseContentMessage(browser, "ss-test:historyReplaceState");
// Check that we have modified the history entry.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({entries} = JSON.parse(ss.getTabState(tab)));
is(entries.length, 2, "there is still two shistory entries");
is(entries[1].url, "http://example.com/test-entry/test-entry2/", "url is correct");
@ -250,7 +250,7 @@ add_task(function test_slow_subframe_load() {
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {entries} = JSON.parse(ss.getTabState(tab));
// Check the number of children.

View File

@ -21,7 +21,7 @@ add_task(function session_storage() {
yield promiseBrowserLoaded(browser);
// Flush to make sure chrome received all data.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {storage} = JSON.parse(ss.getTabState(tab));
is(storage["http://example.com"].test, INNER_VALUE,
@ -32,7 +32,7 @@ add_task(function session_storage() {
// Ensure that modifying sessionStore values works.
yield modifySessionStorage(browser, {test: "modified"});
yield modifySessionStorage2(browser, {test: "modified2"});
SyncHandlers.get(browser).flush();
TabState.flush(browser);
({storage} = JSON.parse(ss.getTabState(tab)));
is(storage["http://example.com"].test, "modified2",
@ -46,7 +46,7 @@ add_task(function session_storage() {
yield promiseTabRestored(tab2);
// Flush to make sure chrome received all data.
SyncHandlers.get(browser2).flush();
TabState.flush(browser2);
({storage} = JSON.parse(ss.getTabState(tab2)));
is(storage["http://example.com"].test, "modified2",
@ -57,7 +57,7 @@ add_task(function session_storage() {
// Ensure that the content script retains restored data
// (by e.g. duplicateTab) and sends it along with new data.
yield modifySessionStorage(browser2, {test: "modified3"});
SyncHandlers.get(browser2).flush();
TabState.flush(browser2);
({storage} = JSON.parse(ss.getTabState(tab2)));
is(storage["http://example.com"].test, "modified2",
@ -68,7 +68,7 @@ add_task(function session_storage() {
// Check that loading a new URL discards data.
browser2.loadURI("http://mochi.test:8888/");
yield promiseBrowserLoaded(browser2);
SyncHandlers.get(browser2).flush();
TabState.flush(browser2);
({storage} = JSON.parse(ss.getTabState(tab2)));
is(storage["http://mochi.test:8888"].test, "modified3",
@ -78,7 +78,7 @@ add_task(function session_storage() {
// Check that loading a new URL discards data.
browser2.loadURI("about:mozilla");
yield promiseBrowserLoaded(browser2);
SyncHandlers.get(browser2).flush();
TabState.flush(browser2);
let state = JSON.parse(ss.getTabState(tab2));
ok(!state.hasOwnProperty("storage"), "storage data was discarded");
@ -101,7 +101,7 @@ add_task(function purge_domain() {
yield purgeDomainData(browser, "mochi.test");
// Flush to make sure chrome received all data.
SyncHandlers.get(browser).flush();
TabState.flush(browser);
let {storage} = JSON.parse(ss.getTabState(tab));
ok(!storage["http://mochi.test:8888"],

View File

@ -58,13 +58,13 @@ add_task(function history() {
let tab = gBrowser.addTab("http://example.org:80/?");
yield promiseBrowserLoaded(tab.linkedBrowser);
try {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics = yield promiseStats();
info("Now changing history");
tab.linkedBrowser.loadURI("http://example.org:80/1");
yield promiseBrowserLoaded(tab.linkedBrowser);
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics2 = yield promiseStats();
// We have changed history, so it must have increased
@ -91,7 +91,7 @@ add_task(function close_tab() {
let tab = gBrowser.addTab("http://example.org:80/?close_tab");
yield promiseBrowserLoaded(tab.linkedBrowser);
try {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics = yield promiseStats();
info("Now closing a tab");
@ -184,12 +184,12 @@ add_task(function dom_storage() {
let tab = gBrowser.addTab("http://example.org:80/?dom_storage");
yield promiseBrowserLoaded(tab.linkedBrowser);
try {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics = yield promiseStats();
info("Now adding some storage");
yield modifySessionStorage(tab.linkedBrowser, {foo: "bar"});
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics2 = yield promiseStats();
@ -217,13 +217,13 @@ add_task(function formdata() {
let tab = gBrowser.addTab("data:text/html;charset=utf-8,<input%20id='input'>");
yield promiseBrowserLoaded(tab.linkedBrowser);
try {
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics = yield promiseStats();
info("Now changing form data");
yield setInputValue(tab.linkedBrowser, {id: "input", value: "This is some form data"});
SyncHandlers.get(tab.linkedBrowser).flush();
TabState.flush(tab.linkedBrowser);
let statistics2 = yield promiseStats();

View File

@ -18,23 +18,10 @@ for (let script of FRAME_SCRIPTS) {
mm.loadFrameScript(script, true);
}
mm.addMessageListener("SessionStore:setupSyncHandler", onSetupSyncHandler);
/**
* This keeps track of all SyncHandlers passed to chrome from frame scripts.
* We need this to let tests communicate with frame scripts and cause (a)sync
* flushes.
*/
let SyncHandlers = new WeakMap();
function onSetupSyncHandler(msg) {
SyncHandlers.set(msg.target, msg.objects.handler);
}
registerCleanupFunction(() => {
for (let script of FRAME_SCRIPTS) {
mm.removeDelayedFrameScript(script, true);
}
mm.removeMessageListener("SessionStore:setupSyncHandler", onSetupSyncHandler);
});
let tmp = {};
@ -43,7 +30,8 @@ Cu.import("resource://gre/modules/Task.jsm", tmp);
Cu.import("resource:///modules/sessionstore/SessionStore.jsm", tmp);
Cu.import("resource:///modules/sessionstore/SessionSaver.jsm", tmp);
Cu.import("resource:///modules/sessionstore/SessionFile.jsm", tmp);
let {Promise, Task, SessionStore, SessionSaver, SessionFile} = tmp;
Cu.import("resource:///modules/sessionstore/TabState.jsm", tmp);
let {Promise, Task, SessionStore, SessionSaver, SessionFile, TabState} = tmp;
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);