summaryrefslogtreecommitdiffstats
path: root/toolkit/components/extensions/test/xpcshell/test_ext_geckoProfiler_control.js
blob: fa2759b7f06fff221a53b6da66b0f2ea06e7f8cb (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

let getExtension = () => {
  return ExtensionTestUtils.loadExtension({
    background: async function () {
      const runningListener = isRunning => {
        if (isRunning) {
          browser.test.sendMessage("started");
        } else {
          browser.test.sendMessage("stopped");
        }
      };

      browser.test.onMessage.addListener(async (message, data) => {
        let result;
        switch (message) {
          case "start":
            result = await browser.geckoProfiler.start({
              bufferSize: 10000,
              windowLength: 20,
              interval: 0.5,
              features: ["js"],
              threads: ["GeckoMain"],
            });
            browser.test.assertEq(undefined, result, "start returns nothing.");
            break;
          case "stop":
            result = await browser.geckoProfiler.stop();
            browser.test.assertEq(undefined, result, "stop returns nothing.");
            break;
          case "pause":
            result = await browser.geckoProfiler.pause();
            browser.test.assertEq(undefined, result, "pause returns nothing.");
            browser.test.sendMessage("paused");
            break;
          case "resume":
            result = await browser.geckoProfiler.resume();
            browser.test.assertEq(undefined, result, "resume returns nothing.");
            browser.test.sendMessage("resumed");
            break;
          case "test profile":
            result = await browser.geckoProfiler.getProfile();
            browser.test.assertTrue(
              "libs" in result,
              "The profile contains libs."
            );
            browser.test.assertTrue(
              "meta" in result,
              "The profile contains meta."
            );
            browser.test.assertTrue(
              "threads" in result,
              "The profile contains threads."
            );
            browser.test.assertTrue(
              result.threads.some(t => t.name == "GeckoMain"),
              "The profile contains a GeckoMain thread."
            );
            browser.test.sendMessage("tested profile");
            break;
          case "test dump to file":
            try {
              await browser.geckoProfiler.dumpProfileToFile(data.fileName);
              browser.test.sendMessage("tested dump to file", {});
            } catch (e) {
              browser.test.sendMessage("tested dump to file", {
                error: e.message,
              });
            }
            break;
          case "test profile as array buffer":
            let arrayBuffer =
              await browser.geckoProfiler.getProfileAsArrayBuffer();
            browser.test.assertTrue(
              arrayBuffer.byteLength >= 2,
              "The profile array buffer contains data."
            );
            let textDecoder = new TextDecoder();
            let profile = JSON.parse(textDecoder.decode(arrayBuffer));
            browser.test.assertTrue(
              "libs" in profile,
              "The profile contains libs."
            );
            browser.test.assertTrue(
              "meta" in profile,
              "The profile contains meta."
            );
            browser.test.assertTrue(
              "threads" in profile,
              "The profile contains threads."
            );
            browser.test.assertTrue(
              profile.threads.some(t => t.name == "GeckoMain"),
              "The profile contains a GeckoMain thread."
            );
            browser.test.sendMessage("tested profile as array buffer");
            break;
          case "remove runningListener":
            browser.geckoProfiler.onRunning.removeListener(runningListener);
            browser.test.sendMessage("removed runningListener");
            break;
        }
      });

      browser.test.sendMessage("ready");

      browser.geckoProfiler.onRunning.addListener(runningListener);
    },

    manifest: {
      permissions: ["geckoProfiler"],
      browser_specific_settings: {
        gecko: {
          id: "profilertest@mozilla.com",
        },
      },
    },
  });
};

let verifyProfileData = profile => {
  ok("libs" in profile, "The profile contains libs.");
  ok("meta" in profile, "The profile contains meta.");
  ok("threads" in profile, "The profile contains threads.");
  ok(
    profile.threads.some(t => t.name == "GeckoMain"),
    "The profile contains a GeckoMain thread."
  );
};

add_task(async function testProfilerControl() {
  const acceptedExtensionIdsPref =
    "extensions.geckoProfiler.acceptedExtensionIds";
  Services.prefs.setCharPref(
    acceptedExtensionIdsPref,
    "profilertest@mozilla.com"
  );

  let extension = getExtension();
  await extension.startup();
  await extension.awaitMessage("ready");
  await extension.awaitMessage("stopped");

  extension.sendMessage("start");
  await extension.awaitMessage("started");

  extension.sendMessage("test profile");
  await extension.awaitMessage("tested profile");

  const profilerPath = PathUtils.join(PathUtils.profileDir, "profiler");
  let data, fileName, targetPath;

  // test with file name only
  fileName = "bar.profile";
  targetPath = PathUtils.join(profilerPath, fileName);
  extension.sendMessage("test dump to file", { fileName });
  data = await extension.awaitMessage("tested dump to file");
  equal(data.error, undefined, "No error thrown");
  ok(await IOUtils.exists(targetPath), "Saved gecko profile exists.");
  verifyProfileData(await IOUtils.readJSON(targetPath));

  // test overwriting the formerly created file
  extension.sendMessage("test dump to file", { fileName });
  data = await extension.awaitMessage("tested dump to file");
  equal(data.error, undefined, "No error thrown");
  ok(await IOUtils.exists(targetPath), "Saved gecko profile exists.");
  verifyProfileData(await IOUtils.readJSON(targetPath));

  // test with a POSIX path, which is not allowed
  fileName = "foo/bar.profile";
  targetPath = PathUtils.join(profilerPath, ...fileName.split("/"));
  extension.sendMessage("test dump to file", { fileName });
  data = await extension.awaitMessage("tested dump to file");
  equal(data.error, "Path cannot contain a subdirectory.");
  ok(!(await IOUtils.exists(targetPath)), "Gecko profile hasn't been saved.");

  // test with a non POSIX path which is not allowed
  fileName = "foo\\bar.profile";
  targetPath = PathUtils.join(profilerPath, ...fileName.split("\\"));
  extension.sendMessage("test dump to file", { fileName });
  data = await extension.awaitMessage("tested dump to file");
  equal(data.error, "Path cannot contain a subdirectory.");
  ok(!(await IOUtils.exists(targetPath)), "Gecko profile hasn't been saved.");

  extension.sendMessage("test profile as array buffer");
  await extension.awaitMessage("tested profile as array buffer");

  extension.sendMessage("pause");
  await extension.awaitMessage("paused");

  extension.sendMessage("resume");
  await extension.awaitMessage("resumed");

  extension.sendMessage("stop");
  await extension.awaitMessage("stopped");

  extension.sendMessage("remove runningListener");
  await extension.awaitMessage("removed runningListener");

  await extension.unload();

  Services.prefs.clearUserPref(acceptedExtensionIdsPref);
});