root/jingle/glue/chrome_async_socket_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GetNextRead
  2. OnWrite
  3. Reset
  4. AddRead
  5. AddWrite
  6. transport_security_state_
  7. CreateTransportClientSocket
  8. CreateSSLClientSocket
  9. addr_
  10. SetUp
  11. TearDown
  12. CaptureSocketState
  13. OnConnect
  14. OnSSLConnect
  15. OnClose
  16. OnRead
  17. OnError
  18. ExpectState
  19. ExpectNonErrorState
  20. ExpectErrorState
  21. ExpectClosed
  22. ExpectNoSignal
  23. ExpectSignalSocketState
  24. ExpectReadSignal
  25. ExpectSSLConnectSignal
  26. ExpectSSLReadSignal
  27. DoOpenClosed
  28. DoCloseOpened
  29. DoCloseOpenedNoError
  30. DoSSLOpenClosed
  31. DoSSLCloseOpened
  32. DoSSLCloseOpenedNoError
  33. DrainRead
  34. TEST_F
  35. TEST_F
  36. TEST_F
  37. TEST_F
  38. TEST_F
  39. TEST_F
  40. TEST_F
  41. TEST_F
  42. TEST_F
  43. TEST_F
  44. TEST_F
  45. TEST_F
  46. TEST_F
  47. TEST_F
  48. TEST_F
  49. TEST_F
  50. TEST_F
  51. TEST_F
  52. TEST_F
  53. TEST_F
  54. TEST_F
  55. TEST_F
  56. TEST_F
  57. TEST_F
  58. TEST_F
  59. TEST_F
  60. TEST_F
  61. TEST_F
  62. TEST_F
  63. TEST_F
  64. TEST_F
  65. TEST_F
  66. TEST_F
  67. TEST_F
  68. TEST_F
  69. TEST_F
  70. TEST_F
  71. TEST_F
  72. TEST_F

// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "jingle/glue/chrome_async_socket.h"

#include <deque>
#include <string>

#include "base/basictypes.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop/message_loop.h"
#include "jingle/glue/resolving_client_socket_factory.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
#include "net/cert/mock_cert_verifier.h"
#include "net/http/transport_security_state.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/ssl_client_socket.h"
#include "net/ssl/ssl_config_service.h"
#include "net/url_request/url_request_context_getter.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/libjingle/source/talk/base/ipaddress.h"
#include "third_party/libjingle/source/talk/base/sigslot.h"
#include "third_party/libjingle/source/talk/base/socketaddress.h"

namespace jingle_glue {

namespace {

// Data provider that handles reads/writes for ChromeAsyncSocket.
class AsyncSocketDataProvider : public net::SocketDataProvider {
 public:
  AsyncSocketDataProvider() : has_pending_read_(false) {}

  virtual ~AsyncSocketDataProvider() {
    EXPECT_TRUE(writes_.empty());
    EXPECT_TRUE(reads_.empty());
  }

  // If there's no read, sets the "has pending read" flag.  Otherwise,
  // pops the next read.
  virtual net::MockRead GetNextRead() OVERRIDE {
    if (reads_.empty()) {
      DCHECK(!has_pending_read_);
      has_pending_read_ = true;
      const net::MockRead pending_read(net::SYNCHRONOUS, net::ERR_IO_PENDING);
      return pending_read;
    }
    net::MockRead mock_read = reads_.front();
    reads_.pop_front();
    return mock_read;
  }

  // Simply pops the next write and, if applicable, compares it to
  // |data|.
  virtual net::MockWriteResult OnWrite(const std::string& data) OVERRIDE {
    DCHECK(!writes_.empty());
    net::MockWrite mock_write = writes_.front();
    writes_.pop_front();
    if (mock_write.result != net::OK) {
      return net::MockWriteResult(mock_write.mode, mock_write.result);
    }
    std::string expected_data(mock_write.data, mock_write.data_len);
    EXPECT_EQ(expected_data, data);
    if (expected_data != data) {
      return net::MockWriteResult(net::SYNCHRONOUS, net::ERR_UNEXPECTED);
    }
    return net::MockWriteResult(mock_write.mode, data.size());
  }

  // We ignore resets so we can pre-load the socket data provider with
  // read/write events.
  virtual void Reset() OVERRIDE {}

