Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
1 /* Any copyright is dedicated to the Public Domain.
2 http://creativecommons.org/publicdomain/zero/1.0/
4 /**
5 * This test case populates the profile with some fake stored
6 * pings, and checks that:
7 *
8 * 1) Pings that are considered "expired" are deleted and never sent.
9 * 2) Pings that are considered "overdue" trigger a send of all
10 * overdue and recent pings.
11 */
13 "use strict"
15 const Cc = Components.classes;
16 const Ci = Components.interfaces;
17 const Cr = Components.results;
18 const Cu = Components.utils;
20 Cu.import("resource://gre/modules/Services.jsm", this);
21 Cu.import("resource://testing-common/httpd.js", this);
22 Cu.import("resource://gre/modules/Promise.jsm", this);
23 Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
24 Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
25 Cu.import("resource://gre/modules/Task.jsm", this);
26 let {OS: {File, Path, Constants}} = Cu.import("resource://gre/modules/osfile.jsm", {});
28 // We increment TelemetryFile's MAX_PING_FILE_AGE and
29 // OVERDUE_PING_FILE_AGE by 1 minute so that our test pings exceed
30 // those points in time, even taking into account file system imprecision.
31 const ONE_MINUTE_MS = 60 * 1000;
32 const EXPIRED_PING_FILE_AGE = TelemetryFile.MAX_PING_FILE_AGE + ONE_MINUTE_MS;
33 const OVERDUE_PING_FILE_AGE = TelemetryFile.OVERDUE_PING_FILE_AGE + ONE_MINUTE_MS;
35 const PING_SAVE_FOLDER = "saved-telemetry-pings";
36 const PING_TIMEOUT_LENGTH = 5000;
37 const EXPIRED_PINGS = 5;
38 const OVERDUE_PINGS = 6;
39 const RECENT_PINGS = 4;
41 const TOTAL_EXPECTED_PINGS = OVERDUE_PINGS + RECENT_PINGS;
43 let gHttpServer = new HttpServer();
44 let gCreatedPings = 0;
45 let gSeenPings = 0;
47 /**
48 * Creates some TelemetryPings for the current session and
49 * saves them to disk. Each ping gets a unique ID slug based on
50 * an incrementor.
51 *
52 * @param aNum the number of pings to create.
53 * @param aAge the age in milliseconds to offset from now. A value
54 * of 10 would make the ping 10ms older than now, for
55 * example.
56 * @returns Promise
57 * @resolve an Array with the created pings.
58 */
59 function createSavedPings(aNum, aAge) {
60 return Task.spawn(function*(){
61 // Create a TelemetryPing service that we can generate payloads from.
62 // Luckily, the TelemetryPing constructor does nothing that we need to
63 // clean up.
64 let pings = [];
65 let age = Date.now() - aAge;
67 for (let i = 0; i < aNum; ++i) {
68 let payload = TelemetryPing.getPayload();
69 let ping = { slug: "test-ping-" + gCreatedPings, reason: "test", payload: payload };
71 yield TelemetryFile.savePing(ping);
73 if (aAge) {
74 // savePing writes to the file synchronously, so we're good to
75 // modify the lastModifedTime now.
76 let file = getSavePathForPing(ping);
77 yield File.setDates(file, null, age);
78 }
79 gCreatedPings++;
80 pings.push(ping);
81 }
82 return pings;
83 });
84 }
86 /**
87 * Deletes locally saved pings in aPings if they
88 * exist.
89 *
90 * @param aPings an Array of pings to delete.
91 * @returns Promise
92 */
93 function clearPings(aPings) {
94 return Task.spawn(function*() {
95 for (let ping of aPings) {
96 let path = getSavePathForPing(ping);
97 yield File.remove(path);
98 }
99 });
100 }
102 /**
103 * Returns a handle for the file that aPing should be
104 * stored in locally.
105 *
106 * @returns path
107 */
108 function getSavePathForPing(aPing) {
109 return Path.join(Constants.Path.profileDir, PING_SAVE_FOLDER, aPing.slug);
110 }
112 /**
113 * Check if the number of TelemetryPings received by the
114 * HttpServer is not equal to aExpectedNum.
115 *
116 * @param aExpectedNum the number of pings we expect to receive.
117 */
118 function assertReceivedPings(aExpectedNum) {
119 do_check_eq(gSeenPings, aExpectedNum);
120 }
122 /**
123 * Throws if any pings in aPings is saved locally.
124 *
125 * @param aPings an Array of pings to check.
126 * @returns Promise
127 */
128 function assertNotSaved(aPings) {
129 return Task.spawn(function*() {
130 let saved = 0;
131 for (let ping of aPings) {
132 let file = getSavePathForPing(ping);
133 if (yield File.exists()) {
134 saved++;
135 }
136 }
137 if (saved > 0) {
138 do_throw("Found " + saved + " unexpected saved pings.");
139 }
140 });
141 }
143 /**
144 * Our handler function for the HttpServer that simply
145 * increments the gSeenPings global when it successfully
146 * receives and decodes a TelemetryPing payload.
147 *
148 * @param aRequest the HTTP request sent from HttpServer.
149 */
150 function pingHandler(aRequest) {
151 gSeenPings++;
152 }
154 /**
155 * Returns a Promise that resolves when gHttpServer has been
156 * successfully shut down.
157 *
158 * @returns Promise
159 */
160 function stopHttpServer() {
161 let deferred = Promise.defer();
162 gHttpServer.stop(function() {
163 deferred.resolve();
164 })
165 return deferred.promise;
166 }
168 /**
169 * Teardown a TelemetryPing instance and clear out any pending
170 * pings to put as back in the starting state.
171 */
172 function resetTelemetry() {
173 TelemetryPing.uninstall();
174 // Quick and dirty way to clear TelemetryFile's pendingPings
175 // collection, and put it back in its initial state.
176 let gen = TelemetryFile.popPendingPings();
177 for (let item of gen) {};
178 }
180 /**
181 * Creates and returns a TelemetryPing instance in "testing"
182 * mode.
183 */
184 function startTelemetry() {
185 return TelemetryPing.setup();
186 }
188 function run_test() {
189 gHttpServer.registerPrefixHandler("/submit/telemetry/", pingHandler);
190 gHttpServer.start(-1);
191 do_get_profile();
192 Services.prefs.setBoolPref(TelemetryPing.Constants.PREF_ENABLED, true);
193 Services.prefs.setCharPref(TelemetryPing.Constants.PREF_SERVER,
194 "http://localhost:" + gHttpServer.identity.primaryPort);
195 run_next_test();
196 }
198 /**
199 * Test that pings that are considered too old are just chucked out
200 * immediately and never sent.
201 */
202 add_task(function test_expired_pings_are_deleted() {
203 let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
204 yield startTelemetry();
205 assertReceivedPings(0);
206 yield assertNotSaved(expiredPings);
207 yield resetTelemetry();
208 });
210 /**
211 * Test that really recent pings are not sent on Telemetry initialization.
212 */
213 add_task(function test_recent_pings_not_sent() {
214 let recentPings = yield createSavedPings(RECENT_PINGS);
215 yield startTelemetry();
216 assertReceivedPings(0);
217 yield resetTelemetry();
218 yield clearPings(recentPings);
219 });
221 /**
222 * Create some recent, expired and overdue pings. The overdue pings should
223 * trigger a send of all recent and overdue pings, but the expired pings
224 * should just be deleted.
225 */
226 add_task(function test_overdue_pings_trigger_send() {
227 let recentPings = yield createSavedPings(RECENT_PINGS);
228 let expiredPings = yield createSavedPings(EXPIRED_PINGS, EXPIRED_PING_FILE_AGE);
229 let overduePings = yield createSavedPings(OVERDUE_PINGS, OVERDUE_PING_FILE_AGE);
231 yield startTelemetry();
232 assertReceivedPings(TOTAL_EXPECTED_PINGS);
234 yield assertNotSaved(recentPings);
235 yield assertNotSaved(expiredPings);
236 yield assertNotSaved(overduePings);
237 yield resetTelemetry();
238 });
240 add_task(function teardown() {
241 yield stopHttpServer();
242 });