This source file includes following definitions.
- CloserFunc
- queued_messages_
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- CreateMockSyncWebSocket
- TEST_F
- TEST_F
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- TEST_F
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- TEST_F
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- TEST_F
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- ReturnCommand
- ReturnBadResponse
- ReturnCommandBadId
- ReturnCommandError
- OnConnected
- OnEvent
- ReturnEventThenResponse
- ReturnEvent
- ReturnOutOfOrderResponses
- ReturnError
- AlwaysTrue
- AlwaysError
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- on_event_called_
- VerifyCalled
- OnConnected
- OnEvent
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- TEST_F
- TEST_F
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- OnConnected
- OnEvent
- other_listener_
- OnConnected
- OnEvent
- TEST_F
- command_count_
- Connect
- Send
- CheckCloserFuncCalled
- TEST_F
- IsConnected
- Connect
- Send
- ReceiveNextMessage
- HasNextMessage
- OnConnected
- OnEvent
- CreateMockSyncWebSocket6
- TEST_F
- TEST_F
- OnEvent
- OnCommandSuccess
- HandleReceivedEvents
- TEST_F
#include <list>
#include <string>
#include "base/bind.h"
#include "base/compiler_specific.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/memory/scoped_ptr.h"
#include "base/strings/stringprintf.h"
#include "base/values.h"
#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
#include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
#include "chrome/test/chromedriver/chrome/status.h"
#include "chrome/test/chromedriver/net/sync_websocket.h"
#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
namespace {
Status CloserFunc() {
return Status(kOk);
}
class MockSyncWebSocket : public SyncWebSocket {
public:
MockSyncWebSocket() : connected_(false), id_(-1), queued_messages_(1) {}
virtual ~MockSyncWebSocket() {}
virtual bool IsConnected() OVERRIDE {
return connected_;
}
virtual bool Connect(const GURL& url) OVERRIDE {
EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
connected_ = true;
return true;
}
virtual bool Send(const std::string& message) OVERRIDE {
EXPECT_TRUE(connected_);
scoped_ptr<base::Value> value(base::JSONReader::Read(message));
base::DictionaryValue* dict = NULL;
EXPECT_TRUE(value->GetAsDictionary(&dict));
if (!dict)
return false;
EXPECT_TRUE(dict->GetInteger("id", &id_));
std::string method;
EXPECT_TRUE(dict->GetString("method", &method));
EXPECT_STREQ("method", method.c_str());
base::DictionaryValue* params = NULL;
EXPECT_TRUE(dict->GetDictionary("params", ¶ms));
if (!params)
return false;
int param = -1;
EXPECT_TRUE(params->GetInteger("param", ¶m));
EXPECT_EQ(1, param);
return true;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
if (timeout <= base::TimeDelta())
return SyncWebSocket::kTimeout;
base::DictionaryValue response;
response.SetInteger("id", id_);
base::DictionaryValue result;
result.SetInteger("param", 1);
response.Set("result", result.DeepCopy());
base::JSONWriter::Write(&response, message);
--queued_messages_;
return SyncWebSocket::kOk;
}
virtual bool HasNextMessage() OVERRIDE {
return queued_messages_ > 0;
}
protected:
bool connected_;
int id_;
int queued_messages_;
};
template <typename T>
scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket() {
return scoped_ptr<SyncWebSocket>(new T());
}
class DevToolsClientImplTest : public testing::Test {
protected:
DevToolsClientImplTest() : long_timeout_(base::TimeDelta::FromMinutes(5)) {}
const base::TimeDelta long_timeout_;
};
}
TEST_F(DevToolsClientImplTest, SendCommand) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
params.SetInteger("param", 1);
ASSERT_EQ(kOk, client.SendCommand("method", params).code());
}
TEST_F(DevToolsClientImplTest, SendCommandAndGetResult) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
params.SetInteger("param", 1);
scoped_ptr<base::DictionaryValue> result;
Status status = client.SendCommandAndGetResult("method", params, &result);
ASSERT_EQ(kOk, status.code());
std::string json;
base::JSONWriter::Write(result.get(), &json);
ASSERT_STREQ("{\"param\":1}", json.c_str());
}
namespace {
class MockSyncWebSocket2 : public SyncWebSocket {
public:
MockSyncWebSocket2() {}
virtual ~MockSyncWebSocket2() {}
virtual bool IsConnected() OVERRIDE {
return false;
}
virtual bool Connect(const GURL& url) OVERRIDE {
return false;
}
virtual bool Send(const std::string& message) OVERRIDE {
EXPECT_TRUE(false);
return false;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
EXPECT_TRUE(false);
return SyncWebSocket::kDisconnected;
}
virtual bool HasNextMessage() OVERRIDE {
return true;
}
};
}
TEST_F(DevToolsClientImplTest, ConnectIfNecessaryConnectFails) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket2>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
ASSERT_EQ(kDisconnected, client.ConnectIfNecessary().code());
}
namespace {
class MockSyncWebSocket3 : public SyncWebSocket {
public:
MockSyncWebSocket3() : connected_(false) {}
virtual ~MockSyncWebSocket3() {}
virtual bool IsConnected() OVERRIDE {
return connected_;
}
virtual bool Connect(const GURL& url) OVERRIDE {
connected_ = true;
return true;
}
virtual bool Send(const std::string& message) OVERRIDE {
return false;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
EXPECT_TRUE(false);
return SyncWebSocket::kDisconnected;
}
virtual bool HasNextMessage() OVERRIDE {
return true;
}
private:
bool connected_;
};
}
TEST_F(DevToolsClientImplTest, SendCommandSendFails) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket3>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
ASSERT_TRUE(client.SendCommand("method", params).IsError());
}
namespace {
class MockSyncWebSocket4 : public SyncWebSocket {
public:
MockSyncWebSocket4() : connected_(false) {}
virtual ~MockSyncWebSocket4() {}
virtual bool IsConnected() OVERRIDE {
return connected_;
}
virtual bool Connect(const GURL& url) OVERRIDE {
connected_ = true;
return true;
}
virtual bool Send(const std::string& message) OVERRIDE {
return true;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
return SyncWebSocket::kDisconnected;
}
virtual bool HasNextMessage() OVERRIDE {
return true;
}
private:
bool connected_;
};
}
TEST_F(DevToolsClientImplTest, SendCommandReceiveNextMessageFails) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket4>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
ASSERT_TRUE(client.SendCommand("method", params).IsError());
}
namespace {
class FakeSyncWebSocket : public SyncWebSocket {
public:
FakeSyncWebSocket() : connected_(false) {}
virtual ~FakeSyncWebSocket() {}
virtual bool IsConnected() OVERRIDE {
return connected_;
}
virtual bool Connect(const GURL& url) OVERRIDE {
EXPECT_FALSE(connected_);
connected_ = true;
return true;
}
virtual bool Send(const std::string& message) OVERRIDE {
return true;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
return SyncWebSocket::kOk;
}
virtual bool HasNextMessage() OVERRIDE {
return true;
}
private:
bool connected_;
};
bool ReturnCommand(
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
*type = internal::kCommandResponseMessageType;
command_response->id = expected_id;
command_response->result.reset(new base::DictionaryValue());
return true;
}
bool ReturnBadResponse(
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
*type = internal::kCommandResponseMessageType;
command_response->id = expected_id;
command_response->result.reset(new base::DictionaryValue());
return false;
}
bool ReturnCommandBadId(
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
*type = internal::kCommandResponseMessageType;
command_response->id = expected_id + 100;
command_response->result.reset(new base::DictionaryValue());
return true;
}
bool ReturnCommandError(
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
*type = internal::kCommandResponseMessageType;
command_response->id = expected_id;
command_response->error = "err";
return true;
}
class MockListener : public DevToolsEventListener {
public:
MockListener() : called_(false) {}
virtual ~MockListener() {
EXPECT_TRUE(called_);
}
virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
return Status(kOk);
}
virtual Status OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE {
called_ = true;
EXPECT_STREQ("method", method.c_str());
EXPECT_TRUE(params.HasKey("key"));
return Status(kOk);
}
private:
bool called_;
};
bool ReturnEventThenResponse(
bool* first,
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
if (*first) {
*type = internal::kEventMessageType;
event->method = "method";
event->params.reset(new base::DictionaryValue());
event->params->SetInteger("key", 1);
} else {
*type = internal::kCommandResponseMessageType;
command_response->id = expected_id;
base::DictionaryValue params;
command_response->result.reset(new base::DictionaryValue());
command_response->result->SetInteger("key", 2);
}
*first = false;
return true;
}
bool ReturnEvent(
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
*type = internal::kEventMessageType;
event->method = "method";
event->params.reset(new base::DictionaryValue());
event->params->SetInteger("key", 1);
return true;
}
bool ReturnOutOfOrderResponses(
int* recurse_count,
DevToolsClient* client,
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
int key = 0;
base::DictionaryValue params;
params.SetInteger("param", 1);
switch ((*recurse_count)++) {
case 0:
client->SendCommand("method", params);
*type = internal::kEventMessageType;
event->method = "method";
event->params.reset(new base::DictionaryValue());
event->params->SetInteger("key", 1);
return true;
case 1:
command_response->id = expected_id - 1;
key = 2;
break;
case 2:
command_response->id = expected_id;
key = 3;
break;
}
*type = internal::kCommandResponseMessageType;
command_response->result.reset(new base::DictionaryValue());
command_response->result->SetInteger("key", key);
return true;
}
bool ReturnError(
const std::string& message,
int expected_id,
internal::InspectorMessageType* type,
internal::InspectorEvent* event,
internal::InspectorCommandResponse* command_response) {
return false;
}
Status AlwaysTrue(bool* is_met) {
*is_met = true;
return Status(kOk);
}
Status AlwaysError(bool* is_met) {
return Status(kUnknownError);
}
}
TEST_F(DevToolsClientImplTest, SendCommandOnlyConnectsOnce) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnCommand));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
ASSERT_TRUE(client.SendCommand("method", params).IsOk());
ASSERT_TRUE(client.SendCommand("method", params).IsOk());
}
TEST_F(DevToolsClientImplTest, SendCommandBadResponse) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnBadResponse));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
ASSERT_TRUE(client.SendCommand("method", params).IsError());
}
TEST_F(DevToolsClientImplTest, SendCommandBadId) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnCommandBadId));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
ASSERT_TRUE(client.SendCommand("method", params).IsError());
}
TEST_F(DevToolsClientImplTest, SendCommandResponseError) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnCommandError));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
ASSERT_TRUE(client.SendCommand("method", params).IsError());
}
TEST_F(DevToolsClientImplTest, SendCommandEventBeforeResponse) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
MockListener listener;
bool first = true;
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnEventThenResponse, &first));
client.AddListener(&listener);
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
scoped_ptr<base::DictionaryValue> result;
ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
ASSERT_TRUE(result);
int key;
ASSERT_TRUE(result->GetInteger("key", &key));
ASSERT_EQ(2, key);
}
TEST(ParseInspectorMessage, NonJson) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_FALSE(internal::ParseInspectorMessage(
"hi", 0, &type, &event, &response));
}
TEST(ParseInspectorMessage, NeitherCommandNorEvent) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_FALSE(internal::ParseInspectorMessage(
"{}", 0, &type, &event, &response));
}
TEST(ParseInspectorMessage, EventNoParams) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_TRUE(internal::ParseInspectorMessage(
"{\"method\":\"method\"}", 0, &type, &event, &response));
ASSERT_EQ(internal::kEventMessageType, type);
ASSERT_STREQ("method", event.method.c_str());
ASSERT_TRUE(event.params->IsType(base::Value::TYPE_DICTIONARY));
}
TEST(ParseInspectorMessage, EventWithParams) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_TRUE(internal::ParseInspectorMessage(
"{\"method\":\"method\",\"params\":{\"key\":100}}",
0, &type, &event, &response));
ASSERT_EQ(internal::kEventMessageType, type);
ASSERT_STREQ("method", event.method.c_str());
int key;
ASSERT_TRUE(event.params->GetInteger("key", &key));
ASSERT_EQ(100, key);
}
TEST(ParseInspectorMessage, CommandNoErrorOrResult) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_FALSE(internal::ParseInspectorMessage(
"{\"id\":1}", 0, &type, &event, &response));
}
TEST(ParseInspectorMessage, CommandError) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_TRUE(internal::ParseInspectorMessage(
"{\"id\":1,\"error\":{}}", 0, &type, &event, &response));
ASSERT_EQ(internal::kCommandResponseMessageType, type);
ASSERT_EQ(1, response.id);
ASSERT_TRUE(response.error.length());
ASSERT_FALSE(response.result);
}
TEST(ParseInspectorMessage, Command) {
internal::InspectorMessageType type;
internal::InspectorEvent event;
internal::InspectorCommandResponse response;
ASSERT_TRUE(internal::ParseInspectorMessage(
"{\"id\":1,\"result\":{\"key\":1}}", 0, &type, &event, &response));
ASSERT_EQ(internal::kCommandResponseMessageType, type);
ASSERT_EQ(1, response.id);
ASSERT_FALSE(response.error.length());
int key;
ASSERT_TRUE(response.result->GetInteger("key", &key));
ASSERT_EQ(1, key);
}
TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
MockListener listener;
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnEvent));
client.AddListener(&listener);
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
long_timeout_);
ASSERT_EQ(kOk, status.code());
}
TEST_F(DevToolsClientImplTest, HandleEventsUntilTimeout) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnEvent));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
base::TimeDelta());
ASSERT_EQ(kTimeout, status.code());
}
TEST_F(DevToolsClientImplTest, WaitForNextEventCommand) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnCommand));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
long_timeout_);
ASSERT_EQ(kUnknownError, status.code());
}
TEST_F(DevToolsClientImplTest, WaitForNextEventError) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnError));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
long_timeout_);
ASSERT_EQ(kUnknownError, status.code());
}
TEST_F(DevToolsClientImplTest, WaitForNextEventConditionalFuncReturnsError) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc),
base::Bind(&ReturnEvent));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
Status status = client.HandleEventsUntil(base::Bind(&AlwaysError),
long_timeout_);
ASSERT_EQ(kUnknownError, status.code());
}
TEST_F(DevToolsClientImplTest, NestedCommandsWithOutOfOrderResults) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
int recurse_count = 0;
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
client.SetParserFuncForTesting(
base::Bind(&ReturnOutOfOrderResponses, &recurse_count, &client));
base::DictionaryValue params;
params.SetInteger("param", 1);
scoped_ptr<base::DictionaryValue> result;
ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
ASSERT_TRUE(result);
int key;
ASSERT_TRUE(result->GetInteger("key", &key));
ASSERT_EQ(2, key);
}
namespace {
class OnConnectedListener : public DevToolsEventListener {
public:
OnConnectedListener(const std::string& method, DevToolsClient* client)
: method_(method),
client_(client),
on_connected_called_(false),
on_event_called_(false) {
client_->AddListener(this);
}
virtual ~OnConnectedListener() {}
void VerifyCalled() {
EXPECT_TRUE(on_connected_called_);
EXPECT_TRUE(on_event_called_);
}
virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
EXPECT_EQ(client_, client);
EXPECT_STREQ("onconnected-id", client->GetId().c_str());
EXPECT_FALSE(on_connected_called_);
EXPECT_FALSE(on_event_called_);
on_connected_called_ = true;
base::DictionaryValue params;
return client_->SendCommand(method_, params);
}
virtual Status OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE {
EXPECT_EQ(client_, client);
EXPECT_STREQ("onconnected-id", client->GetId().c_str());
EXPECT_TRUE(on_connected_called_);
on_event_called_ = true;
return Status(kOk);
}
private:
std::string method_;
DevToolsClient* client_;
bool on_connected_called_;
bool on_event_called_;
};
class OnConnectedSyncWebSocket : public SyncWebSocket {
public:
OnConnectedSyncWebSocket() : connected_(false) {}
virtual ~OnConnectedSyncWebSocket() {}
virtual bool IsConnected() OVERRIDE {
return connected_;
}
virtual bool Connect(const GURL& url) OVERRIDE {
connected_ = true;
return true;
}
virtual bool Send(const std::string& message) OVERRIDE {
EXPECT_TRUE(connected_);
scoped_ptr<base::Value> value(base::JSONReader::Read(message));
base::DictionaryValue* dict = NULL;
EXPECT_TRUE(value->GetAsDictionary(&dict));
if (!dict)
return false;
int id;
EXPECT_TRUE(dict->GetInteger("id", &id));
std::string method;
EXPECT_TRUE(dict->GetString("method", &method));
base::DictionaryValue response;
response.SetInteger("id", id);
response.Set("result", new base::DictionaryValue());
std::string json_response;
base::JSONWriter::Write(&response, &json_response);
queued_response_.push_back(json_response);
base::DictionaryValue event;
event.SetString("method", "updateEvent");
event.Set("params", new base::DictionaryValue());
std::string json_event;
base::JSONWriter::Write(&event, &json_event);
queued_response_.push_back(json_event);
return true;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
if (queued_response_.empty())
return SyncWebSocket::kDisconnected;
*message = queued_response_.front();
queued_response_.pop_front();
return SyncWebSocket::kOk;
}
virtual bool HasNextMessage() OVERRIDE {
return !queued_response_.empty();
}
private:
bool connected_;
std::list<std::string> queued_response_;
};
}
TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnCommand) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "onconnected-id",
base::Bind(&CloserFunc));
OnConnectedListener listener1("DOM.getDocument", &client);
OnConnectedListener listener2("Runtime.enable", &client);
OnConnectedListener listener3("Page.enable", &client);
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
base::DictionaryValue params;
EXPECT_EQ(kOk, client.SendCommand("Runtime.execute", params).code());
listener1.VerifyCalled();
listener2.VerifyCalled();
listener3.VerifyCalled();
}
TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnHandleEventsUntil) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
DevToolsClientImpl client(factory, "http://url", "onconnected-id",
base::Bind(&CloserFunc));
OnConnectedListener listener1("DOM.getDocument", &client);
OnConnectedListener listener2("Runtime.enable", &client);
OnConnectedListener listener3("Page.enable", &client);
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
EXPECT_EQ(kOk, client.HandleReceivedEvents().code());
listener1.VerifyCalled();
listener2.VerifyCalled();
listener3.VerifyCalled();
}
namespace {
class MockSyncWebSocket5 : public SyncWebSocket {
public:
MockSyncWebSocket5() : request_no_(0) {}
virtual ~MockSyncWebSocket5() {}
virtual bool IsConnected() OVERRIDE {
return true;
}
virtual bool Connect(const GURL& url) OVERRIDE {
return true;
}
virtual bool Send(const std::string& message) OVERRIDE {
return true;
}
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
if (request_no_ == 0) {
*message = "{\"method\": \"m\", \"params\": {}}";
} else {
*message = base::StringPrintf(
"{\"result\": {}, \"id\": %d}", request_no_);
}
request_no_++;
return SyncWebSocket::kOk;
}
virtual bool HasNextMessage() OVERRIDE {
return false;
}
private:
int request_no_;
};
class OtherEventListener : public DevToolsEventListener {
public:
OtherEventListener() : received_event_(false) {}
virtual ~OtherEventListener() {}
virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
return Status(kOk);
}
virtual Status OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE {
received_event_ = true;
return Status(kOk);
}
bool received_event_;
};
class OnEventListener : public DevToolsEventListener {
public:
OnEventListener(DevToolsClient* client,
OtherEventListener* other_listener)
: client_(client),
other_listener_(other_listener) {}
virtual ~OnEventListener() {}
virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
EXPECT_EQ(client_, client);
return Status(kOk);
}
virtual Status OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE {
EXPECT_EQ(client_, client);
client_->SendCommand("method", params);
EXPECT_TRUE(other_listener_->received_event_);
return Status(kOk);
}
private:
DevToolsClient* client_;
OtherEventListener* other_listener_;
};
}
TEST_F(DevToolsClientImplTest, ProcessOnEventFirst) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket5>);
DevToolsClientImpl client(factory, "http://url", "id",
base::Bind(&CloserFunc));
OtherEventListener listener2;
OnEventListener listener1(&client, &listener2);
client.AddListener(&listener1);
client.AddListener(&listener2);
base::DictionaryValue params;
EXPECT_EQ(kOk, client.SendCommand("method", params).code());
}
namespace {
class DisconnectedSyncWebSocket : public MockSyncWebSocket {
public:
DisconnectedSyncWebSocket() : connection_count_(0), command_count_(0) {}
virtual ~DisconnectedSyncWebSocket() {}
virtual bool Connect(const GURL& url) OVERRIDE {
connection_count_++;
connected_ = connection_count_ != 2;
return connected_;
}
virtual bool Send(const std::string& message) OVERRIDE {
command_count_++;
if (command_count_ == 1) {
connected_ = false;
return false;
}
return MockSyncWebSocket::Send(message);
}
private:
int connection_count_;
int command_count_;
};
Status CheckCloserFuncCalled(bool* is_called) {
*is_called = true;
return Status(kOk);
}
}
TEST_F(DevToolsClientImplTest, Reconnect) {
SyncWebSocketFactory factory =
base::Bind(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>);
bool is_called = false;
DevToolsClientImpl client(factory,
"http://url",
"id",
base::Bind(&CheckCloserFuncCalled, &is_called));
ASSERT_FALSE(is_called);
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
ASSERT_FALSE(is_called);
base::DictionaryValue params;
params.SetInteger("param", 1);
is_called = false;
ASSERT_EQ(kDisconnected, client.SendCommand("method", params).code());
ASSERT_FALSE(is_called);
ASSERT_EQ(kDisconnected, client.HandleReceivedEvents().code());
ASSERT_FALSE(is_called);
ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
ASSERT_TRUE(is_called);
is_called = false;
ASSERT_EQ(kOk, client.SendCommand("method", params).code());
ASSERT_FALSE(is_called);
}
namespace {
class MockSyncWebSocket6 : public SyncWebSocket {
public:
explicit MockSyncWebSocket6(std::list<std::string>* messages)
: messages_(messages) {}
virtual ~MockSyncWebSocket6() {}
virtual bool IsConnected() OVERRIDE { return true; }
virtual bool Connect(const GURL& url) OVERRIDE { return true; }
virtual bool Send(const std::string& message) OVERRIDE { return true; }
virtual SyncWebSocket::StatusCode ReceiveNextMessage(
std::string* message,
const base::TimeDelta& timeout) OVERRIDE {
if (messages_->empty())
return SyncWebSocket::kDisconnected;
*message = messages_->front();
messages_->pop_front();
return SyncWebSocket::kOk;
}
virtual bool HasNextMessage() OVERRIDE { return messages_->size(); }
private:
std::list<std::string>* messages_;
};
class MockDevToolsEventListener : public DevToolsEventListener {
public:
MockDevToolsEventListener() : id_(1) {}
virtual ~MockDevToolsEventListener() {}
virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
return Status(kOk);
}
virtual Status OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE {
id_++;
Status status = client->SendCommand("hello", params);
id_--;
if (id_ == 3) {
EXPECT_EQ(kUnexpectedAlertOpen, status.code());
} else {
EXPECT_EQ(kOk, status.code());
}
return Status(kOk);
}
private:
int id_;
};
scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket6(
std::list<std::string>* messages) {
return scoped_ptr<MockSyncWebSocket6>(new MockSyncWebSocket6(messages))
.PassAs<SyncWebSocket>();
}
}
TEST_F(DevToolsClientImplTest, BlockedByAlert) {
std::list<std::string> msgs;
SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
DevToolsClientImpl client(
factory, "http://url", "id", base::Bind(&CloserFunc));
msgs.push_back(
"{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
msgs.push_back("{\"id\": 2, \"result\": {}}");
base::DictionaryValue params;
ASSERT_EQ(kUnexpectedAlertOpen,
client.SendCommand("first", params).code());
}
TEST_F(DevToolsClientImplTest, CorrectlyDeterminesWhichIsBlockedByAlert) {
std::list<std::string> msgs;
SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
DevToolsClientImpl client(
factory, "http://url", "id", base::Bind(&CloserFunc));
MockDevToolsEventListener listener;
client.AddListener(&listener);
msgs.push_back("{\"method\": \"FirstEvent\", \"params\": {}}");
msgs.push_back("{\"method\": \"SecondEvent\", \"params\": {}}");
msgs.push_back("{\"method\": \"ThirdEvent\", \"params\": {}}");
msgs.push_back("{\"method\": \"FourthEvent\", \"params\": {}}");
msgs.push_back("{\"id\": 1, \"result\": {}}");
msgs.push_back(
"{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
msgs.push_back("{\"id\": 2, \"result\": {}}");
msgs.push_back("{\"id\": 4, \"result\": {}}");
msgs.push_back("{\"id\": 5, \"result\": {}}");
msgs.push_back("{\"id\": 6, \"result\": {}}");
ASSERT_EQ(kOk, client.HandleReceivedEvents().code());
}
namespace {
class MockCommandListener : public DevToolsEventListener {
public:
MockCommandListener() {}
virtual ~MockCommandListener() {}
virtual Status OnEvent(DevToolsClient* client,
const std::string& method,
const base::DictionaryValue& params) OVERRIDE {
msgs_.push_back(method);
return Status(kOk);
}
virtual Status OnCommandSuccess(DevToolsClient* client,
const std::string& method) OVERRIDE {
msgs_.push_back(method);
if (!callback_.is_null())
callback_.Run(client);
return Status(kOk);
}
base::Callback<void(DevToolsClient*)> callback_;
std::list<std::string> msgs_;
};
void HandleReceivedEvents(DevToolsClient* client) {
EXPECT_EQ(kOk, client->HandleReceivedEvents().code());
}
}
TEST_F(DevToolsClientImplTest, ReceivesCommandResponse) {
std::list<std::string> msgs;
SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
DevToolsClientImpl client(
factory, "http://url", "id", base::Bind(&CloserFunc));
MockCommandListener listener1;
listener1.callback_ = base::Bind(&HandleReceivedEvents);
MockCommandListener listener2;
client.AddListener(&listener1);
client.AddListener(&listener2);
msgs.push_back("{\"id\": 1, \"result\": {}}");
msgs.push_back("{\"method\": \"event\", \"params\": {}}");
base::DictionaryValue params;
ASSERT_EQ(kOk, client.SendCommand("cmd", params).code());
ASSERT_EQ(2u, listener2.msgs_.size());
ASSERT_EQ("cmd", listener2.msgs_.front());
ASSERT_EQ("event", listener2.msgs_.back());
}