michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ michael@0: */ michael@0: /* A testcase to make sure reading late writes stacks works. */ michael@0: michael@0: const Cc = Components.classes; michael@0: const Ci = Components.interfaces; michael@0: const Cu = Components.utils; michael@0: const Cr = Components.results; michael@0: michael@0: Cu.import("resource://gre/modules/Services.jsm", this); michael@0: michael@0: const Telemetry = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry); michael@0: michael@0: // Constants from prio.h for nsIFileOutputStream.init michael@0: const PR_WRONLY = 0x2; michael@0: const PR_CREATE_FILE = 0x8; michael@0: const PR_TRUNCATE = 0x20; michael@0: const RW_OWNER = 0600; michael@0: michael@0: const STACK_SUFFIX1 = "stack1.txt"; michael@0: const STACK_SUFFIX2 = "stack2.txt"; michael@0: const STACK_BOGUS_SUFFIX = "bogus.txt"; michael@0: const LATE_WRITE_PREFIX = "Telemetry.LateWriteFinal-"; michael@0: michael@0: // The names and IDs don't matter, but the format of the IDs does. michael@0: const LOADED_MODULES = { michael@0: '4759A7E6993548C89CAF716A67EC242D00': 'libtest.so', michael@0: 'F77AF15BB8D6419FA875954B4A3506CA00': 'libxul.so', michael@0: '1E2F7FB590424E8F93D60BB88D66B8C500': 'libc.so' michael@0: }; michael@0: const N_MODULES = Object.keys(LOADED_MODULES).length; michael@0: michael@0: // Format of individual items is [index, offset-in-library]. michael@0: const STACK1 = [ michael@0: [ 0, 0 ], michael@0: [ 1, 1 ], michael@0: [ 2, 2 ] michael@0: ]; michael@0: const STACK2 = [ michael@0: [ 0, 0 ], michael@0: [ 1, 5 ], michael@0: [ 2, 10 ], michael@0: ]; michael@0: // XXX The only error checking is for a zero-sized stack. michael@0: const STACK_BOGUS = []; michael@0: michael@0: function write_string_to_file(file, contents) { michael@0: let ostream = Cc["@mozilla.org/network/safe-file-output-stream;1"] michael@0: .createInstance(Ci.nsIFileOutputStream); michael@0: ostream.init(file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, michael@0: RW_OWNER, ostream.DEFER_OPEN); michael@0: ostream.write(contents, contents.length); michael@0: ostream.QueryInterface(Ci.nsISafeOutputStream).finish(); michael@0: ostream.close(); michael@0: } michael@0: michael@0: function construct_file(suffix) { michael@0: let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile); michael@0: let file = profileDirectory.clone(); michael@0: file.append(LATE_WRITE_PREFIX + suffix); michael@0: return file; michael@0: } michael@0: michael@0: function write_late_writes_file(stack, suffix) michael@0: { michael@0: let file = construct_file(suffix); michael@0: let contents = N_MODULES + "\n"; michael@0: for (let id in LOADED_MODULES) { michael@0: contents += id + " " + LOADED_MODULES[id] + "\n"; michael@0: } michael@0: michael@0: contents += stack.length + "\n"; michael@0: for (let element of stack) { michael@0: contents += element[0] + " " + element[1].toString(16) + "\n"; michael@0: } michael@0: michael@0: write_string_to_file(file, contents); michael@0: } michael@0: michael@0: function run_test() { michael@0: do_get_profile(); michael@0: michael@0: write_late_writes_file(STACK1, STACK_SUFFIX1); michael@0: write_late_writes_file(STACK2, STACK_SUFFIX2); michael@0: write_late_writes_file(STACK_BOGUS, STACK_BOGUS_SUFFIX); michael@0: michael@0: let lateWrites = Telemetry.lateWrites; michael@0: do_check_true("memoryMap" in lateWrites); michael@0: do_check_eq(lateWrites.memoryMap.length, 0); michael@0: do_check_true("stacks" in lateWrites); michael@0: do_check_eq(lateWrites.stacks.length, 0); michael@0: michael@0: do_test_pending(); michael@0: Telemetry.asyncFetchTelemetryData(function () { michael@0: actual_test(); michael@0: }); michael@0: } michael@0: michael@0: function actual_test() { michael@0: do_check_false(construct_file(STACK_SUFFIX1).exists()); michael@0: do_check_false(construct_file(STACK_SUFFIX2).exists()); michael@0: do_check_false(construct_file(STACK_BOGUS_SUFFIX).exists()); michael@0: michael@0: let lateWrites = Telemetry.lateWrites; michael@0: michael@0: do_check_true("memoryMap" in lateWrites); michael@0: do_check_eq(lateWrites.memoryMap.length, N_MODULES); michael@0: for (let id in LOADED_MODULES) { michael@0: let matchingLibrary = lateWrites.memoryMap.filter(function(library, idx, array) { michael@0: return library[1] == id; michael@0: }); michael@0: do_check_eq(matchingLibrary.length, 1); michael@0: let library = matchingLibrary[0] michael@0: let name = library[0]; michael@0: do_check_eq(LOADED_MODULES[id], name); michael@0: } michael@0: michael@0: do_check_true("stacks" in lateWrites); michael@0: do_check_eq(lateWrites.stacks.length, 2); michael@0: let uneval_STACKS = [uneval(STACK1), uneval(STACK2)]; michael@0: let first_stack = lateWrites.stacks[0]; michael@0: let second_stack = lateWrites.stacks[1]; michael@0: function stackChecker(canonicalStack) { michael@0: let unevalCanonicalStack = uneval(canonicalStack); michael@0: return function(obj, idx, array) { michael@0: return unevalCanonicalStack == obj; michael@0: } michael@0: } michael@0: do_check_eq(uneval_STACKS.filter(stackChecker(first_stack)).length, 1); michael@0: do_check_eq(uneval_STACKS.filter(stackChecker(second_stack)).length, 1); michael@0: michael@0: do_test_finished(); michael@0: }