// 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 "net/socket/socket_test_util.h"
#include <string.h>
#include "base/memory/ref_counted.h"
#include "testing/platform_test.h"
#include "testing/gtest/include/gtest/gtest.h"
//-----------------------------------------------------------------------------
namespace {
static const char kMsg1[] = "\0hello!\xff";
static const int kLen1 = arraysize(kMsg1);
static const char kMsg2[] = "\012345678\0";
static const int kLen2 = arraysize(kMsg2);
static const char kMsg3[] = "bye!";
static const int kLen3 = arraysize(kMsg3);
} // anonymous namespace
namespace net {
class DeterministicSocketDataTest : public PlatformTest {
public:
DeterministicSocketDataTest();
virtual void TearDown();
void ReentrantReadCallback(int len, int rv);
void ReentrantWriteCallback(const char* data, int len, int rv);
protected:
void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes,
size_t writes_count);
void AssertSyncReadEquals(const char* data, int len);
void AssertAsyncReadEquals(const char* data, int len);
void AssertReadReturns(const char* data, int len, int rv);
void AssertReadBufferEquals(const char* data, int len);
void AssertSyncWriteEquals(const char* data, int len);
void AssertAsyncWriteEquals(const char* data, int len);
void AssertWriteReturns(const char* data, int len, int rv);
TestCompletionCallback read_callback_;
TestCompletionCallback write_callback_;
StreamSocket* sock_;
scoped_ptr<DeterministicSocketData> data_;
private:
scoped_refptr<IOBuffer> read_buf_;
MockConnect connect_data_;
HostPortPair endpoint_;
scoped_refptr<TransportSocketParams> tcp_params_;
ClientSocketPoolHistograms histograms_;
DeterministicMockClientSocketFactory socket_factory_;
MockTransportClientSocketPool socket_pool_;
ClientSocketHandle connection_;
DISALLOW_COPY_AND_ASSIGN(DeterministicSocketDataTest);
};
DeterministicSocketDataTest::DeterministicSocketDataTest()
: sock_(NULL),
read_buf_(NULL),
connect_data_(SYNCHRONOUS, OK),
endpoint_("www.google.com", 443),
tcp_params_(new TransportSocketParams(endpoint_,
false,
false,
OnHostResolutionCallback())),
histograms_(std::string()),
socket_pool_(10, 10, &histograms_, &socket_factory_) {}
void DeterministicSocketDataTest::TearDown() {
// Empty the current queue.
base::MessageLoop::current()->RunUntilIdle();
PlatformTest::TearDown();
}
void DeterministicSocketDataTest::Initialize(MockRead* reads,
size_t reads_count,
MockWrite* writes,
size_t writes_count) {
data_.reset(new DeterministicSocketData(reads, reads_count,
writes, writes_count));
data_->set_connect_data(connect_data_);
socket_factory_.AddSocketDataProvider(data_.get());
// Perform the TCP connect
EXPECT_EQ(OK,
connection_.Init(endpoint_.ToString(),
tcp_params_,
LOWEST,
CompletionCallback(),
reinterpret_cast<TransportClientSocketPool*>(&socket_pool_),
BoundNetLog()));
sock_ = connection_.socket();
}
void DeterministicSocketDataTest::AssertSyncReadEquals(const char* data,
int len) {
// Issue the read, which will complete immediately
AssertReadReturns(data, len, len);
AssertReadBufferEquals(data, len);
}
void DeterministicSocketDataTest::AssertAsyncReadEquals(const char* data,
int len) {
// Issue the read, which will be completed asynchronously
AssertReadReturns(data, len, ERR_IO_PENDING);
EXPECT_FALSE(read_callback_.have_result());
EXPECT_TRUE(sock_->IsConnected());
data_->RunFor(1); // Runs 1 step, to cause the callbacks to be invoked
// Now the read should complete
ASSERT_EQ(len, read_callback_.WaitForResult());
AssertReadBufferEquals(data, len);
}
void DeterministicSocketDataTest::AssertReadReturns(const char* data,
int len, int rv) {
read_buf_ = new IOBuffer(len);
ASSERT_EQ(rv, sock_->Read(read_buf_.get(), len, read_callback_.callback()));
}
void DeterministicSocketDataTest::AssertReadBufferEquals(const char* data,
int len) {
ASSERT_EQ(std::string(data, len), std::string(read_buf_->data(), len));
}
void DeterministicSocketDataTest::AssertSyncWriteEquals(const char* data,
int len) {
scoped_refptr<IOBuffer> buf(new IOBuffer(len));
memcpy(buf->data(), data, len);
// Issue the write, which will complete immediately
ASSERT_EQ(len, sock_->Write(buf.get(), len, write_callback_.callback()));
}
void DeterministicSocketDataTest::AssertAsyncWriteEquals(const char* data,
int len) {
// Issue the read, which will be completed asynchronously
AssertWriteReturns(data, len, ERR_IO_PENDING);
EXPECT_FALSE(read_callback_.have_result());
EXPECT_TRUE(sock_->IsConnected());
data_->RunFor(1); // Runs 1 step, to cause the callbacks to be invoked
ASSERT_EQ(len, write_callback_.WaitForResult());
}
void DeterministicSocketDataTest::AssertWriteReturns(const char* data,
int len, int rv) {
scoped_refptr<IOBuffer> buf(new IOBuffer(len));
memcpy(buf->data(), data, len);
// Issue the read, which will complete asynchronously
ASSERT_EQ(rv, sock_->Write(buf.get(), len, write_callback_.callback()));
}
void DeterministicSocketDataTest::ReentrantReadCallback(int len, int rv) {
scoped_refptr<IOBuffer> read_buf(new IOBuffer(len));
EXPECT_EQ(len,
sock_->Read(
read_buf.get(),
len,
base::Bind(&DeterministicSocketDataTest::ReentrantReadCallback,
base::Unretained(this),
len)));
}
void DeterministicSocketDataTest::ReentrantWriteCallback(
const char* data, int len, int rv) {
scoped_refptr<IOBuffer> write_buf(new IOBuffer(len));
memcpy(write_buf->data(), data, len);
EXPECT_EQ(len,
sock_->Write(
write_buf.get(),
len,
base::Bind(&DeterministicSocketDataTest::ReentrantWriteCallback,
base::Unretained(this),
data,
len)));
}
// ----------- Read
TEST_F(DeterministicSocketDataTest, SingleSyncReadWhileStopped) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
MockRead(SYNCHRONOUS, 0, 1), // EOF
};
Initialize(reads, arraysize(reads), NULL, 0);
data_->SetStopped(true);
AssertReadReturns(kMsg1, kLen1, ERR_UNEXPECTED);
}
TEST_F(DeterministicSocketDataTest, SingleSyncReadTooEarly) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 1), // Sync Read
MockRead(SYNCHRONOUS, 0, 2), // EOF
};
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, 0, 0)
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
data_->StopAfter(2);
ASSERT_FALSE(data_->stopped());
AssertReadReturns(kMsg1, kLen1, ERR_UNEXPECTED);
}
TEST_F(DeterministicSocketDataTest, SingleSyncRead) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
MockRead(SYNCHRONOUS, 0, 1), // EOF
};
Initialize(reads, arraysize(reads), NULL, 0);
// Make sure we don't stop before we've read all the data
data_->StopAfter(1);
AssertSyncReadEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, MultipleSyncReads) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
MockRead(SYNCHRONOUS, kMsg2, kLen2, 1), // Sync Read
MockRead(SYNCHRONOUS, kMsg3, kLen3, 2), // Sync Read
MockRead(SYNCHRONOUS, kMsg3, kLen3, 3), // Sync Read
MockRead(SYNCHRONOUS, kMsg2, kLen2, 4), // Sync Read
MockRead(SYNCHRONOUS, kMsg3, kLen3, 5), // Sync Read
MockRead(SYNCHRONOUS, kMsg1, kLen1, 6), // Sync Read
MockRead(SYNCHRONOUS, 0, 7), // EOF
};
Initialize(reads, arraysize(reads), NULL, 0);
// Make sure we don't stop before we've read all the data
data_->StopAfter(10);
AssertSyncReadEquals(kMsg1, kLen1);
AssertSyncReadEquals(kMsg2, kLen2);
AssertSyncReadEquals(kMsg3, kLen3);
AssertSyncReadEquals(kMsg3, kLen3);
AssertSyncReadEquals(kMsg2, kLen2);
AssertSyncReadEquals(kMsg3, kLen3);
AssertSyncReadEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, SingleAsyncRead) {
MockRead reads[] = {
MockRead(ASYNC, kMsg1, kLen1, 0), // Async Read
MockRead(SYNCHRONOUS, 0, 1), // EOF
};
Initialize(reads, arraysize(reads), NULL, 0);
AssertAsyncReadEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, MultipleAsyncReads) {
MockRead reads[] = {
MockRead(ASYNC, kMsg1, kLen1, 0), // Async Read
MockRead(ASYNC, kMsg2, kLen2, 1), // Async Read
MockRead(ASYNC, kMsg3, kLen3, 2), // Async Read
MockRead(ASYNC, kMsg3, kLen3, 3), // Async Read
MockRead(ASYNC, kMsg2, kLen2, 4), // Async Read
MockRead(ASYNC, kMsg3, kLen3, 5), // Async Read
MockRead(ASYNC, kMsg1, kLen1, 6), // Async Read
MockRead(SYNCHRONOUS, 0, 7), // EOF
};
Initialize(reads, arraysize(reads), NULL, 0);
AssertAsyncReadEquals(kMsg1, kLen1);
AssertAsyncReadEquals(kMsg2, kLen2);
AssertAsyncReadEquals(kMsg3, kLen3);
AssertAsyncReadEquals(kMsg3, kLen3);
AssertAsyncReadEquals(kMsg2, kLen2);
AssertAsyncReadEquals(kMsg3, kLen3);
AssertAsyncReadEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, MixedReads) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
MockRead(ASYNC, kMsg2, kLen2, 1), // Async Read
MockRead(SYNCHRONOUS, kMsg3, kLen3, 2), // Sync Read
MockRead(ASYNC, kMsg3, kLen3, 3), // Async Read
MockRead(SYNCHRONOUS, kMsg2, kLen2, 4), // Sync Read
MockRead(ASYNC, kMsg3, kLen3, 5), // Async Read
MockRead(SYNCHRONOUS, kMsg1, kLen1, 6), // Sync Read
MockRead(SYNCHRONOUS, 0, 7), // EOF
};
Initialize(reads, arraysize(reads), NULL, 0);
data_->StopAfter(1);
AssertSyncReadEquals(kMsg1, kLen1);
AssertAsyncReadEquals(kMsg2, kLen2);
data_->StopAfter(1);
AssertSyncReadEquals(kMsg3, kLen3);
AssertAsyncReadEquals(kMsg3, kLen3);
data_->StopAfter(1);
AssertSyncReadEquals(kMsg2, kLen2);
AssertAsyncReadEquals(kMsg3, kLen3);
data_->StopAfter(1);
AssertSyncReadEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, SyncReadFromCompletionCallback) {
MockRead reads[] = {
MockRead(ASYNC, kMsg1, kLen1, 0), // Async Read
MockRead(SYNCHRONOUS, kMsg2, kLen2, 1), // Sync Read
};
Initialize(reads, arraysize(reads), NULL, 0);
data_->StopAfter(2);
scoped_refptr<IOBuffer> read_buf(new IOBuffer(kLen1));
ASSERT_EQ(ERR_IO_PENDING,
sock_->Read(
read_buf.get(),
kLen1,
base::Bind(&DeterministicSocketDataTest::ReentrantReadCallback,
base::Unretained(this),
kLen2)));
data_->Run();
}
// ----------- Write
TEST_F(DeterministicSocketDataTest, SingleSyncWriteWhileStopped) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
};
Initialize(NULL, 0, writes, arraysize(writes));
data_->SetStopped(true);
AssertWriteReturns(kMsg1, kLen1, ERR_UNEXPECTED);
}
TEST_F(DeterministicSocketDataTest, SingleSyncWriteTooEarly) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 1), // Sync Write
};
MockRead reads[] = {
MockRead(SYNCHRONOUS, 0, 0)
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
data_->StopAfter(2);
ASSERT_FALSE(data_->stopped());
AssertWriteReturns(kMsg1, kLen1, ERR_UNEXPECTED);
}
TEST_F(DeterministicSocketDataTest, SingleSyncWrite) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Write
};
Initialize(NULL, 0, writes, arraysize(writes));
// Make sure we don't stop before we've read all the data
data_->StopAfter(1);
AssertSyncWriteEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, MultipleSyncWrites) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Write
MockWrite(SYNCHRONOUS, kMsg2, kLen2, 1), // Sync Write
MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), // Sync Write
MockWrite(SYNCHRONOUS, kMsg3, kLen3, 3), // Sync Write
MockWrite(SYNCHRONOUS, kMsg2, kLen2, 4), // Sync Write
MockWrite(SYNCHRONOUS, kMsg3, kLen3, 5), // Sync Write
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 6), // Sync Write
};
Initialize(NULL, 0, writes, arraysize(writes));
// Make sure we don't stop before we've read all the data
data_->StopAfter(10);
AssertSyncWriteEquals(kMsg1, kLen1);
AssertSyncWriteEquals(kMsg2, kLen2);
AssertSyncWriteEquals(kMsg3, kLen3);
AssertSyncWriteEquals(kMsg3, kLen3);
AssertSyncWriteEquals(kMsg2, kLen2);
AssertSyncWriteEquals(kMsg3, kLen3);
AssertSyncWriteEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, SingleAsyncWrite) {
MockWrite writes[] = {
MockWrite(ASYNC, kMsg1, kLen1, 0), // Async Write
};
Initialize(NULL, 0, writes, arraysize(writes));
AssertAsyncWriteEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, MultipleAsyncWrites) {
MockWrite writes[] = {
MockWrite(ASYNC, kMsg1, kLen1, 0), // Async Write
MockWrite(ASYNC, kMsg2, kLen2, 1), // Async Write
MockWrite(ASYNC, kMsg3, kLen3, 2), // Async Write
MockWrite(ASYNC, kMsg3, kLen3, 3), // Async Write
MockWrite(ASYNC, kMsg2, kLen2, 4), // Async Write
MockWrite(ASYNC, kMsg3, kLen3, 5), // Async Write
MockWrite(ASYNC, kMsg1, kLen1, 6), // Async Write
};
Initialize(NULL, 0, writes, arraysize(writes));
AssertAsyncWriteEquals(kMsg1, kLen1);
AssertAsyncWriteEquals(kMsg2, kLen2);
AssertAsyncWriteEquals(kMsg3, kLen3);
AssertAsyncWriteEquals(kMsg3, kLen3);
AssertAsyncWriteEquals(kMsg2, kLen2);
AssertAsyncWriteEquals(kMsg3, kLen3);
AssertAsyncWriteEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, MixedWrites) {
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Write
MockWrite(ASYNC, kMsg2, kLen2, 1), // Async Write
MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), // Sync Write
MockWrite(ASYNC, kMsg3, kLen3, 3), // Async Write
MockWrite(SYNCHRONOUS, kMsg2, kLen2, 4), // Sync Write
MockWrite(ASYNC, kMsg3, kLen3, 5), // Async Write
MockWrite(SYNCHRONOUS, kMsg1, kLen1, 6), // Sync Write
};
Initialize(NULL, 0, writes, arraysize(writes));
data_->StopAfter(1);
AssertSyncWriteEquals(kMsg1, kLen1);
AssertAsyncWriteEquals(kMsg2, kLen2);
data_->StopAfter(1);
AssertSyncWriteEquals(kMsg3, kLen3);
AssertAsyncWriteEquals(kMsg3, kLen3);
data_->StopAfter(1);
AssertSyncWriteEquals(kMsg2, kLen2);
AssertAsyncWriteEquals(kMsg3, kLen3);
data_->StopAfter(1);
AssertSyncWriteEquals(kMsg1, kLen1);
}
TEST_F(DeterministicSocketDataTest, SyncWriteFromCompletionCallback) {
MockWrite writes[] = {
MockWrite(ASYNC, kMsg1, kLen1, 0), // Async Write
MockWrite(SYNCHRONOUS, kMsg2, kLen2, 1), // Sync Write
};
Initialize(NULL, 0, writes, arraysize(writes));
data_->StopAfter(2);
scoped_refptr<IOBuffer> write_buf(new IOBuffer(kLen1));
memcpy(write_buf->data(), kMsg1, kLen1);
ASSERT_EQ(ERR_IO_PENDING,
sock_->Write(
write_buf.get(),
kLen1,
base::Bind(&DeterministicSocketDataTest::ReentrantWriteCallback,
base::Unretained(this),
kMsg2,
kLen2)));
data_->Run();
}
// ----------- Mixed Reads and Writes
TEST_F(DeterministicSocketDataTest, MixedSyncOperations) {
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
MockRead(SYNCHRONOUS, kMsg2, kLen2, 3), // Sync Read
MockRead(SYNCHRONOUS, 0, 4), // EOF
};
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, kMsg2, kLen2, 1), // Sync Write
MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), // Sync Write
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
// Make sure we don't stop before we've read/written everything
data_->StopAfter(10);
AssertSyncReadEquals(kMsg1, kLen1);
AssertSyncWriteEquals(kMsg2, kLen2);
AssertSyncWriteEquals(kMsg3, kLen3);
AssertSyncReadEquals(kMsg2, kLen2);
}
TEST_F(DeterministicSocketDataTest, MixedAsyncOperations) {
MockRead reads[] = {
MockRead(ASYNC, kMsg1, kLen1, 0), // Sync Read
MockRead(ASYNC, kMsg2, kLen2, 3), // Sync Read
MockRead(ASYNC, 0, 4), // EOF
};
MockWrite writes[] = {
MockWrite(ASYNC, kMsg2, kLen2, 1), // Sync Write
MockWrite(ASYNC, kMsg3, kLen3, 2), // Sync Write
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
AssertAsyncReadEquals(kMsg1, kLen1);
AssertAsyncWriteEquals(kMsg2, kLen2);
AssertAsyncWriteEquals(kMsg3, kLen3);
AssertAsyncReadEquals(kMsg2, kLen2);
}
TEST_F(DeterministicSocketDataTest, InterleavedAsyncOperations) {
// Order of completion is read, write, write, read
MockRead reads[] = {
MockRead(ASYNC, kMsg1, kLen1, 0), // Async Read
MockRead(ASYNC, kMsg2, kLen2, 3), // Async Read
MockRead(ASYNC, 0, 4), // EOF
};
MockWrite writes[] = {
MockWrite(ASYNC, kMsg2, kLen2, 1), // Async Write
MockWrite(ASYNC, kMsg3, kLen3, 2), // Async Write
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
// Issue the write, which will block until the read completes
AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING);
// Issue the read which will return first
AssertReadReturns(kMsg1, kLen1, ERR_IO_PENDING);
data_->RunFor(1);
ASSERT_TRUE(read_callback_.have_result());
ASSERT_EQ(kLen1, read_callback_.WaitForResult());
AssertReadBufferEquals(kMsg1, kLen1);
data_->RunFor(1);
ASSERT_TRUE(write_callback_.have_result());
ASSERT_EQ(kLen2, write_callback_.WaitForResult());
data_->StopAfter(1);
// Issue the read, which will block until the write completes
AssertReadReturns(kMsg2, kLen2, ERR_IO_PENDING);
// Issue the writes which will return first
AssertWriteReturns(kMsg3, kLen3, ERR_IO_PENDING);
data_->RunFor(1);
ASSERT_TRUE(write_callback_.have_result());
ASSERT_EQ(kLen3, write_callback_.WaitForResult());
data_->RunFor(1);
ASSERT_TRUE(read_callback_.have_result());
ASSERT_EQ(kLen2, read_callback_.WaitForResult());
AssertReadBufferEquals(kMsg2, kLen2);
}
TEST_F(DeterministicSocketDataTest, InterleavedMixedOperations) {
// Order of completion is read, write, write, read
MockRead reads[] = {
MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), // Sync Read
MockRead(ASYNC, kMsg2, kLen2, 3), // Async Read
MockRead(SYNCHRONOUS, 0, 4), // EOF
};
MockWrite writes[] = {
MockWrite(ASYNC, kMsg2, kLen2, 1), // Async Write
MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), // Sync Write
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
// Issue the write, which will block until the read completes
AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING);
// Issue the writes which will complete immediately
data_->StopAfter(1);
AssertSyncReadEquals(kMsg1, kLen1);
data_->RunFor(1);
ASSERT_TRUE(write_callback_.have_result());
ASSERT_EQ(kLen2, write_callback_.WaitForResult());
// Issue the read, which will block until the write completes
AssertReadReturns(kMsg2, kLen2, ERR_IO_PENDING);
// Issue the writes which will complete immediately
data_->StopAfter(1);
AssertSyncWriteEquals(kMsg3, kLen3);
data_->RunFor(1);
ASSERT_TRUE(read_callback_.have_result());
ASSERT_EQ(kLen2, read_callback_.WaitForResult());
AssertReadBufferEquals(kMsg2, kLen2);
}
} // namespace net