Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / test / chromedriver / performance_logger_unittest.cc
blob190fb5e9682b2ee4f6c8b661987e7ad44ca8c67a
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
3 // found in the LICENSE file.
5 #include "chrome/test/chromedriver/performance_logger.h"
7 #include "base/compiler_specific.h"
8 #include "base/format_macros.h"
9 #include "base/json/json_reader.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/time/time.h"
12 #include "base/values.h"
13 #include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
14 #include "chrome/test/chromedriver/chrome/log.h"
15 #include "chrome/test/chromedriver/chrome/status.h"
16 #include "chrome/test/chromedriver/chrome/stub_devtools_client.h"
17 #include "chrome/test/chromedriver/session.h"
18 #include "testing/gtest/include/gtest/gtest.h"
20 namespace {
22 struct DevToolsCommand {
23 DevToolsCommand(const std::string& in_method,
24 base::DictionaryValue* in_params)
25 : method(in_method) {
26 params.reset(in_params);
28 ~DevToolsCommand() {}
30 std::string method;
31 scoped_ptr<base::DictionaryValue> params;
34 class FakeDevToolsClient : public StubDevToolsClient {
35 public:
36 explicit FakeDevToolsClient(const std::string& id)
37 : id_(id), listener_(NULL), command_index_(0) {}
38 ~FakeDevToolsClient() override {}
40 bool PopSentCommand(DevToolsCommand** out_command) {
41 if (sent_commands_.size() > command_index_) {
42 *out_command = sent_commands_.get().at(command_index_++);
43 return true;
45 return false;
48 Status TriggerEvent(const std::string& method) {
49 base::DictionaryValue empty_params;
50 return listener_->OnEvent(this, method, empty_params);
53 Status TriggerEvent(const std::string& method,
54 const base::DictionaryValue& params) {
55 return listener_->OnEvent(this, method, params);
58 // Overridden from DevToolsClient:
59 Status ConnectIfNecessary() override { return listener_->OnConnected(this); }
61 Status SendCommandAndGetResult(
62 const std::string& method,
63 const base::DictionaryValue& params,
64 scoped_ptr<base::DictionaryValue>* result) override {
65 sent_commands_.push_back(new DevToolsCommand(method,
66 params.DeepCopy()));
67 return Status(kOk);
70 void AddListener(DevToolsEventListener* listener) override {
71 CHECK(!listener_);
72 listener_ = listener;
75 const std::string& GetId() override { return id_; }
77 private:
78 const std::string id_; // WebView id.
79 ScopedVector<DevToolsCommand> sent_commands_; // Commands that were sent.
80 DevToolsEventListener* listener_; // The fake allows only one event listener.
81 size_t command_index_;
84 struct LogEntry {
85 const base::Time timestamp;
86 const Log::Level level;
87 const std::string source;
88 const std::string message;
90 LogEntry(const base::Time& timestamp,
91 Log::Level level,
92 const std::string& source,
93 const std::string& message)
94 : timestamp(timestamp), level(level), source(source), message(message) {}
97 class FakeLog : public Log {
98 public:
99 void AddEntryTimestamped(const base::Time& timestamp,
100 Level level,
101 const std::string& source,
102 const std::string& message) override;
104 const ScopedVector<LogEntry>& GetEntries() {
105 return entries_;
108 private:
109 ScopedVector<LogEntry> entries_;
112 void FakeLog::AddEntryTimestamped(const base::Time& timestamp,
113 Level level,
114 const std::string& source,
115 const std::string& message) {
116 entries_.push_back(new LogEntry(timestamp, level, source, message));
119 scoped_ptr<base::DictionaryValue> ParseDictionary(const std::string& json) {
120 std::string error;
121 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError(
122 json, base::JSON_PARSE_RFC, NULL, &error));
123 if (value == NULL) {
124 SCOPED_TRACE(json.c_str());
125 SCOPED_TRACE(error.c_str());
126 ADD_FAILURE();
127 return scoped_ptr<base::DictionaryValue>();
129 base::DictionaryValue* dict = NULL;
130 if (!value->GetAsDictionary(&dict)) {
131 SCOPED_TRACE("JSON object is not a dictionary");
132 ADD_FAILURE();
133 return scoped_ptr<base::DictionaryValue>();
135 return scoped_ptr<base::DictionaryValue>(dict->DeepCopy());
138 void ValidateLogEntry(const LogEntry *entry,
139 const std::string& expected_webview,
140 const std::string& expected_method,
141 const base::DictionaryValue& expected_params) {
142 EXPECT_EQ(Log::kInfo, entry->level);
143 EXPECT_LT(0, entry->timestamp.ToTimeT());
145 scoped_ptr<base::DictionaryValue> message(ParseDictionary(entry->message));
146 std::string webview;
147 EXPECT_TRUE(message->GetString("webview", &webview));
148 EXPECT_EQ(expected_webview, webview);
149 std::string method;
150 EXPECT_TRUE(message->GetString("message.method", &method));
151 EXPECT_EQ(expected_method, method);
152 base::DictionaryValue* params;
153 EXPECT_TRUE(message->GetDictionary("message.params", &params));
154 EXPECT_TRUE(params->Equals(&expected_params));
157 void ValidateLogEntry(const LogEntry *entry,
158 const std::string& expected_webview,
159 const std::string& expected_method) {
160 base::DictionaryValue empty_params;
161 ValidateLogEntry(entry, expected_webview, expected_method, empty_params);
164 void ExpectCommand(FakeDevToolsClient& client, const std::string& method) {
165 DevToolsCommand* cmd;
166 // Use ASSERT so that test fails if no command is returned.
167 ASSERT_TRUE(client.PopSentCommand(&cmd));
168 EXPECT_EQ(method, cmd->method);
171 void ExpectEnableDomains(FakeDevToolsClient& client) {
172 ExpectCommand(client, "Network.enable");
173 ExpectCommand(client, "Page.enable");
174 ExpectCommand(client, "Timeline.start");
177 } // namespace
179 TEST(PerformanceLogger, OneWebView) {
180 FakeDevToolsClient client("webview-1");
181 FakeLog log;
182 Session session("test");
183 PerformanceLogger logger(&log, &session);
185 client.AddListener(&logger);
186 logger.OnConnected(&client);
187 ExpectEnableDomains(client);
188 ASSERT_EQ(kOk, client.TriggerEvent("Network.gaga").code());
189 ASSERT_EQ(kOk, client.TriggerEvent("Page.ulala").code());
190 // Ignore -- different domain.
191 ASSERT_EQ(kOk, client.TriggerEvent("Console.bad").code());
193 ASSERT_EQ(2u, log.GetEntries().size());
194 ValidateLogEntry(log.GetEntries()[0], "webview-1", "Network.gaga");
195 ValidateLogEntry(log.GetEntries()[1], "webview-1", "Page.ulala");
198 TEST(PerformanceLogger, TwoWebViews) {
199 FakeDevToolsClient client1("webview-1");
200 FakeDevToolsClient client2("webview-2");
201 FakeLog log;
202 Session session("test");
203 PerformanceLogger logger(&log, &session);
205 client1.AddListener(&logger);
206 client2.AddListener(&logger);
207 logger.OnConnected(&client1);
208 logger.OnConnected(&client2);
209 ExpectEnableDomains(client1);
210 ExpectEnableDomains(client2);
211 // OnConnected sends the enable command only to that client, not others.
212 client1.ConnectIfNecessary();
213 ExpectEnableDomains(client1);
214 DevToolsCommand* cmd;
215 ASSERT_FALSE(client2.PopSentCommand(&cmd));
217 ASSERT_EQ(kOk, client1.TriggerEvent("Page.gaga1").code());
218 ASSERT_EQ(kOk, client2.TriggerEvent("Timeline.gaga2").code());
220 ASSERT_EQ(2u, log.GetEntries().size());
221 ValidateLogEntry(log.GetEntries()[0], "webview-1", "Page.gaga1");
222 ValidateLogEntry(log.GetEntries()[1], "webview-2", "Timeline.gaga2");
225 TEST(PerformanceLogger, PerfLoggingPrefs) {
226 FakeDevToolsClient client("webview-1");
227 FakeLog log;
228 Session session("test");
229 PerfLoggingPrefs prefs;
230 EXPECT_EQ(PerfLoggingPrefs::InspectorDomainStatus::kDefaultEnabled,
231 prefs.network);
232 prefs.network = PerfLoggingPrefs::InspectorDomainStatus::kExplicitlyDisabled;
233 prefs.trace_categories = "benchmark,blink.console";
234 PerformanceLogger logger(&log, &session, prefs);
236 client.AddListener(&logger);
237 logger.OnConnected(&client);
238 ExpectCommand(client, "Page.enable");
239 // Do not expect Timeline.enable command since specifying trace categories
240 // implicitly disables Timeline feed.
241 DevToolsCommand* cmd;
242 ASSERT_FALSE(client.PopSentCommand(&cmd));
245 namespace {
247 class FakeBrowserwideClient : public FakeDevToolsClient {
248 public:
249 FakeBrowserwideClient()
250 : FakeDevToolsClient(DevToolsClientImpl::kBrowserwideDevToolsClientId),
251 events_handled_(false) {}
252 ~FakeBrowserwideClient() override {}
254 bool events_handled() const {
255 return events_handled_;
258 // Overridden from DevToolsClient:
259 Status HandleEventsUntil(const ConditionalFunc& conditional_func,
260 const base::TimeDelta& timeout) override {
261 TriggerEvent("Tracing.tracingComplete");
262 events_handled_ = true;
263 return Status(kOk);
266 private:
267 bool events_handled_;
270 } // namespace
272 TEST(PerformanceLogger, TracingStartStop) {
273 FakeBrowserwideClient client;
274 FakeLog log;
275 Session session("test");
276 PerfLoggingPrefs prefs;
277 prefs.trace_categories = "benchmark,blink.console";
278 PerformanceLogger logger(&log, &session, prefs);
280 client.AddListener(&logger);
281 logger.OnConnected(&client);
282 DevToolsCommand* cmd;
283 ASSERT_TRUE(client.PopSentCommand(&cmd));
284 EXPECT_EQ("Tracing.start", cmd->method);
285 std::string expected_cats;
286 EXPECT_TRUE(cmd->params->GetString("categories", &expected_cats));
287 EXPECT_EQ("benchmark,blink.console", expected_cats);
288 int expected_interval = 0;
289 EXPECT_TRUE(cmd->params->GetInteger("bufferUsageReportingInterval",
290 &expected_interval));
291 EXPECT_GT(expected_interval, 0);
292 ASSERT_FALSE(client.PopSentCommand(&cmd));
294 EXPECT_FALSE(client.events_handled());
295 // Trigger a dump of the DevTools trace buffer.
296 ASSERT_EQ(kOk, logger.BeforeCommand("GetLog").code());
297 EXPECT_TRUE(client.events_handled());
298 ExpectCommand(client, "Tracing.end");
299 ExpectCommand(client, "Tracing.start"); // Tracing should re-start.
300 ASSERT_FALSE(client.PopSentCommand(&cmd));
303 TEST(PerformanceLogger, RecordTraceEvents) {
304 FakeBrowserwideClient client;
305 FakeLog log;
306 Session session("test");
307 PerfLoggingPrefs prefs;
308 prefs.trace_categories = "benchmark,blink.console";
309 PerformanceLogger logger(&log, &session, prefs);
311 client.AddListener(&logger);
312 logger.OnConnected(&client);
313 base::DictionaryValue params;
314 base::ListValue* trace_events = new base::ListValue();
315 base::DictionaryValue* event1 = new base::DictionaryValue();
316 event1->SetString("cat", "foo");
317 trace_events->Append(event1);
318 base::DictionaryValue* event2 = new base::DictionaryValue();
319 event2->SetString("cat", "bar");
320 trace_events->Append(event2);
321 params.Set("value", trace_events);
322 ASSERT_EQ(kOk, client.TriggerEvent("Tracing.dataCollected", params).code());
324 ASSERT_EQ(2u, log.GetEntries().size());
325 ValidateLogEntry(log.GetEntries()[0],
326 DevToolsClientImpl::kBrowserwideDevToolsClientId,
327 "Tracing.dataCollected", *event1);
328 ValidateLogEntry(log.GetEntries()[1],
329 DevToolsClientImpl::kBrowserwideDevToolsClientId,
330 "Tracing.dataCollected", *event2);
333 TEST(PerformanceLogger, ShouldRequestTraceEvents) {
334 FakeBrowserwideClient client;
335 FakeLog log;
336 Session session("test");
337 PerfLoggingPrefs prefs;
338 prefs.trace_categories = "benchmark,blink.console";
339 PerformanceLogger logger(&log, &session, prefs);
341 client.AddListener(&logger);
342 logger.OnConnected(&client);
343 EXPECT_FALSE(client.events_handled());
344 // Trace events should not be dumped for commands not in whitelist.
345 ASSERT_EQ(kOk, logger.BeforeCommand("Blah").code());
346 EXPECT_FALSE(client.events_handled());
347 ASSERT_EQ(kOk, logger.BeforeCommand("Foo").code());
348 EXPECT_FALSE(client.events_handled());
349 // Trace events should always be dumped for GetLog command.
350 ASSERT_EQ(kOk, logger.BeforeCommand("GetLog").code());
351 EXPECT_TRUE(client.events_handled());
354 TEST(PerformanceLogger, WarnWhenTraceBufferFull) {
355 FakeBrowserwideClient client;
356 FakeLog log;
357 Session session("test");
358 PerfLoggingPrefs prefs;
359 prefs.trace_categories = "benchmark,blink.console";
360 PerformanceLogger logger(&log, &session, prefs);
362 client.AddListener(&logger);
363 logger.OnConnected(&client);
364 base::DictionaryValue params;
365 params.SetDouble("value", 1.0);
366 ASSERT_EQ(kOk, client.TriggerEvent("Tracing.bufferUsage", params).code());
368 ASSERT_EQ(1u, log.GetEntries().size());
369 LogEntry* entry = log.GetEntries()[0];
370 EXPECT_EQ(Log::kWarning, entry->level);
371 EXPECT_LT(0, entry->timestamp.ToTimeT());
372 scoped_ptr<base::DictionaryValue> message(ParseDictionary(entry->message));
373 std::string webview;
374 EXPECT_TRUE(message->GetString("webview", &webview));
375 EXPECT_EQ(DevToolsClientImpl::kBrowserwideDevToolsClientId, webview);
376 std::string method;
377 EXPECT_TRUE(message->GetString("message.method", &method));
378 EXPECT_EQ("Tracing.bufferUsage", method);
379 base::DictionaryValue* actual_params;
380 EXPECT_TRUE(message->GetDictionary("message.params", &actual_params));
381 EXPECT_TRUE(actual_params->HasKey("error"));