  // If there is a pending read, completes it with the given read.
  // Otherwise, queues up the given read.
  void AddRead(const net::MockRead& mock_read) {
    DCHECK_NE(mock_read.result, net::ERR_IO_PENDING);
    if (has_pending_read_) {
      socket()->OnReadComplete(mock_read);
      has_pending_read_ = false;
      return;
    }
    reads_.push_back(mock_read);
  }

  // Simply queues up the given write.
  void AddWrite(const net::MockWrite& mock_write) {
    writes_.push_back(mock_write);
  }

 private:
  std::deque<net::MockRead> reads_;
  bool has_pending_read_;

  std::deque<net::MockWrite> writes_;

  DISALLOW_COPY_AND_ASSIGN(AsyncSocketDataProvider);
};

class MockXmppClientSocketFactory : public ResolvingClientSocketFactory {
 public:
  MockXmppClientSocketFactory(
      net::ClientSocketFactory* mock_client_socket_factory,
      const net::AddressList& address_list)
          : mock_client_socket_factory_(mock_client_socket_factory),
            address_list_(address_list),
            cert_verifier_(new net::MockCertVerifier),
            transport_security_state_(new net::TransportSecurityState) {
  }

  // ResolvingClientSocketFactory implementation.
  virtual scoped_ptr<net::StreamSocket> CreateTransportClientSocket(
      const net::HostPortPair& host_and_port) OVERRIDE {
    return mock_client_socket_factory_->CreateTransportClientSocket(
        address_list_, NULL, net::NetLog::Source());
  }

  virtual scoped_ptr<net::SSLClientSocket> CreateSSLClientSocket(
      scoped_ptr<net::ClientSocketHandle> transport_socket,
      const net::HostPortPair& host_and_port) OVERRIDE {
    net::SSLClientSocketContext context;
    context.cert_verifier = cert_verifier_.get();
    context.transport_security_state = transport_security_state_.get();
    return mock_client_socket_factory_->CreateSSLClientSocket(
        transport_socket.Pass(), host_and_port, ssl_config_, context);
  }

