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 ASSERT_FALSE(internal::ParseInspectorMessage(
573 "{\"id\":1}", 0, &type, &event, &response));
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);
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());
598 ASSERT_TRUE(response.result->GetInteger("key", &key));
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),
613 ASSERT_EQ(kOk, status.code());
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),
625 ASSERT_EQ(kTimeout, status.code());
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),
637 ASSERT_EQ(kUnknownError, status.code());
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),
649 ASSERT_EQ(kUnknownError, status.code());
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),
661 ASSERT_EQ(kUnknownError, status.code());
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());
679 ASSERT_TRUE(result->GetInteger("key", &key));
685 class OnConnectedListener : public DevToolsEventListener {
687 OnConnectedListener(const std::string& method, DevToolsClient* client)
690 on_connected_called_(false),
691 on_event_called_(false) {
692 client_->AddListener(this);
694 virtual ~OnConnectedListener() {}
696 void VerifyCalled() {
697 EXPECT_TRUE(on_connected_called_);
698 EXPECT_TRUE(on_event_called_);
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);
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;
723 DevToolsClient* client_;
724 bool on_connected_called_;
725 bool on_event_called_;
728 class OnConnectedSyncWebSocket : public SyncWebSocket {
730 OnConnectedSyncWebSocket() : connected_(false) {}
731 virtual ~OnConnectedSyncWebSocket() {}
733 virtual bool IsConnected() OVERRIDE {
737 virtual bool Connect(const GURL& url) OVERRIDE {
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));
750 EXPECT_TRUE(dict->GetInteger("id", &id));
752 EXPECT_TRUE(dict->GetString("method", &method));
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);
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);
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;
782 virtual bool HasNextMessage() OVERRIDE {
783 return !queued_response_.empty();
788 std::list<std::string> queued_response_;
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();
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();
826 class MockSyncWebSocket5 : public SyncWebSocket {
828 MockSyncWebSocket5() : request_no_(0) {}
829 virtual ~MockSyncWebSocket5() {}
831 virtual bool IsConnected() OVERRIDE {
835 virtual bool Connect(const GURL& url) OVERRIDE {
839 virtual bool Send(const std::string& message) OVERRIDE {
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\": {}}";
849 *message = base::StringPrintf(
850 "{\"result\": {}, \"id\": %d}", request_no_);
853 return SyncWebSocket::kOk;
856 virtual bool HasNextMessage() OVERRIDE {
864 class OtherEventListener : public DevToolsEventListener {
866 OtherEventListener() : received_event_(false) {}
867 virtual ~OtherEventListener() {}
869 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
872 virtual Status OnEvent(DevToolsClient* client,
873 const std::string& method,
874 const base::DictionaryValue& params) OVERRIDE {
875 received_event_ = true;
879 bool received_event_;
882 class OnEventListener : public DevToolsEventListener {
884 OnEventListener(DevToolsClient* client,
885 OtherEventListener* other_listener)
887 other_listener_(other_listener) {}
888 virtual ~OnEventListener() {}
890 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
891 EXPECT_EQ(client_, client);
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_);
905 DevToolsClient* client_;
906 OtherEventListener* other_listener_;
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());
926 class DisconnectedSyncWebSocket : public MockSyncWebSocket {
928 DisconnectedSyncWebSocket() : connection_count_(0), command_count_(0) {}
929 virtual ~DisconnectedSyncWebSocket() {}
931 virtual bool Connect(const GURL& url) OVERRIDE {
933 connected_ = connection_count_ != 2;
937 virtual bool Send(const std::string& message) OVERRIDE {
939 if (command_count_ == 1) {
943 return MockSyncWebSocket::Send(message);
947 int connection_count_;
951 Status CheckCloserFuncCalled(bool* is_called) {
958 TEST_F(DevToolsClientImplTest, Reconnect) {
959 SyncWebSocketFactory factory =
960 base::Bind(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>);
961 bool is_called = false;
962 DevToolsClientImpl client(factory,
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);
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);
979 ASSERT_EQ(kOk, client.SendCommand("method", params).code());
980 ASSERT_FALSE(is_called);
985 class MockSyncWebSocket6 : public SyncWebSocket {
987 explicit MockSyncWebSocket6(std::list<std::string>* messages)
988 : messages_(messages) {}
989 virtual ~MockSyncWebSocket6() {}
991 virtual bool IsConnected() OVERRIDE { return true; }
993 virtual bool Connect(const GURL& url) OVERRIDE { return true; }
995 virtual bool Send(const std::string& message) OVERRIDE { return true; }
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;
1007 virtual bool HasNextMessage() OVERRIDE { return messages_->size(); }
1010 std::list<std::string>* messages_;
1013 class MockDevToolsEventListener : public DevToolsEventListener {
1015 MockDevToolsEventListener() : id_(1) {}
1016 virtual ~MockDevToolsEventListener() {}
1018 virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
1022 virtual Status OnEvent(DevToolsClient* client,
1023 const std::string& method,
1024 const base::DictionaryValue& params) OVERRIDE {
1026 Status status = client->SendCommand("hello", params);
1029 EXPECT_EQ(kUnexpectedAlertOpen, status.code());
1031 EXPECT_EQ(kOk, status.code());
1040 scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket6(
1041 std::list<std::string>* messages) {
1042 return scoped_ptr<MockSyncWebSocket6>(new MockSyncWebSocket6(messages))
1043 .PassAs<SyncWebSocket>();
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));
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());
1061 TEST_F(DevToolsClientImplTest, CorrectlyDeterminesWhichIsBlockedByAlert) {
1074 // round trip command (id=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\": {}}");
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());
1101 class MockCommandListener : public DevToolsEventListener {
1103 MockCommandListener() {}
1104 virtual ~MockCommandListener() {}
1106 virtual Status OnEvent(DevToolsClient* client,
1107 const std::string& method,
1108 const base::DictionaryValue& params) OVERRIDE {
1109 msgs_.push_back(method);
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);
1121 base::Callback<void(DevToolsClient*)> callback_;
1122 std::list<std::string> msgs_;
1125 void HandleReceivedEvents(DevToolsClient* client) {
1126 EXPECT_EQ(kOk, client->HandleReceivedEvents().code());
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());