summaryrefslogtreecommitdiffstats
path: root/toolkit/components/telemetry/tests/unit/test_TelemetryLateWrites.js
blob: 00891c36e8a97a1d771b812d74f2b9d33264a5f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/
*/
/* A testcase to make sure reading late writes stacks works.  */

// Constants from prio.h for nsIFileOutputStream.init
const PR_WRONLY = 0x2;
const PR_CREATE_FILE = 0x8;
const PR_TRUNCATE = 0x20;
const RW_OWNER = parseInt("0600", 8);

const STACK_SUFFIX1 = "stack1.txt";
const STACK_SUFFIX2 = "stack2.txt";
const STACK_BOGUS_SUFFIX = "bogus.txt";
const LATE_WRITE_PREFIX = "Telemetry.LateWriteFinal-";

// The names and IDs don't matter, but the format of the IDs does.
const LOADED_MODULES = {
  "4759A7E6993548C89CAF716A67EC242D00": "libtest.so",
  F77AF15BB8D6419FA875954B4A3506CA00: "libxul.so",
  "1E2F7FB590424E8F93D60BB88D66B8C500": "libc.so",
  E4D6D70CC09A63EF8B88D532F867858800: "libmodμles.so",
};
const N_MODULES = Object.keys(LOADED_MODULES).length;

// Format of individual items is [index, offset-in-library].
const STACK1 = [
  [0, 0],
  [1, 1],
  [2, 2],
  [3, 3],
];
const STACK2 = [
  [0, 0],
  [1, 5],
  [2, 10],
  [3, 15],
];
// XXX The only error checking is for a zero-sized stack.
const STACK_BOGUS = [];

function write_string_to_file(file, contents) {
  let ostream = Cc[
    "@mozilla.org/network/safe-file-output-stream;1"
  ].createInstance(Ci.nsIFileOutputStream);
  ostream.init(
    file,
    PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE,
    RW_OWNER,
    ostream.DEFER_OPEN
  );

  var bos = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(
    Ci.nsIBinaryOutputStream
  );
  bos.setOutputStream(ostream);

  let utf8 = new TextEncoder().encode(contents);
  bos.writeByteArray(utf8);
  ostream.QueryInterface(Ci.nsISafeOutputStream).finish();
  ostream.close();
}

function construct_file(suffix) {
  let profileDirectory = Services.dirsvc.get("ProfD", Ci.nsIFile);
  let file = profileDirectory.clone();
  file.append(LATE_WRITE_PREFIX + suffix);
  return file;
}

function write_late_writes_file(stack, suffix) {
  let file = construct_file(suffix);
  let contents = N_MODULES + "\n";
  for (let id in LOADED_MODULES) {
    contents += id + " " + LOADED_MODULES[id] + "\n";
  }

  contents += stack.length + "\n";
  for (let element of stack) {
    contents += element[0] + " " + element[1].toString(16) + "\n";
  }

  write_string_to_file(file, contents);
}

function run_test() {
  do_get_profile();

  write_late_writes_file(STACK1, STACK_SUFFIX1);
  write_late_writes_file(STACK2, STACK_SUFFIX2);
  write_late_writes_file(STACK_BOGUS, STACK_BOGUS_SUFFIX);

  let lateWrites = Telemetry.lateWrites;
  Assert.ok("memoryMap" in lateWrites);
  Assert.equal(lateWrites.memoryMap.length, 0);
  Assert.ok("stacks" in lateWrites);
  Assert.equal(lateWrites.stacks.length, 0);

  do_test_pending();
  Telemetry.asyncFetchTelemetryData(function () {
    actual_test();
  });
}

function actual_test() {
  Assert.ok(!construct_file(STACK_SUFFIX1).exists());
  Assert.ok(!construct_file(STACK_SUFFIX2).exists());
  Assert.ok(!construct_file(STACK_BOGUS_SUFFIX).exists());

  let lateWrites = Telemetry.lateWrites;

  Assert.ok("memoryMap" in lateWrites);
  Assert.equal(lateWrites.memoryMap.length, N_MODULES);
  for (let id in LOADED_MODULES) {
    let matchingLibrary = lateWrites.memoryMap.filter(function (
      library,
      idx,
      array
    ) {
      return library[1] == id;
    });
    Assert.equal(matchingLibrary.length, 1);
    let library = matchingLibrary[0];
    let name = library[0];
    Assert.equal(LOADED_MODULES[id], name);
  }

  Assert.ok("stacks" in lateWrites);
  Assert.equal(lateWrites.stacks.length, 2);
  let uneval_STACKS = [uneval(STACK1), uneval(STACK2)];
  let first_stack = lateWrites.stacks[0];
  let second_stack = lateWrites.stacks[1];
  function stackChecker(canonicalStack) {
    let unevalCanonicalStack = uneval(canonicalStack);
    return function (obj, idx, array) {
      return unevalCanonicalStack == obj;
    };
  }
  Assert.equal(uneval_STACKS.filter(stackChecker(first_stack)).length, 1);
  Assert.equal(uneval_STACKS.filter(stackChecker(second_stack)).length, 1);

  do_test_finished();
}