summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-05 18:14:20 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-05 18:14:20 +0000
commit5e660958562309f075c7fcb01c98bb08e5d1e07f (patch)
tree62e23f9c8a5d381259f669ad4805d6891d123942
parente4234829356ce2d10f940ebe021910a187d07298 (diff)
downloadchromium_src-5e660958562309f075c7fcb01c98bb08e5d1e07f.zip
chromium_src-5e660958562309f075c7fcb01c98bb08e5d1e07f.tar.gz
chromium_src-5e660958562309f075c7fcb01c98bb08e5d1e07f.tar.bz2
Clean up DeterministicSocketData class. Add unit tests to document
the correct usage of the class. Enable the class to support async writes. BUG=none TEST=none Review URL: http://codereview.chromium.org/3614002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61531 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--net/net.gyp1
-rw-r--r--net/socket/deterministic_socket_data_unittest.cc530
-rw-r--r--net/socket/socket_test_util.cc117
-rw-r--r--net/socket/socket_test_util.h92
-rw-r--r--net/spdy/spdy_network_transaction_unittest.cc8
-rw-r--r--net/spdy/spdy_proxy_client_socket_unittest.cc195
6 files changed, 798 insertions, 145 deletions
diff --git a/net/net.gyp b/net/net.gyp
index 02e1bcd..9fccc53 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -858,6 +858,7 @@
'proxy/proxy_service_unittest.cc',
'proxy/sync_host_resolver_bridge_unittest.cc',
'socket/client_socket_pool_base_unittest.cc',
+ 'socket/deterministic_socket_data_unittest.cc',
'socket/socks5_client_socket_unittest.cc',
'socket/socks_client_socket_pool_unittest.cc',
'socket/socks_client_socket_unittest.cc',
diff --git a/net/socket/deterministic_socket_data_unittest.cc b/net/socket/deterministic_socket_data_unittest.cc
new file mode 100644
index 0000000..199dd0b
--- /dev/null
+++ b/net/socket/deterministic_socket_data_unittest.cc
@@ -0,0 +1,530 @@
+// Copyright (c) 2010 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 "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();
+
+ 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_;
+ ClientSocket* sock_;
+ scoped_refptr<DeterministicSocketData> data_;
+
+ private:
+ scoped_refptr<IOBuffer> read_buf_;
+ MockConnect connect_data_;
+
+ GURL url_;
+ HostPortPair endpoint_;
+ scoped_refptr<TCPSocketParams> tcp_params_;
+ ClientSocketPoolHistograms histograms_;
+ DeterministicMockClientSocketFactory socket_factory_;
+ MockTCPClientSocketPool socket_pool_;
+ ClientSocketHandle connection_;
+
+ DISALLOW_COPY_AND_ASSIGN(DeterministicSocketDataTest);
+};
+
+DeterministicSocketDataTest::DeterministicSocketDataTest()
+ : read_callback_(),
+ write_callback_(),
+ sock_(NULL),
+ data_(NULL),
+ read_buf_(NULL),
+ connect_data_(false, OK),
+ url_("https://www.google.com"),
+ endpoint_("www.google.com", 443),
+ tcp_params_(new TCPSocketParams(endpoint_, LOWEST, url_, false)),
+ histograms_(""),
+ socket_pool_(10, 10, &histograms_, &socket_factory_) {
+}
+
+void DeterministicSocketDataTest::TearDown() {
+ // Empty the current queue.
+ MessageLoop::current()->RunAllPending();
+ PlatformTest::TearDown();
+}
+
+void DeterministicSocketDataTest::Initialize(MockRead* reads,
+ size_t reads_count,
+ MockWrite* writes,
+ size_t writes_count) {
+ data_ = 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, NULL, (TCPClientSocketPool*)&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_, len, &read_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, len, &write_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, len, &write_callback_));
+}
+
+// ----------- Read
+
+TEST_F(DeterministicSocketDataTest, SingleSyncReadWhileStopped) {
+ MockRead reads[] = {
+ MockRead(false, kMsg1, kLen1, 0), // Sync Read
+ MockRead(false, 0, 1), // EOF
+ };
+
+ Initialize(reads, arraysize(reads), NULL, 0);
+
+ data_->SetStopped(true);
+ AssertReadReturns(kMsg1, kLen1, ERR_UNEXPECTED);
+}
+
+TEST_F(DeterministicSocketDataTest, SingleSyncReadTooEarly) {
+ MockRead reads[] = {
+ MockRead(false, kMsg1, kLen1, 1), // Sync Read
+ MockRead(false, 0, 2), // EOF
+ };
+
+ Initialize(reads, arraysize(reads), NULL, 0);
+
+ data_->StopAfter(2);
+ ASSERT_FALSE(data_->stopped());
+ AssertReadReturns(kMsg1, kLen1, ERR_UNEXPECTED);
+}
+
+TEST_F(DeterministicSocketDataTest, SingleSyncRead) {
+ MockRead reads[] = {
+ MockRead(false, kMsg1, kLen1, 0), // Sync Read
+ MockRead(false, 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(false, kMsg1, kLen1, 0), // Sync Read
+ MockRead(false, kMsg2, kLen2, 1), // Sync Read
+ MockRead(false, kMsg3, kLen3, 2), // Sync Read
+ MockRead(false, kMsg3, kLen3, 3), // Sync Read
+ MockRead(false, kMsg2, kLen2, 4), // Sync Read
+ MockRead(false, kMsg3, kLen3, 5), // Sync Read
+ MockRead(false, kMsg1, kLen1, 6), // Sync Read
+ MockRead(false, 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(true, kMsg1, kLen1, 0), // Async Read
+ MockRead(false, 0, 1), // EOF
+ };
+
+ Initialize(reads, arraysize(reads), NULL, 0);
+
+ AssertAsyncReadEquals(kMsg1, kLen1);
+}
+
+TEST_F(DeterministicSocketDataTest, MultipleAsyncReads) {
+ MockRead reads[] = {
+ MockRead(true, kMsg1, kLen1, 0), // Async Read
+ MockRead(true, kMsg2, kLen2, 1), // Async Read
+ MockRead(true, kMsg3, kLen3, 2), // Async Read
+ MockRead(true, kMsg3, kLen3, 3), // Async Read
+ MockRead(true, kMsg2, kLen2, 4), // Async Read
+ MockRead(true, kMsg3, kLen3, 5), // Async Read
+ MockRead(true, kMsg1, kLen1, 6), // Async Read
+ MockRead(false, 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(false, kMsg1, kLen1, 0), // Sync Read
+ MockRead(true, kMsg2, kLen2, 1), // Async Read
+ MockRead(false, kMsg3, kLen3, 2), // Sync Read
+ MockRead(true, kMsg3, kLen3, 3), // Async Read
+ MockRead(false, kMsg2, kLen2, 4), // Sync Read
+ MockRead(true, kMsg3, kLen3, 5), // Async Read
+ MockRead(false, kMsg1, kLen1, 6), // Sync Read
+ MockRead(false, 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);
+}
+
+// ----------- Write
+
+TEST_F(DeterministicSocketDataTest, SingleSyncWriteWhileStopped) {
+ MockWrite writes[] = {
+ MockWrite(false, 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(false, kMsg1, kLen1, 1), // Sync Write
+ };
+
+ Initialize(NULL, 0, writes, arraysize(writes));
+
+ data_->StopAfter(2);
+ ASSERT_FALSE(data_->stopped());
+ AssertWriteReturns(kMsg1, kLen1, ERR_UNEXPECTED);
+}
+
+TEST_F(DeterministicSocketDataTest, SingleSyncWrite) {
+ MockWrite writes[] = {
+ MockWrite(false, 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(false, kMsg1, kLen1, 0), // Sync Write
+ MockWrite(false, kMsg2, kLen2, 1), // Sync Write
+ MockWrite(false, kMsg3, kLen3, 2), // Sync Write
+ MockWrite(false, kMsg3, kLen3, 3), // Sync Write
+ MockWrite(false, kMsg2, kLen2, 4), // Sync Write
+ MockWrite(false, kMsg3, kLen3, 5), // Sync Write
+ MockWrite(false, 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(true, kMsg1, kLen1, 0), // Async Write
+ };
+
+ Initialize(NULL, 0, writes, arraysize(writes));
+
+ AssertAsyncWriteEquals(kMsg1, kLen1);
+}
+
+TEST_F(DeterministicSocketDataTest, MultipleAsyncWrites) {
+ MockWrite writes[] = {
+ MockWrite(true, kMsg1, kLen1, 0), // Async Write
+ MockWrite(true, kMsg2, kLen2, 1), // Async Write
+ MockWrite(true, kMsg3, kLen3, 2), // Async Write
+ MockWrite(true, kMsg3, kLen3, 3), // Async Write
+ MockWrite(true, kMsg2, kLen2, 4), // Async Write
+ MockWrite(true, kMsg3, kLen3, 5), // Async Write
+ MockWrite(true, 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(false, kMsg1, kLen1, 0), // Sync Write
+ MockWrite(true, kMsg2, kLen2, 1), // Async Write
+ MockWrite(false, kMsg3, kLen3, 2), // Sync Write
+ MockWrite(true, kMsg3, kLen3, 3), // Async Write
+ MockWrite(false, kMsg2, kLen2, 4), // Sync Write
+ MockWrite(true, kMsg3, kLen3, 5), // Async Write
+ MockWrite(false, 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);
+}
+
+// ----------- Mixed Reads and Writes
+
+TEST_F(DeterministicSocketDataTest, MixedSyncOperations) {
+ MockRead reads[] = {
+ MockRead(false, kMsg1, kLen1, 0), // Sync Read
+ MockRead(false, kMsg2, kLen2, 3), // Sync Read
+ MockRead(false, 0, 4), // EOF
+ };
+
+ MockWrite writes[] = {
+ MockWrite(false, kMsg2, kLen2, 1), // Sync Write
+ MockWrite(false, 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(true, kMsg1, kLen1, 0), // Sync Read
+ MockRead(true, kMsg2, kLen2, 3), // Sync Read
+ MockRead(true, 0, 4), // EOF
+ };
+
+ MockWrite writes[] = {
+ MockWrite(true, kMsg2, kLen2, 1), // Sync Write
+ MockWrite(true, 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(true, kMsg1, kLen1, 0), // Async Read
+ MockRead(true, kMsg2, kLen2, 3), // Async Read
+ MockRead(true, 0, 4), // EOF
+ };
+
+ MockWrite writes[] = {
+ MockWrite(true, kMsg2, kLen2, 1), // Async Write
+ MockWrite(true, 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_EQ(kLen1, read_callback_.WaitForResult());
+ AssertReadBufferEquals(kMsg1, kLen1);
+
+ data_->RunFor(1);
+ 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_EQ(kLen3, write_callback_.WaitForResult());
+
+ data_->RunFor(1);
+ ASSERT_EQ(kLen2, read_callback_.WaitForResult());
+ AssertReadBufferEquals(kMsg2, kLen2);
+}
+
+TEST_F(DeterministicSocketDataTest, InterleavedMixedOperations) {
+ // Order of completion is read, write, write, read
+ MockRead reads[] = {
+ MockRead(false, kMsg1, kLen1, 0), // Sync Read
+ MockRead(true, kMsg2, kLen2, 3), // Async Read
+ MockRead(false, 0, 4), // EOF
+ };
+
+ MockWrite writes[] = {
+ MockWrite(true, kMsg2, kLen2, 1), // Async Write
+ MockWrite(false, 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_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_EQ(kLen2, read_callback_.WaitForResult());
+ AssertReadBufferEquals(kMsg2, kLen2);
+}
+
+} // namespace net
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index e9e002a..1cf894a 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -427,8 +427,6 @@ int DeterministicMockTCPClientSocket::CompleteRead() {
DCHECK(read_data_.data);
result = std::min(read_buf_len_, read_data_.data_len);
memcpy(read_buf_->data(), read_data_.data, result);
- } else {
- result = 0;
}
if (read_pending_) {
@@ -794,29 +792,31 @@ DeterministicSocketData::DeterministicSocketData(MockRead* reads,
sequence_number_(0),
current_read_(),
current_write_(),
- next_read_seq_(0),
- stopping_sequence_number_(1<<31),
+ stopping_sequence_number_(0),
stopped_(false),
print_debug_(false) {}
MockRead DeterministicSocketData::GetNextRead() {
- const MockRead& next_read = StaticSocketDataProvider::PeekRead();
- EXPECT_LE(sequence_number_, next_read.sequence_number);
- current_read_ = next_read;
- next_read_seq_ = current_read_.sequence_number;
- if (sequence_number_ >= stopping_sequence_number_) {
- SetStopped(true);
- NET_TRACE(INFO, " *** ") << "Force Stop. I/O Pending on read. Stage "
- << sequence_number_;
- MockRead result = MockRead(false, ERR_IO_PENDING);
- if (print_debug_)
- DumpMockRead(result);
- return result;
+ current_read_ = StaticSocketDataProvider::PeekRead();
+ EXPECT_LE(sequence_number_, current_read_.sequence_number);
+
+ // Synchronous read while stopped is an error
+ if (stopped() && !current_read_.async) {
+ LOG(ERROR) << "Unable to perform synchronous IO while stopped";
+ return MockRead(false, ERR_UNEXPECTED);
}
- if (sequence_number_ < next_read.sequence_number) {
+
+ // Async read which will be called back in a future step.
+ if (sequence_number_ < current_read_.sequence_number) {
NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
<< ": I/O Pending";
MockRead result = MockRead(false, ERR_IO_PENDING);
+ if (!current_read_.async) {
+ LOG(ERROR) << "Unable to perform synchronous read: "
+ << current_read_.sequence_number
+ << " at stage: " << sequence_number_;
+ result = MockRead(false, ERR_UNEXPECTED);
+ }
if (print_debug_)
DumpMockRead(result);
return result;
@@ -825,33 +825,55 @@ MockRead DeterministicSocketData::GetNextRead() {
NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
<< ": Read " << read_index();
if (print_debug_)
- DumpMockRead(next_read);
- sequence_number_++;
- StaticSocketDataProvider::GetNextRead();
- if (current_read_.result == ERR_IO_PENDING)
- current_read_ = StaticSocketDataProvider::GetNextRead();
+ DumpMockRead(current_read_);
- if (!at_read_eof())
- next_read_seq_ = PeekRead().sequence_number;
+ // Increment the sequence number if IO is complete
+ if (!current_read_.async)
+ NextStep();
- return next_read;
+ DCHECK_NE(ERR_IO_PENDING, current_read_.result);
+ StaticSocketDataProvider::GetNextRead();
+
+ return current_read_;
}
MockWriteResult DeterministicSocketData::OnWrite(const std::string& data) {
- NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
- << ": Write " << write_index();
const MockWrite& next_write = StaticSocketDataProvider::PeekWrite();
- DCHECK_LE(next_write.sequence_number, sequence_number_);
+ current_write_ = next_write;
+
+ // Synchronous write while stopped is an error
+ if (stopped() && !next_write.async) {
+ LOG(ERROR) << "Unable to perform synchronous IO while stopped";
+ return MockWriteResult(false, ERR_UNEXPECTED);
+ }
+
+ // Async write which will be called back in a future step.
+ if (sequence_number_ < next_write.sequence_number) {
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
+ << ": I/O Pending";
+ if (!next_write.async) {
+ LOG(ERROR) << "Unable to perform synchronous write: "
+ << next_write.sequence_number << " at stage: " << sequence_number_;
+ return MockWriteResult(false, ERR_UNEXPECTED);
+ }
+ } else {
+ NET_TRACE(INFO, " *** ") << "Stage " << sequence_number_
+ << ": Write " << write_index();
+ }
+
if (print_debug_)
DumpMockRead(next_write);
- ++sequence_number_;
- current_write_ = next_write;
- if (stopping_sequence_number_ == sequence_number_)
- SetStopped(true);
+
+ // Move to the next step if I/O is synchronous, since the operation will
+ // complete when this method returns.
+ if (!next_write.async)
+ NextStep();
+
+ // This is either a sync write for this step, or an async write.
return StaticSocketDataProvider::OnWrite(data);
}
-void DeterministicSocketData::Reset(){
+void DeterministicSocketData::Reset() {
NET_TRACE(INFO, " *** ") << "Stage "
<< sequence_number_ << ": Reset()";
sequence_number_ = 0;
@@ -859,19 +881,25 @@ void DeterministicSocketData::Reset(){
NOTREACHED();
}
-void DeterministicSocketData::Run(){
+void DeterministicSocketData::RunFor(int steps) {
+ StopAfter(steps);
+ Run();
+}
+
+void DeterministicSocketData::Run() {
+ SetStopped(false);
int counter = 0;
// Continue to consume data until all data has run out, or the stopped_ flag
// has been set. Consuming data requires two separate operations -- running
// the tasks in the message loop, and explicitly invoking the read/write
// callbacks (simulating network I/O). We check our conditions between each,
// since they can change in either.
- while ((!at_write_eof() || !at_read_eof()) &&
- !stopped()) {
+ while ((!at_write_eof() || !at_read_eof()) && !stopped()) {
if (counter % 2 == 0)
MessageLoop::current()->RunAllPending();
- if (counter % 2 == 1)
+ if (counter % 2 == 1) {
InvokeCallbacks();
+ }
counter++;
}
// We're done consuming new data, but it is possible there are still some
@@ -884,19 +912,30 @@ void DeterministicSocketData::Run(){
SetStopped(false);
}
-void DeterministicSocketData::InvokeCallbacks(){
+void DeterministicSocketData::InvokeCallbacks() {
if (socket_ && socket_->write_pending() &&
(current_write().sequence_number == sequence_number())) {
socket_->CompleteWrite();
+ NextStep();
return;
}
if (socket_ && socket_->read_pending() &&
- (next_read_seq() == sequence_number())) {
+ (current_read().sequence_number == sequence_number())) {
socket_->CompleteRead();
+ NextStep();
return;
}
}
+void DeterministicSocketData::NextStep() {
+ // Invariant: Can never move *past* the stopping step.
+ DCHECK_LT(sequence_number_, stopping_sequence_number_);
+ sequence_number_++;
+ if (sequence_number_ == stopping_sequence_number_)
+ SetStopped(true);
+}
+
+
void MockClientSocketFactory::AddSocketDataProvider(
SocketDataProvider* data) {
mock_data_.Add(data);
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index c76dfae..7293c05 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -347,28 +347,63 @@ class OrderedSocketData : public StaticSocketDataProvider,
class DeterministicMockTCPClientSocket;
-// This class gives the user full control over the mock socket reads and writes,
-// including the timing of the callbacks. By default, synchronous reads and
-// writes will force the callback for that read or write to complete before
-// allowing another read or write to finish.
+// This class gives the user full control over the network activity,
+// specifically the timing of the COMPLETION of I/O operations. Regardless of
+// the order in which I/O operations are initiated, this class ensures that they
+// complete in the correct order.
+//
+// Network activity is modeled as a sequence of numbered steps which is
+// incremented whenever an I/O operation completes. This can happen under two
+// different circumstances:
+//
+// 1) Performing a synchronous I/O operation. (Invoking Read() or Write()
+// when the corresponding MockRead or MockWrite is marked !async).
+// 2) Running the Run() method of this class. The run method will invoke
+// the current MessageLoop, running all pending events, and will then
+// invoke any pending IO callbacks.
+//
+// In addition, this class allows for I/O processing to "stop" at a specified
+// step, by calling SetStop(int) or StopAfter(int). Initiating an I/O operation
+// by calling Read() or Write() while stopped is permitted if the operation is
+// asynchronous. It is an error to perform synchronous I/O while stopped.
+//
+// When creating the MockReads and MockWrites, note that the sequence number
+// refers to the number of the step in which the I/O will complete. In the
+// case of synchronous I/O, this will be the same step as the I/O is initiated.
+// However, in the case of asynchronous I/O, this I/O may be initiated in
+// a much earlier step. Furthermore, when the a Read() or Write() is separated
+// from its completion by other Read() or Writes()'s, it can not be marked
+// synchronous. If it is, ERR_UNUEXPECTED will be returned indicating that a
+// synchronous Read() or Write() could not be completed synchronously because of
+// the specific ordering constraints.
//
// Sequence numbers are preserved across both reads and writes. There should be
// no gaps in sequence numbers, and no repeated sequence numbers. i.e.
+// MockRead reads[] = {
+// MockRead(false, "first read", length, 0) // sync
+// MockRead(true, "second read", length, 2) // async
+// };
// MockWrite writes[] = {
-// MockWrite(true, "first write", length, 0),
-// MockWrite(false, "second write", length, 3),
+// MockWrite(true, "first write", length, 1), // async
+// MockWrite(false, "second write", length, 3), // sync
// };
//
-// MockRead reads[] = {
-// MockRead(false, "first read", length, 1)
-// MockRead(false, "second read", length, 2)
-// };
// Example control flow:
-// The first write completes. A call to read() returns ERR_IO_PENDING, since the
-// first write's callback has not happened yet. The first write's callback is
-// called. Now the first read's callback will be called. A call to write() will
-// succeed, because the write() API requires this, but the callback will not be
-// called until the second read has completed and its callback called.
+// Read() is called. The current step is 0. The first available read is
+// synchronous, so the call to Read() returns length. The current step is
+// now 1. Next, Read() is called again. The next available read can
+// not be completed until step 2, so Read() returns ERR_IO_PENDING. The current
+// step is still 1. Write is called(). The first available write is able to
+// complete in this step, but is marked asynchronous. Write() returns
+// ERR_IO_PENDING. The current step is still 1. At this point RunFor(1) is
+// called which will cause the write callback to be invoked, and will then
+// stop. The current state is now 2. RunFor(1) is called again, which
+// causes the read callback to be invoked, and will then stop. Then current
+// step is 2. Write() is called again. Then next available write is
+// synchronous so the call to Write() returns length.
+//
+// For examples of how to use this class, see:
+// deterministic_socket_data_unittests.cc
class DeterministicSocketData : public StaticSocketDataProvider,
public base::RefCounted<DeterministicSocketData> {
public:
@@ -377,13 +412,6 @@ class DeterministicSocketData : public StaticSocketDataProvider,
DeterministicSocketData(MockRead* reads, size_t reads_count,
MockWrite* writes, size_t writes_count);
- // |connect| the result for the connect phase.
- // |reads| the list of MockRead completions.
- // |writes| the list of MockWrite completions.
- DeterministicSocketData(const MockConnect& connect,
- MockRead* reads, size_t reads_count,
- MockWrite* writes, size_t writes_count);
-
// When the socket calls Read(), that calls GetNextRead(), and expects either
// ERR_IO_PENDING or data.
virtual MockRead GetNextRead();
@@ -398,16 +426,25 @@ class DeterministicSocketData : public StaticSocketDataProvider,
// Consume all the data up to the give stop point (via SetStop()).
void Run();
- // Stop when Read() is about to consume a MockRead with sequence_number >=
- // seq. Instead feed ERR_IO_PENDING to Read().
- virtual void SetStop(int seq) { stopping_sequence_number_ = seq; }
+ // Set the stop point to be |steps| from now, and then invoke Run().
+ void RunFor(int steps);
+ // Stop at step |seq|, which must be in the future.
+ virtual void SetStop(int seq) {
+ DCHECK_LT(sequence_number_, seq);
+ stopping_sequence_number_ = seq;
+ stopped_ = false;
+ }
+
+ // Stop |seq| steps after the current step.
+ virtual void StopAfter(int seq) {
+ SetStop(sequence_number_ + seq);
+ }
void CompleteRead();
bool stopped() const { return stopped_; }
void SetStopped(bool val) { stopped_ = val; }
MockRead& current_read() { return current_read_; }
MockRead& current_write() { return current_write_; }
- int next_read_seq() const { return next_read_seq_; }
int sequence_number() const { return sequence_number_; }
void set_socket(base::WeakPtr<DeterministicMockTCPClientSocket> socket) {
socket_ = socket;
@@ -417,10 +454,11 @@ class DeterministicSocketData : public StaticSocketDataProvider,
// Invoke the read and write callbacks, if the timing is appropriate.
void InvokeCallbacks();
+ void NextStep();
+
int sequence_number_;
MockRead current_read_;
MockWrite current_write_;
- int next_read_seq_;
int stopping_sequence_number_;
bool stopped_;
base::WeakPtr<DeterministicMockTCPClientSocket> socket_;
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index 5645ad6..e9076d3 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -1451,8 +1451,8 @@ TEST_P(SpdyNetworkTransactionTest, SocketWriteReturnsZero) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp.get(), 1, false),
- MockRead(false, 0, 0, 4) // EOF
+ CreateMockRead(*resp.get(), 1, true),
+ MockRead(true, 0, 0, 4) // EOF
};
scoped_refptr<DeterministicSocketData> data(
@@ -1952,8 +1952,8 @@ TEST_P(SpdyNetworkTransactionTest, CancelledTransactionSendRst) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructSpdyGetSynReply(NULL, 0, 1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 0, 3) // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 0, 3) // EOF
};
scoped_refptr<DeterministicSocketData> data(
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 274c22f..f2f0d23 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -74,6 +74,8 @@ class SpdyProxyClientSocketTest : public PlatformTest {
void AssertReadStarts(const char* data, int len);
void AssertReadReturns(const char* data, int len);
void AssertAsyncWriteSucceeds(const char* data, int len);
+ void AssertWriteReturns(const char* data, int len, int rv);
+ void AssertWriteLength(int len);
void AssertAsyncWriteWithReadsSucceeds(const char* data, int len,
int num_reads);
@@ -85,18 +87,17 @@ class SpdyProxyClientSocketTest : public PlatformTest {
}
void Run(int steps) {
- data_->SetStop(data_->sequence_number() + steps);
+ data_->StopAfter(steps);
data_->Run();
}
scoped_ptr<SpdyProxyClientSocket> sock_;
TestCompletionCallback read_callback_;
TestCompletionCallback write_callback_;
-
+ scoped_refptr<DeterministicSocketData> data_;
private:
scoped_refptr<HttpNetworkSession> session_;
- scoped_refptr<DeterministicSocketData> data_;
scoped_refptr<IOBuffer> read_buf_;
SpdySessionDependencies session_deps_;
MockConnect connect_data_;
@@ -119,8 +120,8 @@ SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
: sock_(NULL),
read_callback_(),
write_callback_(),
- session_(NULL),
data_(NULL),
+ session_(NULL),
read_buf_(NULL),
session_deps_(),
connect_data_(false, OK),
@@ -227,7 +228,7 @@ void SpdyProxyClientSocketTest::AssertSyncReadEquals(const char* data,
void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data,
int len) {
- data_->SetStop(data_->sequence_number() + 1);
+ data_->StopAfter(1);
// Issue the read, which will be completed asynchronously
scoped_refptr<IOBuffer> buf(new IOBuffer(len));
ASSERT_EQ(ERR_IO_PENDING, sock_->Read(buf, len, &read_callback_));
@@ -242,7 +243,7 @@ void SpdyProxyClientSocketTest::AssertAsyncReadEquals(const char* data,
}
void SpdyProxyClientSocketTest::AssertReadStarts(const char* data, int len) {
- data_->SetStop(data_->sequence_number() + 1);
+ data_->StopAfter(1);
// Issue the read, which will be completed asynchronously
read_buf_ = new IOBuffer(len);
ASSERT_EQ(ERR_IO_PENDING, sock_->Read(read_buf_, len, &read_callback_));
@@ -259,13 +260,19 @@ void SpdyProxyClientSocketTest::AssertReadReturns(const char* data, int len) {
void SpdyProxyClientSocketTest::AssertAsyncWriteSucceeds(const char* data,
int len) {
- scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
+ AssertWriteReturns(data, len, ERR_IO_PENDING);
+ data_->RunFor(1);
+ AssertWriteLength(len);
+}
- data_->SetStop(data_->sequence_number() + 1);
- EXPECT_EQ(ERR_IO_PENDING, sock_->Write(buf, buf->size(), &write_callback_));
- data_->Run();
+void SpdyProxyClientSocketTest::AssertWriteReturns(const char* data, int len,
+ int rv) {
+ scoped_refptr<IOBufferWithSize> buf(CreateBuffer(data, len));
+ EXPECT_EQ(rv, sock_->Write(buf, buf->size(), &write_callback_));
+}
- write_callback_.WaitForResult();
+void SpdyProxyClientSocketTest::AssertWriteLength(int len) {
+ EXPECT_EQ(len, write_callback_.WaitForResult());
}
void SpdyProxyClientSocketTest::AssertAsyncWriteWithReadsSucceeds(
@@ -405,8 +412,8 @@ TEST_F(SpdyProxyClientSocketTest, ConnectSendsCorrectRequest) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 3), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -426,8 +433,8 @@ TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthRequested) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectAuthReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 3), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -449,8 +456,8 @@ TEST_F(SpdyProxyClientSocketTest, ConnectWithAuthCredentials) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 3), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -469,7 +476,7 @@ TEST_F(SpdyProxyClientSocketTest, ConnectFails) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- MockRead(false, 0, 1), // EOF
+ MockRead(true, 0, 1), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -491,8 +498,8 @@ TEST_F(SpdyProxyClientSocketTest, WasEverUsedReturnsCorrectValues) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 2), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -514,8 +521,8 @@ TEST_F(SpdyProxyClientSocketTest, GetPeerAddressReturnsCorrectValues) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 2), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -545,8 +552,8 @@ TEST_F(SpdyProxyClientSocketTest, WriteSendsDataInDataFrame) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -571,8 +578,8 @@ TEST_F(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 5), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 5), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -580,7 +587,13 @@ TEST_F(SpdyProxyClientSocketTest, WriteSplitsLargeDataIntoMultipleFrames) {
AssertConnectSucceeds();
std::string big_data(kMaxSpdyFrameChunkSize * 3, 'x');
- AssertAsyncWriteSucceeds(big_data.data(), big_data.length());
+ scoped_refptr<IOBufferWithSize> buf(CreateBuffer(big_data.data(),
+ big_data.length()));
+
+ EXPECT_EQ(ERR_IO_PENDING, sock_->Write(buf, buf->size(), &write_callback_));
+ data_->RunFor(3);
+
+ EXPECT_EQ(buf->size(), write_callback_.WaitForResult());
}
// ----------- Read
@@ -594,9 +607,9 @@ TEST_F(SpdyProxyClientSocketTest, ReadReadsDataInDataFrame) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ MockRead(true, 0, 3), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -618,10 +631,10 @@ TEST_F(SpdyProxyClientSocketTest, ReadDataFromBufferedFrames) {
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- CreateMockRead(*msg2, 3, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg2, 3, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -646,10 +659,10 @@ TEST_F(SpdyProxyClientSocketTest, ReadDataMultipleBufferedFrames) {
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- CreateMockRead(*msg2, 3, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg2, 3, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -672,10 +685,10 @@ TEST_F(SpdyProxyClientSocketTest, LargeReadWillMergeDataFromDifferentFrames) {
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg3, 2, false),
- CreateMockRead(*msg3, 3, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg3, 2, true),
+ CreateMockRead(*msg3, 3, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -700,12 +713,12 @@ TEST_F(SpdyProxyClientSocketTest, MultipleShortReadsThenMoreRead) {
scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- CreateMockRead(*msg3, 3, false),
- CreateMockRead(*msg3, 4, false),
- CreateMockRead(*msg2, 5, false),
- MockRead(false, 0, 6), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg3, 3, true),
+ CreateMockRead(*msg3, 4, true),
+ CreateMockRead(*msg2, 5, true),
+ MockRead(true, 0, 6), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -732,10 +745,10 @@ TEST_F(SpdyProxyClientSocketTest, ReadWillSplitDataFromLargeFrame) {
scoped_ptr<spdy::SpdyFrame> msg33(ConstructBodyFrame(kMsg33, kLen33));
scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- CreateMockRead(*msg33, 3, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg33, 3, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -760,10 +773,10 @@ TEST_F(SpdyProxyClientSocketTest, ReadAuthResponseBody) {
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- CreateMockRead(*msg2, 3, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg2, 3, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -786,10 +799,10 @@ TEST_F(SpdyProxyClientSocketTest, ReadErrorResponseBody) {
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false),
- CreateMockRead(*msg2, 3, false),
- MockRead(false, 0, 4), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg2, 3, true),
+ MockRead(true, 0, 4), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -816,10 +829,10 @@ TEST_F(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- CreateMockRead(*msg1, 2, false), // sync read
- CreateMockRead(*msg3, 4, false), // async read
- MockRead(false, 0, 5), // EOF
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true), // sync read
+ CreateMockRead(*msg3, 4, true), // async read
+ MockRead(true, 0, 5), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -840,9 +853,41 @@ TEST_F(SpdyProxyClientSocketTest, AsyncReadAroundWrite) {
AssertReadReturns(kMsg3, kLen3);
}
-// TODO(rch): augment DeterministicSocketData to permit the scheduling
-// of an aync write so that we can test an async write around an
-// async read.
+TEST_F(SpdyProxyClientSocketTest, AsyncWriteAroundReads) {
+ scoped_ptr<spdy::SpdyFrame> conn(ConstructConnectRequestFrame());
+ scoped_ptr<spdy::SpdyFrame> msg2(ConstructBodyFrame(kMsg2, kLen2));
+ MockWrite writes[] = {
+ CreateMockWrite(*conn, 0, false),
+ CreateMockWrite(*msg2, 4, true),
+ };
+
+ scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
+ scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
+ scoped_ptr<spdy::SpdyFrame> msg3(ConstructBodyFrame(kMsg3, kLen3));
+ MockRead reads[] = {
+ CreateMockRead(*resp, 1, true),
+ CreateMockRead(*msg1, 2, true),
+ CreateMockRead(*msg3, 3, true),
+ MockRead(true, 0, 5), // EOF
+ };
+
+ Initialize(reads, arraysize(reads), writes, arraysize(writes));
+
+ AssertConnectSucceeds();
+
+ Run(1);
+ AssertSyncReadEquals(kMsg1, kLen1);
+ // Write should block until the read completes
+ AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING);
+
+ AssertAsyncReadEquals(kMsg3, kLen3);
+
+ ASSERT_FALSE(write_callback_.have_result());
+
+ // Now the write will complete
+ Run(1);
+ AssertWriteLength(kLen2);
+}
// ----------- Reading/Writing on Closed socket
@@ -855,8 +900,8 @@ TEST_F(SpdyProxyClientSocketTest, ReadOnClosedSocketReturnsZero) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 2), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 2), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -880,8 +925,8 @@ TEST_F(SpdyProxyClientSocketTest, WriteOnClosedStream) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
scoped_ptr<spdy::SpdyFrame> msg1(ConstructBodyFrame(kMsg1, kLen1));
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 2), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 2), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -906,8 +951,8 @@ TEST_F(SpdyProxyClientSocketTest, DisconnectWithWritePending) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1),
- MockRead(false, 0, 3), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 3), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));
@@ -935,8 +980,8 @@ TEST_F(SpdyProxyClientSocketTest, DisconnectWithReadPending) {
scoped_ptr<spdy::SpdyFrame> resp(ConstructConnectReplyFrame());
MockRead reads[] = {
- CreateMockRead(*resp, 1, false),
- MockRead(false, 0, 2), // EOF
+ CreateMockRead(*resp, 1, true),
+ MockRead(true, 0, 2), // EOF
};
Initialize(reads, arraysize(reads), writes, arraysize(writes));