toolkit/components/telemetry/tests/unit/test_TelemetryPing.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* Any copyright is dedicated to the Public Domain.
michael@0 2 http://creativecommons.org/publicdomain/zero/1.0/
michael@0 3 */
michael@0 4 /* This testcase triggers two telemetry pings.
michael@0 5 *
michael@0 6 * Telemetry code keeps histograms of past telemetry pings. The first
michael@0 7 * ping populates these histograms. One of those histograms is then
michael@0 8 * checked in the second request.
michael@0 9 */
michael@0 10
michael@0 11 const Cc = Components.classes;
michael@0 12 const Ci = Components.interfaces;
michael@0 13 const Cu = Components.utils;
michael@0 14 const Cr = Components.results;
michael@0 15
michael@0 16 Cu.import("resource://testing-common/httpd.js", this);
michael@0 17 Cu.import("resource://gre/modules/Services.jsm");
michael@0 18 Cu.import("resource://gre/modules/LightweightThemeManager.jsm", this);
michael@0 19 Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
michael@0 20 Cu.import("resource://gre/modules/TelemetryPing.jsm", this);
michael@0 21 Cu.import("resource://gre/modules/TelemetryFile.jsm", this);
michael@0 22 Cu.import("resource://gre/modules/Task.jsm", this);
michael@0 23 Cu.import("resource://gre/modules/Promise.jsm", this);
michael@0 24
michael@0 25 const IGNORE_HISTOGRAM = "test::ignore_me";
michael@0 26 const IGNORE_HISTOGRAM_TO_CLONE = "MEMORY_HEAP_ALLOCATED";
michael@0 27 const IGNORE_CLONED_HISTOGRAM = "test::ignore_me_also";
michael@0 28 const ADDON_NAME = "Telemetry test addon";
michael@0 29 const ADDON_HISTOGRAM = "addon-histogram";
michael@0 30 // Add some unicode characters here to ensure that sending them works correctly.
michael@0 31 const FLASH_VERSION = "\u201c1.1.1.1\u201d";
michael@0 32 const SHUTDOWN_TIME = 10000;
michael@0 33 const FAILED_PROFILE_LOCK_ATTEMPTS = 2;
michael@0 34
michael@0 35 // Constants from prio.h for nsIFileOutputStream.init
michael@0 36 const PR_WRONLY = 0x2;
michael@0 37 const PR_CREATE_FILE = 0x8;
michael@0 38 const PR_TRUNCATE = 0x20;
michael@0 39 const RW_OWNER = 0600;
michael@0 40
michael@0 41 const NUMBER_OF_THREADS_TO_LAUNCH = 30;
michael@0 42 let gNumberOfThreadsLaunched = 0;
michael@0 43
michael@0 44 const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
michael@0 45
michael@0 46 let gHttpServer = new HttpServer();
michael@0 47 let gServerStarted = false;
michael@0 48 let gRequestIterator = null;
michael@0 49
michael@0 50 function sendPing () {
michael@0 51 TelemetryPing.gatherStartup();
michael@0 52 if (gServerStarted) {
michael@0 53 return TelemetryPing.testPing("http://localhost:" + gHttpServer.identity.primaryPort);
michael@0 54 } else {
michael@0 55 return TelemetryPing.testPing("http://doesnotexist");
michael@0 56 }
michael@0 57 }
michael@0 58
michael@0 59 function wrapWithExceptionHandler(f) {
michael@0 60 function wrapper(...args) {
michael@0 61 try {
michael@0 62 f(...args);
michael@0 63 } catch (ex if typeof(ex) == 'object') {
michael@0 64 dump("Caught exception: " + ex.message + "\n");
michael@0 65 dump(ex.stack);
michael@0 66 do_test_finished();
michael@0 67 }
michael@0 68 }
michael@0 69 return wrapper;
michael@0 70 }
michael@0 71
michael@0 72 function registerPingHandler(handler) {
michael@0 73 gHttpServer.registerPrefixHandler("/submit/telemetry/",
michael@0 74 wrapWithExceptionHandler(handler));
michael@0 75 }
michael@0 76
michael@0 77 function setupTestData() {
michael@0 78 Telemetry.newHistogram(IGNORE_HISTOGRAM, "never", 1, 2, 3, Telemetry.HISTOGRAM_BOOLEAN);
michael@0 79 Telemetry.histogramFrom(IGNORE_CLONED_HISTOGRAM, IGNORE_HISTOGRAM_TO_CLONE);
michael@0 80 Services.startup.interrupted = true;
michael@0 81 Telemetry.registerAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM, 1, 5, 6,
michael@0 82 Telemetry.HISTOGRAM_LINEAR);
michael@0 83 h1 = Telemetry.getAddonHistogram(ADDON_NAME, ADDON_HISTOGRAM);
michael@0 84 h1.add(1);
michael@0 85 }
michael@0 86
michael@0 87 function getSavedHistogramsFile(basename) {
michael@0 88 let tmpDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
michael@0 89 let histogramsFile = tmpDir.clone();
michael@0 90 histogramsFile.append(basename);
michael@0 91 if (histogramsFile.exists()) {
michael@0 92 histogramsFile.remove(true);
michael@0 93 }
michael@0 94 do_register_cleanup(function () {
michael@0 95 try {
michael@0 96 histogramsFile.remove(true);
michael@0 97 } catch (e) {
michael@0 98 }
michael@0 99 });
michael@0 100 return histogramsFile;
michael@0 101 }
michael@0 102
michael@0 103 function decodeRequestPayload(request) {
michael@0 104 let s = request.bodyInputStream;
michael@0 105 let payload = null;
michael@0 106 let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON)
michael@0 107
michael@0 108 if (request.getHeader("content-encoding") == "gzip") {
michael@0 109 let observer = {
michael@0 110 buffer: "",
michael@0 111 onStreamComplete: function(loader, context, status, length, result) {
michael@0 112 this.buffer = String.fromCharCode.apply(this, result);
michael@0 113 }
michael@0 114 };
michael@0 115
michael@0 116 let scs = Cc["@mozilla.org/streamConverters;1"]
michael@0 117 .getService(Ci.nsIStreamConverterService);
michael@0 118 let listener = Cc["@mozilla.org/network/stream-loader;1"]
michael@0 119 .createInstance(Ci.nsIStreamLoader);
michael@0 120 listener.init(observer);
michael@0 121 let converter = scs.asyncConvertData("gzip", "uncompressed",
michael@0 122 listener, null);
michael@0 123 converter.onStartRequest(null, null);
michael@0 124 converter.onDataAvailable(null, null, s, 0, s.available());
michael@0 125 converter.onStopRequest(null, null, null);
michael@0 126 let unicodeConverter = Cc["@mozilla.org/intl/scriptableunicodeconverter"]
michael@0 127 .createInstance(Ci.nsIScriptableUnicodeConverter);
michael@0 128 unicodeConverter.charset = "UTF-8";
michael@0 129 let utf8string = unicodeConverter.ConvertToUnicode(observer.buffer);
michael@0 130 utf8string += unicodeConverter.Finish();
michael@0 131 payload = decoder.decode(utf8string);
michael@0 132 } else {
michael@0 133 payload = decoder.decodeFromStream(s, s.available());
michael@0 134 }
michael@0 135
michael@0 136 return payload;
michael@0 137 }
michael@0 138
michael@0 139 function checkPayloadInfo(payload, reason) {
michael@0 140 // get rid of the non-deterministic field
michael@0 141 const expected_info = {
michael@0 142 OS: "XPCShell",
michael@0 143 appID: "xpcshell@tests.mozilla.org",
michael@0 144 appVersion: "1",
michael@0 145 appName: "XPCShell",
michael@0 146 appBuildID: "2007010101",
michael@0 147 platformBuildID: "2007010101",
michael@0 148 flashVersion: FLASH_VERSION
michael@0 149 };
michael@0 150
michael@0 151 for (let f in expected_info) {
michael@0 152 do_check_eq(payload.info[f], expected_info[f]);
michael@0 153 }
michael@0 154
michael@0 155 do_check_eq(payload.info.reason, reason);
michael@0 156 do_check_true("appUpdateChannel" in payload.info);
michael@0 157 do_check_true("locale" in payload.info);
michael@0 158 do_check_true("revision" in payload.info);
michael@0 159 do_check_true(payload.info.revision.startsWith("http"));
michael@0 160
michael@0 161 try {
michael@0 162 // If we've not got nsIGfxInfoDebug, then this will throw and stop us doing
michael@0 163 // this test.
michael@0 164 let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
michael@0 165 let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
michael@0 166 let isOSX = ("nsILocalFileMac" in Components.interfaces);
michael@0 167
michael@0 168 if (isWindows || isOSX) {
michael@0 169 do_check_true("adapterVendorID" in payload.info);
michael@0 170 do_check_true("adapterDeviceID" in payload.info);
michael@0 171 }
michael@0 172 }
michael@0 173 catch (x) {
michael@0 174 }
michael@0 175 }
michael@0 176
michael@0 177 function checkPayload(request, reason, successfulPings) {
michael@0 178 let payload = decodeRequestPayload(request);
michael@0 179 // Take off ["","submit","telemetry"].
michael@0 180 let pathComponents = request.path.split("/").slice(3);
michael@0 181
michael@0 182 checkPayloadInfo(payload, reason);
michael@0 183 do_check_eq(reason, pathComponents[1]);
michael@0 184 do_check_eq(request.getHeader("content-type"), "application/json; charset=UTF-8");
michael@0 185 do_check_true(payload.simpleMeasurements.uptime >= 0);
michael@0 186 do_check_true(payload.simpleMeasurements.startupInterrupted === 1);
michael@0 187 do_check_eq(payload.simpleMeasurements.shutdownDuration, SHUTDOWN_TIME);
michael@0 188 do_check_eq(payload.simpleMeasurements.savedPings, 1);
michael@0 189 do_check_true("maximalNumberOfConcurrentThreads" in payload.simpleMeasurements);
michael@0 190 do_check_true(payload.simpleMeasurements.maximalNumberOfConcurrentThreads >= gNumberOfThreadsLaunched);
michael@0 191
michael@0 192 do_check_eq(payload.simpleMeasurements.failedProfileLockCount,
michael@0 193 FAILED_PROFILE_LOCK_ATTEMPTS);
michael@0 194 let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
michael@0 195 let failedProfileLocksFile = profileDirectory.clone();
michael@0 196 failedProfileLocksFile.append("Telemetry.FailedProfileLocks.txt");
michael@0 197 do_check_true(!failedProfileLocksFile.exists());
michael@0 198
michael@0 199
michael@0 200 let isWindows = ("@mozilla.org/windows-registry-key;1" in Components.classes);
michael@0 201 if (isWindows) {
michael@0 202 do_check_true(payload.simpleMeasurements.startupSessionRestoreReadBytes > 0);
michael@0 203 do_check_true(payload.simpleMeasurements.startupSessionRestoreWriteBytes > 0);
michael@0 204 }
michael@0 205
michael@0 206 const TELEMETRY_PING = "TELEMETRY_PING";
michael@0 207 const TELEMETRY_SUCCESS = "TELEMETRY_SUCCESS";
michael@0 208 const TELEMETRY_TEST_FLAG = "TELEMETRY_TEST_FLAG";
michael@0 209 const READ_SAVED_PING_SUCCESS = "READ_SAVED_PING_SUCCESS";
michael@0 210 do_check_true(TELEMETRY_PING in payload.histograms);
michael@0 211 do_check_true(READ_SAVED_PING_SUCCESS in payload.histograms);
michael@0 212 let rh = Telemetry.registeredHistograms([]);
michael@0 213 for (let name of rh) {
michael@0 214 if (/SQLITE/.test(name) && name in payload.histograms) {
michael@0 215 do_check_true(("STARTUP_" + name) in payload.histograms);
michael@0 216 }
michael@0 217 }
michael@0 218 do_check_false(IGNORE_HISTOGRAM in payload.histograms);
michael@0 219 do_check_false(IGNORE_CLONED_HISTOGRAM in payload.histograms);
michael@0 220
michael@0 221 // Flag histograms should automagically spring to life.
michael@0 222 const expected_flag = {
michael@0 223 range: [1, 2],
michael@0 224 bucket_count: 3,
michael@0 225 histogram_type: 3,
michael@0 226 values: {0:1, 1:0},
michael@0 227 sum: 0,
michael@0 228 sum_squares_lo: 0,
michael@0 229 sum_squares_hi: 0
michael@0 230 };
michael@0 231 let flag = payload.histograms[TELEMETRY_TEST_FLAG];
michael@0 232 do_check_eq(uneval(flag), uneval(expected_flag));
michael@0 233
michael@0 234 // There should be one successful report from the previous telemetry ping.
michael@0 235 const expected_tc = {
michael@0 236 range: [1, 2],
michael@0 237 bucket_count: 3,
michael@0 238 histogram_type: 2,
michael@0 239 values: {0:1, 1:successfulPings, 2:0},
michael@0 240 sum: successfulPings,
michael@0 241 sum_squares_lo: successfulPings,
michael@0 242 sum_squares_hi: 0
michael@0 243 };
michael@0 244 let tc = payload.histograms[TELEMETRY_SUCCESS];
michael@0 245 do_check_eq(uneval(tc), uneval(expected_tc));
michael@0 246
michael@0 247 let h = payload.histograms[READ_SAVED_PING_SUCCESS];
michael@0 248 do_check_eq(h.values[0], 1);
michael@0 249
michael@0 250 // The ping should include data from memory reporters. We can't check that
michael@0 251 // this data is correct, because we can't control the values returned by the
michael@0 252 // memory reporters. But we can at least check that the data is there.
michael@0 253 //
michael@0 254 // It's important to check for the presence of reporters with a mix of units,
michael@0 255 // because TelemetryPing has separate logic for each one. But we can't
michael@0 256 // currently check UNITS_COUNT_CUMULATIVE or UNITS_PERCENTAGE because
michael@0 257 // Telemetry doesn't touch a memory reporter with these units that's
michael@0 258 // available on all platforms.
michael@0 259
michael@0 260 do_check_true('MEMORY_JS_GC_HEAP' in payload.histograms); // UNITS_BYTES
michael@0 261 do_check_true('MEMORY_JS_COMPARTMENTS_SYSTEM' in payload.histograms); // UNITS_COUNT
michael@0 262
michael@0 263 // We should have included addon histograms.
michael@0 264 do_check_true("addonHistograms" in payload);
michael@0 265 do_check_true(ADDON_NAME in payload.addonHistograms);
michael@0 266 do_check_true(ADDON_HISTOGRAM in payload.addonHistograms[ADDON_NAME]);
michael@0 267
michael@0 268 do_check_true(("mainThread" in payload.slowSQL) &&
michael@0 269 ("otherThreads" in payload.slowSQL));
michael@0 270 }
michael@0 271
michael@0 272 function dummyTheme(id) {
michael@0 273 return {
michael@0 274 id: id,
michael@0 275 name: Math.random().toString(),
michael@0 276 headerURL: "http://lwttest.invalid/a.png",
michael@0 277 footerURL: "http://lwttest.invalid/b.png",
michael@0 278 textcolor: Math.random().toString(),
michael@0 279 accentcolor: Math.random().toString()
michael@0 280 };
michael@0 281 }
michael@0 282
michael@0 283 // A fake plugin host for testing flash version telemetry
michael@0 284 let PluginHost = {
michael@0 285 getPluginTags: function(countRef) {
michael@0 286 let plugins = [{name: "Shockwave Flash", version: FLASH_VERSION}];
michael@0 287 countRef.value = plugins.length;
michael@0 288 return plugins;
michael@0 289 },
michael@0 290
michael@0 291 QueryInterface: function(iid) {
michael@0 292 if (iid.equals(Ci.nsIPluginHost)
michael@0 293 || iid.equals(Ci.nsISupports))
michael@0 294 return this;
michael@0 295
michael@0 296 throw Components.results.NS_ERROR_NO_INTERFACE;
michael@0 297 }
michael@0 298 }
michael@0 299
michael@0 300 let PluginHostFactory = {
michael@0 301 createInstance: function (outer, iid) {
michael@0 302 if (outer != null)
michael@0 303 throw Components.results.NS_ERROR_NO_AGGREGATION;
michael@0 304 return PluginHost.QueryInterface(iid);
michael@0 305 }
michael@0 306 };
michael@0 307
michael@0 308 const PLUGINHOST_CONTRACTID = "@mozilla.org/plugin/host;1";
michael@0 309 const PLUGINHOST_CID = Components.ID("{2329e6ea-1f15-4cbe-9ded-6e98e842de0e}");
michael@0 310
michael@0 311 function registerFakePluginHost() {
michael@0 312 let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
michael@0 313 registrar.registerFactory(PLUGINHOST_CID, "Fake Plugin Host",
michael@0 314 PLUGINHOST_CONTRACTID, PluginHostFactory);
michael@0 315 }
michael@0 316
michael@0 317 function writeStringToFile(file, contents) {
michael@0 318 let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"]
michael@0 319 .createInstance(Ci.nsIFileOutputStream);
michael@0 320 ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
michael@0 321 RW_OWNER, ostream.DEFER_OPEN);
michael@0 322 ostream.write(contents, contents.length);
michael@0 323 ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
michael@0 324 ostream.close();
michael@0 325 }
michael@0 326
michael@0 327 function write_fake_shutdown_file() {
michael@0 328 let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
michael@0 329 let file = profileDirectory.clone();
michael@0 330 file.append("Telemetry.ShutdownTime.txt");
michael@0 331 let contents = "" + SHUTDOWN_TIME;
michael@0 332 writeStringToFile(file, contents);
michael@0 333 }
michael@0 334
michael@0 335 function write_fake_failedprofilelocks_file() {
michael@0 336 let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
michael@0 337 let file = profileDirectory.clone();
michael@0 338 file.append("Telemetry.FailedProfileLocks.txt");
michael@0 339 let contents = "" + FAILED_PROFILE_LOCK_ATTEMPTS;
michael@0 340 writeStringToFile(file, contents);
michael@0 341 }
michael@0 342
michael@0 343 function run_test() {
michael@0 344 do_test_pending();
michael@0 345 try {
michael@0 346 let gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(Ci.nsIGfxInfoDebug);
michael@0 347 gfxInfo.spoofVendorID("0xabcd");
michael@0 348 gfxInfo.spoofDeviceID("0x1234");
michael@0 349 } catch (x) {
michael@0 350 // If we can't test gfxInfo, that's fine, we'll note it later.
michael@0 351 }
michael@0 352
michael@0 353 // Addon manager needs a profile directory
michael@0 354 do_get_profile();
michael@0 355 createAppInfo("xpcshell@tests.mozilla.org", "XPCShell", "1", "1.9.2");
michael@0 356
michael@0 357 // Make it look like we've previously failed to lock a profile a couple times.
michael@0 358 write_fake_failedprofilelocks_file();
michael@0 359
michael@0 360 // Make it look like we've shutdown before.
michael@0 361 write_fake_shutdown_file();
michael@0 362
michael@0 363 let currentMaxNumberOfThreads = Telemetry.maximalNumberOfConcurrentThreads;
michael@0 364 do_check_true(currentMaxNumberOfThreads > 0);
michael@0 365
michael@0 366 // Try to augment the maximal number of threads currently launched
michael@0 367 let threads = [];
michael@0 368 try {
michael@0 369 for (let i = 0; i < currentMaxNumberOfThreads + 10; ++i) {
michael@0 370 threads.push(Services.tm.newThread(0));
michael@0 371 }
michael@0 372 } catch (ex) {
michael@0 373 // If memory is too low, it is possible that not all threads will be launched.
michael@0 374 }
michael@0 375 gNumberOfThreadsLaunched = threads.length;
michael@0 376
michael@0 377 do_check_true(Telemetry.maximalNumberOfConcurrentThreads >= gNumberOfThreadsLaunched);
michael@0 378
michael@0 379 do_register_cleanup(function() {
michael@0 380 threads.forEach(function(thread) {
michael@0 381 thread.shutdown();
michael@0 382 });
michael@0 383 });
michael@0 384
michael@0 385 Telemetry.asyncFetchTelemetryData(wrapWithExceptionHandler(actualTest));
michael@0 386 }
michael@0 387
michael@0 388 function actualTest() {
michael@0 389 // try to make LightweightThemeManager do stuff
michael@0 390 let gInternalManager = Cc["@mozilla.org/addons/integration;1"]
michael@0 391 .getService(Ci.nsIObserver)
michael@0 392 .QueryInterface(Ci.nsITimerCallback);
michael@0 393
michael@0 394 gInternalManager.observe(null, "addons-startup", null);
michael@0 395 LightweightThemeManager.currentTheme = dummyTheme("1234");
michael@0 396
michael@0 397 // fake plugin host for consistent flash version data
michael@0 398 registerFakePluginHost();
michael@0 399
michael@0 400 run_next_test();
michael@0 401 }
michael@0 402
michael@0 403 // Ensure that not overwriting an existing file fails silently
michael@0 404 add_task(function* test_overwritePing() {
michael@0 405 let ping = {slug: "foo"}
michael@0 406 yield TelemetryFile.savePing(ping, true);
michael@0 407 yield TelemetryFile.savePing(ping, false);
michael@0 408 yield TelemetryFile.cleanupPingFile(ping);
michael@0 409 });
michael@0 410
michael@0 411 // Ensures that expired histograms are not part of the payload.
michael@0 412 add_task(function* test_expiredHistogram() {
michael@0 413 let histogram_id = "FOOBAR";
michael@0 414 let dummy = Telemetry.newHistogram(histogram_id, "30", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL);
michael@0 415
michael@0 416 dummy.add(1);
michael@0 417
michael@0 418 do_check_eq(TelemetryPing.getPayload()["histograms"][histogram_id], undefined);
michael@0 419 do_check_eq(TelemetryPing.getPayload()["histograms"]["TELEMETRY_TEST_EXPIRED"], undefined);
michael@0 420 });
michael@0 421
michael@0 422 // Checks that an invalid histogram file is deleted if TelemetryFile fails to parse it.
michael@0 423 add_task(function* test_runInvalidJSON() {
michael@0 424 let histogramsFile = getSavedHistogramsFile("invalid-histograms.dat");
michael@0 425
michael@0 426 writeStringToFile(histogramsFile, "this.is.invalid.JSON");
michael@0 427 do_check_true(histogramsFile.exists());
michael@0 428
michael@0 429 yield TelemetryPing.testLoadHistograms(histogramsFile);
michael@0 430 do_check_false(histogramsFile.exists());
michael@0 431 });
michael@0 432
michael@0 433 // Sends a ping to a non existing server.
michael@0 434 add_task(function* test_noServerPing() {
michael@0 435 yield sendPing();
michael@0 436 });
michael@0 437
michael@0 438 // Checks that a sent ping is correctly received by a dummy http server.
michael@0 439 add_task(function* test_simplePing() {
michael@0 440 gHttpServer.start(-1);
michael@0 441 gServerStarted = true;
michael@0 442 gRequestIterator = Iterator(new Request());
michael@0 443
michael@0 444 yield sendPing();
michael@0 445 decodeRequestPayload(yield gRequestIterator.next());
michael@0 446 });
michael@0 447
michael@0 448 // Saves the current session histograms, reloads them, perfoms a ping
michael@0 449 // and checks that the dummy http server received both the previously
michael@0 450 // saved histograms and the new ones.
michael@0 451 add_task(function* test_saveLoadPing() {
michael@0 452 let histogramsFile = getSavedHistogramsFile("saved-histograms.dat");
michael@0 453
michael@0 454 setupTestData();
michael@0 455 yield TelemetryPing.testSaveHistograms(histogramsFile);
michael@0 456 yield TelemetryPing.testLoadHistograms(histogramsFile);
michael@0 457 yield sendPing();
michael@0 458 checkPayload((yield gRequestIterator.next()), "test-ping", 1);
michael@0 459 checkPayload((yield gRequestIterator.next()), "saved-session", 1);
michael@0 460 });
michael@0 461
michael@0 462 // Checks that an expired histogram file is deleted when loaded.
michael@0 463 add_task(function* test_runOldPingFile() {
michael@0 464 let histogramsFile = getSavedHistogramsFile("old-histograms.dat");
michael@0 465
michael@0 466 yield TelemetryPing.testSaveHistograms(histogramsFile);
michael@0 467 do_check_true(histogramsFile.exists());
michael@0 468 let mtime = histogramsFile.lastModifiedTime;
michael@0 469 histogramsFile.lastModifiedTime = mtime - (14 * 24 * 60 * 60 * 1000 + 60000); // 14 days, 1m
michael@0 470
michael@0 471 yield TelemetryPing.testLoadHistograms(histogramsFile);
michael@0 472 do_check_false(histogramsFile.exists());
michael@0 473 });
michael@0 474
michael@0 475 add_task(function* stopServer(){
michael@0 476 gHttpServer.stop(do_test_finished);
michael@0 477 });
michael@0 478
michael@0 479 // An iterable sequence of http requests
michael@0 480 function Request() {
michael@0 481 let defers = [];
michael@0 482 let current = 0;
michael@0 483
michael@0 484 function RequestIterator() {}
michael@0 485
michael@0 486 // Returns a promise that resolves to the next http request
michael@0 487 RequestIterator.prototype.next = function() {
michael@0 488 let deferred = defers[current++];
michael@0 489 return deferred.promise;
michael@0 490 }
michael@0 491
michael@0 492 this.__iterator__ = function(){
michael@0 493 return new RequestIterator();
michael@0 494 }
michael@0 495
michael@0 496 registerPingHandler((request, response) => {
michael@0 497 let deferred = defers[defers.length - 1];
michael@0 498 defers.push(Promise.defer());
michael@0 499 deferred.resolve(request);
michael@0 500 });
michael@0 501
michael@0 502 defers.push(Promise.defer());
michael@0 503 }

mercurial