12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <list>
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <string>
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/compiler_specific.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_reader.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/json/json_writer.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/values.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/devtools_client_impl.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/devtools_event_listener.h"
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/chromedriver/chrome/status.h"
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/chromedriver/net/sync_websocket.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/test/chromedriver/net/sync_websocket_factory.h"
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
217dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Status CloserFunc() {
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Status(kOk);
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockSyncWebSocket : public SyncWebSocket {
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockSyncWebSocket() : connected_(false), id_(-1), queued_messages_(1) {}
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockSyncWebSocket() {}
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return connected_;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_STREQ("http://url/", url.possibly_invalid_spec().c_str());
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connected_ = true;
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(connected_);
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::Value> value(base::JSONReader::Read(message));
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* dict = NULL;
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(value->GetAsDictionary(&dict));
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!dict)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(dict->GetInteger("id", &id_));
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string method;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(dict->GetString("method", &method));
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_STREQ("method", method.c_str());
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* params = NULL;
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(dict->GetDictionary("params", &params));
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!params)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int param = -1;
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(params->GetInteger("param", &param));
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_EQ(1, param);
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
65868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
68424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)    if (timeout <= base::TimeDelta())
69424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      return SyncWebSocket::kTimeout;
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue response;
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    response.SetInteger("id", id_);
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue result;
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    result.SetInteger("param", 1);
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    response.Set("result", result.DeepCopy());
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONWriter::Write(&response, message);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    --queued_messages_;
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kOk;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return queued_messages_ > 0;
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected:
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool connected_;
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int id_;
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int queued_messages_;
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)template <typename T>
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket() {
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return scoped_ptr<SyncWebSocket>(new T());
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)class DevToolsClientImplTest : public testing::Test {
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) protected:
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DevToolsClientImplTest() : long_timeout_(base::TimeDelta::FromMinutes(5)) {}
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
99868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const base::TimeDelta long_timeout_;
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
104868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommand) {
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
10858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.SetInteger("param", 1);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.SendCommand("method", params).code());
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandAndGetResult) {
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
11958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.SetInteger("param", 1);
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> result;
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Status status = client.SendCommandAndGetResult("method", params, &result);
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, status.code());
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string json;
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::JSONWriter::Write(result.get(), &json);
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_STREQ("{\"param\":1}", json.c_str());
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockSyncWebSocket2 : public SyncWebSocket {
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockSyncWebSocket2() {}
1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockSyncWebSocket2() {}
1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
1472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(false);
1482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(false);
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kDisconnected;
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, ConnectIfNecessaryConnectFails) {
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket2>);
168c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
16958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kDisconnected, client.ConnectIfNecessary().code());
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockSyncWebSocket3 : public SyncWebSocket {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockSyncWebSocket3() : connected_(false) {}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockSyncWebSocket3() {}
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
1812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return connected_;
1822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connected_ = true;
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
1872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
1902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
193868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(false);
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kDisconnected;
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool connected_;
2062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandSendFails) {
2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket3>);
213c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsError());
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockSyncWebSocket4 : public SyncWebSocket {
2232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
2242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockSyncWebSocket4() : connected_(false) {}
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockSyncWebSocket4() {}
2262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return connected_;
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connected_ = true;
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
243868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kDisconnected;
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool connected_;
2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandReceiveNextMessageFails) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
2582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket4>);
259c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
26058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
2632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsError());
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class FakeSyncWebSocket : public SyncWebSocket {
2692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
2702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  FakeSyncWebSocket() : connected_(false) {}
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~FakeSyncWebSocket() {}
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
2742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return connected_;
2752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
2782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_FALSE(connected_);
2792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connected_ = true;
2802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
2842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
289868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
290868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kOk;
2912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
2952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
2982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool connected_;
2992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnCommand(
3022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
3032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
3042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
3052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
3062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
3072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *type = internal::kCommandResponseMessageType;
3082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->id = expected_id;
3092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->result.reset(new base::DictionaryValue());
3102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnBadResponse(
3142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *type = internal::kCommandResponseMessageType;
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->id = expected_id;
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->result.reset(new base::DictionaryValue());
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnCommandBadId(
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *type = internal::kCommandResponseMessageType;
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->id = expected_id + 100;
3332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->result.reset(new base::DictionaryValue());
3342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnCommandError(
3382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
3392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
3402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
3412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
3422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
3432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *type = internal::kCommandResponseMessageType;
3442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->id = expected_id;
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->error = "err";
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockListener : public DevToolsEventListener {
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockListener() : called_(false) {}
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockListener() {
3532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(called_);
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
356c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
3572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return Status(kOk);
3582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
360868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual Status OnEvent(DevToolsClient* client,
361868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const std::string& method,
362868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const base::DictionaryValue& params) OVERRIDE {
3632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    called_ = true;
3642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_STREQ("method", method.c_str());
3652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(params.HasKey("key"));
366868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
3672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
3702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool called_;
3712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
3722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnEventThenResponse(
3742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    bool* first,
3752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
3762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
3772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (*first) {
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *type = internal::kEventMessageType;
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->method = "method";
3832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->params.reset(new base::DictionaryValue());
3842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event->params->SetInteger("key", 1);
3852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
3862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *type = internal::kCommandResponseMessageType;
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    command_response->id = expected_id;
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue params;
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    command_response->result.reset(new base::DictionaryValue());
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    command_response->result->SetInteger("key", 2);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *first = false;
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
3942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnEvent(
3972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
3982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
3992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
4002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
4012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *type = internal::kEventMessageType;
4032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->method = "method";
4042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->params.reset(new base::DictionaryValue());
4052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  event->params->SetInteger("key", 1);
4062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnOutOfOrderResponses(
4102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int* recurse_count,
4112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    DevToolsClient* client,
4122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
4132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
4142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
4152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
4162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
4172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int key = 0;
4182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
4192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.SetInteger("param", 1);
4202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  switch ((*recurse_count)++) {
4212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case 0:
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      client->SendCommand("method", params);
4232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *type = internal::kEventMessageType;
4242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event->method = "method";
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event->params.reset(new base::DictionaryValue());
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      event->params->SetInteger("key", 1);
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return true;
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case 1:
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      command_response->id = expected_id - 1;
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key = 2;
4312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    case 2:
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      command_response->id = expected_id;
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      key = 3;
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      break;
4362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *type = internal::kCommandResponseMessageType;
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->result.reset(new base::DictionaryValue());
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  command_response->result->SetInteger("key", key);
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool ReturnError(
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& message,
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int expected_id,
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorMessageType* type,
4472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorEvent* event,
4482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    internal::InspectorCommandResponse* command_response) {
4492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return false;
4502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Status AlwaysTrue(bool* is_met) {
4532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *is_met = true;
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Status(kOk);
4552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Status AlwaysError(bool* is_met) {
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Status(kUnknownError);
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
463868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandOnlyConnectsOnce) {
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
466c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
46758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnCommand));
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
4702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsOk());
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsOk());
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
475868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandBadResponse) {
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
478c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
47958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnBadResponse));
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsError());
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
486868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandBadId) {
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
489c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
49058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnCommandBadId));
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsError());
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
497868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandResponseError) {
4982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
4992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
500c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
50158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
5022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnCommandError));
5032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
5042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
5052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommand("method", params).IsError());
5062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
508868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, SendCommandEventBeforeResponse) {
5092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
5102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<FakeSyncWebSocket>);
5112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockListener listener;
5122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool first = true;
513c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
51458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
5152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnEventThenResponse, &first));
5162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client.AddListener(&listener);
5172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
5182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
5192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> result;
5202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
5212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(result);
5222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int key;
5232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(result->GetInteger("key", &key));
5242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(2, key);
5252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, NonJson) {
5282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(internal::ParseInspectorMessage(
5322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "hi", 0, &type, &event, &response));
5332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, NeitherCommandNorEvent) {
5362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(internal::ParseInspectorMessage(
5402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "{}", 0, &type, &event, &response));
5412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, EventNoParams) {
5442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(internal::ParseInspectorMessage(
5482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "{\"method\":\"method\"}", 0, &type, &event, &response));
5492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(internal::kEventMessageType, type);
5502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_STREQ("method", event.method.c_str());
5512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(event.params->IsType(base::Value::TYPE_DICTIONARY));
5522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, EventWithParams) {
5552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(internal::ParseInspectorMessage(
5592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "{\"method\":\"method\",\"params\":{\"key\":100}}",
5602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      0, &type, &event, &response));
5612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(internal::kEventMessageType, type);
5622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_STREQ("method", event.method.c_str());
5632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int key;
5642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(event.params->GetInteger("key", &key));
5652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(100, key);
5662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, CommandNoErrorOrResult) {
5692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // As per Chromium issue 392577, DevTools does not necessarily return a
5735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // "result" dictionary for every valid response. If neither "error" nor
5745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // "result" keys are present, a blank result dictionary should be inferred.
5755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_TRUE(internal::ParseInspectorMessage(
5762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "{\"id\":1}", 0, &type, &event, &response));
5775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_TRUE(response.result->empty());
5782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, CommandError) {
5812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(internal::ParseInspectorMessage(
5852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "{\"id\":1,\"error\":{}}", 0, &type, &event, &response));
5862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(internal::kCommandResponseMessageType, type);
5872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(1, response.id);
5882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(response.error.length());
5892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(response.result);
5902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
5912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)TEST(ParseInspectorMessage, Command) {
5932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorMessageType type;
5942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorEvent event;
5952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  internal::InspectorCommandResponse response;
5962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(internal::ParseInspectorMessage(
5972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      "{\"id\":1,\"result\":{\"key\":1}}", 0, &type, &event, &response));
5982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(internal::kCommandResponseMessageType, type);
5992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(1, response.id);
6002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(response.error.length());
6012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int key;
6022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(response.result->GetInteger("key", &key));
6032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(1, key);
6042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
606868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, HandleEventsUntil) {
6072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockListener listener;
6082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
6092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
610c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
61158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
6122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnEvent));
6132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client.AddListener(&listener);
6142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
615868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
616868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           long_timeout_);
6172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, status.code());
6182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
620868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, HandleEventsUntilTimeout) {
621868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  SyncWebSocketFactory factory =
622868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
623868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
62458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
625868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                            base::Bind(&ReturnEvent));
626868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
627868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
628868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           base::TimeDelta());
629868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  ASSERT_EQ(kTimeout, status.code());
630868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
631868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
632868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, WaitForNextEventCommand) {
6332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
6342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
635c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
63658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
6372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnCommand));
6382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
639868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
640868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           long_timeout_);
6412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kUnknownError, status.code());
6422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
644868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, WaitForNextEventError) {
6452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
6462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
647c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
64858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
6492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnError));
6502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
651868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = client.HandleEventsUntil(base::Bind(&AlwaysTrue),
652868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           long_timeout_);
6532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kUnknownError, status.code());
6542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
656868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, WaitForNextEventConditionalFuncReturnsError) {
6572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
6582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
659c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
66058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc),
6612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                            base::Bind(&ReturnEvent));
6622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
663868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  Status status = client.HandleEventsUntil(base::Bind(&AlwaysError),
664868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           long_timeout_);
6652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kUnknownError, status.code());
6662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
668868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, NestedCommandsWithOutOfOrderResults) {
6692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
6702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket>);
6712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int recurse_count = 0;
672c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
67358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
6742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
6752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client.SetParserFuncForTesting(
6762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ReturnOutOfOrderResponses, &recurse_count, &client));
6772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
6782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.SetInteger("param", 1);
6792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scoped_ptr<base::DictionaryValue> result;
6802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(client.SendCommandAndGetResult("method", params, &result).IsOk());
6812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(result);
6822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int key;
6832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(result->GetInteger("key", &key));
6842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(2, key);
6852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
6862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
6882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
6892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OnConnectedListener : public DevToolsEventListener {
6902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
6912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener(const std::string& method, DevToolsClient* client)
6922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : method_(method),
6932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        client_(client),
6942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        on_connected_called_(false),
6952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        on_event_called_(false) {
6962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    client_->AddListener(this);
6972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
6982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~OnConnectedListener() {}
6992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void VerifyCalled() {
7012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(on_connected_called_);
7022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(on_event_called_);
7032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
705c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
706c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_EQ(client_, client);
707c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_STREQ("onconnected-id", client->GetId().c_str());
7082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_FALSE(on_connected_called_);
7092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_FALSE(on_event_called_);
7102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    on_connected_called_ = true;
7112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue params;
7122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return client_->SendCommand(method_, params);
7132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
715868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual Status OnEvent(DevToolsClient* client,
716868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const std::string& method,
717868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const base::DictionaryValue& params) OVERRIDE {
718c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_EQ(client_, client);
719c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_STREQ("onconnected-id", client->GetId().c_str());
7202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(on_connected_called_);
7212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    on_event_called_ = true;
722868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
7232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
7262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::string method_;
7272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsClient* client_;
7282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool on_connected_called_;
7292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool on_event_called_;
7302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
7312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OnConnectedSyncWebSocket : public SyncWebSocket {
7332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
7342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedSyncWebSocket() : connected_(false) {}
7352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~OnConnectedSyncWebSocket() {}
7362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
7382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return connected_;
7392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
7422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connected_ = true;
7432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
7442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
7472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(connected_);
7482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    scoped_ptr<base::Value> value(base::JSONReader::Read(message));
7492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue* dict = NULL;
7502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(value->GetAsDictionary(&dict));
7512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!dict)
7522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
7532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int id;
7542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(dict->GetInteger("id", &id));
7552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string method;
7562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(dict->GetString("method", &method));
7572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue response;
7592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    response.SetInteger("id", id);
7602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    response.Set("result", new base::DictionaryValue());
7612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string json_response;
7622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONWriter::Write(&response, &json_response);
7632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queued_response_.push_back(json_response);
7642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Push one event.
7662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::DictionaryValue event;
7672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event.SetString("method", "updateEvent");
7682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    event.Set("params", new base::DictionaryValue());
7692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    std::string json_event;
7702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::JSONWriter::Write(&event, &json_event);
7712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queued_response_.push_back(json_event);
7722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
7742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
776868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
777868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
778868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
7792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (queued_response_.empty())
780868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return SyncWebSocket::kDisconnected;
7812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    *message = queued_response_.front();
7822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    queued_response_.pop_front();
783868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kOk;
7842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
7872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return !queued_response_.empty();
7882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
7892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
7912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool connected_;
7922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::list<std::string> queued_response_;
7932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
7942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
7952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
7962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
797868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnCommand) {
7982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
7992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
800c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "onconnected-id",
80158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
8022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener listener1("DOM.getDocument", &client);
8032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener listener2("Runtime.enable", &client);
8042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener listener3("Page.enable", &client);
8052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
8062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
8072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(kOk, client.SendCommand("Runtime.execute", params).code());
8082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener1.VerifyCalled();
8092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener2.VerifyCalled();
8102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener3.VerifyCalled();
8112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
813868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, ProcessOnConnectedFirstOnHandleEventsUntil) {
8142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
8152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<OnConnectedSyncWebSocket>);
816c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "onconnected-id",
81758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
8182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener listener1("DOM.getDocument", &client);
8192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener listener2("Runtime.enable", &client);
8202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnConnectedListener listener3("Page.enable", &client);
8212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
8222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(kOk, client.HandleReceivedEvents().code());
8232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener1.VerifyCalled();
8242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener2.VerifyCalled();
8252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  listener3.VerifyCalled();
8262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
8272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
8292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class MockSyncWebSocket5 : public SyncWebSocket {
8312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
8322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  MockSyncWebSocket5() : request_no_(0) {}
8332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~MockSyncWebSocket5() {}
8342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE {
8362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
8372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
8402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
8412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
8442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return true;
8452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
847868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
848868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
849868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
8502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (request_no_ == 0) {
8512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *message = "{\"method\": \"m\", \"params\": {}}";
8522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
8532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      *message = base::StringPrintf(
8542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          "{\"result\": {}, \"id\": %d}", request_no_);
8552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
8562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    request_no_++;
857868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kOk;
8582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE {
8612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
8622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
8652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int request_no_;
8662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
8672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OtherEventListener : public DevToolsEventListener {
8692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
8702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OtherEventListener() : received_event_(false) {}
8712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~OtherEventListener() {}
8722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
873c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
8742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return Status(kOk);
8752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
876868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual Status OnEvent(DevToolsClient* client,
877868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const std::string& method,
878868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const base::DictionaryValue& params) OVERRIDE {
8792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    received_event_ = true;
880868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
8812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool received_event_;
8842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
8852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
8862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OnEventListener : public DevToolsEventListener {
8872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
8882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnEventListener(DevToolsClient* client,
8892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                  OtherEventListener* other_listener)
8902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      : client_(client),
8912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        other_listener_(other_listener) {}
8922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~OnEventListener() {}
8932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
894c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
895c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    EXPECT_EQ(client_, client);
8962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return Status(kOk);
8972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
8982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
899868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual Status OnEvent(DevToolsClient* client,
900868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const std::string& method,
901868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const base::DictionaryValue& params) OVERRIDE {
902868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    EXPECT_EQ(client_, client);
9032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    client_->SendCommand("method", params);
9042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    EXPECT_TRUE(other_listener_->received_event_);
905868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
9062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
9092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DevToolsClient* client_;
9102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OtherEventListener* other_listener_;
9112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
9122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
9142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
915868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, ProcessOnEventFirst) {
9162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
9172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<MockSyncWebSocket5>);
918c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DevToolsClientImpl client(factory, "http://url", "id",
91958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CloserFunc));
9202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OtherEventListener listener2;
9212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  OnEventListener listener1(&client, &listener2);
9222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client.AddListener(&listener1);
9232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  client.AddListener(&listener2);
9242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
9252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  EXPECT_EQ(kOk, client.SendCommand("method", params).code());
9262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
9292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class DisconnectedSyncWebSocket : public MockSyncWebSocket {
9312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
9322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DisconnectedSyncWebSocket() : connection_count_(0), command_count_(0) {}
9332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~DisconnectedSyncWebSocket() {}
9342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE {
9362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connection_count_++;
9372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    connected_ = connection_count_ != 2;
9382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return connected_;
9392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE {
9422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    command_count_++;
9432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (command_count_ == 1) {
9442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      connected_ = false;
9452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return false;
9462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
9472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return MockSyncWebSocket::Send(message);
9482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
9492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
9512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int connection_count_;
9522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  int command_count_;
9532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
9542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Status CheckCloserFuncCalled(bool* is_called) {
9562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  *is_called = true;
9572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return Status(kOk);
9582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
9592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
9612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
962868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, Reconnect) {
9632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  SyncWebSocketFactory factory =
9642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&CreateMockSyncWebSocket<DisconnectedSyncWebSocket>);
9652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  bool is_called = false;
96690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DevToolsClientImpl client(factory,
96790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            "http://url",
96890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                            "id",
96958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                            base::Bind(&CheckCloserFuncCalled, &is_called));
9702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(is_called);
9712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
9722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(is_called);
9732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::DictionaryValue params;
9742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  params.SetInteger("param", 1);
9752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  is_called = false;
9762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kDisconnected, client.SendCommand("method", params).code());
9772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(is_called);
9782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kDisconnected, client.HandleReceivedEvents().code());
9792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(is_called);
9802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.ConnectIfNecessary().code());
9812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_TRUE(is_called);
9822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  is_called = false;
9832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_EQ(kOk, client.SendCommand("method", params).code());
9842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ASSERT_FALSE(is_called);
9852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
98690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
98790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
98890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
98990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class MockSyncWebSocket6 : public SyncWebSocket {
99090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
99190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  explicit MockSyncWebSocket6(std::list<std::string>* messages)
99290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      : messages_(messages) {}
99390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~MockSyncWebSocket6() {}
99490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
99590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool IsConnected() OVERRIDE { return true; }
99690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
99790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool Connect(const GURL& url) OVERRIDE { return true; }
99890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
99990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool Send(const std::string& message) OVERRIDE { return true; }
100090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1001868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual SyncWebSocket::StatusCode ReceiveNextMessage(
1002868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string* message,
1003868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const base::TimeDelta& timeout) OVERRIDE {
100490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (messages_->empty())
1005868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return SyncWebSocket::kDisconnected;
100690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    *message = messages_->front();
100790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    messages_->pop_front();
1008868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return SyncWebSocket::kOk;
100990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
101090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
101190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual bool HasNextMessage() OVERRIDE { return messages_->size(); }
101290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
101390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
101490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::list<std::string>* messages_;
101590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
101690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
101790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class MockDevToolsEventListener : public DevToolsEventListener {
101890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
101990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MockDevToolsEventListener() : id_(1) {}
102090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~MockDevToolsEventListener() {}
102190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
102290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual Status OnConnected(DevToolsClient* client) OVERRIDE {
102390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return Status(kOk);
102490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
102590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1026868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual Status OnEvent(DevToolsClient* client,
1027868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const std::string& method,
1028868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const base::DictionaryValue& params) OVERRIDE {
102990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    id_++;
103090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    Status status = client->SendCommand("hello", params);
103190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    id_--;
103290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (id_ == 3) {
103390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(kUnexpectedAlertOpen, status.code());
103490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    } else {
103590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      EXPECT_EQ(kOk, status.code());
103690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    }
1037868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
103890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
103990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
104090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) private:
104190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  int id_;
104290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
104390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
104490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)scoped_ptr<SyncWebSocket> CreateMockSyncWebSocket6(
104590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    std::list<std::string>* messages) {
104690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return scoped_ptr<MockSyncWebSocket6>(new MockSyncWebSocket6(messages))
104790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      .PassAs<SyncWebSocket>();
104890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
104990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
105090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
105190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1052868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, BlockedByAlert) {
105390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::list<std::string> msgs;
105490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
105590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DevToolsClientImpl client(
105658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      factory, "http://url", "id", base::Bind(&CloserFunc));
105790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back(
105890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
105990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 2, \"result\": {}}");
106090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::DictionaryValue params;
106190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(kUnexpectedAlertOpen,
106290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)            client.SendCommand("first", params).code());
106390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
106490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1065868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, CorrectlyDeterminesWhichIsBlockedByAlert) {
106690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // OUT                 | IN
106790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       FirstEvent
106890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // hello (id=1)
106990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       SecondEvent
107090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // hello (id=2)
107190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       ThirdEvent
107290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // hello (id=3)
107390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       FourthEvent
107490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // hello (id=4)
107590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       response for 1
107690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       alert
107790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // hello (id=5)
107890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // round trip command (id=6)
107990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       response for 2
108090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       response for 4
108190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       response for 5
108290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  //                       response for 6
108390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::list<std::string> msgs;
108490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
108590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DevToolsClientImpl client(
108658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      factory, "http://url", "id", base::Bind(&CloserFunc));
108790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MockDevToolsEventListener listener;
108890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  client.AddListener(&listener);
108990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"method\": \"FirstEvent\", \"params\": {}}");
109090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"method\": \"SecondEvent\", \"params\": {}}");
109190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"method\": \"ThirdEvent\", \"params\": {}}");
109290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"method\": \"FourthEvent\", \"params\": {}}");
109390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 1, \"result\": {}}");
109490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back(
109590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      "{\"method\": \"Page.javascriptDialogOpening\", \"params\": {}}");
109690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 2, \"result\": {}}");
109790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 4, \"result\": {}}");
109890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 5, \"result\": {}}");
109990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 6, \"result\": {}}");
110090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(kOk, client.HandleReceivedEvents().code());
110190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
110290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
110390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace {
110490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
110590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)class MockCommandListener : public DevToolsEventListener {
110690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) public:
110790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MockCommandListener() {}
110890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual ~MockCommandListener() {}
110990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual Status OnEvent(DevToolsClient* client,
1111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const std::string& method,
1112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                         const base::DictionaryValue& params) OVERRIDE {
111390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    msgs_.push_back(method);
1114868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return Status(kOk);
111590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
111690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
111790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  virtual Status OnCommandSuccess(DevToolsClient* client,
111890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                  const std::string& method) OVERRIDE {
111990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    msgs_.push_back(method);
112090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    if (!callback_.is_null())
112190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      callback_.Run(client);
112290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    return Status(kOk);
112390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  }
112490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
112590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::Callback<void(DevToolsClient*)> callback_;
112690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::list<std::string> msgs_;
112790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)};
112890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
112990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void HandleReceivedEvents(DevToolsClient* client) {
113090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  EXPECT_EQ(kOk, client->HandleReceivedEvents().code());
113190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
113290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
113390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}  // namespace
113490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
1135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)TEST_F(DevToolsClientImplTest, ReceivesCommandResponse) {
113690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  std::list<std::string> msgs;
113790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  SyncWebSocketFactory factory = base::Bind(&CreateMockSyncWebSocket6, &msgs);
113890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  DevToolsClientImpl client(
113958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      factory, "http://url", "id", base::Bind(&CloserFunc));
114090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MockCommandListener listener1;
114190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  listener1.callback_ = base::Bind(&HandleReceivedEvents);
114290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  MockCommandListener listener2;
114390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  client.AddListener(&listener1);
114490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  client.AddListener(&listener2);
114590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"id\": 1, \"result\": {}}");
114690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  msgs.push_back("{\"method\": \"event\", \"params\": {}}");
114790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  base::DictionaryValue params;
114890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(kOk, client.SendCommand("cmd", params).code());
114990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ(2u, listener2.msgs_.size());
115090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ("cmd", listener2.msgs_.front());
115190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  ASSERT_EQ("event", listener2.msgs_.back());
115290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
1153