 private:
  scoped_ptr<net::ClientSocketFactory> mock_client_socket_factory_;
  net::AddressList address_list_;
  net::SSLConfig ssl_config_;
  scoped_ptr<net::CertVerifier> cert_verifier_;
  scoped_ptr<net::TransportSecurityState> transport_security_state_;
};

class ChromeAsyncSocketTest
    : public testing::Test,
      public sigslot::has_slots<> {
 protected:
  ChromeAsyncSocketTest()
      : ssl_socket_data_provider_(net::ASYNC, net::OK),
        addr_("localhost", 35) {}

  virtual ~ChromeAsyncSocketTest() {}

  virtual void SetUp() {
    scoped_ptr<net::MockClientSocketFactory> mock_client_socket_factory(
        new net::MockClientSocketFactory());
    mock_client_socket_factory->AddSocketDataProvider(
        &async_socket_data_provider_);
    mock_client_socket_factory->AddSSLSocketDataProvider(
        &ssl_socket_data_provider_);

    // Fake DNS resolution for |addr_| and pass it to the factory.
    net::IPAddressNumber resolved_addr;
    EXPECT_TRUE(net::ParseIPLiteralToNumber("127.0.0.1", &resolved_addr));
    const net::AddressList address_list =
        net::AddressList::CreateFromIPAddress(resolved_addr, addr_.port());
    scoped_ptr<MockXmppClientSocketFactory> mock_xmpp_client_socket_factory(
        new MockXmppClientSocketFactory(
            mock_client_socket_factory.release(),
            address_list));
    chrome_async_socket_.reset(
        new ChromeAsyncSocket(mock_xmpp_client_socket_factory.release(),
                              14, 20)),

    chrome_async_socket_->SignalConnected.connect(
        this, &ChromeAsyncSocketTest::OnConnect);
    chrome_async_socket_->SignalSSLConnected.connect(
        this, &ChromeAsyncSocketTest::OnSSLConnect);
    chrome_async_socket_->SignalClosed.connect(
        this, &ChromeAsyncSocketTest::OnClose);
    chrome_async_socket_->SignalRead.connect(
        this, &ChromeAsyncSocketTest::OnRead);
    chrome_async_socket_->SignalError.connect(
        this, &ChromeAsyncSocketTest::OnError);
  }

  virtual void TearDown() {
    // Run any tasks that we forgot to pump.
    message_loop_.RunUntilIdle();
    ExpectClosed();
    ExpectNoSignal();
    chrome_async_socket_.reset();
  }

  enum Signal {
    SIGNAL_CONNECT,
    SIGNAL_SSL_CONNECT,
    SIGNAL_CLOSE,
    SIGNAL_READ,
    SIGNAL_ERROR,
  };

  // Helper struct that records the state at the time of a signal.

  struct SignalSocketState {
    SignalSocketState()
        : signal(SIGNAL_ERROR),
          state(ChromeAsyncSocket::STATE_CLOSED),
          error(ChromeAsyncSocket::ERROR_NONE),
          net_error(net::OK) {}

    SignalSocketState(
        Signal signal,
        ChromeAsyncSocket::State state,
        ChromeAsyncSocket::Error error,
        net::Error net_error)
        : signal(signal),
          state(state),
          error(error),
          net_error(net_error) {}

    bool IsEqual(const SignalSocketState& other) const {
      return
          (signal == other.signal) &&
          (state == other.state) &&
          (error == other.error) &&
          (net_error == other.net_error);
    }

    static SignalSocketState FromAsyncSocket(
        Signal signal,
        buzz::AsyncSocket* async_socket) {
      return SignalSocketState(signal,
                               async_socket->state(),
                               async_socket->error(),
                               static_cast<net::Error>(
                                   async_socket->GetError()));
    }

    static SignalSocketState NoError(
        Signal signal, buzz::AsyncSocket::State state) {
        return SignalSocketState(signal, state,
                                 buzz::AsyncSocket::ERROR_NONE,
                                 net::OK);
    }

    Signal signal;
    ChromeAsyncSocket::State state;
    ChromeAsyncSocket::Error error;
    net::Error net_error;
  };

  void CaptureSocketState(Signal signal) {
    signal_socket_states_.push_back(
        SignalSocketState::FromAsyncSocket(
            signal, chrome_async_socket_.get()));
  }

  void OnConnect() {
    CaptureSocketState(SIGNAL_CONNECT);
  }

  void OnSSLConnect() {
    CaptureSocketState(SIGNAL_SSL_CONNECT);
  }

  void OnClose() {
    CaptureSocketState(SIGNAL_CLOSE);
  }

  void OnRead() {
    CaptureSocketState(SIGNAL_READ);
  }

  void OnError() {
    ADD_FAILURE();
  }

  // State expect functions.

  void ExpectState(ChromeAsyncSocket::State state,
                   ChromeAsyncSocket::Error error,
                   net::Error net_error) {
    EXPECT_EQ(state, chrome_async_socket_->state());
    EXPECT_EQ(error, chrome_async_socket_->error());
    EXPECT_EQ(net_error, chrome_async_socket_->GetError());
  }

  void ExpectNonErrorState(ChromeAsyncSocket::State state) {
    ExpectState(state, ChromeAsyncSocket::ERROR_NONE, net::OK);
  }

  void ExpectErrorState(ChromeAsyncSocket::State state,
                        ChromeAsyncSocket::Error error) {
    ExpectState(state, error, net::OK);
  }

  void ExpectClosed() {
    ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED);
  }

  // Signal expect functions.

  void ExpectNoSignal() {
    if (!signal_socket_states_.empty()) {
      ADD_FAILURE() << signal_socket_states_.front().signal;
    }
  }

  void ExpectSignalSocketState(
      SignalSocketState expected_signal_socket_state) {
    if (signal_socket_states_.empty()) {
      ADD_FAILURE() << expected_signal_socket_state.signal;
      return;
    }
    EXPECT_TRUE(expected_signal_socket_state.IsEqual(
        signal_socket_states_.front()))
        << signal_socket_states_.front().signal;
    signal_socket_states_.pop_front();
  }

  void ExpectReadSignal() {
    ExpectSignalSocketState(
        SignalSocketState::NoError(
            SIGNAL_READ, ChromeAsyncSocket::STATE_OPEN));
  }

