michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: const {utils: Cu} = Components; michael@0: michael@0: michael@0: Cu.import("resource://gre/modules/Promise.jsm"); michael@0: Cu.import("resource://gre/modules/Metrics.jsm"); michael@0: Cu.import("resource://gre/modules/Task.jsm"); michael@0: Cu.import("resource://gre/modules/services-common/utils.js"); michael@0: Cu.import("resource://gre/modules/services/datareporting/sessions.jsm"); michael@0: Cu.import("resource://gre/modules/services/healthreport/providers.jsm"); michael@0: michael@0: michael@0: function run_test() { michael@0: run_next_test(); michael@0: } michael@0: michael@0: add_test(function test_constructor() { michael@0: let provider = new SessionsProvider(); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: add_task(function test_init() { michael@0: let storage = yield Metrics.Storage("init"); michael@0: let provider = new SessionsProvider(); michael@0: yield provider.init(storage); michael@0: yield provider.shutdown(); michael@0: michael@0: yield storage.close(); michael@0: }); michael@0: michael@0: function monkeypatchStartupInfo(recorder, start=new Date(), offset=500) { michael@0: Object.defineProperty(recorder, "_getStartupInfo", { michael@0: value: function _getStartupInfo() { michael@0: return { michael@0: process: start, michael@0: main: new Date(start.getTime() + offset), michael@0: firstPaint: new Date(start.getTime() + 2 * offset), michael@0: sessionRestored: new Date(start.getTime() + 3 * offset), michael@0: }; michael@0: } michael@0: }); michael@0: } michael@0: michael@0: function sleep(wait) { michael@0: let deferred = Promise.defer(); michael@0: michael@0: let timer = CommonUtils.namedTimer(function onTimer() { michael@0: deferred.resolve(); michael@0: }, wait, deferred.promise, "_sleepTimer"); michael@0: michael@0: return deferred.promise; michael@0: } michael@0: michael@0: function getProvider(name, now=new Date(), init=true) { michael@0: return Task.spawn(function () { michael@0: let storage = yield Metrics.Storage(name); michael@0: let provider = new SessionsProvider(); michael@0: michael@0: let recorder = new SessionRecorder("testing." + name + ".sessions."); michael@0: monkeypatchStartupInfo(recorder, now); michael@0: provider.healthReporter = {sessionRecorder: recorder}; michael@0: recorder.onStartup(); michael@0: michael@0: if (init) { michael@0: yield provider.init(storage); michael@0: } michael@0: michael@0: throw new Task.Result([provider, storage, recorder]); michael@0: }); michael@0: } michael@0: michael@0: add_task(function test_current_session() { michael@0: let now = new Date(); michael@0: let [provider, storage, recorder] = yield getProvider("current_session", now); michael@0: michael@0: yield sleep(25); michael@0: recorder.onActivity(true); michael@0: michael@0: let current = provider.getMeasurement("current", 3); michael@0: let values = yield current.getValues(); michael@0: let fields = values.singular; michael@0: michael@0: for (let field of ["startDay", "activeTicks", "totalTime", "main", "firstPaint", "sessionRestored"]) { michael@0: do_check_true(fields.has(field)); michael@0: } michael@0: michael@0: do_check_eq(fields.get("startDay")[1], Metrics.dateToDays(now)); michael@0: do_check_eq(fields.get("totalTime")[1], recorder.totalTime); michael@0: do_check_eq(fields.get("activeTicks")[1], 1); michael@0: do_check_eq(fields.get("main")[1], 500); michael@0: do_check_eq(fields.get("firstPaint")[1], 1000); michael@0: do_check_eq(fields.get("sessionRestored")[1], 1500); michael@0: michael@0: yield provider.shutdown(); michael@0: yield storage.close(); michael@0: }); michael@0: michael@0: add_task(function test_collect() { michael@0: let now = new Date(); michael@0: let [provider, storage, recorder] = yield getProvider("collect"); michael@0: michael@0: recorder.onShutdown(); michael@0: yield sleep(25); michael@0: michael@0: for (let i = 0; i < 5; i++) { michael@0: let recorder2 = new SessionRecorder("testing.collect.sessions."); michael@0: recorder2.onStartup(); michael@0: yield sleep(25); michael@0: recorder2.onShutdown(); michael@0: yield sleep(25); michael@0: } michael@0: michael@0: recorder = new SessionRecorder("testing.collect.sessions."); michael@0: recorder.onStartup(); michael@0: michael@0: // Collecting the provider should prune all previous sessions. michael@0: let sessions = recorder.getPreviousSessions(); michael@0: do_check_eq(Object.keys(sessions).length, 6); michael@0: yield provider.collectConstantData(); michael@0: sessions = recorder.getPreviousSessions(); michael@0: do_check_eq(Object.keys(sessions).length, 0); michael@0: michael@0: // And those previous sessions should make it to storage. michael@0: let daily = provider.getMeasurement("previous", 3); michael@0: let values = yield daily.getValues(); michael@0: do_check_true(values.days.hasDay(now)); michael@0: do_check_eq(values.days.size, 1); michael@0: let day = values.days.getDay(now); michael@0: do_check_eq(day.size, 5); michael@0: let previousStorageCount = day.get("main").length; michael@0: michael@0: for (let field of ["cleanActiveTicks", "cleanTotalTime", "main", "firstPaint", "sessionRestored"]) { michael@0: do_check_true(day.has(field)); michael@0: do_check_true(Array.isArray(day.get(field))); michael@0: do_check_eq(day.get(field).length, 6); michael@0: } michael@0: michael@0: let lastIndex = yield provider.getState("lastSession"); michael@0: do_check_eq(lastIndex, "" + (previousStorageCount - 1)); // 0-indexed michael@0: michael@0: // Fake an aborted session. If we create a 2nd recorder against the same michael@0: // prefs branch as a running one, this simulates what would happen if the michael@0: // first recorder didn't shut down. michael@0: let recorder2 = new SessionRecorder("testing.collect.sessions."); michael@0: recorder2.onStartup(); michael@0: do_check_eq(Object.keys(recorder.getPreviousSessions()).length, 1); michael@0: yield provider.collectConstantData(); michael@0: do_check_eq(Object.keys(recorder.getPreviousSessions()).length, 0); michael@0: michael@0: values = yield daily.getValues(); michael@0: day = values.days.getDay(now); michael@0: do_check_eq(day.size, previousStorageCount + 1); michael@0: previousStorageCount = day.get("main").length; michael@0: for (let field of ["abortedActiveTicks", "abortedTotalTime"]) { michael@0: do_check_true(day.has(field)); michael@0: do_check_true(Array.isArray(day.get(field))); michael@0: do_check_eq(day.get(field).length, 1); michael@0: } michael@0: michael@0: lastIndex = yield provider.getState("lastSession"); michael@0: do_check_eq(lastIndex, "" + (previousStorageCount - 1)); michael@0: michael@0: recorder.onShutdown(); michael@0: recorder2.onShutdown(); michael@0: michael@0: // If we try to insert a already-inserted session, it will be ignored. michael@0: recorder = new SessionRecorder("testing.collect.sessions."); michael@0: recorder._currentIndex = recorder._currentIndex - 1; michael@0: recorder._prunedIndex = recorder._currentIndex; michael@0: recorder.onStartup(); michael@0: // Session is left over from recorder2. michael@0: sessions = recorder.getPreviousSessions(); michael@0: do_check_eq(Object.keys(sessions).length, 1); michael@0: do_check_true(previousStorageCount - 1 in sessions); michael@0: yield provider.collectConstantData(); michael@0: lastIndex = yield provider.getState("lastSession"); michael@0: do_check_eq(lastIndex, "" + (previousStorageCount - 1)); michael@0: values = yield daily.getValues(); michael@0: day = values.days.getDay(now); michael@0: // We should not get additional entry. michael@0: do_check_eq(day.get("main").length, previousStorageCount); michael@0: recorder.onShutdown(); michael@0: michael@0: yield provider.shutdown(); michael@0: yield storage.close(); michael@0: }); michael@0: michael@0: add_task(function test_serialization() { michael@0: let [provider, storage, recorder] = yield getProvider("serialization"); michael@0: michael@0: yield sleep(1025); michael@0: recorder.onActivity(true); michael@0: michael@0: let current = provider.getMeasurement("current", 3); michael@0: let data = yield current.getValues(); michael@0: do_check_true("singular" in data); michael@0: michael@0: let serializer = current.serializer(current.SERIALIZE_JSON); michael@0: let fields = serializer.singular(data.singular); michael@0: michael@0: do_check_eq(fields._v, 3); michael@0: do_check_eq(fields.activeTicks, 1); michael@0: do_check_eq(fields.startDay, Metrics.dateToDays(recorder.startDate)); michael@0: do_check_eq(fields.main, 500); michael@0: do_check_eq(fields.firstPaint, 1000); michael@0: do_check_eq(fields.sessionRestored, 1500); michael@0: do_check_true(fields.totalTime > 0); michael@0: michael@0: yield provider.shutdown(); michael@0: yield storage.close(); michael@0: }); michael@0: