mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 01:05:45 +00:00
Bug 911115 - Simple tests for the tab state cache. r=ttaubert
This commit is contained in:
parent
4dc222fd0e
commit
d431f68a6f
@ -20,6 +20,7 @@ MOCHITEST_BROWSER_FILES = \
|
||||
browser_input_sample.html \
|
||||
browser_pageshow.js \
|
||||
browser_sessionStorage.js \
|
||||
browser_tabStateCache.js \
|
||||
browser_upgrade_backup.js \
|
||||
browser_windowRestore_perwindowpb.js \
|
||||
browser_248970_b_perwindowpb.js \
|
||||
|
@ -7,26 +7,6 @@ Cu.import("resource://gre/modules/Task.jsm", Scope);
|
||||
Cu.import("resource://gre/modules/Promise.jsm", Scope);
|
||||
let {Task, Promise} = Scope;
|
||||
|
||||
function promiseBrowserLoaded(aBrowser) {
|
||||
let deferred = Promise.defer();
|
||||
whenBrowserLoaded(aBrowser, () => deferred.resolve());
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function forceWriteState() {
|
||||
let deferred = Promise.defer();
|
||||
const PREF = "browser.sessionstore.interval";
|
||||
const TOPIC = "sessionstore-state-write";
|
||||
|
||||
Services.obs.addObserver(function observe() {
|
||||
Services.obs.removeObserver(observe, TOPIC);
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
deferred.resolve();
|
||||
}, TOPIC, false);
|
||||
|
||||
Services.prefs.setIntPref(PREF, 0);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function waitForStorageChange(aTab) {
|
||||
let deferred = Promise.defer();
|
||||
@ -57,7 +37,7 @@ function test() {
|
||||
// Flush loading and next save, call getBrowserState()
|
||||
// a few times to ensure that everything is cached.
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
yield forceWriteState();
|
||||
yield forceSaveState();
|
||||
info("Calling getBrowserState() to populate cache");
|
||||
ss.getBrowserState();
|
||||
|
||||
@ -66,7 +46,7 @@ function test() {
|
||||
win.sessionStorage[SESSION_STORAGE_KEY] = SESSION_STORAGE_VALUE;
|
||||
let storageChanged = yield storageChangedPromise;
|
||||
ok(storageChanged, "Changing sessionStorage triggered the right message");
|
||||
yield forceWriteState();
|
||||
yield forceSaveState();
|
||||
|
||||
let state = ss.getBrowserState();
|
||||
ok(state.indexOf(SESSION_STORAGE_KEY) != -1, "Key appears in state");
|
||||
@ -78,7 +58,7 @@ function test() {
|
||||
win.localStorage[LOCAL_STORAGE_KEY] = LOCAL_STORAGE_VALUE;
|
||||
storageChanged = yield storageChangedPromise;
|
||||
ok(!storageChanged, "Changing localStorage did not trigger a message");
|
||||
yield forceWriteState();
|
||||
yield forceSaveState();
|
||||
|
||||
state = ss.getBrowserState();
|
||||
ok(state.indexOf(LOCAL_STORAGE_KEY) == -1, "Key does not appear in state");
|
||||
|
138
browser/components/sessionstore/test/browser_tabStateCache.js
Normal file
138
browser/components/sessionstore/test/browser_tabStateCache.js
Normal file
@ -0,0 +1,138 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let wrapper = {};
|
||||
Cu.import("resource:///modules/sessionstore/TabStateCache.jsm", wrapper);
|
||||
let {TabStateCache} = wrapper;
|
||||
|
||||
// The number of tabs that are present in the browser but that we're not dealing
|
||||
// with. This should be one (for an empty about:blank), but let's not make this
|
||||
// a magic number.
|
||||
let numberOfUntrackedTabs;
|
||||
|
||||
// Arbitrary URL prefix, used to generate the URL of pages we visit
|
||||
const URL_PREFIX = "http://example.org:80/";
|
||||
|
||||
/**
|
||||
* Check tab state cache telemetry statistics before and after an operation.
|
||||
*
|
||||
* @param {function} f The operation being measured. If it returns a promise,
|
||||
* we wait until the promise is resolved before proceeding.
|
||||
* @return {promise}
|
||||
*/
|
||||
function getTelemetryDelta(f) {
|
||||
return Task.spawn(function() {
|
||||
let KEYS = ["hits", "misses", "clears"];
|
||||
let old = {};
|
||||
for (let key of KEYS) {
|
||||
old[key] = TabStateCache[key];
|
||||
}
|
||||
yield f();
|
||||
let result = {};
|
||||
for (let key of KEYS) {
|
||||
result[key] = TabStateCache[key] - old[key];
|
||||
}
|
||||
ok(result.hits >= 0, "Sanity check: hits have not decreased");
|
||||
ok(result.misses >= 0, "Sanity check: misses have not decreased");
|
||||
ok(result.clears >= 0, "Sanity check: clears have not decreased");
|
||||
throw new Task.Result(result);
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function init() {
|
||||
// Start with an empty cache
|
||||
closeAllButPrimaryWindow();
|
||||
TabStateCache.clear();
|
||||
numberOfUntrackedTabs = gBrowser.tabs.length;
|
||||
info("Starting with " + numberOfUntrackedTabs + " tabs");
|
||||
});
|
||||
|
||||
add_task(function add_remove() {
|
||||
info("Adding the first tab");
|
||||
// Initialize one tab, save to initialize cache
|
||||
let tab1 = gBrowser.addTab(URL_PREFIX + "?tab1");
|
||||
yield promiseBrowserLoaded(tab1.linkedBrowser);
|
||||
yield getTelemetryDelta(forceSaveState);
|
||||
|
||||
// Save/collect again a few times, ensure that we always hit
|
||||
info("Save/collect a few times with one tab");
|
||||
for (let collector of [forceSaveState, ss.getBrowserState]) {
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
let PREFIX = "Trivial test " + i + " using " + collector.name + ": ";
|
||||
let delta = yield getTelemetryDelta(collector);
|
||||
is(delta.hits, numberOfUntrackedTabs + 1, PREFIX + " has at least one hit " + delta.hits);
|
||||
is(delta.misses, 0, PREFIX + " has no miss");
|
||||
is(delta.clears, 0, PREFIX + " has no clear");
|
||||
}
|
||||
}
|
||||
|
||||
// Add a second tab, ensure that we have both hits and misses
|
||||
info("Adding the second tab");
|
||||
let tab2 = gBrowser.addTab(URL_PREFIX + "?tab2");
|
||||
yield promiseBrowserLoaded(tab2.linkedBrowser);
|
||||
let PREFIX = "Adding second tab: ";
|
||||
let delta = yield getTelemetryDelta(forceSaveState);
|
||||
is(delta.hits, numberOfUntrackedTabs + 1, PREFIX + " we hit one tab");
|
||||
is(delta.misses, 1, PREFIX + " we missed one tab");
|
||||
is(delta.clears, 0, PREFIX + " has no clear");
|
||||
|
||||
// Save/collect again a few times, ensure that we always hit
|
||||
info("Save/collect a few times with two tabs");
|
||||
for (let collector of [forceSaveState, ss.getBrowserState]) {
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
let PREFIX = "With two tabs " + i + " using " + collector.name + ": ";
|
||||
let delta = yield getTelemetryDelta(collector);
|
||||
is(delta.hits, numberOfUntrackedTabs + 2, PREFIX + " both tabs hit");
|
||||
is(delta.misses, 0, PREFIX + " has no miss");
|
||||
is(delta.clears, 0, PREFIX + " has no clear");
|
||||
}
|
||||
}
|
||||
|
||||
info("Removing second tab");
|
||||
gBrowser.removeTab(tab2);
|
||||
PREFIX = "Removing second tab: ";
|
||||
delta = yield getTelemetryDelta(forceSaveState);
|
||||
is(delta.hits, numberOfUntrackedTabs + 1, PREFIX + " we hit for one tab");
|
||||
is(delta.misses, 0, PREFIX + " has no miss");
|
||||
is(delta.clears, 0, PREFIX + " has no clear");
|
||||
|
||||
info("Removing first tab");
|
||||
gBrowser.removeTab(tab1);
|
||||
});
|
||||
|
||||
add_task(function browsing() {
|
||||
info("Opening first browsing tab");
|
||||
let tab1 = gBrowser.addTab(URL_PREFIX + "?do_not_move_from_here");
|
||||
let browser1 = tab1.linkedBrowser;
|
||||
yield promiseBrowserLoaded(browser1);
|
||||
yield forceSaveState();
|
||||
|
||||
info("Opening second browsing tab");
|
||||
let tab2 = gBrowser.addTab(URL_PREFIX + "?start_browsing_from_here");
|
||||
let browser2 = tab2.linkedBrowser;
|
||||
yield promiseBrowserLoaded(browser2);
|
||||
|
||||
for (let i = 0; i < 4; ++i) {
|
||||
let url = URL_PREFIX + "?browsing" + i; // Arbitrary url, easy to recognize
|
||||
let PREFIX = "Browsing to " + url;
|
||||
info(PREFIX);
|
||||
let delta = yield getTelemetryDelta(function() {
|
||||
return Task.spawn(function() {
|
||||
// Move to new URI then save session
|
||||
let promise = promiseBrowserLoaded(browser2);
|
||||
browser2.loadURI(url);
|
||||
yield promise;
|
||||
yield forceSaveState();
|
||||
});
|
||||
});
|
||||
is(delta.hits, numberOfUntrackedTabs + 1, PREFIX + " has at least one hit");
|
||||
is(delta.misses, 1, PREFIX + " has one miss");
|
||||
is(delta.clears, 0, PREFIX + " has no clear");
|
||||
}
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab1);
|
||||
});
|
||||
|
||||
|
@ -240,6 +240,34 @@ function waitForSaveState(aCallback) {
|
||||
Services.prefs.getIntPref("browser.sessionstore.interval");
|
||||
return waitForTopic("sessionstore-state-write", timeout, aCallback);
|
||||
}
|
||||
function promiseSaveState() {
|
||||
let deferred = Promise.defer();
|
||||
waitForSaveState(isSuccessful => {
|
||||
if (isSuccessful) {
|
||||
deferred.resolve();
|
||||
} else {
|
||||
deferred.reject(new Error("timeout"));
|
||||
}});
|
||||
return deferred.promise;
|
||||
}
|
||||
function forceSaveState() {
|
||||
let promise = promiseSaveState();
|
||||
const PREF = "browser.sessionstore.interval";
|
||||
// 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);
|
||||
return x;
|
||||
},
|
||||
function onError(x) {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
throw x;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function whenBrowserLoaded(aBrowser, aCallback = next) {
|
||||
aBrowser.addEventListener("load", function onLoad() {
|
||||
@ -247,6 +275,22 @@ function whenBrowserLoaded(aBrowser, aCallback = next) {
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
}
|
||||
function promiseBrowserLoaded(aBrowser) {
|
||||
let deferred = Promise.defer();
|
||||
whenBrowserLoaded(aBrowser, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
function whenBrowserUnloaded(aBrowser, aContainer, aCallback = next) {
|
||||
aBrowser.addEventListener("unload", function onUnload() {
|
||||
aBrowser.removeEventListener("unload", onUnload, true);
|
||||
executeSoon(aCallback);
|
||||
}, true);
|
||||
}
|
||||
function promiseBrowserUnloaded(aBrowser, aContainer) {
|
||||
let deferred = Promise.defer();
|
||||
whenBrowserUnloaded(aBrowser, aContainer, deferred.resolve);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function whenWindowLoaded(aWindow, aCallback = next) {
|
||||
aWindow.addEventListener("load", function windowLoadListener() {
|
||||
|
Loading…
Reference in New Issue
Block a user