  void ExpectSSLConnectSignal() {
    ExpectSignalSocketState(
        SignalSocketState::NoError(SIGNAL_SSL_CONNECT,
                                   ChromeAsyncSocket::STATE_TLS_OPEN));
  }

  void ExpectSSLReadSignal() {
    ExpectSignalSocketState(
        SignalSocketState::NoError(
            SIGNAL_READ, ChromeAsyncSocket::STATE_TLS_OPEN));
  }

  // Open/close utility functions.

  void DoOpenClosed() {
    ExpectClosed();
    async_socket_data_provider_.set_connect_data(
        net::MockConnect(net::SYNCHRONOUS, net::OK));
    EXPECT_TRUE(chrome_async_socket_->Connect(addr_));
    ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING);

    message_loop_.RunUntilIdle();
    // We may not necessarily be open; may have been other events
    // queued up.
    ExpectSignalSocketState(
        SignalSocketState::NoError(
            SIGNAL_CONNECT, ChromeAsyncSocket::STATE_OPEN));
  }

  void DoCloseOpened(SignalSocketState expected_signal_socket_state) {
    // We may be in an error state, so just compare state().
    EXPECT_EQ(ChromeAsyncSocket::STATE_OPEN, chrome_async_socket_->state());
    EXPECT_TRUE(chrome_async_socket_->Close());
    ExpectSignalSocketState(expected_signal_socket_state);
    ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED);
  }

  void DoCloseOpenedNoError() {
    DoCloseOpened(
        SignalSocketState::NoError(
            SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));
  }

  void DoSSLOpenClosed() {
    const char kDummyData[] = "dummy_data";
    async_socket_data_provider_.AddRead(net::MockRead(kDummyData));
    DoOpenClosed();
    ExpectReadSignal();
    EXPECT_EQ(kDummyData, DrainRead(1));

    EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
    message_loop_.RunUntilIdle();
    ExpectSSLConnectSignal();
    ExpectNoSignal();
    ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN);
  }

  void DoSSLCloseOpened(SignalSocketState expected_signal_socket_state) {
    // We may be in an error state, so just compare state().
    EXPECT_EQ(ChromeAsyncSocket::STATE_TLS_OPEN,
              chrome_async_socket_->state());
    EXPECT_TRUE(chrome_async_socket_->Close());
    ExpectSignalSocketState(expected_signal_socket_state);
    ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED);
  }

  void DoSSLCloseOpenedNoError() {
    DoSSLCloseOpened(
        SignalSocketState::NoError(
            SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));
  }

  // Read utility fucntions.

  std::string DrainRead(size_t buf_size) {
    std::string read;
    scoped_ptr<char[]> buf(new char[buf_size]);
    size_t len_read;
    while (true) {
      bool success =
          chrome_async_socket_->Read(buf.get(), buf_size, &len_read);
      if (!success) {
        ADD_FAILURE();
        break;
      }
      if (len_read == 0U) {
        break;
      }
      read.append(buf.get(), len_read);
    }
    return read;
  }

  // ChromeAsyncSocket expects a message loop.
  base::MessageLoop message_loop_;

  AsyncSocketDataProvider async_socket_data_provider_;
  net::SSLSocketDataProvider ssl_socket_data_provider_;

  scoped_ptr<ChromeAsyncSocket> chrome_async_socket_;
  std::deque<SignalSocketState> signal_socket_states_;
  const talk_base::SocketAddress addr_;

 private:
  DISALLOW_COPY_AND_ASSIGN(ChromeAsyncSocketTest);
};

TEST_F(ChromeAsyncSocketTest, InitialState) {
  ExpectClosed();
  ExpectNoSignal();
}

TEST_F(ChromeAsyncSocketTest, EmptyClose) {
  ExpectClosed();
  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
}

TEST_F(ChromeAsyncSocketTest, ImmediateConnectAndClose) {
  DoOpenClosed();

  ExpectNonErrorState(ChromeAsyncSocket::STATE_OPEN);

  DoCloseOpenedNoError();
}

// After this, no need to test immediate successful connect and
// Close() so thoroughly.

TEST_F(ChromeAsyncSocketTest, DoubleClose) {
  DoOpenClosed();

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
}

