|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 "use strict"; |
|
5 |
|
6 const {utils: Cu} = Components; |
|
7 |
|
8 |
|
9 Cu.import("resource://gre/modules/Promise.jsm"); |
|
10 Cu.import("resource://gre/modules/Metrics.jsm"); |
|
11 Cu.import("resource://gre/modules/Task.jsm"); |
|
12 Cu.import("resource://gre/modules/services-common/utils.js"); |
|
13 Cu.import("resource://gre/modules/services/datareporting/sessions.jsm"); |
|
14 Cu.import("resource://gre/modules/services/healthreport/providers.jsm"); |
|
15 |
|
16 |
|
17 function run_test() { |
|
18 run_next_test(); |
|
19 } |
|
20 |
|
21 add_test(function test_constructor() { |
|
22 let provider = new SessionsProvider(); |
|
23 |
|
24 run_next_test(); |
|
25 }); |
|
26 |
|
27 add_task(function test_init() { |
|
28 let storage = yield Metrics.Storage("init"); |
|
29 let provider = new SessionsProvider(); |
|
30 yield provider.init(storage); |
|
31 yield provider.shutdown(); |
|
32 |
|
33 yield storage.close(); |
|
34 }); |
|
35 |
|
36 function monkeypatchStartupInfo(recorder, start=new Date(), offset=500) { |
|
37 Object.defineProperty(recorder, "_getStartupInfo", { |
|
38 value: function _getStartupInfo() { |
|
39 return { |
|
40 process: start, |
|
41 main: new Date(start.getTime() + offset), |
|
42 firstPaint: new Date(start.getTime() + 2 * offset), |
|
43 sessionRestored: new Date(start.getTime() + 3 * offset), |
|
44 }; |
|
45 } |
|
46 }); |
|
47 } |
|
48 |
|
49 function sleep(wait) { |
|
50 let deferred = Promise.defer(); |
|
51 |
|
52 let timer = CommonUtils.namedTimer(function onTimer() { |
|
53 deferred.resolve(); |
|
54 }, wait, deferred.promise, "_sleepTimer"); |
|
55 |
|
56 return deferred.promise; |
|
57 } |
|
58 |
|
59 function getProvider(name, now=new Date(), init=true) { |
|
60 return Task.spawn(function () { |
|
61 let storage = yield Metrics.Storage(name); |
|
62 let provider = new SessionsProvider(); |
|
63 |
|
64 let recorder = new SessionRecorder("testing." + name + ".sessions."); |
|
65 monkeypatchStartupInfo(recorder, now); |
|
66 provider.healthReporter = {sessionRecorder: recorder}; |
|
67 recorder.onStartup(); |
|
68 |
|
69 if (init) { |
|
70 yield provider.init(storage); |
|
71 } |
|
72 |
|
73 throw new Task.Result([provider, storage, recorder]); |
|
74 }); |
|
75 } |
|
76 |
|
77 add_task(function test_current_session() { |
|
78 let now = new Date(); |
|
79 let [provider, storage, recorder] = yield getProvider("current_session", now); |
|
80 |
|
81 yield sleep(25); |
|
82 recorder.onActivity(true); |
|
83 |
|
84 let current = provider.getMeasurement("current", 3); |
|
85 let values = yield current.getValues(); |
|
86 let fields = values.singular; |
|
87 |
|
88 for (let field of ["startDay", "activeTicks", "totalTime", "main", "firstPaint", "sessionRestored"]) { |
|
89 do_check_true(fields.has(field)); |
|
90 } |
|
91 |
|
92 do_check_eq(fields.get("startDay")[1], Metrics.dateToDays(now)); |
|
93 do_check_eq(fields.get("totalTime")[1], recorder.totalTime); |
|
94 do_check_eq(fields.get("activeTicks")[1], 1); |
|
95 do_check_eq(fields.get("main")[1], 500); |
|
96 do_check_eq(fields.get("firstPaint")[1], 1000); |
|
97 do_check_eq(fields.get("sessionRestored")[1], 1500); |
|
98 |
|
99 yield provider.shutdown(); |
|
100 yield storage.close(); |
|
101 }); |
|
102 |
|
103 add_task(function test_collect() { |
|
104 let now = new Date(); |
|
105 let [provider, storage, recorder] = yield getProvider("collect"); |
|
106 |
|
107 recorder.onShutdown(); |
|
108 yield sleep(25); |
|
109 |
|
110 for (let i = 0; i < 5; i++) { |
|
111 let recorder2 = new SessionRecorder("testing.collect.sessions."); |
|
112 recorder2.onStartup(); |
|
113 yield sleep(25); |
|
114 recorder2.onShutdown(); |
|
115 yield sleep(25); |
|
116 } |
|
117 |
|
118 recorder = new SessionRecorder("testing.collect.sessions."); |
|
119 recorder.onStartup(); |
|
120 |
|
121 // Collecting the provider should prune all previous sessions. |
|
122 let sessions = recorder.getPreviousSessions(); |
|
123 do_check_eq(Object.keys(sessions).length, 6); |
|
124 yield provider.collectConstantData(); |
|
125 sessions = recorder.getPreviousSessions(); |
|
126 do_check_eq(Object.keys(sessions).length, 0); |
|
127 |
|
128 // And those previous sessions should make it to storage. |
|
129 let daily = provider.getMeasurement("previous", 3); |
|
130 let values = yield daily.getValues(); |
|
131 do_check_true(values.days.hasDay(now)); |
|
132 do_check_eq(values.days.size, 1); |
|
133 let day = values.days.getDay(now); |
|
134 do_check_eq(day.size, 5); |
|
135 let previousStorageCount = day.get("main").length; |
|
136 |
|
137 for (let field of ["cleanActiveTicks", "cleanTotalTime", "main", "firstPaint", "sessionRestored"]) { |
|
138 do_check_true(day.has(field)); |
|
139 do_check_true(Array.isArray(day.get(field))); |
|
140 do_check_eq(day.get(field).length, 6); |
|
141 } |
|
142 |
|
143 let lastIndex = yield provider.getState("lastSession"); |
|
144 do_check_eq(lastIndex, "" + (previousStorageCount - 1)); // 0-indexed |
|
145 |
|
146 // Fake an aborted session. If we create a 2nd recorder against the same |
|
147 // prefs branch as a running one, this simulates what would happen if the |
|
148 // first recorder didn't shut down. |
|
149 let recorder2 = new SessionRecorder("testing.collect.sessions."); |
|
150 recorder2.onStartup(); |
|
151 do_check_eq(Object.keys(recorder.getPreviousSessions()).length, 1); |
|
152 yield provider.collectConstantData(); |
|
153 do_check_eq(Object.keys(recorder.getPreviousSessions()).length, 0); |
|
154 |
|
155 values = yield daily.getValues(); |
|
156 day = values.days.getDay(now); |
|
157 do_check_eq(day.size, previousStorageCount + 1); |
|
158 previousStorageCount = day.get("main").length; |
|
159 for (let field of ["abortedActiveTicks", "abortedTotalTime"]) { |
|
160 do_check_true(day.has(field)); |
|
161 do_check_true(Array.isArray(day.get(field))); |
|
162 do_check_eq(day.get(field).length, 1); |
|
163 } |
|
164 |
|
165 lastIndex = yield provider.getState("lastSession"); |
|
166 do_check_eq(lastIndex, "" + (previousStorageCount - 1)); |
|
167 |
|
168 recorder.onShutdown(); |
|
169 recorder2.onShutdown(); |
|
170 |
|
171 // If we try to insert a already-inserted session, it will be ignored. |
|
172 recorder = new SessionRecorder("testing.collect.sessions."); |
|
173 recorder._currentIndex = recorder._currentIndex - 1; |
|
174 recorder._prunedIndex = recorder._currentIndex; |
|
175 recorder.onStartup(); |
|
176 // Session is left over from recorder2. |
|
177 sessions = recorder.getPreviousSessions(); |
|
178 do_check_eq(Object.keys(sessions).length, 1); |
|
179 do_check_true(previousStorageCount - 1 in sessions); |
|
180 yield provider.collectConstantData(); |
|
181 lastIndex = yield provider.getState("lastSession"); |
|
182 do_check_eq(lastIndex, "" + (previousStorageCount - 1)); |
|
183 values = yield daily.getValues(); |
|
184 day = values.days.getDay(now); |
|
185 // We should not get additional entry. |
|
186 do_check_eq(day.get("main").length, previousStorageCount); |
|
187 recorder.onShutdown(); |
|
188 |
|
189 yield provider.shutdown(); |
|
190 yield storage.close(); |
|
191 }); |
|
192 |
|
193 add_task(function test_serialization() { |
|
194 let [provider, storage, recorder] = yield getProvider("serialization"); |
|
195 |
|
196 yield sleep(1025); |
|
197 recorder.onActivity(true); |
|
198 |
|
199 let current = provider.getMeasurement("current", 3); |
|
200 let data = yield current.getValues(); |
|
201 do_check_true("singular" in data); |
|
202 |
|
203 let serializer = current.serializer(current.SERIALIZE_JSON); |
|
204 let fields = serializer.singular(data.singular); |
|
205 |
|
206 do_check_eq(fields._v, 3); |
|
207 do_check_eq(fields.activeTicks, 1); |
|
208 do_check_eq(fields.startDay, Metrics.dateToDays(recorder.startDate)); |
|
209 do_check_eq(fields.main, 500); |
|
210 do_check_eq(fields.firstPaint, 1000); |
|
211 do_check_eq(fields.sessionRestored, 1500); |
|
212 do_check_true(fields.totalTime > 0); |
|
213 |
|
214 yield provider.shutdown(); |
|
215 yield storage.close(); |
|
216 }); |
|
217 |