// 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