|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 "use strict"; |
|
5 |
|
6 const Profiler = Cc["@mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler); |
|
7 |
|
8 function run_test() |
|
9 { |
|
10 // Ensure the profiler is not running when the test starts (it could |
|
11 // happen if the MOZ_PROFILER_STARTUP environment variable is set) |
|
12 Profiler.StopProfiler(); |
|
13 DebuggerServer.init(function () { return true; }); |
|
14 DebuggerServer.addBrowserActors(); |
|
15 var client = new DebuggerClient(DebuggerServer.connectPipe()); |
|
16 client.connect(function () { |
|
17 client.listTabs(function(aResponse) { |
|
18 test_profiler_actor(client, aResponse.profilerActor); |
|
19 }); |
|
20 }); |
|
21 do_test_pending(); |
|
22 } |
|
23 |
|
24 function test_profiler_actor(aClient, aProfiler) |
|
25 { |
|
26 aClient.request({ to: aProfiler, type: "isActive" }, function (aResponse) { |
|
27 do_check_false(aResponse.isActive); |
|
28 |
|
29 aClient.request({ to: aProfiler, type: "getFeatures" }, function (aResponse) { |
|
30 var features = Profiler.GetFeatures([]); |
|
31 do_check_eq(aResponse.features.length, features.length); |
|
32 for (var i = 0; i < features.length; i++) |
|
33 do_check_eq(aResponse.features[i], features[i]); |
|
34 |
|
35 aClient.request({ to: aProfiler, type: "startProfiler", features: ['jank', 'js'] }, function (aResponse) { |
|
36 do_check_eq(typeof aResponse.msg, "string"); |
|
37 aClient.request({ to: aProfiler, type: "isActive" }, function (aResponse) { |
|
38 do_check_true(aResponse.isActive); |
|
39 |
|
40 aClient.request({ to: aProfiler, type: "getResponsivenessTimes" }, function (aResponse) { |
|
41 do_check_eq(typeof aResponse.responsivenessTimes, "object"); |
|
42 |
|
43 aClient.request({ to: aProfiler, type: "getSharedLibraryInformation" }, function (aResponse) { |
|
44 do_check_eq(typeof aResponse.sharedLibraryInformation, "string"); |
|
45 try { |
|
46 JSON.parse(aResponse.sharedLibraryInformation); |
|
47 } catch(e) { |
|
48 do_throw(e.toString(), Components.stack.caller); |
|
49 } |
|
50 |
|
51 test_event_notifications(aClient, aProfiler); |
|
52 }); |
|
53 }); |
|
54 }); |
|
55 }); |
|
56 }); |
|
57 }); |
|
58 } |
|
59 |
|
60 function test_event_notifications(aClient, aProfiler) |
|
61 { |
|
62 aClient.request({ to: aProfiler, type: "registerEventNotifications", events: ["foo", "bar"] }, function (aResponse) { |
|
63 do_check_eq(typeof aResponse.registered, "object"); |
|
64 do_check_eq(aResponse.registered.length, 2); |
|
65 do_check_eq(aResponse.registered[0], "foo"); |
|
66 do_check_eq(aResponse.registered[1], "bar"); |
|
67 |
|
68 aClient.request({ to: aProfiler, type: "registerEventNotifications", events: ["foo"] }, function (aResponse) { |
|
69 do_check_eq(typeof aResponse.registered, "object"); |
|
70 do_check_eq(aResponse.registered.length, 0); |
|
71 |
|
72 aClient.addListener("eventNotification", function (aType, aData) { |
|
73 do_check_eq(aType, "eventNotification"); |
|
74 do_check_eq(aData.event, "foo"); |
|
75 do_check_eq(typeof aData.subject, "object"); |
|
76 do_check_eq(aData.subject.foo, "foo"); |
|
77 do_check_eq(aData.data, "foo"); |
|
78 }); |
|
79 var subject = { foo: "foo" }; |
|
80 subject.wrappedJSObject = subject; |
|
81 Services.obs.notifyObservers(subject, "foo", "foo"); |
|
82 |
|
83 aClient.request({ to: aProfiler, type: "unregisterEventNotifications", events: ["foo", "bar", "qux"] }, function (aResponse) { |
|
84 do_check_eq(typeof aResponse.unregistered, "object"); |
|
85 do_check_eq(aResponse.unregistered.length, 2); |
|
86 do_check_eq(aResponse.unregistered[0], "foo"); |
|
87 do_check_eq(aResponse.unregistered[1], "bar"); |
|
88 |
|
89 // All events being now unregistered, sending an event shouldn't |
|
90 // do anything. If it does, the eventNotification listener above |
|
91 // will catch the event and fail on the aData.event test. |
|
92 Services.obs.notifyObservers(null, "bar", null); |
|
93 |
|
94 test_profile(aClient, aProfiler); |
|
95 }); |
|
96 }); |
|
97 }); |
|
98 } |
|
99 |
|
100 function test_profile(aClient, aProfiler) |
|
101 { |
|
102 // No idea why, but Components.stack.sourceLine returns null. |
|
103 var funcLine = Components.stack.lineNumber - 3; |
|
104 // Busy wait a few milliseconds |
|
105 var start = Date.now(); |
|
106 var stack; |
|
107 while (Date.now() - start < 200) { stack = Components.stack; } |
|
108 aClient.request({ to: aProfiler, type: "getProfile" }, function (aResponse) { |
|
109 do_check_eq(typeof aResponse.profile, "object"); |
|
110 do_check_eq(typeof aResponse.profile.meta, "object"); |
|
111 do_check_eq(typeof aResponse.profile.meta.platform, "string"); |
|
112 do_check_eq(typeof aResponse.profile.threads, "object"); |
|
113 do_check_eq(typeof aResponse.profile.threads[0], "object"); |
|
114 do_check_eq(typeof aResponse.profile.threads[0].samples, "object"); |
|
115 do_check_neq(aResponse.profile.threads[0].samples.length, 0); |
|
116 |
|
117 let location = stack.name + " (" + stack.filename + ":" + funcLine + ")"; |
|
118 // At least one sample is expected to have been in the busy wait above. |
|
119 do_check_true(aResponse.profile.threads[0].samples.some(function(sample) { |
|
120 return typeof sample.frames == "object" && |
|
121 sample.frames.length != 0 && |
|
122 sample.frames.some(function(f) { |
|
123 return (f.line == stack.lineNumber) && |
|
124 (f.location == location); |
|
125 }); |
|
126 })); |
|
127 |
|
128 aClient.request({ to: aProfiler, type: "stopProfiler" }, function (aResponse) { |
|
129 do_check_eq(typeof aResponse.msg, "string"); |
|
130 aClient.request({ to: aProfiler, type: "isActive" }, function (aResponse) { |
|
131 do_check_false(aResponse.isActive); |
|
132 aClient.close(function() { |
|
133 test_profiler_status(); |
|
134 }); |
|
135 }); |
|
136 }); |
|
137 }); |
|
138 } |
|
139 |
|
140 function test_profiler_status() |
|
141 { |
|
142 var connectionClosed = DebuggerServer._connectionClosed; |
|
143 var client = new DebuggerClient(DebuggerServer.connectPipe()); |
|
144 |
|
145 client.connect(() => { |
|
146 client.listTabs((aResponse) => { |
|
147 DebuggerServer._connectionClosed = function (conn) { |
|
148 connectionClosed.call(this, conn); |
|
149 |
|
150 // Check that closing the last (only?) connection stops the profiler. |
|
151 do_check_false(Profiler.IsActive()); |
|
152 do_test_finished(); |
|
153 } |
|
154 |
|
155 var profiler = aResponse.profilerActor; |
|
156 do_check_false(Profiler.IsActive()); |
|
157 client.request({ |
|
158 to: profiler, |
|
159 type: "startProfiler", |
|
160 features: [] |
|
161 }, function (aResponse) { |
|
162 do_check_true(Profiler.IsActive()); |
|
163 client.close(); |
|
164 }); |
|
165 }); |
|
166 }); |
|
167 } |