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.
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"
29 class MockSyncWebSocket : public SyncWebSocket {
31 MockSyncWebSocket() : connected_(false), id_(-1), queued_messages_(1) {}
32 virtual ~MockSyncWebSocket() {}
34 virtual bool IsConnected() OVERRIDE {
38 virtual bool Connect(const GURL& url) OVERRIDE {
39 EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
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));
51 EXPECT_TRUE(dict->GetInteger("id", &id_));
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", ¶ms));
60 EXPECT_TRUE(params->GetInteger("param", ¶m));
65 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
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);
77 return SyncWebSocket::kOk;
80 virtual bool HasNextMessage() OVERRIDE {
81 return queued_messages_ > 0;
91 scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket() {
92 return scoped_ptr<SyncWebSocket>(new T());
95 class DevToolsClientImplTest : public testing::Test {
97 DevToolsClientImplTest() : long_timeout_(base::TimeDelta::FromMinutes(5)) {}
99 const base::TimeDelta long_timeout_;
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());
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());
127 base::JSONWriter::Write(result.get(), &json);
128 ASSERT_STREQ("{\"param\":1}", json.c_str());
133 class MockSyncWebSocket2 : public SyncWebSocket {
135 MockSyncWebSocket2() {}
136 virtual ~MockSyncWebSocket2() {}
138 virtual bool IsConnected() OVERRIDE {
142 virtual bool Connect(const GURL& url) OVERRIDE {
146 virtual bool Send(const std::string& message) OVERRIDE {
151 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
152 std::string* message,
153 const base::TimeDelta& timeout) OVERRIDE {
155 return SyncWebSocket::kDisconnected;
158 virtual bool HasNextMessage() OVERRIDE {
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());
175 class MockSyncWebSocket3 : public SyncWebSocket {
177 MockSyncWebSocket3() : connected_(false) {}
178 virtual ~MockSyncWebSocket3() {}
180 virtual bool IsConnected() OVERRIDE {
184 virtual bool Connect(const GURL& url) OVERRIDE {
189 virtual bool Send(const std::string& message) OVERRIDE {
193 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
194 std::string* message,
195 const base::TimeDelta& timeout) OVERRIDE {
197 return SyncWebSocket::kDisconnected;
200 virtual bool HasNextMessage() OVERRIDE {
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());
222 class MockSyncWebSocket4 : public SyncWebSocket {
224 MockSyncWebSocket4() : connected_(false) {}
225 virtual ~MockSyncWebSocket4() {}
227 virtual bool IsConnected() OVERRIDE {
231 virtual bool Connect(const GURL& url) OVERRIDE {
236 virtual bool Send(const std::string& message) OVERRIDE {
240 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
241 std::string* message,
242 const base::TimeDelta& timeout) OVERRIDE {
243 return SyncWebSocket::kDisconnected;
246 virtual bool HasNextMessage() OVERRIDE {
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());
268 class FakeSyncWebSocket : public SyncWebSocket {
270 FakeSyncWebSocket() : connected_(false) {}
271 virtual ~FakeSyncWebSocket() {}
273 virtual bool IsConnected() OVERRIDE {
277 virtual bool Connect(const GURL& url) OVERRIDE {
278 EXPECT_FALSE(connected_);
283 virtual bool Send(const std::string& message) OVERRIDE {
287 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
288 std::string* message,
289 const base::TimeDelta& timeout) OVERRIDE {
290 return SyncWebSocket::kOk;
293 virtual bool HasNextMessage() OVERRIDE {
302 const std::string& message,
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());
313 bool ReturnBadResponse(
314 const std::string& message,
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());
325 bool ReturnCommandBadId(
326 const std::string& message,
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());
337 bool ReturnCommandError(
338 const std::string& message,
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";
349 class MockListener : public DevToolsEventListener {
351 MockListener() : called_(false) {}
352 virtual ~MockListener() {
353 EXPECT_TRUE(called_);
356 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
360 virtual Status OnEvent(DevToolsClient* client,
361 const std::string& method,
362 const base::DictionaryValue& params) OVERRIDE {
364 EXPECT_STREQ("method", method.c_str());
365 EXPECT_TRUE(params.HasKey("key"));
373 bool ReturnEventThenResponse(
375 const std::string& message,
377 internal::InspectorMessageType* type,
378 internal::InspectorEvent* event,
379 internal::InspectorCommandResponse* command_response) {
381 *type = internal::kEventMessageType;
382 event->method = "method";
383 event->params.reset(new base::DictionaryValue());
384 event->params->SetInteger("key", 1);
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);
397 const std::string& message,
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);
409 bool ReturnOutOfOrderResponses(
411 DevToolsClient* client,
412 const std::string& message,
414 internal::InspectorMessageType* type,
415 internal::InspectorEvent* event,
416 internal::InspectorCommandResponse* command_response) {
418 base::DictionaryValue params;
419 params.SetInteger("param", 1);
420 switch ((*recurse_count)++) {
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);
429 command_response->id = expected_id - 1;
433 command_response->id = expected_id;
437 *type = internal::kCommandResponseMessageType;
438 command_response->result.reset(new base::DictionaryValue());
439 command_response->result->SetInteger("key", key);
444 const std::string& message,
446 internal::InspectorMessageType* type,
447 internal::InspectorEvent* event,
448 internal::InspectorCommandResponse* command_response) {
452 Status AlwaysTrue(bool* is_met) {
457 Status AlwaysError(bool* is_met) {
458 return Status(kUnknownError);
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());
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());
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());
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());
508 TEST_F(DevToolsClientImplTest, SendCommandEventBeforeResponse) {
509 SyncWebSocketFactory factory =
510 base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
511 MockListener listener;
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());
523 ASSERT_TRUE(result->GetInteger("key", &key));
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));
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));
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));
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());
564 ASSERT_TRUE(event.params->GetInteger("key", &key));
568 TEST(ParseInspectorMessage, CommandNoErrorOrResult) {
569 internal::InspectorMessageType type;
570 internal::InspectorEvent event;
571 internal::InspectorCommandResponse response;
572 // As per Chromium issue 392577, DevTools does not necessarily return a
573 // "result" dictionary for every valid response. If neither "error" nor
574 // "result" keys are present, a blank result dictionary should be inferred.
575 ASSERT_TRUE(internal::ParseInspectorMessage(
576 "{\"id\":1}", 0, &type, &event, &response));
577 ASSERT_TRUE(response.result->empty());
580 TEST(ParseInspectorMessage, CommandError) {
581 internal::InspectorMessageType type;
582 internal::InspectorEvent event;
583 internal::InspectorCommandResponse response;
584 ASSERT_TRUE(internal::ParseInspectorMessage(
585 "{\"id\":1,\"error\":{}}", 0, &type, &event, &response));
586 ASSERT_EQ(internal::kCommandResponseMessageType, type);
587 ASSERT_EQ(1, response.id);
588 ASSERT_TRUE(response.error.length());
589 ASSERT_FALSE(response.result);
592 TEST(ParseInspectorMessage, Command) {
593 internal::InspectorMessageType type;
594 internal::InspectorEvent event;
595 internal::InspectorCommandResponse response;
596 ASSERT_TRUE(internal::ParseInspectorMessage(
597 "{\"id\":1,\"result\":{\"key\":1}}", 0, &type, &event, &response));
598 ASSERT_EQ(internal::kCommandResponseMessageType, type);
599 ASSERT_EQ(1, response.id);
600 ASSERT_FALSE(response.error.length());
602 ASSERT_TRUE(response.result->GetInteger("key", &key));
606 TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
607 MockListener listener;
608 SyncWebSocketFactory factory =
609 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
610 DevToolsClientImpl client(factory, "http://url", "id",
611 base::Bind(&CloserFunc),
612 base::Bind(&ReturnEvent));
613 client.AddListener(&listener);
614 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
615 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
617 ASSERT_EQ(kOk, status.code());
620 TEST_F(DevToolsClientImplTest, HandleEventsUntilTimeout) {
621 SyncWebSocketFactory factory =
622 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
623 DevToolsClientImpl client(factory, "http://url", "id",
624 base::Bind(&CloserFunc),
625 base::Bind(&ReturnEvent));
626 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
627 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
629 ASSERT_EQ(kTimeout, status.code());
632 TEST_F(DevToolsClientImplTest, WaitForNextEventCommand) {
633 SyncWebSocketFactory factory =
634 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
635 DevToolsClientImpl client(factory, "http://url", "id",
636 base::Bind(&CloserFunc),
637 base::Bind(&ReturnCommand));
638 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
639 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
641 ASSERT_EQ(kUnknownError, status.code());
644 TEST_F(DevToolsClientImplTest, WaitForNextEventError) {
645 SyncWebSocketFactory factory =
646 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
647 DevToolsClientImpl client(factory, "http://url", "id",
648 base::Bind(&CloserFunc),
649 base::Bind(&ReturnError));
650 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
651 Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
653 ASSERT_EQ(kUnknownError, status.code());
656 TEST_F(DevToolsClientImplTest, WaitForNextEventConditionalFuncReturnsError) {
657 SyncWebSocketFactory factory =
658 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
659 DevToolsClientImpl client(factory, "http://url", "id",
660 base::Bind(&CloserFunc),
661 base::Bind(&ReturnEvent));
662 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
663 Status status = client.HandleEventsUntil(base::Bind(&AlwaysError),
665 ASSERT_EQ(kUnknownError, status.code());
668 TEST_F(DevToolsClientImplTest, NestedCommandsWithOutOfOrderResults) {
669 SyncWebSocketFactory factory =
670 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
671 int recurse_count = 0;
672 DevToolsClientImpl client(factory, "http://url", "id",
673 base::Bind(&CloserFunc));
674 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
675 client.SetParserFuncForTesting(
676 base::Bind(&ReturnOutOfOrderResponses, &recurse_count, &client));
677 base::DictionaryValue params;
678 params.SetInteger("param", 1);
679 scoped_ptr<base::DictionaryValue> result;
680 ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
683 ASSERT_TRUE(result->GetInteger("key", &key));
689 class OnConnectedListener : public DevToolsEventListener {
691 OnConnectedListener(const std::string& method, DevToolsClient* client)
694 on_connected_called_(false),
695 on_event_called_(false) {
696 client_->AddListener(this);
698 virtual ~OnConnectedListener() {}
700 void VerifyCalled() {
701 EXPECT_TRUE(on_connected_called_);
702 EXPECT_TRUE(on_event_called_);
705 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
706 EXPECT_EQ(client_, client);
707 EXPECT_STREQ("onconnected-id", client->GetId().c_str());
708 EXPECT_FALSE(on_connected_called_);
709 EXPECT_FALSE(on_event_called_);
710 on_connected_called_ = true;
711 base::DictionaryValue params;
712 return client_->SendCommand(method_, params);
715 virtual Status OnEvent(DevToolsClient* client,
716 const std::string& method,
717 const base::DictionaryValue& params) OVERRIDE {
718 EXPECT_EQ(client_, client);
719 EXPECT_STREQ("onconnected-id", client->GetId().c_str());
720 EXPECT_TRUE(on_connected_called_);
721 on_event_called_ = true;
727 DevToolsClient* client_;
728 bool on_connected_called_;
729 bool on_event_called_;
732 class OnConnectedSyncWebSocket : public SyncWebSocket {
734 OnConnectedSyncWebSocket() : connected_(false) {}
735 virtual ~OnConnectedSyncWebSocket() {}
737 virtual bool IsConnected() OVERRIDE {
741 virtual bool Connect(const GURL& url) OVERRIDE {
746 virtual bool Send(const std::string& message) OVERRIDE {
747 EXPECT_TRUE(connected_);
748 scoped_ptr<base::Value> value(base::JSONReader::Read(message));
749 base::DictionaryValue* dict = NULL;
750 EXPECT_TRUE(value->GetAsDictionary(&dict));
754 EXPECT_TRUE(dict->GetInteger("id", &id));
756 EXPECT_TRUE(dict->GetString("method", &method));
758 base::DictionaryValue response;
759 response.SetInteger("id", id);
760 response.Set("result", new base::DictionaryValue());
761 std::string json_response;
762 base::JSONWriter::Write(&response, &json_response);
763 queued_response_.push_back(json_response);
766 base::DictionaryValue event;
767 event.SetString("method", "updateEvent");
768 event.Set("params", new base::DictionaryValue());
769 std::string json_event;
770 base::JSONWriter::Write(&event, &json_event);
771 queued_response_.push_back(json_event);
776 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
777 std::string* message,
778 const base::TimeDelta& timeout) OVERRIDE {
779 if (queued_response_.empty())
780 return SyncWebSocket::kDisconnected;
781 *message = queued_response_.front();
782 queued_response_.pop_front();
783 return SyncWebSocket::kOk;
786 virtual bool HasNextMessage() OVERRIDE {
787 return !queued_response_.empty();
792 std::list<std::string> queued_response_;
797 TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnCommand) {
798 SyncWebSocketFactory factory =
799 base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
800 DevToolsClientImpl client(factory, "http://url", "onconnected-id",
801 base::Bind(&CloserFunc));
802 OnConnectedListener listener1("DOM.getDocument", &client);
803 OnConnectedListener listener2("Runtime.enable", &client);
804 OnConnectedListener listener3("Page.enable", &client);
805 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
806 base::DictionaryValue params;
807 EXPECT_EQ(kOk, client.SendCommand("Runtime.execute", params).code());
808 listener1.VerifyCalled();
809 listener2.VerifyCalled();
810 listener3.VerifyCalled();
813 TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnHandleEventsUntil) {
814 SyncWebSocketFactory factory =
815 base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
816 DevToolsClientImpl client(factory, "http://url", "onconnected-id",
817 base::Bind(&CloserFunc));
818 OnConnectedListener listener1("DOM.getDocument", &client);
819 OnConnectedListener listener2("Runtime.enable", &client);
820 OnConnectedListener listener3("Page.enable", &client);
821 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
822 EXPECT_EQ(kOk, client.HandleReceivedEvents().code());
823 listener1.VerifyCalled();
824 listener2.VerifyCalled();
825 listener3.VerifyCalled();
830 class MockSyncWebSocket5 : public SyncWebSocket {
832 MockSyncWebSocket5() : request_no_(0) {}
833 virtual ~MockSyncWebSocket5() {}
835 virtual bool IsConnected() OVERRIDE {
839 virtual bool Connect(const GURL& url) OVERRIDE {
843 virtual bool Send(const std::string& message) OVERRIDE {
847 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
848 std::string* message,
849 const base::TimeDelta& timeout) OVERRIDE {
850 if (request_no_ == 0) {
851 *message = "{\"method\": \"m\", \"params\": {}}";
853 *message = base::StringPrintf(
854 "{\"result\": {}, \"id\": %d}", request_no_);
857 return SyncWebSocket::kOk;
860 virtual bool HasNextMessage() OVERRIDE {
868 class OtherEventListener : public DevToolsEventListener {
870 OtherEventListener() : received_event_(false) {}
871 virtual ~OtherEventListener() {}
873 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
876 virtual Status OnEvent(DevToolsClient* client,
877 const std::string& method,
878 const base::DictionaryValue& params) OVERRIDE {
879 received_event_ = true;
883 bool received_event_;
886 class OnEventListener : public DevToolsEventListener {
888 OnEventListener(DevToolsClient* client,
889 OtherEventListener* other_listener)
891 other_listener_(other_listener) {}
892 virtual ~OnEventListener() {}
894 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
895 EXPECT_EQ(client_, client);
899 virtual Status OnEvent(DevToolsClient* client,
900 const std::string& method,
901 const base::DictionaryValue& params) OVERRIDE {
902 EXPECT_EQ(client_, client);
903 client_->SendCommand("method", params);
904 EXPECT_TRUE(other_listener_->received_event_);
909 DevToolsClient* client_;
910 OtherEventListener* other_listener_;
915 TEST_F(DevToolsClientImplTest, ProcessOnEventFirst) {
916 SyncWebSocketFactory factory =
917 base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket5>);
918 DevToolsClientImpl client(factory, "http://url", "id",
919 base::Bind(&CloserFunc));
920 OtherEventListener listener2;
921 OnEventListener listener1(&client, &listener2);
922 client.AddListener(&listener1);
923 client.AddListener(&listener2);
924 base::DictionaryValue params;
925 EXPECT_EQ(kOk, client.SendCommand("method", params).code());
930 class DisconnectedSyncWebSocket : public MockSyncWebSocket {
932 DisconnectedSyncWebSocket() : connection_count_(0), command_count_(0) {}
933 virtual ~DisconnectedSyncWebSocket() {}
935 virtual bool Connect(const GURL& url) OVERRIDE {
937 connected_ = connection_count_ != 2;
941 virtual bool Send(const std::string& message) OVERRIDE {
943 if (command_count_ == 1) {
947 return MockSyncWebSocket::Send(message);
951 int connection_count_;
955 Status CheckCloserFuncCalled(bool* is_called) {
962 TEST_F(DevToolsClientImplTest, Reconnect) {
963 SyncWebSocketFactory factory =
964 base::Bind(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>);
965 bool is_called = false;
966 DevToolsClientImpl client(factory,
969 base::Bind(&CheckCloserFuncCalled, &is_called));
970 ASSERT_FALSE(is_called);
971 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
972 ASSERT_FALSE(is_called);
973 base::DictionaryValue params;
974 params.SetInteger("param", 1);
976 ASSERT_EQ(kDisconnected, client.SendCommand("method", params).code());
977 ASSERT_FALSE(is_called);
978 ASSERT_EQ(kDisconnected, client.HandleReceivedEvents().code());
979 ASSERT_FALSE(is_called);
980 ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
981 ASSERT_TRUE(is_called);
983 ASSERT_EQ(kOk, client.SendCommand("method", params).code());
984 ASSERT_FALSE(is_called);
989 class MockSyncWebSocket6 : public SyncWebSocket {
991 explicit MockSyncWebSocket6(std::list<std::string>* messages)
992 : messages_(messages) {}
993 virtual ~MockSyncWebSocket6() {}
995 virtual bool IsConnected() OVERRIDE { return true; }
997 virtual bool Connect(const GURL& url) OVERRIDE { return true; }
999 virtual bool Send(const std::string& message) OVERRIDE { return true; }
1001 virtual SyncWebSocket::StatusCode ReceiveNextMessage(
1002 std::string* message,
1003 const base::TimeDelta& timeout) OVERRIDE {
1004 if (messages_->empty())
1005 return SyncWebSocket::kDisconnected;
1006 *message = messages_->front();
1007 messages_->pop_front();
1008 return SyncWebSocket::kOk;
1011 virtual bool HasNextMessage() OVERRIDE { return messages_->size(); }
1014 std::list<std::string>* messages_;
1017 class MockDevToolsEventListener : public DevToolsEventListener {
1019 MockDevToolsEventListener() : id_(1) {}
1020 virtual ~MockDevToolsEventListener() {}
1022 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
1026 virtual Status OnEvent(DevToolsClient* client,
1027 const std::string& method,
1028 const base::DictionaryValue& params) OVERRIDE {
1030 Status status = client->SendCommand("hello", params);
1033 EXPECT_EQ(kUnexpectedAlertOpen, status.code());
1035 EXPECT_EQ(kOk, status.code());
1044 scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket6(
1045 std::list<std::string>* messages) {
1046 return scoped_ptr<MockSyncWebSocket6>(new MockSyncWebSocket6(messages))
1047 .PassAs<SyncWebSocket>();
1052 TEST_F(DevToolsClientImplTest, BlockedByAlert) {
1053 std::list<std::string> msgs;
1054 SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
1055 DevToolsClientImpl client(
1056 factory, "http://url", "id", base::Bind(&CloserFunc));
1058 "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
1059 msgs.push_back("{\"id\": 2, \"result\": {}}");
1060 base::DictionaryValue params;
1061 ASSERT_EQ(kUnexpectedAlertOpen,
1062 client.SendCommand("first", params).code());
1065 TEST_F(DevToolsClientImplTest, CorrectlyDeterminesWhichIsBlockedByAlert) {
1078 // round trip command (id=6)
1083 std::list<std::string> msgs;
1084 SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
1085 DevToolsClientImpl client(
1086 factory, "http://url", "id", base::Bind(&CloserFunc));
1087 MockDevToolsEventListener listener;
1088 client.AddListener(&listener);
1089 msgs.push_back("{\"method\": \"FirstEvent\", \"params\": {}}");
1090 msgs.push_back("{\"method\": \"SecondEvent\", \"params\": {}}");
1091 msgs.push_back("{\"method\": \"ThirdEvent\", \"params\": {}}");
1092 msgs.push_back("{\"method\": \"FourthEvent\", \"params\": {}}");
1093 msgs.push_back("{\"id\": 1, \"result\": {}}");
1095 "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
1096 msgs.push_back("{\"id\": 2, \"result\": {}}");
1097 msgs.push_back("{\"id\": 4, \"result\": {}}");
1098 msgs.push_back("{\"id\": 5, \"result\": {}}");
1099 msgs.push_back("{\"id\": 6, \"result\": {}}");
1100 ASSERT_EQ(kOk, client.HandleReceivedEvents().code());
1105 class MockCommandListener : public DevToolsEventListener {
1107 MockCommandListener() {}
1108 virtual ~MockCommandListener() {}
1110 virtual Status OnEvent(DevToolsClient* client,
1111 const std::string& method,
1112 const base::DictionaryValue& params) OVERRIDE {
1113 msgs_.push_back(method);
1117 virtual Status OnCommandSuccess(DevToolsClient* client,
1118 const std::string& method) OVERRIDE {
1119 msgs_.push_back(method);
1120 if (!callback_.is_null())
1121 callback_.Run(client);
1125 base::Callback<void(DevToolsClient*)> callback_;
1126 std::list<std::string> msgs_;
1129 void HandleReceivedEvents(DevToolsClient* client) {
1130 EXPECT_EQ(kOk, client->HandleReceivedEvents().code());
1135 TEST_F(DevToolsClientImplTest, ReceivesCommandResponse) {
1136 std::list<std::string> msgs;
1137 SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
1138 DevToolsClientImpl client(
1139 factory, "http://url", "id", base::Bind(&CloserFunc));
1140 MockCommandListener listener1;
1141 listener1.callback_ = base::Bind(&HandleReceivedEvents);
1142 MockCommandListener listener2;
1143 client.AddListener(&listener1);
1144 client.AddListener(&listener2);
1145 msgs.push_back("{\"id\": 1, \"result\": {}}");
1146 msgs.push_back("{\"method\": \"event\", \"params\": {}}");
1147 base::DictionaryValue params;
1148 ASSERT_EQ(kOk, client.SendCommand("cmd", params).code());
1149 ASSERT_EQ(2u, listener2.msgs_.size());
1150 ASSERT_EQ("cmd", listener2.msgs_.front());
1151 ASSERT_EQ("event", listener2.msgs_.back());