1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/telemetry/tests/unit/test_nsITelemetry.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,388 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +const Cc = Components.classes; 1.8 +const Ci = Components.interfaces; 1.9 +const Cu = Components.utils; 1.10 +const INT_MAX = 0x7FFFFFFF; 1.11 + 1.12 +const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); 1.13 +Cu.import("resource://gre/modules/Services.jsm", this); 1.14 + 1.15 +function test_expired_histogram() { 1.16 + var histogram_id = "FOOBAR"; 1.17 + var test_expired_id = "TELEMETRY_TEST_EXPIRED"; 1.18 + var clone_id = "ExpiredClone"; 1.19 + var dummy = Telemetry.newHistogram(histogram_id, "28.0a1", 1, 2, 3, Telemetry.HISTOGRAM_EXPONENTIAL); 1.20 + var dummy_clone = Telemetry.histogramFrom(clone_id, test_expired_id); 1.21 + var rh = Telemetry.registeredHistograms([]); 1.22 + 1.23 + dummy.add(1); 1.24 + dummy_clone.add(1); 1.25 + 1.26 + do_check_eq(Telemetry.histogramSnapshots["__expired__"], undefined); 1.27 + do_check_eq(Telemetry.histogramSnapshots[histogram_id], undefined); 1.28 + do_check_eq(Telemetry.histogramSnapshots[test_expired_id], undefined); 1.29 + do_check_eq(Telemetry.histogramSnapshots[clone_id], undefined); 1.30 + do_check_eq(rh[test_expired_id], undefined); 1.31 +} 1.32 + 1.33 +function test_histogram(histogram_type, name, min, max, bucket_count) { 1.34 + var h = Telemetry.newHistogram(name, "never", min, max, bucket_count, histogram_type); 1.35 + var r = h.snapshot().ranges; 1.36 + var sum = 0; 1.37 + var log_sum = 0; 1.38 + var log_sum_squares = 0; 1.39 + for(var i=0;i<r.length;i++) { 1.40 + var v = r[i]; 1.41 + sum += v; 1.42 + if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { 1.43 + var log_v = Math.log(1+v); 1.44 + log_sum += log_v; 1.45 + log_sum_squares += log_v*log_v; 1.46 + } 1.47 + h.add(v); 1.48 + } 1.49 + var s = h.snapshot(); 1.50 + // verify properties 1.51 + do_check_eq(sum, s.sum); 1.52 + if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { 1.53 + // We do the log with float precision in C++ and double precision in 1.54 + // JS, so there's bound to be tiny discrepancies. Just check the 1.55 + // integer part. 1.56 + do_check_eq(Math.floor(log_sum), Math.floor(s.log_sum)); 1.57 + do_check_eq(Math.floor(log_sum_squares), Math.floor(s.log_sum_squares)); 1.58 + do_check_false("sum_squares_lo" in s); 1.59 + do_check_false("sum_squares_hi" in s); 1.60 + } else { 1.61 + // Doing the math to verify sum_squares was reflected correctly is 1.62 + // tedious in JavaScript. Just make sure we have something. 1.63 + do_check_neq(s.sum_squares_lo + s.sum_squares_hi, 0); 1.64 + do_check_false("log_sum" in s); 1.65 + do_check_false("log_sum_squares" in s); 1.66 + } 1.67 + 1.68 + // there should be exactly one element per bucket 1.69 + for each(var i in s.counts) { 1.70 + do_check_eq(i, 1); 1.71 + } 1.72 + var hgrams = Telemetry.histogramSnapshots 1.73 + gh = hgrams[name] 1.74 + do_check_eq(gh.histogram_type, histogram_type); 1.75 + 1.76 + do_check_eq(gh.min, min) 1.77 + do_check_eq(gh.max, max) 1.78 + 1.79 + // Check that booleans work with nonboolean histograms 1.80 + h.add(false); 1.81 + h.add(true); 1.82 + var s = h.snapshot().counts; 1.83 + do_check_eq(s[0], 2) 1.84 + do_check_eq(s[1], 2) 1.85 + 1.86 + // Check that clearing works. 1.87 + h.clear(); 1.88 + var s = h.snapshot(); 1.89 + for each(var i in s.counts) { 1.90 + do_check_eq(i, 0); 1.91 + } 1.92 + do_check_eq(s.sum, 0); 1.93 + if (histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { 1.94 + do_check_eq(s.log_sum, 0); 1.95 + do_check_eq(s.log_sum_squares, 0); 1.96 + } else { 1.97 + do_check_eq(s.sum_squares_lo, 0); 1.98 + do_check_eq(s.sum_squares_hi, 0); 1.99 + } 1.100 + 1.101 + h.add(0); 1.102 + h.add(1); 1.103 + var c = h.snapshot().counts; 1.104 + do_check_eq(c[0], 1); 1.105 + do_check_eq(c[1], 1); 1.106 +} 1.107 + 1.108 +function expect_fail(f) { 1.109 + let failed = false; 1.110 + try { 1.111 + f(); 1.112 + failed = false; 1.113 + } catch (e) { 1.114 + failed = true; 1.115 + } 1.116 + do_check_true(failed); 1.117 +} 1.118 + 1.119 +function expect_success(f) { 1.120 + let succeeded = false; 1.121 + try { 1.122 + f(); 1.123 + succeeded = true; 1.124 + } catch (e) { 1.125 + succeeded = false; 1.126 + } 1.127 + do_check_true(succeeded); 1.128 +} 1.129 + 1.130 +function test_boolean_histogram() 1.131 +{ 1.132 + var h = Telemetry.newHistogram("test::boolean histogram", "never", 99,1,4, Telemetry.HISTOGRAM_BOOLEAN); 1.133 + var r = h.snapshot().ranges; 1.134 + // boolean histograms ignore numeric parameters 1.135 + do_check_eq(uneval(r), uneval([0, 1, 2])) 1.136 + var sum = 0 1.137 + for(var i=0;i<r.length;i++) { 1.138 + var v = r[i]; 1.139 + sum += v; 1.140 + h.add(v); 1.141 + } 1.142 + h.add(true); 1.143 + h.add(false); 1.144 + var s = h.snapshot(); 1.145 + do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_BOOLEAN); 1.146 + // last bucket should always be 0 since .add parameters are normalized to either 0 or 1 1.147 + do_check_eq(s.counts[2], 0); 1.148 + do_check_eq(s.sum, 3); 1.149 + do_check_eq(s.counts[0], 2); 1.150 +} 1.151 + 1.152 +function test_flag_histogram() 1.153 +{ 1.154 + var h = Telemetry.newHistogram("test::flag histogram", "never", 130, 4, 5, Telemetry.HISTOGRAM_FLAG); 1.155 + var r = h.snapshot().ranges; 1.156 + // Flag histograms ignore numeric parameters. 1.157 + do_check_eq(uneval(r), uneval([0, 1, 2])) 1.158 + // Should already have a 0 counted. 1.159 + var c = h.snapshot().counts; 1.160 + var s = h.snapshot().sum; 1.161 + do_check_eq(uneval(c), uneval([1, 0, 0])); 1.162 + do_check_eq(s, 1); 1.163 + // Should switch counts. 1.164 + h.add(2); 1.165 + var c2 = h.snapshot().counts; 1.166 + var s2 = h.snapshot().sum; 1.167 + do_check_eq(uneval(c2), uneval([0, 1, 0])); 1.168 + do_check_eq(s, 1); 1.169 + // Should only switch counts once. 1.170 + h.add(3); 1.171 + var c3 = h.snapshot().counts; 1.172 + var s3 = h.snapshot().sum; 1.173 + do_check_eq(uneval(c3), uneval([0, 1, 0])); 1.174 + do_check_eq(s3, 1); 1.175 + do_check_eq(h.snapshot().histogram_type, Telemetry.FLAG_HISTOGRAM); 1.176 +} 1.177 + 1.178 +function test_getHistogramById() { 1.179 + try { 1.180 + Telemetry.getHistogramById("nonexistent"); 1.181 + do_throw("This can't happen"); 1.182 + } catch (e) { 1.183 + 1.184 + } 1.185 + var h = Telemetry.getHistogramById("CYCLE_COLLECTOR"); 1.186 + var s = h.snapshot(); 1.187 + do_check_eq(s.histogram_type, Telemetry.HISTOGRAM_EXPONENTIAL); 1.188 + do_check_eq(s.min, 1); 1.189 + do_check_eq(s.max, 10000); 1.190 +} 1.191 + 1.192 +function compareHistograms(h1, h2) { 1.193 + let s1 = h1.snapshot(); 1.194 + let s2 = h2.snapshot(); 1.195 + 1.196 + do_check_eq(s1.histogram_type, s2.histogram_type); 1.197 + do_check_eq(s1.min, s2.min); 1.198 + do_check_eq(s1.max, s2.max); 1.199 + do_check_eq(s1.sum, s2.sum); 1.200 + if (s1.histogram_type == Telemetry.HISTOGRAM_EXPONENTIAL) { 1.201 + do_check_eq(s1.log_sum, s2.log_sum); 1.202 + do_check_eq(s1.log_sum_squares, s2.log_sum_squares); 1.203 + } else { 1.204 + do_check_eq(s1.sum_squares_lo, s2.sum_squares_lo); 1.205 + do_check_eq(s1.sum_squares_hi, s2.sum_squares_hi); 1.206 + } 1.207 + 1.208 + do_check_eq(s1.counts.length, s2.counts.length); 1.209 + for (let i = 0; i < s1.counts.length; i++) 1.210 + do_check_eq(s1.counts[i], s2.counts[i]); 1.211 + 1.212 + do_check_eq(s1.ranges.length, s2.ranges.length); 1.213 + for (let i = 0; i < s1.ranges.length; i++) 1.214 + do_check_eq(s1.ranges[i], s2.ranges[i]); 1.215 +} 1.216 + 1.217 +function test_histogramFrom() { 1.218 + // Test one histogram of each type. 1.219 + let names = [ 1.220 + "CYCLE_COLLECTOR", // EXPONENTIAL 1.221 + "GC_REASON_2", // LINEAR 1.222 + "GC_RESET", // BOOLEAN 1.223 + "TELEMETRY_TEST_FLAG" // FLAG 1.224 + ]; 1.225 + 1.226 + for each (let name in names) { 1.227 + let [min, max, bucket_count] = [1, INT_MAX - 1, 10] 1.228 + let original = Telemetry.getHistogramById(name); 1.229 + let clone = Telemetry.histogramFrom("clone" + name, name); 1.230 + compareHistograms(original, clone); 1.231 + } 1.232 + 1.233 + // Additionally, set the flag on TELEMETRY_TEST_FLAG, and check it gets set on the clone. 1.234 + let testFlag = Telemetry.getHistogramById("TELEMETRY_TEST_FLAG"); 1.235 + testFlag.add(1); 1.236 + let clone = Telemetry.histogramFrom("FlagClone", "TELEMETRY_TEST_FLAG"); 1.237 + compareHistograms(testFlag, clone); 1.238 +} 1.239 + 1.240 +function test_getSlowSQL() { 1.241 + var slow = Telemetry.slowSQL; 1.242 + do_check_true(("mainThread" in slow) && ("otherThreads" in slow)); 1.243 +} 1.244 + 1.245 +function test_addons() { 1.246 + var addon_id = "testing-addon"; 1.247 + var fake_addon_id = "fake-addon"; 1.248 + var name1 = "testing-histogram1"; 1.249 + var register = Telemetry.registerAddonHistogram; 1.250 + expect_success(function () 1.251 + register(addon_id, name1, 1, 5, 6, Telemetry.HISTOGRAM_LINEAR)); 1.252 + // Can't register the same histogram multiple times. 1.253 + expect_fail(function () 1.254 + register(addon_id, name1, 1, 5, 6, Telemetry.HISTOGRAM_LINEAR)); 1.255 + // Make sure we can't get at it with another name. 1.256 + expect_fail(function () Telemetry.getAddonHistogram(fake_addon_id, name1)); 1.257 + 1.258 + // Check for reflection capabilities. 1.259 + var h1 = Telemetry.getAddonHistogram(addon_id, name1); 1.260 + // Verify that although we've created storage for it, we don't reflect it into JS. 1.261 + var snapshots = Telemetry.addonHistogramSnapshots; 1.262 + do_check_false(name1 in snapshots[addon_id]); 1.263 + h1.add(1); 1.264 + h1.add(3); 1.265 + var s1 = h1.snapshot(); 1.266 + do_check_eq(s1.histogram_type, Telemetry.HISTOGRAM_LINEAR); 1.267 + do_check_eq(s1.min, 1); 1.268 + do_check_eq(s1.max, 5); 1.269 + do_check_eq(s1.counts[1], 1); 1.270 + do_check_eq(s1.counts[3], 1); 1.271 + 1.272 + var name2 = "testing-histogram2"; 1.273 + expect_success(function () 1.274 + register(addon_id, name2, 2, 4, 4, Telemetry.HISTOGRAM_LINEAR)); 1.275 + 1.276 + var h2 = Telemetry.getAddonHistogram(addon_id, name2); 1.277 + h2.add(2); 1.278 + h2.add(3); 1.279 + var s2 = h2.snapshot(); 1.280 + do_check_eq(s2.histogram_type, Telemetry.HISTOGRAM_LINEAR); 1.281 + do_check_eq(s2.min, 2); 1.282 + do_check_eq(s2.max, 4); 1.283 + do_check_eq(s2.counts[1], 1); 1.284 + do_check_eq(s2.counts[2], 1); 1.285 + 1.286 + // Check that we can register histograms for a different addon with 1.287 + // identical names. 1.288 + var extra_addon = "testing-extra-addon"; 1.289 + expect_success(function () 1.290 + register(extra_addon, name1, 0, 1, 2, Telemetry.HISTOGRAM_BOOLEAN)); 1.291 + 1.292 + // Check that we can register flag histograms. 1.293 + var flag_addon = "testing-flag-addon"; 1.294 + var flag_histogram = "flag-histogram"; 1.295 + expect_success(function() 1.296 + register(flag_addon, flag_histogram, 0, 1, 2, Telemetry.HISTOGRAM_FLAG)) 1.297 + expect_success(function() 1.298 + register(flag_addon, name2, 2, 4, 4, Telemetry.HISTOGRAM_LINEAR)); 1.299 + 1.300 + // Check that we reflect registered addons and histograms. 1.301 + snapshots = Telemetry.addonHistogramSnapshots; 1.302 + do_check_true(addon_id in snapshots) 1.303 + do_check_true(extra_addon in snapshots); 1.304 + do_check_true(flag_addon in snapshots); 1.305 + 1.306 + // Check that we have data for our created histograms. 1.307 + do_check_true(name1 in snapshots[addon_id]); 1.308 + do_check_true(name2 in snapshots[addon_id]); 1.309 + var s1_alt = snapshots[addon_id][name1]; 1.310 + var s2_alt = snapshots[addon_id][name2]; 1.311 + do_check_eq(s1_alt.min, s1.min); 1.312 + do_check_eq(s1_alt.max, s1.max); 1.313 + do_check_eq(s1_alt.histogram_type, s1.histogram_type); 1.314 + do_check_eq(s2_alt.min, s2.min); 1.315 + do_check_eq(s2_alt.max, s2.max); 1.316 + do_check_eq(s2_alt.histogram_type, s2.histogram_type); 1.317 + 1.318 + // Even though we've registered it, it shouldn't show up until data is added to it. 1.319 + do_check_false(name1 in snapshots[extra_addon]); 1.320 + 1.321 + // Flag histograms should show up automagically. 1.322 + do_check_true(flag_histogram in snapshots[flag_addon]); 1.323 + do_check_false(name2 in snapshots[flag_addon]); 1.324 + 1.325 + // Check that we can remove addon histograms. 1.326 + Telemetry.unregisterAddonHistograms(addon_id); 1.327 + snapshots = Telemetry.addonHistogramSnapshots; 1.328 + do_check_false(addon_id in snapshots); 1.329 + // Make sure other addons are unaffected. 1.330 + do_check_true(extra_addon in snapshots); 1.331 +} 1.332 + 1.333 +// Check that telemetry doesn't record in private mode 1.334 +function test_privateMode() { 1.335 + var h = Telemetry.newHistogram("test::private_mode_boolean", "never", 1,2,3, Telemetry.HISTOGRAM_BOOLEAN); 1.336 + var orig = h.snapshot(); 1.337 + Telemetry.canRecord = false; 1.338 + h.add(1); 1.339 + do_check_eq(uneval(orig), uneval(h.snapshot())); 1.340 + Telemetry.canRecord = true; 1.341 + h.add(1); 1.342 + do_check_neq(uneval(orig), uneval(h.snapshot())); 1.343 +} 1.344 + 1.345 +// Check that histograms that aren't flagged as needing extended stats 1.346 +// don't record extended stats. 1.347 +function test_extended_stats() { 1.348 + var h = Telemetry.getHistogramById("GRADIENT_DURATION"); 1.349 + var s = h.snapshot(); 1.350 + do_check_eq(s.sum, 0); 1.351 + do_check_eq(s.log_sum, 0); 1.352 + do_check_eq(s.log_sum_squares, 0); 1.353 + h.add(1); 1.354 + s = h.snapshot(); 1.355 + do_check_eq(s.sum, 1); 1.356 + do_check_eq(s.log_sum, 0); 1.357 + do_check_eq(s.log_sum_squares, 0); 1.358 +} 1.359 + 1.360 +function generateUUID() { 1.361 + let str = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator).generateUUID().toString(); 1.362 + // strip {} 1.363 + return str.substring(1, str.length - 1); 1.364 +} 1.365 + 1.366 +function run_test() 1.367 +{ 1.368 + let kinds = [Telemetry.HISTOGRAM_EXPONENTIAL, Telemetry.HISTOGRAM_LINEAR] 1.369 + for each (let histogram_type in kinds) { 1.370 + let [min, max, bucket_count] = [1, INT_MAX - 1, 10] 1.371 + test_histogram(histogram_type, "test::"+histogram_type, min, max, bucket_count); 1.372 + 1.373 + const nh = Telemetry.newHistogram; 1.374 + expect_fail(function () nh("test::min", "never", 0, max, bucket_count, histogram_type)); 1.375 + expect_fail(function () nh("test::bucket_count", "never", min, max, 1, histogram_type)); 1.376 + } 1.377 + 1.378 + // Instantiate the storage for this histogram and make sure it doesn't 1.379 + // get reflected into JS, as it has no interesting data in it. 1.380 + let h = Telemetry.getHistogramById("NEWTAB_PAGE_PINNED_SITES_COUNT"); 1.381 + do_check_false("NEWTAB_PAGE_PINNED_SITES_COUNT" in Telemetry.histogramSnapshots); 1.382 + 1.383 + test_boolean_histogram(); 1.384 + test_getHistogramById(); 1.385 + test_histogramFrom(); 1.386 + test_getSlowSQL(); 1.387 + test_privateMode(); 1.388 + test_addons(); 1.389 + test_extended_stats(); 1.390 + test_expired_histogram(); 1.391 +}