TEST_F(ChromeAsyncSocketTest, NoHostnameConnect) {
  talk_base::IPAddress ip_address;
  EXPECT_TRUE(talk_base::IPFromString("127.0.0.1", &ip_address));
  const talk_base::SocketAddress no_hostname_addr(ip_address, addr_.port());
  EXPECT_FALSE(chrome_async_socket_->Connect(no_hostname_addr));
  ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED,
                   ChromeAsyncSocket::ERROR_DNS);

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
}

TEST_F(ChromeAsyncSocketTest, ZeroPortConnect) {
  const talk_base::SocketAddress zero_port_addr(addr_.hostname(), 0);
  EXPECT_FALSE(chrome_async_socket_->Connect(zero_port_addr));
  ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED,
                   ChromeAsyncSocket::ERROR_DNS);

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
}

TEST_F(ChromeAsyncSocketTest, DoubleConnect) {
  EXPECT_DEBUG_DEATH({
    DoOpenClosed();

    EXPECT_FALSE(chrome_async_socket_->Connect(addr_));
    ExpectErrorState(ChromeAsyncSocket::STATE_OPEN,
                     ChromeAsyncSocket::ERROR_WRONGSTATE);

    DoCloseOpened(
        SignalSocketState(SIGNAL_CLOSE,
                          ChromeAsyncSocket::STATE_CLOSED,
                          ChromeAsyncSocket::ERROR_WRONGSTATE,
                          net::OK));
  }, "non-closed socket");
}

TEST_F(ChromeAsyncSocketTest, ImmediateConnectCloseBeforeRead) {
  DoOpenClosed();

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));

  message_loop_.RunUntilIdle();
}

TEST_F(ChromeAsyncSocketTest, HangingConnect) {
  EXPECT_TRUE(chrome_async_socket_->Connect(addr_));
  ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING);
  ExpectNoSignal();

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));
}

TEST_F(ChromeAsyncSocketTest, PendingConnect) {
  async_socket_data_provider_.set_connect_data(
      net::MockConnect(net::ASYNC, net::OK));
  EXPECT_TRUE(chrome_async_socket_->Connect(addr_));
  ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING);
  ExpectNoSignal();

  message_loop_.RunUntilIdle();
  ExpectNonErrorState(ChromeAsyncSocket::STATE_OPEN);
  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CONNECT, ChromeAsyncSocket::STATE_OPEN));
  ExpectNoSignal();

  message_loop_.RunUntilIdle();

  DoCloseOpenedNoError();
}

// After this no need to test successful pending connect so
// thoroughly.

TEST_F(ChromeAsyncSocketTest, PendingConnectCloseBeforeRead) {
  async_socket_data_provider_.set_connect_data(
      net::MockConnect(net::ASYNC, net::OK));
  EXPECT_TRUE(chrome_async_socket_->Connect(addr_));

  message_loop_.RunUntilIdle();
  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CONNECT, ChromeAsyncSocket::STATE_OPEN));

  DoCloseOpenedNoError();

  message_loop_.RunUntilIdle();
}

TEST_F(ChromeAsyncSocketTest, PendingConnectError) {
  async_socket_data_provider_.set_connect_data(
      net::MockConnect(net::ASYNC, net::ERR_TIMED_OUT));
  EXPECT_TRUE(chrome_async_socket_->Connect(addr_));

  message_loop_.RunUntilIdle();

  ExpectSignalSocketState(
      SignalSocketState(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
          ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT));
}

// After this we can assume Connect() and Close() work as expected.

TEST_F(ChromeAsyncSocketTest, EmptyRead) {
  DoOpenClosed();

  char buf[4096];
  size_t len_read = 10000U;
  EXPECT_TRUE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read));
  EXPECT_EQ(0U, len_read);

  DoCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, WrongRead) {
  EXPECT_DEBUG_DEATH({
    async_socket_data_provider_.set_connect_data(
        net::MockConnect(net::ASYNC, net::OK));
    EXPECT_TRUE(chrome_async_socket_->Connect(addr_));
    ExpectNonErrorState(ChromeAsyncSocket::STATE_CONNECTING);
    ExpectNoSignal();

    char buf[4096];
    size_t len_read;
    EXPECT_FALSE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read));
    ExpectErrorState(ChromeAsyncSocket::STATE_CONNECTING,
                     ChromeAsyncSocket::ERROR_WRONGSTATE);
    EXPECT_TRUE(chrome_async_socket_->Close());
    ExpectSignalSocketState(
        SignalSocketState(
            SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
            ChromeAsyncSocket::ERROR_WRONGSTATE, net::OK));
  }, "non-open");
}

