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