Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / chrome / test / chromedriver / chrome / devtools_client_impl_unittest.cc
1 // Copyright (c) 2012 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.
4
5 #include <list>
6 #include <string>
7
8 #include "base/bind.h"
9 #include "base/compiler_specific.h"
10 #include "base/json/json_reader.h"
11 #include "base/json/json_writer.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
16 #include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
17 #include "chrome/test/chromedriver/chrome/status.h"
18 #include "chrome/test/chromedriver/net/sync_websocket.h"
19 #include "chrome/test/chromedriver/net/sync_websocket_factory.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "url/gurl.h"
22
23 namespace {
24
25 Status CloserFunc() {
26   return Status(kOk);
27 }
28
29 class MockSyncWebSocket : public SyncWebSocket {
30  public:
31   MockSyncWebSocket() : connected_(false), id_(-1), queued_messages_(1) {}
32   ~MockSyncWebSocket() override {}
33
34   bool IsConnected() override { return connected_; }
35
36   bool Connect(const GURL& url) override {
37     EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
38     connected_ = true;
39     return true;
40   }
41
42   bool Send(const std::string& message) override {
43     EXPECT_TRUE(connected_);
44     scoped_ptr<base::Value> value(base::JSONReader::Read(message));
45     base::DictionaryValue* dict = NULL;
46     EXPECT_TRUE(value->GetAsDictionary(&dict));
47     if (!dict)
48       return false;
49     EXPECT_TRUE(dict->GetInteger("id", &id_));
50     std::string method;
51     EXPECT_TRUE(dict->GetString("method", &method));
52     EXPECT_STREQ("method", method.c_str());
53     base::DictionaryValue* params = NULL;
54     EXPECT_TRUE(dict->GetDictionary("params", &params));
55     if (!params)
56       return false;
57     int param = -1;
58     EXPECT_TRUE(params->GetInteger("param", &param));
59     EXPECT_EQ(1, param);
60     return true;
61   }
62
63   SyncWebSocket::StatusCode ReceiveNextMessage(
64       std::string* message,
65       const base::TimeDelta& timeout) override {
66     if (timeout <= base::TimeDelta())
67       return SyncWebSocket::kTimeout;
68     base::DictionaryValue response;
69     response.SetInteger("id", id_);
70     base::DictionaryValue result;
71     result.SetInteger("param", 1);
72     response.Set("result", result.DeepCopy());
73     base::JSONWriter::Write(&response, message);
74     --queued_messages_;
75     return SyncWebSocket::kOk;
76   }
77
78   bool HasNextMessage() override { return queued_messages_ > 0; }
79
80  protected:
81   bool connected_;
82   int id_;
83   int queued_messages_;
84 };
85
86 template <typename T>
87 scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket() {
88   return scoped_ptr<SyncWebSocket>(new T());
89 }
90
91 class DevToolsClientImplTest : public testing::Test {
92  protected:
93   DevToolsClientImplTest() : long_timeout_(base::TimeDelta::FromMinutes(5)) {}
94
95   const base::TimeDelta long_timeout_;
96 };
97
98 }  // namespace
99
100 TEST_F(DevToolsClientImplTest, SendCommand) {
101   SyncWebSocketFactory factory =
102       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
103   DevToolsClientImpl client(factory, "http://url", "id",
104                             base::Bind(&CloserFunc));
105   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
106   base::DictionaryValue params;
107   params.SetInteger("param", 1);
108   ASSERT_EQ(kOk, client.SendCommand("method", params).code());
109 }
110
111 TEST_F(DevToolsClientImplTest, SendCommandAndGetResult) {
112   SyncWebSocketFactory factory =
113       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
114   DevToolsClientImpl client(factory, "http://url", "id",
115                             base::Bind(&CloserFunc));
116   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
117   base::DictionaryValue params;
118   params.SetInteger("param", 1);
119   scoped_ptr<base::DictionaryValue> result;
120   Status status = client.SendCommandAndGetResult("method", params, &result);
121   ASSERT_EQ(kOk, status.code());
122   std::string json;
123   base::JSONWriter::Write(result.get(), &json);
124   ASSERT_STREQ("{\"param\":1}", json.c_str());
125 }
126
127 namespace {
128
129 class MockSyncWebSocket2 : public SyncWebSocket {
130  public:
131   MockSyncWebSocket2() {}
132   ~MockSyncWebSocket2() override {}
133
134   bool IsConnected() override { return false; }
135
136   bool Connect(const GURL& url) override { return false; }
137
138   bool Send(const std::string& message) override {
139     EXPECT_TRUE(false);
140     return false;
141   }
142
143   SyncWebSocket::StatusCode ReceiveNextMessage(
144       std::string* message,
145       const base::TimeDelta& timeout) override {
146     EXPECT_TRUE(false);
147     return SyncWebSocket::kDisconnected;
148   }
149
150   bool HasNextMessage() override { return true; }
151 };
152
153 }  // namespace
154
155 TEST_F(DevToolsClientImplTest, ConnectIfNecessaryConnectFails) {
156   SyncWebSocketFactory factory =
157       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket2>);
158   DevToolsClientImpl client(factory, "http://url", "id",
159                             base::Bind(&CloserFunc));
160   ASSERT_EQ(kDisconnected, client.ConnectIfNecessary().code());
161 }
162
163 namespace {
164
165 class MockSyncWebSocket3 : public SyncWebSocket {
166  public:
167   MockSyncWebSocket3() : connected_(false) {}
168   ~MockSyncWebSocket3() override {}
169
170   bool IsConnected() override { return connected_; }
171
172   bool Connect(const GURL& url) override {
173     connected_ = true;
174     return true;
175   }
176
177   bool Send(const std::string& message) override { return false; }
178
179   SyncWebSocket::StatusCode ReceiveNextMessage(
180       std::string* message,
181       const base::TimeDelta& timeout) override {
182     EXPECT_TRUE(false);
183     return SyncWebSocket::kDisconnected;
184   }
185
186   bool HasNextMessage() override { return true; }
187
188  private:
189   bool connected_;
190 };
191
192 }  // namespace
193
194 TEST_F(DevToolsClientImplTest, SendCommandSendFails) {
195   SyncWebSocketFactory factory =
196       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket3>);
197   DevToolsClientImpl client(factory, "http://url", "id",
198                             base::Bind(&CloserFunc));
199   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
200   base::DictionaryValue params;
201   ASSERT_TRUE(client.SendCommand("method", params).IsError());
202 }
203
204 namespace {
205
206 class MockSyncWebSocket4 : public SyncWebSocket {
207  public:
208   MockSyncWebSocket4() : connected_(false) {}
209   ~MockSyncWebSocket4() override {}
210
211   bool IsConnected() override { return connected_; }
212
213   bool Connect(const GURL& url) override {
214     connected_ = true;
215     return true;
216   }
217
218   bool Send(const std::string& message) override { return true; }
219
220   SyncWebSocket::StatusCode ReceiveNextMessage(
221       std::string* message,
222       const base::TimeDelta& timeout) override {
223     return SyncWebSocket::kDisconnected;
224   }
225
226   bool HasNextMessage() override { return true; }
227
228  private:
229   bool connected_;
230 };
231
232 }  // namespace
233
234 TEST_F(DevToolsClientImplTest, SendCommandReceiveNextMessageFails) {
235   SyncWebSocketFactory factory =
236       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket4>);
237   DevToolsClientImpl client(factory, "http://url", "id",
238                             base::Bind(&CloserFunc));
239   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
240   base::DictionaryValue params;
241   ASSERT_TRUE(client.SendCommand("method", params).IsError());
242 }
243
244 namespace {
245
246 class FakeSyncWebSocket : public SyncWebSocket {
247  public:
248   FakeSyncWebSocket() : connected_(false) {}
249   ~FakeSyncWebSocket() override {}
250
251   bool IsConnected() override { return connected_; }
252
253   bool Connect(const GURL& url) override {
254     EXPECT_FALSE(connected_);
255     connected_ = true;
256     return true;
257   }
258
259   bool Send(const std::string& message) override { return true; }
260
261   SyncWebSocket::StatusCode ReceiveNextMessage(
262       std::string* message,
263       const base::TimeDelta& timeout) override {
264     return SyncWebSocket::kOk;
265   }
266
267   bool HasNextMessage() override { return true; }
268
269  private:
270   bool connected_;
271 };
272
273 bool ReturnCommand(
274     const std::string& message,
275     int expected_id,
276     internal::InspectorMessageType* type,
277     internal::InspectorEvent* event,
278     internal::InspectorCommandResponse* command_response) {
279   *type = internal::kCommandResponseMessageType;
280   command_response->id = expected_id;
281   command_response->result.reset(new base::DictionaryValue());
282   return true;
283 }
284
285 bool ReturnBadResponse(
286     const std::string& message,
287     int expected_id,
288     internal::InspectorMessageType* type,
289     internal::InspectorEvent* event,
290     internal::InspectorCommandResponse* command_response) {
291   *type = internal::kCommandResponseMessageType;
292   command_response->id = expected_id;
293   command_response->result.reset(new base::DictionaryValue());
294   return false;
295 }
296
297 bool ReturnCommandBadId(
298     const std::string& message,
299     int expected_id,
300     internal::InspectorMessageType* type,
301     internal::InspectorEvent* event,
302     internal::InspectorCommandResponse* command_response) {
303   *type = internal::kCommandResponseMessageType;
304   command_response->id = expected_id + 100;
305   command_response->result.reset(new base::DictionaryValue());
306   return true;
307 }
308
309 bool ReturnCommandError(
310     const std::string& message,
311     int expected_id,
312     internal::InspectorMessageType* type,
313     internal::InspectorEvent* event,
314     internal::InspectorCommandResponse* command_response) {
315   *type = internal::kCommandResponseMessageType;
316   command_response->id = expected_id;
317   command_response->error = "err";
318   return true;
319 }
320
321 class MockListener : public DevToolsEventListener {
322  public:
323   MockListener() : called_(false) {}
324   ~MockListener() override { EXPECT_TRUE(called_); }
325
326   Status OnConnected(DevToolsClient* client) override { return Status(kOk); }
327
328   Status OnEvent(DevToolsClient* client,
329                  const std::string& method,
330                  const base::DictionaryValue& params) override {
331     called_ = true;
332     EXPECT_STREQ("method", method.c_str());
333     EXPECT_TRUE(params.HasKey("key"));
334     return Status(kOk);
335   }
336
337  private:
338   bool called_;
339 };
340
341 bool ReturnEventThenResponse(
342     bool* first,
343     const std::string& message,
344     int expected_id,
345     internal::InspectorMessageType* type,
346     internal::InspectorEvent* event,
347     internal::InspectorCommandResponse* command_response) {
348   if (*first) {
349     *type = internal::kEventMessageType;
350     event->method = "method";
351     event->params.reset(new base::DictionaryValue());
352     event->params->SetInteger("key", 1);
353   } else {
354     *type = internal::kCommandResponseMessageType;
355     command_response->id = expected_id;
356     base::DictionaryValue params;
357     command_response->result.reset(new base::DictionaryValue());
358     command_response->result->SetInteger("key", 2);
359   }
360   *first = false;
361   return true;
362 }
363
364 bool ReturnEvent(
365     const std::string& message,
366     int expected_id,
367     internal::InspectorMessageType* type,
368     internal::InspectorEvent* event,
369     internal::InspectorCommandResponse* command_response) {
370   *type = internal::kEventMessageType;
371   event->method = "method";
372   event->params.reset(new base::DictionaryValue());
373   event->params->SetInteger("key", 1);
374   return true;
375 }
376
377 bool ReturnOutOfOrderResponses(
378     int* recurse_count,
379     DevToolsClient* client,
380     const std::string& message,
381     int expected_id,
382     internal::InspectorMessageType* type,
383     internal::InspectorEvent* event,
384     internal::InspectorCommandResponse* command_response) {
385   int key = 0;
386   base::DictionaryValue params;
387   params.SetInteger("param", 1);
388   switch ((*recurse_count)++) {
389     case 0:
390       client->SendCommand("method", params);
391       *type = internal::kEventMessageType;
392       event->method = "method";
393       event->params.reset(new base::DictionaryValue());
394       event->params->SetInteger("key", 1);
395       return true;
396     case 1:
397       command_response->id = expected_id - 1;
398       key = 2;
399       break;
400     case 2:
401       command_response->id = expected_id;
402       key = 3;
403       break;
404   }
405   *type = internal::kCommandResponseMessageType;
406   command_response->result.reset(new base::DictionaryValue());
407   command_response->result->SetInteger("key", key);
408   return true;
409 }
410
411 bool ReturnError(
412     const std::string& message,
413     int expected_id,
414     internal::InspectorMessageType* type,
415     internal::InspectorEvent* event,
416     internal::InspectorCommandResponse* command_response) {
417   return false;
418 }
419
420 Status AlwaysTrue(bool* is_met) {
421   *is_met = true;
422   return Status(kOk);
423 }
424
425 Status AlwaysError(bool* is_met) {
426   return Status(kUnknownError);
427 }
428
429 }  // namespace
430
431 TEST_F(DevToolsClientImplTest, SendCommandOnlyConnectsOnce) {
432   SyncWebSocketFactory factory =
433       base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
434   DevToolsClientImpl client(factory, "http://url", "id",
435                             base::Bind(&CloserFunc),
436                             base::Bind(&ReturnCommand));
437   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
438   base::DictionaryValue params;
439   ASSERT_TRUE(client.SendCommand("method", params).IsOk());
440   ASSERT_TRUE(client.SendCommand("method", params).IsOk());
441 }
442
443 TEST_F(DevToolsClientImplTest, SendCommandBadResponse) {
444   SyncWebSocketFactory factory =
445       base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
446   DevToolsClientImpl client(factory, "http://url", "id",
447                             base::Bind(&CloserFunc),
448                             base::Bind(&ReturnBadResponse));
449   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
450   base::DictionaryValue params;
451   ASSERT_TRUE(client.SendCommand("method", params).IsError());
452 }
453
454 TEST_F(DevToolsClientImplTest, SendCommandBadId) {
455   SyncWebSocketFactory factory =
456       base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
457   DevToolsClientImpl client(factory, "http://url", "id",
458                             base::Bind(&CloserFunc),
459                             base::Bind(&ReturnCommandBadId));
460   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
461   base::DictionaryValue params;
462   ASSERT_TRUE(client.SendCommand("method", params).IsError());
463 }
464
465 TEST_F(DevToolsClientImplTest, SendCommandResponseError) {
466   SyncWebSocketFactory factory =
467       base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
468   DevToolsClientImpl client(factory, "http://url", "id",
469                             base::Bind(&CloserFunc),
470                             base::Bind(&ReturnCommandError));
471   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
472   base::DictionaryValue params;
473   ASSERT_TRUE(client.SendCommand("method", params).IsError());
474 }
475
476 TEST_F(DevToolsClientImplTest, SendCommandEventBeforeResponse) {
477   SyncWebSocketFactory factory =
478       base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
479   MockListener listener;
480   bool first = true;
481   DevToolsClientImpl client(factory, "http://url", "id",
482                             base::Bind(&CloserFunc),
483                             base::Bind(&ReturnEventThenResponse, &first));
484   client.AddListener(&listener);
485   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
486   base::DictionaryValue params;
487   scoped_ptr<base::DictionaryValue> result;
488   ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
489   ASSERT_TRUE(result);
490   int key;
491   ASSERT_TRUE(result->GetInteger("key", &key));
492   ASSERT_EQ(2, key);
493 }
494
495 TEST(ParseInspectorMessage, NonJson) {
496   internal::InspectorMessageType type;
497   internal::InspectorEvent event;
498   internal::InspectorCommandResponse response;
499   ASSERT_FALSE(internal::ParseInspectorMessage(
500       "hi", 0, &type, &event, &response));
501 }
502
503 TEST(ParseInspectorMessage, NeitherCommandNorEvent) {
504   internal::InspectorMessageType type;
505   internal::InspectorEvent event;
506   internal::InspectorCommandResponse response;
507   ASSERT_FALSE(internal::ParseInspectorMessage(
508       "{}", 0, &type, &event, &response));
509 }
510
511 TEST(ParseInspectorMessage, EventNoParams) {
512   internal::InspectorMessageType type;
513   internal::InspectorEvent event;
514   internal::InspectorCommandResponse response;
515   ASSERT_TRUE(internal::ParseInspectorMessage(
516       "{\"method\":\"method\"}", 0, &type, &event, &response));
517   ASSERT_EQ(internal::kEventMessageType, type);
518   ASSERT_STREQ("method", event.method.c_str());
519   ASSERT_TRUE(event.params->IsType(base::Value::TYPE_DICTIONARY));
520 }
521
522 TEST(ParseInspectorMessage, EventWithParams) {
523   internal::InspectorMessageType type;
524   internal::InspectorEvent event;
525   internal::InspectorCommandResponse response;
526   ASSERT_TRUE(internal::ParseInspectorMessage(
527       "{\"method\":\"method\",\"params\":{\"key\":100}}",
528       0, &type, &event, &response));
529   ASSERT_EQ(internal::kEventMessageType, type);
530   ASSERT_STREQ("method", event.method.c_str());
531   int key;
532   ASSERT_TRUE(event.params->GetInteger("key", &key));
533   ASSERT_EQ(100, key);
534 }
535
536 TEST(ParseInspectorMessage, CommandNoErrorOrResult) {
537   internal::InspectorMessageType type;
538   internal::InspectorEvent event;
539   internal::InspectorCommandResponse response;
540   // As per Chromium issue 392577, DevTools does not necessarily return a
541   // "result" dictionary for every valid response. If neither "error" nor
542   // "result" keys are present, a blank result dictionary should be inferred.
543   ASSERT_TRUE(internal::ParseInspectorMessage(
544       "{\"id\":1}", 0, &type, &event, &response));
545   ASSERT_TRUE(response.result->empty());
546 }
547
548 TEST(ParseInspectorMessage, CommandError) {
549   internal::InspectorMessageType type;
550   internal::InspectorEvent event;
551   internal::InspectorCommandResponse response;
552   ASSERT_TRUE(internal::ParseInspectorMessage(
553       "{\"id\":1,\"error\":{}}", 0, &type, &event, &response));
554   ASSERT_EQ(internal::kCommandResponseMessageType, type);
555   ASSERT_EQ(1, response.id);
556   ASSERT_TRUE(response.error.length());
557   ASSERT_FALSE(response.result);
558 }
559
560 TEST(ParseInspectorMessage, Command) {
561   internal::InspectorMessageType type;
562   internal::InspectorEvent event;
563   internal::InspectorCommandResponse response;
564   ASSERT_TRUE(internal::ParseInspectorMessage(
565       "{\"id\":1,\"result\":{\"key\":1}}", 0, &type, &event, &response));
566   ASSERT_EQ(internal::kCommandResponseMessageType, type);
567   ASSERT_EQ(1, response.id);
568   ASSERT_FALSE(response.error.length());
569   int key;
570   ASSERT_TRUE(response.result->GetInteger("key", &key));
571   ASSERT_EQ(1, key);
572 }
573
574 TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
575   MockListener listener;
576   SyncWebSocketFactory factory =
577       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
578   DevToolsClientImpl client(factory, "http://url", "id",
579                             base::Bind(&CloserFunc),
580                             base::Bind(&ReturnEvent));
581   client.AddListener(&listener);
582   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
583   Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
584                                            long_timeout_);
585   ASSERT_EQ(kOk, status.code());
586 }
587
588 TEST_F(DevToolsClientImplTest, HandleEventsUntilTimeout) {
589   SyncWebSocketFactory factory =
590       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
591   DevToolsClientImpl client(factory, "http://url", "id",
592                             base::Bind(&CloserFunc),
593                             base::Bind(&ReturnEvent));
594   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
595   Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
596                                            base::TimeDelta());
597   ASSERT_EQ(kTimeout, status.code());
598 }
599
600 TEST_F(DevToolsClientImplTest, WaitForNextEventCommand) {
601   SyncWebSocketFactory factory =
602       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
603   DevToolsClientImpl client(factory, "http://url", "id",
604                             base::Bind(&CloserFunc),
605                             base::Bind(&ReturnCommand));
606   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
607   Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
608                                            long_timeout_);
609   ASSERT_EQ(kUnknownError, status.code());
610 }
611
612 TEST_F(DevToolsClientImplTest, WaitForNextEventError) {
613   SyncWebSocketFactory factory =
614       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
615   DevToolsClientImpl client(factory, "http://url", "id",
616                             base::Bind(&CloserFunc),
617                             base::Bind(&ReturnError));
618   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
619   Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
620                                            long_timeout_);
621   ASSERT_EQ(kUnknownError, status.code());
622 }
623
624 TEST_F(DevToolsClientImplTest, WaitForNextEventConditionalFuncReturnsError) {
625   SyncWebSocketFactory factory =
626       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
627   DevToolsClientImpl client(factory, "http://url", "id",
628                             base::Bind(&CloserFunc),
629                             base::Bind(&ReturnEvent));
630   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
631   Status status = client.HandleEventsUntil(base::Bind(&AlwaysError),
632                                            long_timeout_);
633   ASSERT_EQ(kUnknownError, status.code());
634 }
635
636 TEST_F(DevToolsClientImplTest, NestedCommandsWithOutOfOrderResults) {
637   SyncWebSocketFactory factory =
638       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
639   int recurse_count = 0;
640   DevToolsClientImpl client(factory, "http://url", "id",
641                             base::Bind(&CloserFunc));
642   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
643   client.SetParserFuncForTesting(
644       base::Bind(&ReturnOutOfOrderResponses, &recurse_count, &client));
645   base::DictionaryValue params;
646   params.SetInteger("param", 1);
647   scoped_ptr<base::DictionaryValue> result;
648   ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
649   ASSERT_TRUE(result);
650   int key;
651   ASSERT_TRUE(result->GetInteger("key", &key));
652   ASSERT_EQ(2, key);
653 }
654
655 namespace {
656
657 class OnConnectedListener : public DevToolsEventListener {
658  public:
659   OnConnectedListener(const std::string& method, DevToolsClient* client)
660       : method_(method),
661         client_(client),
662         on_connected_called_(false),
663         on_event_called_(false) {
664     client_->AddListener(this);
665   }
666   ~OnConnectedListener() override {}
667
668   void VerifyCalled() {
669     EXPECT_TRUE(on_connected_called_);
670     EXPECT_TRUE(on_event_called_);
671   }
672
673   Status OnConnected(DevToolsClient* client) override {
674     EXPECT_EQ(client_, client);
675     EXPECT_STREQ("onconnected-id", client->GetId().c_str());
676     EXPECT_FALSE(on_connected_called_);
677     EXPECT_FALSE(on_event_called_);
678     on_connected_called_ = true;
679     base::DictionaryValue params;
680     return client_->SendCommand(method_, params);
681   }
682
683   Status OnEvent(DevToolsClient* client,
684                  const std::string& method,
685                  const base::DictionaryValue& params) override {
686     EXPECT_EQ(client_, client);
687     EXPECT_STREQ("onconnected-id", client->GetId().c_str());
688     EXPECT_TRUE(on_connected_called_);
689     on_event_called_ = true;
690     return Status(kOk);
691   }
692
693  private:
694   std::string method_;
695   DevToolsClient* client_;
696   bool on_connected_called_;
697   bool on_event_called_;
698 };
699
700 class OnConnectedSyncWebSocket : public SyncWebSocket {
701  public:
702   OnConnectedSyncWebSocket() : connected_(false) {}
703   ~OnConnectedSyncWebSocket() override {}
704
705   bool IsConnected() override { return connected_; }
706
707   bool Connect(const GURL& url) override {
708     connected_ = true;
709     return true;
710   }
711
712   bool Send(const std::string& message) override {
713     EXPECT_TRUE(connected_);
714     scoped_ptr<base::Value> value(base::JSONReader::Read(message));
715     base::DictionaryValue* dict = NULL;
716     EXPECT_TRUE(value->GetAsDictionary(&dict));
717     if (!dict)
718       return false;
719     int id;
720     EXPECT_TRUE(dict->GetInteger("id", &id));
721     std::string method;
722     EXPECT_TRUE(dict->GetString("method", &method));
723
724     base::DictionaryValue response;
725     response.SetInteger("id", id);
726     response.Set("result", new base::DictionaryValue());
727     std::string json_response;
728     base::JSONWriter::Write(&response, &json_response);
729     queued_response_.push_back(json_response);
730
731     // Push one event.
732     base::DictionaryValue event;
733     event.SetString("method", "updateEvent");
734     event.Set("params", new base::DictionaryValue());
735     std::string json_event;
736     base::JSONWriter::Write(&event, &json_event);
737     queued_response_.push_back(json_event);
738
739     return true;
740   }
741
742   SyncWebSocket::StatusCode ReceiveNextMessage(
743       std::string* message,
744       const base::TimeDelta& timeout) override {
745     if (queued_response_.empty())
746       return SyncWebSocket::kDisconnected;
747     *message = queued_response_.front();
748     queued_response_.pop_front();
749     return SyncWebSocket::kOk;
750   }
751
752   bool HasNextMessage() override { return !queued_response_.empty(); }
753
754  private:
755   bool connected_;
756   std::list<std::string> queued_response_;
757 };
758
759 }  // namespace
760
761 TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnCommand) {
762   SyncWebSocketFactory factory =
763       base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
764   DevToolsClientImpl client(factory, "http://url", "onconnected-id",
765                             base::Bind(&CloserFunc));
766   OnConnectedListener listener1("DOM.getDocument", &client);
767   OnConnectedListener listener2("Runtime.enable", &client);
768   OnConnectedListener listener3("Page.enable", &client);
769   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
770   base::DictionaryValue params;
771   EXPECT_EQ(kOk, client.SendCommand("Runtime.execute", params).code());
772   listener1.VerifyCalled();
773   listener2.VerifyCalled();
774   listener3.VerifyCalled();
775 }
776
777 TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnHandleEventsUntil) {
778   SyncWebSocketFactory factory =
779       base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
780   DevToolsClientImpl client(factory, "http://url", "onconnected-id",
781                             base::Bind(&CloserFunc));
782   OnConnectedListener listener1("DOM.getDocument", &client);
783   OnConnectedListener listener2("Runtime.enable", &client);
784   OnConnectedListener listener3("Page.enable", &client);
785   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
786   EXPECT_EQ(kOk, client.HandleReceivedEvents().code());
787   listener1.VerifyCalled();
788   listener2.VerifyCalled();
789   listener3.VerifyCalled();
790 }
791
792 namespace {
793
794 class MockSyncWebSocket5 : public SyncWebSocket {
795  public:
796   MockSyncWebSocket5() : request_no_(0) {}
797   ~MockSyncWebSocket5() override {}
798
799   bool IsConnected() override { return true; }
800
801   bool Connect(const GURL& url) override { return true; }
802
803   bool Send(const std::string& message) override { return true; }
804
805   SyncWebSocket::StatusCode ReceiveNextMessage(
806       std::string* message,
807       const base::TimeDelta& timeout) override {
808     if (request_no_ == 0) {
809       *message = "{\"method\": \"m\", \"params\": {}}";
810     } else {
811       *message = base::StringPrintf(
812           "{\"result\": {}, \"id\": %d}", request_no_);
813     }
814     request_no_++;
815     return SyncWebSocket::kOk;
816   }
817
818   bool HasNextMessage() override { return false; }
819
820  private:
821   int request_no_;
822 };
823
824 class OtherEventListener : public DevToolsEventListener {
825  public:
826   OtherEventListener() : received_event_(false) {}
827   ~OtherEventListener() override {}
828
829   Status OnConnected(DevToolsClient* client) override { return Status(kOk); }
830   Status OnEvent(DevToolsClient* client,
831                  const std::string& method,
832                  const base::DictionaryValue& params) override {
833     received_event_ = true;
834     return Status(kOk);
835   }
836
837   bool received_event_;
838 };
839
840 class OnEventListener : public DevToolsEventListener {
841  public:
842   OnEventListener(DevToolsClient* client,
843                   OtherEventListener* other_listener)
844       : client_(client),
845         other_listener_(other_listener) {}
846   ~OnEventListener() override {}
847
848   Status OnConnected(DevToolsClient* client) override {
849     EXPECT_EQ(client_, client);
850     return Status(kOk);
851   }
852
853   Status OnEvent(DevToolsClient* client,
854                  const std::string& method,
855                  const base::DictionaryValue& params) override {
856     EXPECT_EQ(client_, client);
857     client_->SendCommand("method", params);
858     EXPECT_TRUE(other_listener_->received_event_);
859     return Status(kOk);
860   }
861
862  private:
863   DevToolsClient* client_;
864   OtherEventListener* other_listener_;
865 };
866
867 }  // namespace
868
869 TEST_F(DevToolsClientImplTest, ProcessOnEventFirst) {
870   SyncWebSocketFactory factory =
871       base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket5>);
872   DevToolsClientImpl client(factory, "http://url", "id",
873                             base::Bind(&CloserFunc));
874   OtherEventListener listener2;
875   OnEventListener listener1(&client, &listener2);
876   client.AddListener(&listener1);
877   client.AddListener(&listener2);
878   base::DictionaryValue params;
879   EXPECT_EQ(kOk, client.SendCommand("method", params).code());
880 }
881
882 namespace {
883
884 class DisconnectedSyncWebSocket : public MockSyncWebSocket {
885  public:
886   DisconnectedSyncWebSocket() : connection_count_(0), command_count_(0) {}
887   ~DisconnectedSyncWebSocket() override {}
888
889   bool Connect(const GURL& url) override {
890     connection_count_++;
891     connected_ = connection_count_ != 2;
892     return connected_;
893   }
894
895   bool Send(const std::string& message) override {
896     command_count_++;
897     if (command_count_ == 1) {
898       connected_ = false;
899       return false;
900     }
901     return MockSyncWebSocket::Send(message);
902   }
903
904  private:
905   int connection_count_;
906   int command_count_;
907 };
908
909 Status CheckCloserFuncCalled(bool* is_called) {
910   *is_called = true;
911   return Status(kOk);
912 }
913
914 }  // namespace
915
916 TEST_F(DevToolsClientImplTest, Reconnect) {
917   SyncWebSocketFactory factory =
918       base::Bind(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>);
919   bool is_called = false;
920   DevToolsClientImpl client(factory,
921                             "http://url",
922                             "id",
923                             base::Bind(&CheckCloserFuncCalled, &is_called));
924   ASSERT_FALSE(is_called);
925   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
926   ASSERT_FALSE(is_called);
927   base::DictionaryValue params;
928   params.SetInteger("param", 1);
929   is_called = false;
930   ASSERT_EQ(kDisconnected, client.SendCommand("method", params).code());
931   ASSERT_FALSE(is_called);
932   ASSERT_EQ(kDisconnected, client.HandleReceivedEvents().code());
933   ASSERT_FALSE(is_called);
934   ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
935   ASSERT_TRUE(is_called);
936   is_called = false;
937   ASSERT_EQ(kOk, client.SendCommand("method", params).code());
938   ASSERT_FALSE(is_called);
939 }
940
941 namespace {
942
943 class MockSyncWebSocket6 : public SyncWebSocket {
944  public:
945   explicit MockSyncWebSocket6(std::list<std::string>* messages)
946       : messages_(messages) {}
947   ~MockSyncWebSocket6() override {}
948
949   bool IsConnected() override { return true; }
950
951   bool Connect(const GURL& url) override { return true; }
952
953   bool Send(const std::string& message) override { return true; }
954
955   SyncWebSocket::StatusCode ReceiveNextMessage(
956       std::string* message,
957       const base::TimeDelta& timeout) override {
958     if (messages_->empty())
959       return SyncWebSocket::kDisconnected;
960     *message = messages_->front();
961     messages_->pop_front();
962     return SyncWebSocket::kOk;
963   }
964
965   bool HasNextMessage() override { return messages_->size(); }
966
967  private:
968   std::list<std::string>* messages_;
969 };
970
971 class MockDevToolsEventListener : public DevToolsEventListener {
972  public:
973   MockDevToolsEventListener() : id_(1) {}
974   ~MockDevToolsEventListener() override {}
975
976   Status OnConnected(DevToolsClient* client) override { return Status(kOk); }
977
978   Status OnEvent(DevToolsClient* client,
979                  const std::string& method,
980                  const base::DictionaryValue& params) override {
981     id_++;
982     Status status = client->SendCommand("hello", params);
983     id_--;
984     if (id_ == 3) {
985       EXPECT_EQ(kUnexpectedAlertOpen, status.code());
986     } else {
987       EXPECT_EQ(kOk, status.code());
988     }
989     return Status(kOk);
990   }
991
992  private:
993   int id_;
994 };
995
996 scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket6(
997     std::list<std::string>* messages) {
998   return make_scoped_ptr(new MockSyncWebSocket6(messages));
999 }
1000
1001 }  // namespace
1002
1003 TEST_F(DevToolsClientImplTest, BlockedByAlert) {
1004   std::list<std::string> msgs;
1005   SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
1006   DevToolsClientImpl client(
1007       factory, "http://url", "id", base::Bind(&CloserFunc));
1008   msgs.push_back(
1009       "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
1010   msgs.push_back("{\"id\": 2, \"result\": {}}");
1011   base::DictionaryValue params;
1012   ASSERT_EQ(kUnexpectedAlertOpen,
1013             client.SendCommand("first", params).code());
1014 }
1015
1016 TEST_F(DevToolsClientImplTest, CorrectlyDeterminesWhichIsBlockedByAlert) {
1017   // OUT                 | IN
1018   //                       FirstEvent
1019   // hello (id=1)
1020   //                       SecondEvent
1021   // hello (id=2)
1022   //                       ThirdEvent
1023   // hello (id=3)
1024   //                       FourthEvent
1025   // hello (id=4)
1026   //                       response for 1
1027   //                       alert
1028   // hello (id=5)
1029   // round trip command (id=6)
1030   //                       response for 2
1031   //                       response for 4
1032   //                       response for 5
1033   //                       response for 6
1034   std::list<std::string> msgs;
1035   SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
1036   DevToolsClientImpl client(
1037       factory, "http://url", "id", base::Bind(&CloserFunc));
1038   MockDevToolsEventListener listener;
1039   client.AddListener(&listener);
1040   msgs.push_back("{\"method\": \"FirstEvent\", \"params\": {}}");
1041   msgs.push_back("{\"method\": \"SecondEvent\", \"params\": {}}");
1042   msgs.push_back("{\"method\": \"ThirdEvent\", \"params\": {}}");
1043   msgs.push_back("{\"method\": \"FourthEvent\", \"params\": {}}");
1044   msgs.push_back("{\"id\": 1, \"result\": {}}");
1045   msgs.push_back(
1046       "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
1047   msgs.push_back("{\"id\": 2, \"result\": {}}");
1048   msgs.push_back("{\"id\": 4, \"result\": {}}");
1049   msgs.push_back("{\"id\": 5, \"result\": {}}");
1050   msgs.push_back("{\"id\": 6, \"result\": {}}");
1051   ASSERT_EQ(kOk, client.HandleReceivedEvents().code());
1052 }
1053
1054 namespace {
1055
1056 class MockCommandListener : public DevToolsEventListener {
1057  public:
1058   MockCommandListener() {}
1059   ~MockCommandListener() override {}
1060
1061   Status OnEvent(DevToolsClient* client,
1062                  const std::string& method,
1063                  const base::DictionaryValue& params) override {
1064     msgs_.push_back(method);
1065     return Status(kOk);
1066   }
1067
1068   Status OnCommandSuccess(DevToolsClient* client,
1069                           const std::string& method) override {
1070     msgs_.push_back(method);
1071     if (!callback_.is_null())
1072       callback_.Run(client);
1073     return Status(kOk);
1074   }
1075
1076   base::Callback<void(DevToolsClient*)> callback_;
1077   std::list<std::string> msgs_;
1078 };
1079
1080 void HandleReceivedEvents(DevToolsClient* client) {
1081   EXPECT_EQ(kOk, client->HandleReceivedEvents().code());
1082 }
1083
1084 }  // namespace
1085
1086 TEST_F(DevToolsClientImplTest, ReceivesCommandResponse) {
1087   std::list<std::string> msgs;
1088   SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
1089   DevToolsClientImpl client(
1090       factory, "http://url", "id", base::Bind(&CloserFunc));
1091   MockCommandListener listener1;
1092   listener1.callback_ = base::Bind(&HandleReceivedEvents);
1093   MockCommandListener listener2;
1094   client.AddListener(&listener1);
1095   client.AddListener(&listener2);
1096   msgs.push_back("{\"id\": 1, \"result\": {}}");
1097   msgs.push_back("{\"method\": \"event\", \"params\": {}}");
1098   base::DictionaryValue params;
1099   ASSERT_EQ(kOk, client.SendCommand("cmd", params).code());
1100   ASSERT_EQ(2u, listener2.msgs_.size());
1101   ASSERT_EQ("cmd", listener2.msgs_.front());
1102   ASSERT_EQ("event", listener2.msgs_.back());
1103 }