TEST_F(ChromeAsyncSocketTest, WrongReadClosed) {
  char buf[4096];
  size_t len_read;
  EXPECT_FALSE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read));
  ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED,
                   ChromeAsyncSocket::ERROR_WRONGSTATE);
  EXPECT_TRUE(chrome_async_socket_->Close());
}

const char kReadData[] = "mydatatoread";

TEST_F(ChromeAsyncSocketTest, Read) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();

  ExpectReadSignal();
  ExpectNoSignal();

  EXPECT_EQ(kReadData, DrainRead(1));

  message_loop_.RunUntilIdle();

  DoCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, ReadTwice) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();

  ExpectReadSignal();
  ExpectNoSignal();

  EXPECT_EQ(kReadData, DrainRead(1));

  message_loop_.RunUntilIdle();

  const char kReadData2[] = "mydatatoread2";
  async_socket_data_provider_.AddRead(net::MockRead(kReadData2));

  ExpectReadSignal();
  ExpectNoSignal();

  EXPECT_EQ(kReadData2, DrainRead(1));

  DoCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, ReadError) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();

  ExpectReadSignal();
  ExpectNoSignal();

  EXPECT_EQ(kReadData, DrainRead(1));

  message_loop_.RunUntilIdle();

  async_socket_data_provider_.AddRead(
      net::MockRead(net::SYNCHRONOUS, net::ERR_TIMED_OUT));

  ExpectSignalSocketState(
      SignalSocketState(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
          ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT));
}

TEST_F(ChromeAsyncSocketTest, ReadEmpty) {
  async_socket_data_provider_.AddRead(net::MockRead(""));
  DoOpenClosed();

  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));
}

TEST_F(ChromeAsyncSocketTest, PendingRead) {
  DoOpenClosed();

  ExpectNoSignal();

  async_socket_data_provider_.AddRead(net::MockRead(kReadData));

  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_READ, ChromeAsyncSocket::STATE_OPEN));
  ExpectNoSignal();

  EXPECT_EQ(kReadData, DrainRead(1));

  message_loop_.RunUntilIdle();

  DoCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, PendingEmptyRead) {
  DoOpenClosed();

  ExpectNoSignal();

  async_socket_data_provider_.AddRead(net::MockRead(""));

  ExpectSignalSocketState(
      SignalSocketState::NoError(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED));
}

TEST_F(ChromeAsyncSocketTest, PendingReadError) {
  DoOpenClosed();

  ExpectNoSignal();

  async_socket_data_provider_.AddRead(
      net::MockRead(net::ASYNC, net::ERR_TIMED_OUT));

  ExpectSignalSocketState(
      SignalSocketState(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
          ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT));
}

// After this we can assume non-SSL Read() works as expected.

TEST_F(ChromeAsyncSocketTest, WrongWrite) {
  EXPECT_DEBUG_DEATH({
    std::string data("foo");
    EXPECT_FALSE(chrome_async_socket_->Write(data.data(), data.size()));
    ExpectErrorState(ChromeAsyncSocket::STATE_CLOSED,
                     ChromeAsyncSocket::ERROR_WRONGSTATE);
    EXPECT_TRUE(chrome_async_socket_->Close());
  }, "non-open");
}

const char kWriteData[] = "mydatatowrite";

TEST_F(ChromeAsyncSocketTest, SyncWrite) {
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::SYNCHRONOUS, kWriteData, 3));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::SYNCHRONOUS, kWriteData + 3, 5));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::SYNCHRONOUS,
                     kWriteData + 8, arraysize(kWriteData) - 8));
  DoOpenClosed();

  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8,
                                          arraysize(kWriteData) - 8));
  message_loop_.RunUntilIdle();

  ExpectNoSignal();

  DoCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, AsyncWrite) {
  DoOpenClosed();

  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData, 3));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData + 3, 5));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData + 8, arraysize(kWriteData) - 8));

  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8,
                                          arraysize(kWriteData) - 8));
  message_loop_.RunUntilIdle();

  ExpectNoSignal();

  DoCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, AsyncWriteError) {
  DoOpenClosed();

  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData, 3));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData + 3, 5));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, net::ERR_TIMED_OUT));

  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8,
                                          arraysize(kWriteData) - 8));
  message_loop_.RunUntilIdle();

  ExpectSignalSocketState(
      SignalSocketState(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
          ChromeAsyncSocket::ERROR_WINSOCK, net::ERR_TIMED_OUT));
}

