mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 944557 - Remove sessionstore-state-write. r=ttaubert
This commit is contained in:
parent
e5f3b4f65a
commit
213d2f3a40
@ -43,14 +43,6 @@ XPCOMUtils.defineLazyGetter(this, "gInterval", function () {
|
||||
return Services.prefs.getIntPref(PREF);
|
||||
});
|
||||
|
||||
// Wrap a string as a nsISupports.
|
||||
function createSupportsString(data) {
|
||||
let string = Cc["@mozilla.org/supports-string;1"]
|
||||
.createInstance(Ci.nsISupportsString);
|
||||
string.data = data;
|
||||
return string;
|
||||
}
|
||||
|
||||
// Notify observers about a given topic with a given subject.
|
||||
function notify(subject, topic) {
|
||||
Services.obs.notifyObservers(subject, topic, "");
|
||||
@ -252,19 +244,13 @@ let SessionSaverInternal = {
|
||||
* Write the given state object to disk.
|
||||
*/
|
||||
_writeState: function (state) {
|
||||
// Inform observers
|
||||
notify(null, "sessionstore-state-write");
|
||||
|
||||
stopWatchStart("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS", "WRITE_STATE_LONGEST_OP_MS");
|
||||
let data = JSON.stringify(state);
|
||||
stopWatchFinish("SERIALIZE_DATA_MS", "SERIALIZE_DATA_LONGEST_OP_MS");
|
||||
|
||||
// Give observers a chance to modify session data.
|
||||
data = this._notifyObserversBeforeStateWrite(data);
|
||||
|
||||
// Don't touch the file if an observer has deleted all state data.
|
||||
if (!data) {
|
||||
stopWatchCancel("WRITE_STATE_LONGEST_OP_MS");
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
// We update the time stamp before writing so that we don't write again
|
||||
// too soon, if saving is requested before the write completes. Without
|
||||
// this update we may save repeatedly if actions cause a runDelayed
|
||||
@ -285,14 +271,4 @@ let SessionSaverInternal = {
|
||||
|
||||
return promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Notify sessionstore-state-write observer and give them a
|
||||
* chance to modify session data before we'll write it to disk.
|
||||
*/
|
||||
_notifyObserversBeforeStateWrite: function (data) {
|
||||
let stateString = createSupportsString(data);
|
||||
notify(stateString, "sessionstore-state-write");
|
||||
return stateString.data;
|
||||
}
|
||||
};
|
||||
|
@ -98,7 +98,6 @@ skip-if = true
|
||||
[browser_394759_purge.js]
|
||||
[browser_423132.js]
|
||||
[browser_447951.js]
|
||||
[browser_448741.js]
|
||||
[browser_454908.js]
|
||||
[browser_456342.js]
|
||||
[browser_461634.js]
|
||||
|
@ -75,15 +75,13 @@ function test() {
|
||||
// Wait for the sessionstore.js file to be written before going on.
|
||||
// Note: we don't wait for the complete event, since if asyncCopy fails we
|
||||
// would timeout.
|
||||
Services.obs.addObserver(function (aSubject, aTopic, aData) {
|
||||
Services.obs.removeObserver(arguments.callee, aTopic);
|
||||
info("sessionstore.js is being written");
|
||||
|
||||
waitForSaveState(function(writing) {
|
||||
ok(writing, "sessionstore.js is being written");
|
||||
closedWindowCount = ss.getClosedWindowCount();
|
||||
is(closedWindowCount, 0, "Correctly set window count");
|
||||
|
||||
executeSoon(aCallback);
|
||||
}, "sessionstore-state-write", false);
|
||||
});
|
||||
|
||||
// Remove the sessionstore.js file before setting the interval to 0
|
||||
let profilePath = Services.dirsvc.get("ProfD", Ci.nsIFile);
|
||||
|
@ -1,62 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 448741 **/
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let uniqueName = "bug 448741";
|
||||
let uniqueValue = "as good as unique: " + Date.now();
|
||||
|
||||
// set a unique value on a new, blank tab
|
||||
var tab = gBrowser.addTab();
|
||||
tab.linkedBrowser.stop();
|
||||
ss.setTabValue(tab, uniqueName, uniqueValue);
|
||||
let valueWasCleaned = false;
|
||||
|
||||
// prevent our value from being written to disk
|
||||
function cleaningObserver(aSubject, aTopic, aData) {
|
||||
ok(aTopic == "sessionstore-state-write", "observed correct topic?");
|
||||
ok(aSubject instanceof Ci.nsISupportsString, "subject is a string?");
|
||||
ok(aSubject.data.indexOf(uniqueValue) > -1, "data contains our value?");
|
||||
|
||||
// find the data for the newly added tab and delete it
|
||||
let state = JSON.parse(aSubject.data);
|
||||
state.windows.forEach(function (winData) {
|
||||
winData.tabs.forEach(function (tabData) {
|
||||
if (tabData.extData && uniqueName in tabData.extData &&
|
||||
tabData.extData[uniqueName] == uniqueValue) {
|
||||
delete tabData.extData[uniqueName];
|
||||
valueWasCleaned = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ok(valueWasCleaned, "found and removed the specific tab value");
|
||||
aSubject.data = JSON.stringify(state);
|
||||
Services.obs.removeObserver(cleaningObserver, aTopic);
|
||||
}
|
||||
|
||||
// make sure that all later observers don't see that value any longer
|
||||
function checkingObserver(aSubject, aTopic, aData) {
|
||||
ok(valueWasCleaned && aSubject instanceof Ci.nsISupportsString,
|
||||
"ready to check the cleaned state?");
|
||||
ok(aSubject.data.indexOf(uniqueValue) == -1, "data no longer contains our value?");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab);
|
||||
Services.obs.removeObserver(checkingObserver, aTopic);
|
||||
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
|
||||
gPrefService.clearUserPref("browser.sessionstore.interval");
|
||||
finish();
|
||||
}
|
||||
|
||||
// last added observers are invoked first
|
||||
Services.obs.addObserver(checkingObserver, "sessionstore-state-write", false);
|
||||
Services.obs.addObserver(cleaningObserver, "sessionstore-state-write", false);
|
||||
|
||||
// trigger an immediate save operation
|
||||
gPrefService.setIntPref("browser.sessionstore.interval", 0);
|
||||
}
|
@ -20,11 +20,12 @@ function testBug600545() {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
});
|
||||
|
||||
// This tests the following use case:
|
||||
// When multiple windows are open and browser.sessionstore.resume_from_crash
|
||||
// preference is false, tab session data for non-active window is stripped for
|
||||
// non-pinned tabs. This occurs after "sessionstore-state-write" fires which
|
||||
// will only fire in this case if there is at least one pinned tab.
|
||||
// This tests the following use case: When multiple windows are open
|
||||
// and browser.sessionstore.resume_from_crash preference is false,
|
||||
// tab session data for non-active window is stripped for non-pinned
|
||||
// tabs. This occurs after "sessionstore-state-write-complete"
|
||||
// fires which will only fire in this case if there is at least one
|
||||
// pinned tab.
|
||||
let state = { windows: [
|
||||
{
|
||||
tabs: [
|
||||
|
@ -1,125 +1,86 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let newWin;
|
||||
let newTab;
|
||||
|
||||
function test() {
|
||||
add_task(function* setup() {
|
||||
/** Test for Bug 625016 - Restore windows closed in succession to quit (non-OSX only) **/
|
||||
|
||||
// We'll test this by opening a new window, waiting for the save event, then
|
||||
// closing that window. We'll observe the "sessionstore-state-write" notification
|
||||
// and check that the state contains no _closedWindows. We'll then add a new
|
||||
// tab and make sure that the state following that was reset and the closed
|
||||
// window is now in _closedWindows.
|
||||
// We'll test this by opening a new window, waiting for the save
|
||||
// event, then closing that window. We'll observe the
|
||||
// "sessionstore-state-write-complete" notification and check that
|
||||
// the state contains no _closedWindows. We'll then add a new tab
|
||||
// and make sure that the state following that was reset and the
|
||||
// closed window is now in _closedWindows.
|
||||
|
||||
waitForExplicitFinish();
|
||||
requestLongerTimeout(2);
|
||||
|
||||
// We speed up the interval between session saves to ensure that the test
|
||||
// runs quickly.
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 4000);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
});
|
||||
yield forceSaveState();
|
||||
|
||||
waitForSaveState(setup);
|
||||
}
|
||||
|
||||
function setup() {
|
||||
// We'll clear all closed windows to make sure our state is clean
|
||||
// forgetClosedWindow doesn't trigger a delayed save
|
||||
while (ss.getClosedWindowCount()) {
|
||||
ss.forgetClosedWindow(0);
|
||||
}
|
||||
is(ss.getClosedWindowCount(), 0, "starting with no closed windows");
|
||||
});
|
||||
|
||||
// Open a new window, which should trigger a save event soon.
|
||||
waitForSaveState(onSaveState);
|
||||
newWin = openDialog(location, "_blank", "chrome,all,dialog=no", "about:rights");
|
||||
}
|
||||
|
||||
function onSaveState() {
|
||||
add_task(function* new_window() {
|
||||
let newWin;
|
||||
try {
|
||||
ss.getWindowValue(newWin, "foobar");
|
||||
} catch (e) {
|
||||
// The window is untracked which means that the saveState() call isn't the
|
||||
// one we're waiting for. It's most likely been triggered by an async
|
||||
// collection running in the background.
|
||||
waitForSaveState(onSaveState);
|
||||
return;
|
||||
newWin = yield promiseNewWindowLoaded();
|
||||
let tab = newWin.gBrowser.addTab("http://example.com/browser_625016.js?" + Math.random());
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
// Double check that we have no closed windows
|
||||
is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
|
||||
|
||||
yield promiseWindowClosed(newWin);
|
||||
newWin = null;
|
||||
|
||||
let state = JSON.parse((yield promiseSaveFileContents()));
|
||||
is(state.windows.length, 2,
|
||||
"observe1: 2 windows in data written to disk");
|
||||
is(state._closedWindows.length, 0,
|
||||
"observe1: no closed windows in data written to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe1: 1 closed window according to API");
|
||||
} finally {
|
||||
if (newWin) {
|
||||
yield promiseWindowClosed(newWin);
|
||||
}
|
||||
yield forceSaveState();
|
||||
}
|
||||
|
||||
// Double check that we have no closed windows
|
||||
is(ss.getClosedWindowCount(), 0, "no closed windows on first save");
|
||||
|
||||
Services.obs.addObserver(observe1, "sessionstore-state-write", false);
|
||||
|
||||
// Now close the new window, which should trigger another save event
|
||||
newWin.close();
|
||||
}
|
||||
|
||||
function observe1(aSubject, aTopic, aData) {
|
||||
info("observe1: " + aTopic);
|
||||
switch (aTopic) {
|
||||
case "sessionstore-state-write":
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
let state = JSON.parse(aSubject.data);
|
||||
is(state.windows.length, 2,
|
||||
"observe1: 2 windows in data being writted to disk");
|
||||
is(state._closedWindows.length, 0,
|
||||
"observe1: no closed windows in data being writted to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe1: 1 closed window according to API");
|
||||
Services.obs.removeObserver(observe1, "sessionstore-state-write");
|
||||
Services.obs.addObserver(observe1, "sessionstore-state-write-complete", false);
|
||||
break;
|
||||
case "sessionstore-state-write-complete":
|
||||
Services.obs.removeObserver(observe1, "sessionstore-state-write-complete");
|
||||
openTab();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function observe2(aSubject, aTopic, aData) {
|
||||
info("observe2: " + aTopic);
|
||||
switch (aTopic) {
|
||||
case "sessionstore-state-write":
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
let state = JSON.parse(aSubject.data);
|
||||
is(state.windows.length, 1,
|
||||
"observe2: 1 window in data being writted to disk");
|
||||
is(state._closedWindows.length, 1,
|
||||
"observe2: 1 closed window in data being writted to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe2: 1 closed window according to API");
|
||||
Services.obs.removeObserver(observe2, "sessionstore-state-write");
|
||||
Services.obs.addObserver(observe2, "sessionstore-state-write-complete", false);
|
||||
break;
|
||||
case "sessionstore-state-write-complete":
|
||||
Services.obs.removeObserver(observe2, "sessionstore-state-write-complete");
|
||||
done();
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// We'll open a tab, which should trigger another state save which would wipe
|
||||
// the _shouldRestore attribute from the closed window
|
||||
function openTab() {
|
||||
Services.obs.addObserver(observe2, "sessionstore-state-write", false);
|
||||
newTab = gBrowser.addTab("about:mozilla");
|
||||
}
|
||||
add_task(function* new_tab() {
|
||||
let newTab;
|
||||
try {
|
||||
newTab = gBrowser.addTab("about:mozilla");
|
||||
|
||||
function done() {
|
||||
gBrowser.removeTab(newTab);
|
||||
let state = JSON.parse((yield promiseSaveFileContents()));
|
||||
is(state.windows.length, 1,
|
||||
"observe2: 1 window in data being written to disk");
|
||||
is(state._closedWindows.length, 1,
|
||||
"observe2: 1 closed window in data being written to disk");
|
||||
|
||||
// The API still treats the closed window as closed, so ensure that window is there
|
||||
is(ss.getClosedWindowCount(), 1,
|
||||
"observe2: 1 closed window according to API");
|
||||
} finally {
|
||||
gBrowser.removeTab(newTab);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
add_task(function* done() {
|
||||
// The API still represents the closed window as closed, so we can clear it
|
||||
// with the API, but just to make sure...
|
||||
is(ss.getClosedWindowCount(), 1, "1 closed window according to API");
|
||||
ss.forgetClosedWindow(0);
|
||||
executeSoon(finish);
|
||||
}
|
||||
|
||||
// is(ss.getClosedWindowCount(), 1, "1 closed window according to API");
|
||||
while (ss.getClosedWindowCount()) {
|
||||
ss.forgetClosedWindow(0);
|
||||
}
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
});
|
||||
|
@ -162,15 +162,9 @@ function waitForWindowClose(aWin, aCallback) {
|
||||
}
|
||||
|
||||
function forceWriteState(aCallback) {
|
||||
Services.obs.addObserver(function observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "sessionstore-state-write") {
|
||||
Services.obs.removeObserver(observe, aTopic);
|
||||
Services.prefs.clearUserPref("browser.sessionstore.interval");
|
||||
aSubject.QueryInterface(Ci.nsISupportsString);
|
||||
aCallback(JSON.parse(aSubject.data));
|
||||
}
|
||||
}, "sessionstore-state-write", false);
|
||||
Services.prefs.setIntPref("browser.sessionstore.interval", 0);
|
||||
return promiseSaveFileContents().then(function(data) {
|
||||
aCallback(JSON.parse(data));
|
||||
});
|
||||
}
|
||||
|
||||
function testOnWindow(aIsPrivate, aCallback) {
|
||||
|
@ -24,43 +24,9 @@ let gDecoder = new TextDecoder();
|
||||
let gSSData;
|
||||
let gSSBakData;
|
||||
|
||||
// Wait for a state write to complete and then execute a callback.
|
||||
function waitForSaveStateComplete(aSaveStateCallback) {
|
||||
let topic = "sessionstore-state-write-complete";
|
||||
|
||||
function observer() {
|
||||
Services.prefs.clearUserPref(PREF_SS_INTERVAL);
|
||||
Services.obs.removeObserver(observer, topic);
|
||||
executeSoon(function taskCallback() {
|
||||
Task.spawn(aSaveStateCallback);
|
||||
});
|
||||
}
|
||||
|
||||
Services.obs.addObserver(observer, topic, false);
|
||||
}
|
||||
|
||||
// Register next test callback and trigger state saving change.
|
||||
function nextTest(testFunc) {
|
||||
waitForSaveStateComplete(testFunc);
|
||||
|
||||
// We set the interval for session store state saves to be zero
|
||||
// to cause a save ASAP.
|
||||
Services.prefs.setIntPref(PREF_SS_INTERVAL, 0);
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
// Cleaning up after the test: removing the sessionstore.bak file.
|
||||
Task.spawn(function cleanupTask() {
|
||||
yield OS.File.remove(backupPath);
|
||||
});
|
||||
});
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
nextTest(testAfterFirstWrite);
|
||||
}
|
||||
|
||||
function testAfterFirstWrite() {
|
||||
add_task(function* testAfterFirstWrite() {
|
||||
// Ensure sessionstore.bak is not created. We start with a clean
|
||||
// profile so there was nothing to move to sessionstore.bak before
|
||||
// initially writing sessionstore.js
|
||||
@ -78,10 +44,10 @@ function testAfterFirstWrite() {
|
||||
// and a backup would not be triggered again.
|
||||
yield OS.File.move(path, backupPath);
|
||||
|
||||
nextTest(testReadBackup);
|
||||
}
|
||||
yield forceSaveState();
|
||||
});
|
||||
|
||||
function testReadBackup() {
|
||||
add_task(function* testReadBackup() {
|
||||
// Ensure sessionstore.bak is finally created.
|
||||
let ssExists = yield OS.File.exists(path);
|
||||
let ssBackupExists = yield OS.File.exists(backupPath);
|
||||
@ -114,10 +80,10 @@ function testReadBackup() {
|
||||
is(ssDataRead, gSSBakData,
|
||||
"SessionFile.read read sessionstore.bak correctly.");
|
||||
|
||||
nextTest(testBackupUnchanged);
|
||||
}
|
||||
yield forceSaveState();
|
||||
});
|
||||
|
||||
function testBackupUnchanged() {
|
||||
add_task(function* testBackupUnchanged() {
|
||||
// Ensure sessionstore.bak is backed up only once.
|
||||
|
||||
// Read sessionstore.bak data.
|
||||
@ -125,6 +91,9 @@ function testBackupUnchanged() {
|
||||
let ssBakData = gDecoder.decode(array);
|
||||
// Ensure the sessionstore.bak did not change.
|
||||
is(ssBakData, gSSBakData, "sessionstore.bak is unchanged.");
|
||||
});
|
||||
|
||||
executeSoon(finish);
|
||||
}
|
||||
add_task(function* cleanup() {
|
||||
// Cleaning up after the test: removing the sessionstore.bak file.
|
||||
yield OS.File.remove(backupPath);
|
||||
});
|
||||
|
@ -243,12 +243,7 @@ function waitForTopic(aTopic, aTimeout, aCallback) {
|
||||
|
||||
/**
|
||||
* Wait until session restore has finished collecting its data and is
|
||||
* getting ready to write that data ("sessionstore-state-write").
|
||||
*
|
||||
* This function is meant to be called immediately after the code
|
||||
* that will trigger the saving.
|
||||
*
|
||||
* Note that this does not wait for the disk write to be complete.
|
||||
* has written that data ("sessionstore-state-write-complete").
|
||||
*
|
||||
* @param {function} aCallback If sessionstore-state-write is sent
|
||||
* within buffering interval + 100 ms, the callback is passed |true|,
|
||||
@ -257,7 +252,7 @@ function waitForTopic(aTopic, aTimeout, aCallback) {
|
||||
function waitForSaveState(aCallback) {
|
||||
let timeout = 100 +
|
||||
Services.prefs.getIntPref("browser.sessionstore.interval");
|
||||
return waitForTopic("sessionstore-state-write", timeout, aCallback);
|
||||
return waitForTopic("sessionstore-state-write-complete", timeout, aCallback);
|
||||
}
|
||||
function promiseSaveState() {
|
||||
let deferred = Promise.defer();
|
||||
@ -272,22 +267,30 @@ function promiseSaveState() {
|
||||
function forceSaveState() {
|
||||
let promise = promiseSaveState();
|
||||
const PREF = "browser.sessionstore.interval";
|
||||
let original = Services.prefs.getIntPref(PREF);
|
||||
// Set interval to an arbitrary non-0 duration
|
||||
// to ensure that setting it to 0 will notify observers
|
||||
Services.prefs.setIntPref(PREF, 1000);
|
||||
Services.prefs.setIntPref(PREF, 0);
|
||||
return promise.then(
|
||||
function onSuccess(x) {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
Services.prefs.setIntPref(PREF, original);
|
||||
return x;
|
||||
},
|
||||
function onError(x) {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
Services.prefs.setIntPref(PREF, original);
|
||||
throw x;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function promiseSaveFileContents() {
|
||||
let promise = forceSaveState();
|
||||
return promise.then(function() {
|
||||
return OS.File.read(OS.Path.join(OS.Constants.Path.profileDir, "sessionstore.js"), { encoding: "utf-8" });
|
||||
});
|
||||
}
|
||||
|
||||
function whenBrowserLoaded(aBrowser, aCallback = next, ignoreSubFrames = true) {
|
||||
aBrowser.addEventListener("load", function onLoad(event) {
|
||||
if (!ignoreSubFrames || event.target == aBrowser.contentDocument) {
|
||||
@ -321,6 +324,11 @@ function whenWindowLoaded(aWindow, aCallback = next) {
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
function promiseWindowLoaded(aWindow) {
|
||||
let deferred = Promise.defer();
|
||||
whenWindowLoaded(aWindow, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function whenTabRestored(aTab, aCallback = next) {
|
||||
aTab.addEventListener("SSTabRestored", function onRestored(aEvent) {
|
||||
|
Loading…
Reference in New Issue
Block a user