OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/test/chromedriver/performance_logger.h" | 5 #include "chrome/test/chromedriver/performance_logger.h" |
6 | 6 |
7 #include "base/compiler_specific.h" | 7 #include "base/compiler_specific.h" |
8 #include "base/format_macros.h" | 8 #include "base/format_macros.h" |
9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
10 #include "base/memory/scoped_vector.h" | 10 #include "base/memory/scoped_vector.h" |
11 #include "base/time/time.h" | 11 #include "base/time/time.h" |
12 #include "base/values.h" | 12 #include "base/values.h" |
13 #include "chrome/test/chromedriver/chrome/devtools_client_impl.h" | |
13 #include "chrome/test/chromedriver/chrome/log.h" | 14 #include "chrome/test/chromedriver/chrome/log.h" |
14 #include "chrome/test/chromedriver/chrome/status.h" | 15 #include "chrome/test/chromedriver/chrome/status.h" |
15 #include "chrome/test/chromedriver/chrome/stub_devtools_client.h" | 16 #include "chrome/test/chromedriver/chrome/stub_devtools_client.h" |
17 #include "chrome/test/chromedriver/session.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | 18 #include "testing/gtest/include/gtest/gtest.h" |
17 | 19 |
18 namespace { | 20 namespace { |
19 | 21 |
22 struct DevToolsCommand { | |
23 DevToolsCommand(const std::string& in_method, | |
24 base::DictionaryValue* in_params) | |
25 : method(in_method) { | |
26 params.reset(in_params); | |
27 } | |
28 ~DevToolsCommand() {} | |
29 | |
30 std::string method; | |
31 scoped_ptr<base::DictionaryValue> params; | |
32 }; | |
33 | |
20 class FakeDevToolsClient : public StubDevToolsClient { | 34 class FakeDevToolsClient : public StubDevToolsClient { |
21 public: | 35 public: |
22 explicit FakeDevToolsClient(const std::string& id) | 36 explicit FakeDevToolsClient(const std::string& id) |
23 : id_(id), listener_(NULL) {} | 37 : id_(id), listener_(NULL), command_index_(0) {} |
24 virtual ~FakeDevToolsClient() {} | 38 virtual ~FakeDevToolsClient() {} |
25 | 39 |
26 std::string PopSentCommand() { | 40 bool PopSentCommand(DevToolsCommand** out_command) { |
27 std::string command; | 41 if (sent_commands_.size() > command_index_) { |
28 if (!sent_command_queue_.empty()) { | 42 *out_command = sent_commands_.get().at(command_index_++); |
29 command = sent_command_queue_.front(); | 43 return true; |
30 sent_command_queue_.pop_front(); | |
31 } | 44 } |
32 return command; | 45 return false; |
33 } | 46 } |
34 | 47 |
35 Status TriggerEvent(const std::string& method) { | 48 Status TriggerEvent(const std::string& method) { |
36 base::DictionaryValue empty_params; | 49 base::DictionaryValue empty_params; |
37 return listener_->OnEvent(this, method, empty_params); | 50 return listener_->OnEvent(this, method, empty_params); |
38 } | 51 } |
39 | 52 |
53 Status TriggerEvent(const std::string& method, | |
54 const base::DictionaryValue& params) { | |
55 return listener_->OnEvent(this, method, params); | |
56 } | |
57 | |
40 // Overridden from DevToolsClient: | 58 // Overridden from DevToolsClient: |
41 virtual Status ConnectIfNecessary() OVERRIDE { | 59 virtual Status ConnectIfNecessary() OVERRIDE { |
42 return listener_->OnConnected(this); | 60 return listener_->OnConnected(this); |
43 } | 61 } |
44 | 62 |
45 virtual Status SendCommandAndGetResult( | 63 virtual Status SendCommandAndGetResult( |
46 const std::string& method, | 64 const std::string& method, |
47 const base::DictionaryValue& params, | 65 const base::DictionaryValue& params, |
48 scoped_ptr<base::DictionaryValue>* result) OVERRIDE { | 66 scoped_ptr<base::DictionaryValue>* result) OVERRIDE { |
49 sent_command_queue_.push_back(method); | 67 sent_commands_.push_back(new DevToolsCommand(method, |
68 params.DeepCopy())); | |
50 return Status(kOk); | 69 return Status(kOk); |
51 } | 70 } |
52 | 71 |
53 virtual void AddListener(DevToolsEventListener* listener) OVERRIDE { | 72 virtual void AddListener(DevToolsEventListener* listener) OVERRIDE { |
54 CHECK(!listener_); | 73 CHECK(!listener_); |
55 listener_ = listener; | 74 listener_ = listener; |
56 } | 75 } |
57 | 76 |
58 virtual const std::string& GetId() OVERRIDE { | 77 virtual const std::string& GetId() OVERRIDE { |
59 return id_; | 78 return id_; |
60 } | 79 } |
61 | 80 |
62 private: | 81 private: |
63 const std::string id_; // WebView id. | 82 const std::string id_; // WebView id. |
64 std::list<std::string> sent_command_queue_; // Commands that were sent. | 83 ScopedVector<DevToolsCommand> sent_commands_; // Commands that were sent. |
65 DevToolsEventListener* listener_; // The fake allows only one event listener. | 84 DevToolsEventListener* listener_; // The fake allows only one event listener. |
85 size_t command_index_; | |
66 }; | 86 }; |
67 | 87 |
68 struct LogEntry { | 88 struct LogEntry { |
69 const base::Time timestamp; | 89 const base::Time timestamp; |
70 const Log::Level level; | 90 const Log::Level level; |
71 const std::string source; | 91 const std::string source; |
72 const std::string message; | 92 const std::string message; |
73 | 93 |
74 LogEntry(const base::Time& timestamp, | 94 LogEntry(const base::Time& timestamp, |
75 Log::Level level, | 95 Log::Level level, |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
114 if (!value->GetAsDictionary(&dict)) { | 134 if (!value->GetAsDictionary(&dict)) { |
115 SCOPED_TRACE("JSON object is not a dictionary"); | 135 SCOPED_TRACE("JSON object is not a dictionary"); |
116 ADD_FAILURE(); | 136 ADD_FAILURE(); |
117 return scoped_ptr<base::DictionaryValue>(); | 137 return scoped_ptr<base::DictionaryValue>(); |
118 } | 138 } |
119 return scoped_ptr<base::DictionaryValue>(dict->DeepCopy()); | 139 return scoped_ptr<base::DictionaryValue>(dict->DeepCopy()); |
120 } | 140 } |
121 | 141 |
122 void ValidateLogEntry(const LogEntry *entry, | 142 void ValidateLogEntry(const LogEntry *entry, |
123 const std::string& expected_webview, | 143 const std::string& expected_webview, |
124 const std::string& expected_method) { | 144 const std::string& expected_method, |
145 const base::DictionaryValue& expected_params) { | |
125 EXPECT_EQ(Log::kInfo, entry->level); | 146 EXPECT_EQ(Log::kInfo, entry->level); |
126 EXPECT_LT(0, entry->timestamp.ToTimeT()); | 147 EXPECT_LT(0, entry->timestamp.ToTimeT()); |
127 | 148 |
128 scoped_ptr<base::DictionaryValue> message(ParseDictionary(entry->message)); | 149 scoped_ptr<base::DictionaryValue> message(ParseDictionary(entry->message)); |
129 std::string webview; | 150 std::string webview; |
130 EXPECT_TRUE(message->GetString("webview", &webview)); | 151 EXPECT_TRUE(message->GetString("webview", &webview)); |
131 EXPECT_EQ(expected_webview, webview); | 152 EXPECT_EQ(expected_webview, webview); |
132 std::string method; | 153 std::string method; |
133 EXPECT_TRUE(message->GetString("message.method", &method)); | 154 EXPECT_TRUE(message->GetString("message.method", &method)); |
134 EXPECT_EQ(expected_method, method); | 155 EXPECT_EQ(expected_method, method); |
135 base::DictionaryValue* params; | 156 base::DictionaryValue* params; |
136 EXPECT_TRUE(message->GetDictionary("message.params", ¶ms)); | 157 EXPECT_TRUE(message->GetDictionary("message.params", ¶ms)); |
137 EXPECT_EQ(0u, params->size()); | 158 EXPECT_TRUE(params->Equals(&expected_params)); |
159 } | |
160 | |
161 void ValidateLogEntry(const LogEntry *entry, | |
162 const std::string& expected_webview, | |
163 const std::string& expected_method) { | |
164 base::DictionaryValue empty_params; | |
165 ValidateLogEntry(entry, expected_webview, expected_method, empty_params); | |
166 } | |
167 | |
168 void ExpectCommand(FakeDevToolsClient& client, const std::string& method) { | |
169 DevToolsCommand* cmd; | |
170 // Use ASSERT so that test fails if no command is returned. | |
171 ASSERT_TRUE(client.PopSentCommand(&cmd)); | |
172 EXPECT_EQ(method, cmd->method); | |
138 } | 173 } |
139 | 174 |
140 void ExpectEnableDomains(FakeDevToolsClient& client) { | 175 void ExpectEnableDomains(FakeDevToolsClient& client) { |
141 EXPECT_EQ("Network.enable", client.PopSentCommand()); | 176 ExpectCommand(client, "Network.enable"); |
142 EXPECT_EQ("Page.enable", client.PopSentCommand()); | 177 ExpectCommand(client, "Page.enable"); |
143 EXPECT_EQ("Timeline.start", client.PopSentCommand()); | 178 ExpectCommand(client, "Timeline.start"); |
144 EXPECT_TRUE(client.PopSentCommand().empty()); | |
145 } | 179 } |
146 | 180 |
147 } // namespace | 181 } // namespace |
148 | 182 |
149 TEST(PerformanceLogger, OneWebView) { | 183 TEST(PerformanceLogger, OneWebView) { |
150 FakeDevToolsClient client("webview-1"); | 184 FakeDevToolsClient client("webview-1"); |
151 FakeLog log; | 185 FakeLog log; |
152 PerformanceLogger logger(&log); | 186 Session session("test"); |
187 PerformanceLogger logger(&log, &session); | |
153 | 188 |
154 client.AddListener(&logger); | 189 client.AddListener(&logger); |
155 logger.OnConnected(&client); | 190 logger.OnConnected(&client); |
156 ExpectEnableDomains(client); | 191 ExpectEnableDomains(client); |
157 ASSERT_EQ(kOk, client.TriggerEvent("Network.gaga").code()); | 192 ASSERT_EQ(kOk, client.TriggerEvent("Network.gaga").code()); |
158 ASSERT_EQ(kOk, client.TriggerEvent("Page.ulala").code()); | 193 ASSERT_EQ(kOk, client.TriggerEvent("Page.ulala").code()); |
159 // Ignore -- different domain. | 194 // Ignore -- different domain. |
160 ASSERT_EQ(kOk, client.TriggerEvent("Console.bad").code()); | 195 ASSERT_EQ(kOk, client.TriggerEvent("Console.bad").code()); |
161 | 196 |
162 ASSERT_EQ(2u, log.GetEntries().size()); | 197 ASSERT_EQ(2u, log.GetEntries().size()); |
163 ValidateLogEntry(log.GetEntries()[0], "webview-1", "Network.gaga"); | 198 ValidateLogEntry(log.GetEntries()[0], "webview-1", "Network.gaga"); |
164 ValidateLogEntry(log.GetEntries()[1], "webview-1", "Page.ulala"); | 199 ValidateLogEntry(log.GetEntries()[1], "webview-1", "Page.ulala"); |
165 } | 200 } |
166 | 201 |
167 TEST(PerformanceLogger, TwoWebViews) { | 202 TEST(PerformanceLogger, TwoWebViews) { |
168 FakeDevToolsClient client1("webview-1"); | 203 FakeDevToolsClient client1("webview-1"); |
169 FakeDevToolsClient client2("webview-2"); | 204 FakeDevToolsClient client2("webview-2"); |
170 FakeLog log; | 205 FakeLog log; |
171 PerformanceLogger logger(&log); | 206 Session session("test"); |
207 PerformanceLogger logger(&log, &session); | |
172 | 208 |
173 client1.AddListener(&logger); | 209 client1.AddListener(&logger); |
174 client2.AddListener(&logger); | 210 client2.AddListener(&logger); |
175 logger.OnConnected(&client1); | 211 logger.OnConnected(&client1); |
176 logger.OnConnected(&client2); | 212 logger.OnConnected(&client2); |
177 ExpectEnableDomains(client1); | 213 ExpectEnableDomains(client1); |
178 ExpectEnableDomains(client2); | 214 ExpectEnableDomains(client2); |
179 // OnConnected sends the enable command only to that client, not others. | 215 // OnConnected sends the enable command only to that client, not others. |
180 client1.ConnectIfNecessary(); | 216 client1.ConnectIfNecessary(); |
181 ExpectEnableDomains(client1); | 217 ExpectEnableDomains(client1); |
182 EXPECT_TRUE(client2.PopSentCommand().empty()); | 218 DevToolsCommand* cmd; |
219 ASSERT_FALSE(client2.PopSentCommand(&cmd)); | |
183 | 220 |
184 ASSERT_EQ(kOk, client1.TriggerEvent("Page.gaga1").code()); | 221 ASSERT_EQ(kOk, client1.TriggerEvent("Page.gaga1").code()); |
185 ASSERT_EQ(kOk, client2.TriggerEvent("Timeline.gaga2").code()); | 222 ASSERT_EQ(kOk, client2.TriggerEvent("Timeline.gaga2").code()); |
186 | 223 |
187 ASSERT_EQ(2u, log.GetEntries().size()); | 224 ASSERT_EQ(2u, log.GetEntries().size()); |
188 ValidateLogEntry(log.GetEntries()[0], "webview-1", "Page.gaga1"); | 225 ValidateLogEntry(log.GetEntries()[0], "webview-1", "Page.gaga1"); |
189 ValidateLogEntry(log.GetEntries()[1], "webview-2", "Timeline.gaga2"); | 226 ValidateLogEntry(log.GetEntries()[1], "webview-2", "Timeline.gaga2"); |
190 } | 227 } |
191 | 228 |
192 TEST(PerformanceLogger, PerfLoggingPrefs) { | 229 TEST(PerformanceLogger, PerfLoggingPrefs) { |
193 FakeDevToolsClient client("webview-1"); | 230 FakeDevToolsClient client("webview-1"); |
194 FakeLog log; | 231 FakeLog log; |
232 Session session("test"); | |
195 PerfLoggingPrefs prefs; | 233 PerfLoggingPrefs prefs; |
196 ASSERT_EQ(PerfLoggingPrefs::InspectorDomainStatus::kDefaultEnabled, | 234 EXPECT_EQ(PerfLoggingPrefs::InspectorDomainStatus::kDefaultEnabled, |
197 prefs.network); | 235 prefs.network); |
198 prefs.network = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyDisabled; | 236 prefs.network = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyDisabled; |
199 // Trace categories should be ignored until tracing support is implemented. | |
200 prefs.trace_categories = "benchmark,webkit.console"; | 237 prefs.trace_categories = "benchmark,webkit.console"; |
samuong
2014/08/19 20:02:50
blink.console?
| |
201 PerformanceLogger logger(&log, prefs); | 238 PerformanceLogger logger(&log, &session, prefs); |
202 | 239 |
203 client.AddListener(&logger); | 240 client.AddListener(&logger); |
204 logger.OnConnected(&client); | 241 logger.OnConnected(&client); |
205 EXPECT_EQ("Page.enable", client.PopSentCommand()); | 242 ExpectCommand(client, "Page.enable"); |
206 // Trace categories ignored, so Timeline shouldn't be implicitly disabled. | 243 // Do not expect Timeline.enable command since specifying trace categories |
207 EXPECT_EQ("Timeline.start", client.PopSentCommand()); | 244 // implicitly disables Timeline feed. |
208 EXPECT_TRUE(client.PopSentCommand().empty()); | 245 DevToolsCommand* cmd; |
246 ASSERT_FALSE(client.PopSentCommand(&cmd)); | |
209 } | 247 } |
248 | |
249 namespace { | |
250 | |
251 class FakeBrowserwideClient : public FakeDevToolsClient { | |
252 public: | |
253 FakeBrowserwideClient() | |
254 : FakeDevToolsClient(DevToolsClientImpl::kBrowserwideDevToolsClientId), | |
255 events_handled_(false) {} | |
256 virtual ~FakeBrowserwideClient() {} | |
257 | |
258 bool events_handled() const { | |
259 return events_handled_; | |
260 } | |
261 | |
262 // Overridden from DevToolsClient: | |
263 virtual Status HandleEventsUntil( | |
264 const ConditionalFunc& conditional_func, | |
265 const base::TimeDelta& timeout) OVERRIDE { | |
266 TriggerEvent("Tracing.tracingComplete"); | |
267 events_handled_ = true; | |
268 return Status(kOk); | |
269 } | |
270 | |
271 private: | |
272 bool events_handled_; | |
273 }; | |
274 | |
275 } // namespace | |
276 | |
277 TEST(PerformanceLogger, TracingStartStop) { | |
278 FakeBrowserwideClient client; | |
279 FakeLog log; | |
280 Session session("test"); | |
281 PerfLoggingPrefs prefs; | |
282 prefs.trace_categories = "benchmark,blink.console"; | |
283 PerformanceLogger logger(&log, &session, prefs); | |
284 | |
285 client.AddListener(&logger); | |
286 logger.OnConnected(&client); | |
287 DevToolsCommand* cmd; | |
288 ASSERT_TRUE(client.PopSentCommand(&cmd)); | |
289 EXPECT_EQ("Tracing.start", cmd->method); | |
290 std::string expected_cats; | |
291 EXPECT_TRUE(cmd->params->GetString("categories", &expected_cats)); | |
292 EXPECT_EQ("benchmark,blink.console", expected_cats); | |
293 int expected_interval = 0; | |
294 EXPECT_TRUE(cmd->params->GetInteger("bufferUsageReportingInterval", | |
295 &expected_interval)); | |
296 EXPECT_GT(expected_interval, 0); | |
297 ASSERT_FALSE(client.PopSentCommand(&cmd)); | |
298 | |
299 EXPECT_FALSE(client.events_handled()); | |
300 // Trigger a dump of the DevTools trace buffer. | |
301 ASSERT_EQ(kOk, logger.BeforeCommand("GetLog").code()); | |
302 EXPECT_TRUE(client.events_handled()); | |
303 ExpectCommand(client, "Tracing.end"); | |
304 ExpectCommand(client, "Tracing.start"); // Tracing should re-start. | |
305 ASSERT_FALSE(client.PopSentCommand(&cmd)); | |
306 } | |
307 | |
308 TEST(PerformanceLogger, RecordTraceEvents) { | |
309 FakeBrowserwideClient client; | |
310 FakeLog log; | |
311 Session session("test"); | |
312 PerfLoggingPrefs prefs; | |
313 prefs.trace_categories = "benchmark,webkit.console"; | |
samuong
2014/08/19 20:02:50
blink.console?
| |
314 PerformanceLogger logger(&log, &session, prefs); | |
315 | |
316 client.AddListener(&logger); | |
317 logger.OnConnected(&client); | |
318 base::DictionaryValue params; | |
319 base::ListValue* trace_events = new base::ListValue(); | |
320 base::DictionaryValue* event1 = new base::DictionaryValue(); | |
321 event1->SetString("cat", "foo"); | |
322 trace_events->Append(event1); | |
323 base::DictionaryValue* event2 = new base::DictionaryValue(); | |
324 event2->SetString("cat", "bar"); | |
325 trace_events->Append(event2); | |
326 params.Set("value", trace_events); | |
327 ASSERT_EQ(kOk, client.TriggerEvent("Tracing.dataCollected", params).code()); | |
328 | |
329 ASSERT_EQ(2u, log.GetEntries().size()); | |
330 ValidateLogEntry(log.GetEntries()[0], | |
331 DevToolsClientImpl::kBrowserwideDevToolsClientId, | |
332 "Tracing.dataCollected", *event1); | |
333 ValidateLogEntry(log.GetEntries()[1], | |
334 DevToolsClientImpl::kBrowserwideDevToolsClientId, | |
335 "Tracing.dataCollected", *event2); | |
336 } | |
337 | |
338 TEST(PerformanceLogger, ShouldRequestTraceEvents) { | |
339 FakeBrowserwideClient client; | |
340 FakeLog log; | |
341 Session session("test"); | |
342 PerfLoggingPrefs prefs; | |
343 prefs.trace_categories = "benchmark,blink.console"; | |
344 PerformanceLogger logger(&log, &session, prefs); | |
345 | |
346 client.AddListener(&logger); | |
347 logger.OnConnected(&client); | |
348 EXPECT_FALSE(client.events_handled()); | |
349 // Trace events should not be dumped for commands not in whitelist. | |
350 ASSERT_EQ(kOk, logger.BeforeCommand("Blah").code()); | |
351 EXPECT_FALSE(client.events_handled()); | |
352 ASSERT_EQ(kOk, logger.BeforeCommand("Foo").code()); | |
353 EXPECT_FALSE(client.events_handled()); | |
354 // Trace events should always be dumped for GetLog command. | |
355 ASSERT_EQ(kOk, logger.BeforeCommand("GetLog").code()); | |
356 EXPECT_TRUE(client.events_handled()); | |
357 } | |
358 | |
359 TEST(PerformanceLogger, WarnWhenTraceBufferFull) { | |
360 FakeBrowserwideClient client; | |
361 FakeLog log; | |
362 Session session("test"); | |
363 PerfLoggingPrefs prefs; | |
364 prefs.trace_categories = "benchmark,blink.console"; | |
365 PerformanceLogger logger(&log, &session, prefs); | |
366 | |
367 client.AddListener(&logger); | |
368 logger.OnConnected(&client); | |
369 base::DictionaryValue params; | |
370 params.SetDouble("value", 1.0); | |
371 ASSERT_EQ(kOk, client.TriggerEvent("Tracing.bufferUsage", params).code()); | |
372 | |
373 ASSERT_EQ(1u, log.GetEntries().size()); | |
374 LogEntry* entry = log.GetEntries()[0]; | |
375 EXPECT_EQ(Log::kWarning, entry->level); | |
376 EXPECT_LT(0, entry->timestamp.ToTimeT()); | |
377 scoped_ptr<base::DictionaryValue> message(ParseDictionary(entry->message)); | |
378 std::string webview; | |
379 EXPECT_TRUE(message->GetString("webview", &webview)); | |
380 EXPECT_EQ(DevToolsClientImpl::kBrowserwideDevToolsClientId, webview); | |
381 std::string method; | |
382 EXPECT_TRUE(message->GetString("message.method", &method)); | |
383 EXPECT_EQ("Tracing.bufferUsage", method); | |
384 base::DictionaryValue* actual_params; | |
385 EXPECT_TRUE(message->GetDictionary("message.params", &actual_params)); | |
386 EXPECT_TRUE(actual_params->HasKey("error")); | |
387 } | |
OLD | NEW |