TEST_F(ChromeAsyncSocketTest, LargeWrite) {
  EXPECT_DEBUG_DEATH({
    DoOpenClosed();

    std::string large_data(100, 'x');
    EXPECT_FALSE(chrome_async_socket_->Write(large_data.data(),
                                             large_data.size()));
    ExpectState(ChromeAsyncSocket::STATE_OPEN,
                ChromeAsyncSocket::ERROR_WINSOCK,
                net::ERR_INSUFFICIENT_RESOURCES);
    DoCloseOpened(
        SignalSocketState(
            SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
            ChromeAsyncSocket::ERROR_WINSOCK,
            net::ERR_INSUFFICIENT_RESOURCES));
    }, "exceed the max write buffer");
}

TEST_F(ChromeAsyncSocketTest, LargeAccumulatedWrite) {
  EXPECT_DEBUG_DEATH({
    DoOpenClosed();

    std::string data(15, 'x');
    EXPECT_TRUE(chrome_async_socket_->Write(data.data(), data.size()));
    EXPECT_FALSE(chrome_async_socket_->Write(data.data(), data.size()));
    ExpectState(ChromeAsyncSocket::STATE_OPEN,
                ChromeAsyncSocket::ERROR_WINSOCK,
                net::ERR_INSUFFICIENT_RESOURCES);
    DoCloseOpened(
        SignalSocketState(
            SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
            ChromeAsyncSocket::ERROR_WINSOCK,
            net::ERR_INSUFFICIENT_RESOURCES));
    }, "exceed the max write buffer");
}

// After this we can assume non-SSL I/O works as expected.

TEST_F(ChromeAsyncSocketTest, HangingSSLConnect) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();
  ExpectReadSignal();

  EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
  ExpectNoSignal();

  ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_CONNECTING);
  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectSignalSocketState(
      SignalSocketState::NoError(SIGNAL_CLOSE,
                                 ChromeAsyncSocket::STATE_CLOSED));
  ExpectNonErrorState(ChromeAsyncSocket::STATE_CLOSED);
}

TEST_F(ChromeAsyncSocketTest, ImmediateSSLConnect) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();
  ExpectReadSignal();

  EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
  message_loop_.RunUntilIdle();
  ExpectSSLConnectSignal();
  ExpectNoSignal();
  ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN);

  DoSSLCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, DoubleSSLConnect) {
  EXPECT_DEBUG_DEATH({
    async_socket_data_provider_.AddRead(net::MockRead(kReadData));
    DoOpenClosed();
    ExpectReadSignal();

    EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
    message_loop_.RunUntilIdle();
    ExpectSSLConnectSignal();
    ExpectNoSignal();
    ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN);

    EXPECT_FALSE(chrome_async_socket_->StartTls("fakedomain.com"));

    DoSSLCloseOpened(
        SignalSocketState(SIGNAL_CLOSE,
                          ChromeAsyncSocket::STATE_CLOSED,
                          ChromeAsyncSocket::ERROR_WRONGSTATE,
                          net::OK));
  }, "wrong state");
}

TEST_F(ChromeAsyncSocketTest, FailedSSLConnect) {
  ssl_socket_data_provider_.connect =
      net::MockConnect(net::ASYNC, net::ERR_CERT_COMMON_NAME_INVALID),

  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();
  ExpectReadSignal();

  EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
  message_loop_.RunUntilIdle();
  ExpectSignalSocketState(
      SignalSocketState(
          SIGNAL_CLOSE, ChromeAsyncSocket::STATE_CLOSED,
          ChromeAsyncSocket::ERROR_WINSOCK,
          net::ERR_CERT_COMMON_NAME_INVALID));

  EXPECT_TRUE(chrome_async_socket_->Close());
  ExpectClosed();
}

