diff options
author | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-05 18:14:20 +0000 |
---|---|---|
committer | rch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-05 18:14:20 +0000 |
commit | 5e660958562309f075c7fcb01c98bb08e5d1e07f (patch) | |
tree | 62e23f9c8a5d381259f669ad4805d6891d123942 | |
parent | e4234829356ce2d10f940ebe021910a187d07298 (diff) | |
download | chromium_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.gyp | 1 | ||||
-rw-r--r-- | net/socket/deterministic_socket_data_unittest.cc | 530 | ||||
-rw-r--r-- | net/socket/socket_test_util.cc | 117 | ||||
-rw-r--r-- | net/socket/socket_test_util.h | 92 | ||||
-rw-r--r-- | net/spdy/spdy_network_transaction_unittest.cc | 8 | ||||
-rw-r--r-- | net/spdy/spdy_proxy_client_socket_unittest.cc | 195 |
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)); |