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.
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 | } |