TEST_F(ChromeAsyncSocketTest, ReadDuringSSLConnecting) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();
  ExpectReadSignal();
  EXPECT_EQ(kReadData, DrainRead(1));

  EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
  ExpectNoSignal();

  // Shouldn't do anything.
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));

  char buf[4096];
  size_t len_read = 10000U;
  EXPECT_TRUE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read));
  EXPECT_EQ(0U, len_read);

  message_loop_.RunUntilIdle();
  ExpectSSLConnectSignal();
  ExpectSSLReadSignal();
  ExpectNoSignal();
  ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_OPEN);

  len_read = 10000U;
  EXPECT_TRUE(chrome_async_socket_->Read(buf, sizeof(buf), &len_read));
  EXPECT_EQ(kReadData, std::string(buf, len_read));

  DoSSLCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, WriteDuringSSLConnecting) {
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  DoOpenClosed();
  ExpectReadSignal();

  EXPECT_TRUE(chrome_async_socket_->StartTls("fakedomain.com"));
  ExpectNoSignal();
  ExpectNonErrorState(ChromeAsyncSocket::STATE_TLS_CONNECTING);

  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData, 3));

  // Shouldn't do anything.
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));

  // TODO(akalin): Figure out how to test that the write happens
  // *after* the SSL connect.

  message_loop_.RunUntilIdle();
  ExpectSSLConnectSignal();
  ExpectNoSignal();

  message_loop_.RunUntilIdle();

  DoSSLCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, SSLConnectDuringPendingRead) {
  EXPECT_DEBUG_DEATH({
    DoOpenClosed();

    EXPECT_FALSE(chrome_async_socket_->StartTls("fakedomain.com"));

    DoCloseOpened(
        SignalSocketState(SIGNAL_CLOSE,
                          ChromeAsyncSocket::STATE_CLOSED,
                          ChromeAsyncSocket::ERROR_WRONGSTATE,
                          net::OK));
  }, "wrong state");
}

TEST_F(ChromeAsyncSocketTest, SSLConnectDuringPostedWrite) {
  EXPECT_DEBUG_DEATH({
    DoOpenClosed();

    async_socket_data_provider_.AddWrite(
        net::MockWrite(net::ASYNC, kWriteData, 3));
    EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));

    EXPECT_FALSE(chrome_async_socket_->StartTls("fakedomain.com"));

    message_loop_.RunUntilIdle();

    DoCloseOpened(
        SignalSocketState(SIGNAL_CLOSE,
                          ChromeAsyncSocket::STATE_CLOSED,
                          ChromeAsyncSocket::ERROR_WRONGSTATE,
                          net::OK));
  }, "wrong state");
}

// After this we can assume SSL connect works as expected.

TEST_F(ChromeAsyncSocketTest, SSLRead) {
  DoSSLOpenClosed();
  async_socket_data_provider_.AddRead(net::MockRead(kReadData));
  message_loop_.RunUntilIdle();

  ExpectSSLReadSignal();
  ExpectNoSignal();

  EXPECT_EQ(kReadData, DrainRead(1));

  message_loop_.RunUntilIdle();

  DoSSLCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, SSLSyncWrite) {
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::SYNCHRONOUS, kWriteData, 3));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::SYNCHRONOUS, kWriteData + 3, 5));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::SYNCHRONOUS,
                     kWriteData + 8, arraysize(kWriteData) - 8));
  DoSSLOpenClosed();

  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8,
                                          arraysize(kWriteData) - 8));
  message_loop_.RunUntilIdle();

  ExpectNoSignal();

  DoSSLCloseOpenedNoError();
}

TEST_F(ChromeAsyncSocketTest, SSLAsyncWrite) {
  DoSSLOpenClosed();

  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData, 3));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData + 3, 5));
  async_socket_data_provider_.AddWrite(
      net::MockWrite(net::ASYNC, kWriteData + 8, arraysize(kWriteData) - 8));

  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData, 3));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 3, 5));
  message_loop_.RunUntilIdle();
  EXPECT_TRUE(chrome_async_socket_->Write(kWriteData + 8,
                                          arraysize(kWriteData) - 8));
  message_loop_.RunUntilIdle();

  ExpectNoSignal();

  DoSSLCloseOpenedNoError();
}

}  // namespace

}  // namespace jingle_glue

/* [<][>][^][v][top][bottom][index][help] */