Bug 974086 - [australis-measuring] UITour.seenPageIDs should persist across sessions. r=MattN sr=taras

This commit is contained in:
Blair McBride 2014-02-27 22:25:44 +13:00
parent 72e872508d
commit 8b81ea1fd3
2 changed files with 123 additions and 11 deletions

View File

@ -26,6 +26,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry",
const UITOUR_PERMISSION = "uitour";
const PREF_PERM_BRANCH = "browser.uitour.";
const PREF_SEENPAGEIDS = "browser.uitour.seenPageIDs";
const MAX_BUTTONS = 4;
const BUCKET_NAME = "UITour";
@ -36,10 +37,12 @@ const BUCKET_TIMESTEPS = [
60 * 60 * 1000, // Until 1 hour after tab is closed/inactive.
];
// Time after which seen Page IDs expire.
const SEENPAGEID_EXPIRY = 2 * 7 * 24 * 60 * 60 * 1000; // 2 weeks.
this.UITour = {
seenPageIDs: new Set(),
seenPageIDs: null,
pageIDSourceTabs: new WeakMap(),
pageIDSourceWindows: new WeakMap(),
/* Map from browser windows to a set of tabs in which a tour is open */
@ -115,10 +118,72 @@ this.UITour = {
]),
init: function() {
// Lazy getter is initialized here so it can be replicated any time
// in a test.
delete this.seenPageIDs;
Object.defineProperty(this, "seenPageIDs", {
get: this.restoreSeenPageIDs.bind(this),
configurable: true,
});
UITelemetry.addSimpleMeasureFunction("UITour",
this.getTelemetry.bind(this));
},
restoreSeenPageIDs: function() {
delete this.seenPageIDs;
if (UITelemetry.enabled) {
let dateThreshold = Date.now() - SEENPAGEID_EXPIRY;
try {
let data = Services.prefs.getCharPref(PREF_SEENPAGEIDS);
data = new Map(JSON.parse(data));
for (let [pageID, details] of data) {
if (typeof pageID != "string" ||
typeof details != "object" ||
typeof details.lastSeen != "number" ||
details.lastSeen < dateThreshold) {
data.delete(pageID);
}
}
this.seenPageIDs = data;
} catch (e) {}
}
if (!this.seenPageIDs)
this.seenPageIDs = new Map();
this.persistSeenIDs();
return this.seenPageIDs;
},
addSeenPageID: function(aPageID) {
if (!UITelemetry.enabled)
return;
this.seenPageIDs.set(aPageID, {
lastSeen: Date.now(),
});
this.persistSeenIDs();
},
persistSeenIDs: function() {
if (this.seenPageIDs.size === 0) {
Services.prefs.clearUserPref(PREF_SEENPAGEIDS);
return;
}
Services.prefs.setCharPref(PREF_SEENPAGEIDS,
JSON.stringify([...this.seenPageIDs]));
},
onPageEvent: function(aEvent) {
let contentDocument = null;
if (aEvent.target instanceof Ci.nsIDOMHTMLDocument)
@ -161,11 +226,15 @@ this.UITour = {
switch (action) {
case "registerPageID": {
// This is only relevant if Telemtry is enabled.
if (!UITelemetry.enabled)
break;
// We don't want to allow BrowserUITelemetry.BUCKET_SEPARATOR in the
// pageID, as it could make parsing the telemetry bucket name difficult.
if (typeof data.pageID == "string" &&
!data.pageID.contains(BrowserUITelemetry.BUCKET_SEPARATOR)) {
this.seenPageIDs.add(data.pageID);
this.addSeenPageID(data.pageID);
// Store tabs and windows separately so we don't need to loop over all
// tabs when a window is closed.
@ -444,7 +513,7 @@ this.UITour = {
getTelemetry: function() {
return {
seenPageIDs: [...this.seenPageIDs],
seenPageIDs: [...this.seenPageIDs.keys()],
};
},

View File

@ -8,23 +8,68 @@ let gContentAPI;
let gContentWindow;
Components.utils.import("resource:///modules/UITour.jsm");
Components.utils.import("resource://gre/modules/UITelemetry.jsm");
Components.utils.import("resource:///modules/BrowserUITelemetry.jsm");
function test() {
UITelemetry._enabled = true;
registerCleanupFunction(function() {
UITour.seenPageIDs.clear();
Services.prefs.clearUserPref("browser.uitour.seenPageIDs");
resetSeenPageIDsLazyGetter();
UITelemetry._enabled = undefined;
BrowserUITelemetry.setBucket(null);
delete window.UITelemetry;
delete window.BrowserUITelemetry;
});
UITourTest();
}
function resetSeenPageIDsLazyGetter() {
delete UITour.seenPageIDs;
// This should be kept in sync with how UITour.init() sets this.
Object.defineProperty(UITour, "seenPageIDs", {
get: UITour.restoreSeenPageIDs.bind(UITour),
configurable: true,
});
}
function checkExpectedSeenPageIDs(expected) {
is(UITour.seenPageIDs.size, expected.length, "Should be " + expected.length + " total seen page IDs");
for (let id of expected)
ok(UITour.seenPageIDs.has(id), "Should have seen '" + id + "' page ID");
let prefData = Services.prefs.getCharPref("browser.uitour.seenPageIDs");
prefData = new Map(JSON.parse(prefData));
is(prefData.size, expected.length, "Should be " + expected.length + " total seen page IDs persisted");
for (let id of expected)
ok(prefData.has(id), "Should have seen '" + id + "' page ID persisted");
}
let tests = [
function test_seenPageIDs_1(done) {
function test_seenPageIDs_restore(done) {
info("Setting up seenPageIDs to be restored from pref");
let data = JSON.stringify([
["savedID1", { lastSeen: Date.now() }],
["savedID2", { lastSeen: Date.now() }],
// 3 weeks ago, should auto expire.
["savedID3", { lastSeen: Date.now() - 3 * 7 * 24 * 60 * 60 * 1000 }],
]);
Services.prefs.setCharPref("browser.uitour.seenPageIDs",
data);
resetSeenPageIDsLazyGetter();
checkExpectedSeenPageIDs(["savedID1", "savedID2"]);
done();
},
function test_seenPageIDs_set_1(done) {
gContentAPI.registerPageID("testpage1");
is(UITour.seenPageIDs.size, 1, "Should be 1 seen page ID");
ok(UITour.seenPageIDs.has("testpage1"), "Should have seen 'testpage1' page ID");
checkExpectedSeenPageIDs(["savedID1", "savedID2", "testpage1"]);
const PREFIX = BrowserUITelemetry.BUCKET_PREFIX;
const SEP = BrowserUITelemetry.BUCKET_SEPARATOR;
@ -42,12 +87,10 @@ let tests = [
BrowserUITelemetry.setBucket(null);
done();
},
function test_seenPageIDs_2(done) {
function test_seenPageIDs_set_2(done) {
gContentAPI.registerPageID("testpage2");
is(UITour.seenPageIDs.size, 2, "Should be 2 seen page IDs");
ok(UITour.seenPageIDs.has("testpage1"), "Should have seen 'testpage1' page ID");
ok(UITour.seenPageIDs.has("testpage2"), "Should have seen 'testpage2' page ID");
checkExpectedSeenPageIDs(["savedID1", "savedID2", "testpage1", "testpage2"]);
const PREFIX = BrowserUITelemetry.BUCKET_PREFIX;
const SEP = BrowserUITelemetry.BUCKET_SEPARATOR;