// Copyright 2015 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 #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/run_loop.h" #include "net/base/io_buffer.h" #include "net/base/test_completion_callback.h" #include "net/socket/client_socket_handle.h" #include "net/socket/socket_test_util.h" #include "net/socket/transport_client_socket_pool.h" #include "testing/gtest/include/gtest/gtest-spi.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" //----------------------------------------------------------------------------- namespace net { namespace { const char kMsg1[] = "\0hello!\xff"; const int kLen1 = arraysize(kMsg1); const char kMsg2[] = "\0a2345678\0"; const int kLen2 = arraysize(kMsg2); const char kMsg3[] = "bye!"; const int kLen3 = arraysize(kMsg3); const char kMsg4[] = "supercalifragilisticexpialidocious"; const int kLen4 = arraysize(kMsg4); // Helper class for starting the next operation operation reentrantly after the // previous operation completed asynchronously. When OnIOComplete is called, // it will first verify that the previous operation behaved as expected. This is // specified by either SetExpectedRead or SetExpectedWrite. It will then invoke // a read or write operation specified by SetInvokeRead or SetInvokeWrite. class ReentrantHelper { public: ReentrantHelper(StreamSocket* socket) : socket_(socket), verify_read_(false), first_read_data_(nullptr), first_len_(-1), second_read_(false), second_write_data_(nullptr), second_len_(-1) {} // Expect that the previous operation will return |first_len| and will fill // |first_read_data_| with |first_read_data|. void SetExpectedRead(const char* first_read_data, int first_len) { verify_read_ = true; first_read_buf_ = new IOBuffer(first_len); first_read_data_ = first_read_data; first_len_ = first_len; } // Expect that the previous operation will return |first_len|. void SetExpectedWrite(int first_len) { verify_read_ = false; first_len_ = first_len; } // After verifying expectations, invoke a read of |read_len| bytes into // |read_buf|, notifying |callback| when complete. void SetInvokeRead(scoped_refptr read_buf, int read_len, int second_rv, CompletionCallback callback) { second_read_ = true; second_read_buf_ = read_buf; second_rv_ = second_rv; second_callback_ = callback; second_len_ = read_len; } // After verifying expectations, invoke a write of |write_len| bytes from // |write_data|, notifying |callback| when complete. void SetInvokeWrite(const char* write_data, int write_len, int second_rv, CompletionCallback callback) { second_read_ = false; second_rv_ = second_rv; second_write_data_ = write_data; second_callback_ = callback; second_len_ = write_len; } // Returns the OnIOComplete callback for this helper. CompletionCallback callback() { return base::Bind(&ReentrantHelper::OnIOComplete, base::Unretained(this)); } // Retuns the buffer where data is expected to have been written, // when checked by SetExpectRead() scoped_refptr read_buf() { return first_read_buf_; } private: void OnIOComplete(int rv) { CHECK_NE(-1, first_len_) << "Expectation not set."; CHECK_NE(-1, second_len_) << "Invocation not set."; ASSERT_EQ(first_len_, rv); if (verify_read_) { ASSERT_EQ(std::string(first_read_data_, first_len_), std::string(first_read_buf_->data(), rv)); } if (second_read_) { ASSERT_EQ(second_rv_, socket_->Read(second_read_buf_.get(), second_len_, second_callback_)); } else { scoped_refptr write_buf = new IOBuffer(second_len_); memcpy(write_buf->data(), second_write_data_, second_len_); ASSERT_EQ(second_rv_, socket_->Write(write_buf.get(), second_len_, second_callback_)); } } StreamSocket* socket_; bool verify_read_; scoped_refptr first_read_buf_; const char* first_read_data_; int first_len_; CompletionCallback second_callback_; bool second_read_; int second_rv_; scoped_refptr second_read_buf_; const char* second_write_data_; int second_len_; DISALLOW_COPY_AND_ASSIGN(ReentrantHelper); }; class SequencedSocketDataTest : public testing::Test { public: SequencedSocketDataTest(); ~SequencedSocketDataTest() override; // This method is used as the completion callback for an async read // operation and when invoked, it verifies that the correct data was read, // then reads from the socket and verifies that that it returns the correct // value. void ReentrantReadCallback(const char* data, int len1, int len2, int expected_rv2, int rv); // This method is used at the completion callback for an async operation. // When executed, verifies that |rv| equals |expected_rv| and then // attempts an aync read from the socket into |read_buf_| (initialized // to |read_buf_len|) using |callback|. void ReentrantAsyncReadCallback(int len1, int len2, int rv); // This method is used as the completion callback for an async write // operation and when invoked, it verifies that the write returned correctly, // then // attempts to write to the socket and verifies that that it returns the // correct value. void ReentrantWriteCallback(int expected_rv1, const char* data, int len, int expected_rv2, int rv); // This method is used at the completion callback for an async operation. // When executed, verifies that |rv| equals |expected_rv| and then // attempts an aync write of |data| with |callback| void ReentrantAsyncWriteCallback(const char* data, int len, CompletionCallback callback, int expected_rv, int rv); // Callback which adds a failure if it's ever called. void FailingCompletionCallback(int rv); protected: void Initialize(MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count); void AssertSyncReadEquals(const char* data, int len); void AssertAsyncReadEquals(const char* data, int len); void AssertReadReturns(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); bool IsPaused() const; void Resume(); void RunUntilPaused(); // When a given test completes, data_.at_eof() is expected to // match the value specified here. Most test should consume all // reads and writes, but some tests verify error handling behavior // do not consume all data. void set_expect_eof(bool expect_eof) { expect_eof_ = expect_eof; } TestCompletionCallback read_callback_; scoped_refptr read_buf_; TestCompletionCallback write_callback_; CompletionCallback failing_callback_; StreamSocket* sock_; private: MockConnect connect_data_; scoped_ptr data_; const HostPortPair endpoint_; scoped_refptr tcp_params_; MockClientSocketFactory socket_factory_; MockTransportClientSocketPool socket_pool_; ClientSocketHandle connection_; bool expect_eof_; DISALLOW_COPY_AND_ASSIGN(SequencedSocketDataTest); }; SequencedSocketDataTest::SequencedSocketDataTest() : failing_callback_( base::Bind(&SequencedSocketDataTest::FailingCompletionCallback, base::Unretained(this))), sock_(nullptr), connect_data_(SYNCHRONOUS, OK), endpoint_("www.google.com", 443), tcp_params_(new TransportSocketParams( endpoint_, false, OnHostResolutionCallback(), TransportSocketParams::COMBINE_CONNECT_AND_WRITE_DEFAULT)), socket_pool_(10, 10, &socket_factory_), expect_eof_(true) { } SequencedSocketDataTest::~SequencedSocketDataTest() { // Make sure no unexpected pending tasks will cause a failure. base::RunLoop().RunUntilIdle(); if (expect_eof_) { EXPECT_EQ(expect_eof_, data_->AllReadDataConsumed()); EXPECT_EQ(expect_eof_, data_->AllWriteDataConsumed()); } } void SequencedSocketDataTest::Initialize(MockRead* reads, size_t reads_count, MockWrite* writes, size_t writes_count) { data_.reset( new SequencedSocketData(reads, reads_count, writes, writes_count)); data_->set_connect_data(connect_data_); socket_factory_.AddSocketDataProvider(data_.get()); EXPECT_EQ(OK, connection_.Init( endpoint_.ToString(), tcp_params_, LOWEST, ClientSocketPool::RespectLimits::ENABLED, CompletionCallback(), reinterpret_cast(&socket_pool_), BoundNetLog())); sock_ = connection_.socket(); } void SequencedSocketDataTest::AssertSyncReadEquals(const char* data, int len) { // Issue the read, which will complete immediately. AssertReadReturns(len, len); AssertReadBufferEquals(data, len); } void SequencedSocketDataTest::AssertAsyncReadEquals(const char* data, int len) { // Issue the read, which will be completed asynchronously. AssertReadReturns(len, ERR_IO_PENDING); EXPECT_TRUE(sock_->IsConnected()); // Now the read should complete. ASSERT_EQ(len, read_callback_.WaitForResult()); AssertReadBufferEquals(data, len); } void SequencedSocketDataTest::AssertReadReturns(int len, int rv) { read_buf_ = new IOBuffer(len); if (rv == ERR_IO_PENDING) { ASSERT_EQ(rv, sock_->Read(read_buf_.get(), len, read_callback_.callback())); ASSERT_FALSE(read_callback_.have_result()); } else { ASSERT_EQ(rv, sock_->Read(read_buf_.get(), len, failing_callback_)); } } void SequencedSocketDataTest::AssertReadBufferEquals(const char* data, int len) { ASSERT_EQ(std::string(data, len), std::string(read_buf_->data(), len)); } void SequencedSocketDataTest::AssertSyncWriteEquals(const char* data, int len) { // Issue the write, which should be complete immediately. AssertWriteReturns(data, len, len); ASSERT_FALSE(write_callback_.have_result()); } void SequencedSocketDataTest::AssertAsyncWriteEquals(const char* data, int len) { // Issue the read, which should be completed asynchronously. AssertWriteReturns(data, len, ERR_IO_PENDING); EXPECT_FALSE(read_callback_.have_result()); EXPECT_TRUE(sock_->IsConnected()); ASSERT_EQ(len, write_callback_.WaitForResult()); } bool SequencedSocketDataTest::IsPaused() const { return data_->IsPaused(); } void SequencedSocketDataTest::Resume() { data_->Resume(); } void SequencedSocketDataTest::RunUntilPaused() { data_->RunUntilPaused(); } void SequencedSocketDataTest::AssertWriteReturns(const char* data, int len, int rv) { scoped_refptr buf(new IOBuffer(len)); memcpy(buf->data(), data, len); if (rv == ERR_IO_PENDING) { ASSERT_EQ(rv, sock_->Write(buf.get(), len, write_callback_.callback())); ASSERT_FALSE(write_callback_.have_result()); } else { ASSERT_EQ(rv, sock_->Write(buf.get(), len, failing_callback_)); } } void SequencedSocketDataTest::ReentrantReadCallback(const char* data, int len1, int len2, int expected_rv2, int rv) { ASSERT_EQ(len1, rv); AssertReadBufferEquals(data, len1); AssertReadReturns(len2, expected_rv2); } void SequencedSocketDataTest::ReentrantAsyncReadCallback(int expected_rv, int len, int rv) { ASSERT_EQ(expected_rv, rv); AssertReadReturns(len, ERR_IO_PENDING); } void SequencedSocketDataTest::ReentrantWriteCallback(int expected_rv1, const char* data, int len, int expected_rv2, int rv) { ASSERT_EQ(expected_rv1, rv); AssertWriteReturns(data, len, expected_rv2); } void SequencedSocketDataTest::ReentrantAsyncWriteCallback( const char* data, int len, CompletionCallback callback, int expected_rv, int rv) { EXPECT_EQ(expected_rv, rv); scoped_refptr write_buf(new IOBuffer(len)); memcpy(write_buf->data(), data, len); EXPECT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), len, callback)); } void SequencedSocketDataTest::FailingCompletionCallback(int rv) { ADD_FAILURE() << "Callback should not have been invoked"; } // ----------- Read TEST_F(SequencedSocketDataTest, SingleSyncRead) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), nullptr, 0); AssertSyncReadEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, MultipleSyncReads) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), MockRead(SYNCHRONOUS, kMsg2, kLen2, 1), MockRead(SYNCHRONOUS, kMsg3, kLen3, 2), MockRead(SYNCHRONOUS, kMsg3, kLen3, 3), MockRead(SYNCHRONOUS, kMsg2, kLen2, 4), MockRead(SYNCHRONOUS, kMsg3, kLen3, 5), MockRead(SYNCHRONOUS, kMsg1, kLen1, 6), }; Initialize(reads, arraysize(reads), nullptr, 0); AssertSyncReadEquals(kMsg1, kLen1); AssertSyncReadEquals(kMsg2, kLen2); AssertSyncReadEquals(kMsg3, kLen3); AssertSyncReadEquals(kMsg3, kLen3); AssertSyncReadEquals(kMsg2, kLen2); AssertSyncReadEquals(kMsg3, kLen3); AssertSyncReadEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, SingleAsyncRead) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), nullptr, 0); AssertAsyncReadEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, MultipleAsyncReads) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 1), MockRead(ASYNC, kMsg3, kLen3, 2), MockRead(ASYNC, kMsg3, kLen3, 3), MockRead(ASYNC, kMsg2, kLen2, 4), MockRead(ASYNC, kMsg3, kLen3, 5), MockRead(ASYNC, kMsg1, kLen1, 6), }; Initialize(reads, arraysize(reads), nullptr, 0); AssertAsyncReadEquals(kMsg1, kLen1); AssertAsyncReadEquals(kMsg2, kLen2); AssertAsyncReadEquals(kMsg3, kLen3); AssertAsyncReadEquals(kMsg3, kLen3); AssertAsyncReadEquals(kMsg2, kLen2); AssertAsyncReadEquals(kMsg3, kLen3); AssertAsyncReadEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, MixedReads) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 1), MockRead(SYNCHRONOUS, kMsg3, kLen3, 2), MockRead(ASYNC, kMsg3, kLen3, 3), MockRead(SYNCHRONOUS, kMsg2, kLen2, 4), MockRead(ASYNC, kMsg3, kLen3, 5), MockRead(SYNCHRONOUS, kMsg1, kLen1, 6), }; Initialize(reads, arraysize(reads), nullptr, 0); AssertSyncReadEquals(kMsg1, kLen1); AssertAsyncReadEquals(kMsg2, kLen2); AssertSyncReadEquals(kMsg3, kLen3); AssertAsyncReadEquals(kMsg3, kLen3); AssertSyncReadEquals(kMsg2, kLen2); AssertAsyncReadEquals(kMsg3, kLen3); AssertSyncReadEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, SyncReadFromCompletionCallback) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(SYNCHRONOUS, kMsg2, kLen2, 1), }; Initialize(reads, arraysize(reads), nullptr, 0); read_buf_ = new IOBuffer(kLen1); ASSERT_EQ( ERR_IO_PENDING, sock_->Read( read_buf_.get(), kLen1, base::Bind(&SequencedSocketDataTest::ReentrantReadCallback, base::Unretained(this), kMsg1, kLen1, kLen2, kLen2))); base::MessageLoop::current()->RunUntilIdle(); AssertReadBufferEquals(kMsg2, kLen2); } TEST_F(SequencedSocketDataTest, ManyReentrantReads) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 1), MockRead(ASYNC, kMsg3, kLen3, 2), MockRead(ASYNC, kMsg4, kLen4, 3), }; Initialize(reads, arraysize(reads), nullptr, 0); read_buf_ = new IOBuffer(kLen4); ReentrantHelper helper3(sock_); helper3.SetExpectedRead(kMsg3, kLen3); helper3.SetInvokeRead(read_buf_, kLen4, ERR_IO_PENDING, read_callback_.callback()); ReentrantHelper helper2(sock_); helper2.SetExpectedRead(kMsg2, kLen2); helper2.SetInvokeRead(helper3.read_buf(), kLen3, ERR_IO_PENDING, helper3.callback()); ReentrantHelper helper(sock_); helper.SetExpectedRead(kMsg1, kLen1); helper.SetInvokeRead(helper2.read_buf(), kLen2, ERR_IO_PENDING, helper2.callback()); sock_->Read(helper.read_buf().get(), kLen1, helper.callback()); ASSERT_EQ(kLen4, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg4, kLen4); } TEST_F(SequencedSocketDataTest, AsyncReadFromCompletionCallback) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 1), }; Initialize(reads, arraysize(reads), nullptr, 0); read_buf_ = new IOBuffer(kLen1); ASSERT_EQ( ERR_IO_PENDING, sock_->Read(read_buf_.get(), kLen1, base::Bind(&SequencedSocketDataTest::ReentrantReadCallback, base::Unretained(this), kMsg1, kLen1, kLen2, ERR_IO_PENDING))); ASSERT_FALSE(read_callback_.have_result()); ASSERT_EQ(kLen2, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg2, kLen2); } TEST_F(SequencedSocketDataTest, SingleSyncReadTooEarly) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 1), }; MockWrite writes[] = {MockWrite(SYNCHRONOUS, 0, 0)}; Initialize(reads, arraysize(reads), writes, arraysize(writes)); EXPECT_NONFATAL_FAILURE(AssertReadReturns(kLen1, ERR_UNEXPECTED), "Unable to perform synchronous IO while stopped"); set_expect_eof(false); } TEST_F(SequencedSocketDataTest, SingleSyncReadSmallBuffer) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), nullptr, 0); // Read the first chunk. AssertReadReturns(kLen1 - 1, kLen1 - 1); AssertReadBufferEquals(kMsg1, kLen1 - 1); // Then read the second chunk. AssertReadReturns(1, 1); AssertReadBufferEquals(kMsg1 + kLen1 - 1, 1); } TEST_F(SequencedSocketDataTest, SingleSyncReadLargeBuffer) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), nullptr, 0); scoped_refptr read_buf(new IOBuffer(2 * kLen1)); ASSERT_EQ(kLen1, sock_->Read(read_buf.get(), 2 * kLen1, failing_callback_)); ASSERT_EQ(std::string(kMsg1, kLen1), std::string(read_buf->data(), kLen1)); } TEST_F(SequencedSocketDataTest, SingleAsyncReadLargeBuffer) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), nullptr, 0); scoped_refptr read_buf(new IOBuffer(2 * kLen1)); ASSERT_EQ(ERR_IO_PENDING, sock_->Read(read_buf.get(), 2 * kLen1, read_callback_.callback())); ASSERT_EQ(kLen1, read_callback_.WaitForResult()); ASSERT_EQ(std::string(kMsg1, kLen1), std::string(read_buf->data(), kLen1)); } TEST_F(SequencedSocketDataTest, HangingRead) { MockRead reads[] = { MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0), }; Initialize(reads, arraysize(reads), nullptr, 0); scoped_refptr read_buf(new IOBuffer(1)); ASSERT_EQ(ERR_IO_PENDING, sock_->Read(read_buf.get(), 1, read_callback_.callback())); ASSERT_FALSE(read_callback_.have_result()); // Even though the read is scheduled to complete at sequence number 0, // verify that the read callback in never called. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(read_callback_.have_result()); } // ----------- Write TEST_F(SequencedSocketDataTest, SingleSyncWriteTooEarly) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1, 1), }; MockRead reads[] = {MockRead(SYNCHRONOUS, 0, 0)}; Initialize(reads, arraysize(reads), writes, arraysize(writes)); EXPECT_NONFATAL_FAILURE(AssertWriteReturns(kMsg1, kLen1, ERR_UNEXPECTED), "Unable to perform synchronous IO while stopped"); set_expect_eof(false); } TEST_F(SequencedSocketDataTest, SingleSyncWriteTooSmall) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), }; Initialize(nullptr, 0, writes, arraysize(writes)); // Expecting too small of a write triggers multiple expectation failures. // // The gtest infrastructure does not have a macro similar to // EXPECT_NONFATAL_FAILURE which works when there is more than one // failure. // // However, tests can gather the TestPartResultArray and directly // validate the test failures. That's what the rest of this test does. ::testing::TestPartResultArray gtest_failures; { ::testing::ScopedFakeTestPartResultReporter gtest_reporter( ::testing::ScopedFakeTestPartResultReporter:: INTERCEPT_ONLY_CURRENT_THREAD, >est_failures); AssertSyncWriteEquals(kMsg1, kLen1 - 1); } static const char* kExpectedFailures[] = { "Expected: (data.length()) >= (expected_data.length())", "Value of: actual_data", "Value of: sock_->Write(buf.get(), len, failing_callback_)"}; ASSERT_EQ(arraysize(kExpectedFailures), static_cast(gtest_failures.size())); for (int i = 0; i < gtest_failures.size(); ++i) { const ::testing::TestPartResult& result = gtest_failures.GetTestPartResult(i); EXPECT_TRUE(strstr(result.message(), kExpectedFailures[i]) != NULL); } set_expect_eof(false); } TEST_F(SequencedSocketDataTest, SingleSyncPartialWrite) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1 - 1, 0), MockWrite(SYNCHRONOUS, kMsg1 + kLen1 - 1, 1, 1), }; Initialize(nullptr, 0, writes, arraysize(writes)); // Attempt to write all of the message, but only some will be written. AssertSyncWriteEquals(kMsg1, kLen1 - 1); // Write the rest of the message. AssertSyncWriteEquals(kMsg1 + kLen1 - 1, 1); } TEST_F(SequencedSocketDataTest, SingleSyncWrite) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), }; Initialize(nullptr, 0, writes, arraysize(writes)); AssertSyncWriteEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, MultipleSyncWrites) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), MockWrite(SYNCHRONOUS, kMsg2, kLen2, 1), MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), MockWrite(SYNCHRONOUS, kMsg3, kLen3, 3), MockWrite(SYNCHRONOUS, kMsg2, kLen2, 4), MockWrite(SYNCHRONOUS, kMsg3, kLen3, 5), MockWrite(SYNCHRONOUS, kMsg1, kLen1, 6), }; Initialize(nullptr, 0, writes, arraysize(writes)); AssertSyncWriteEquals(kMsg1, kLen1); AssertSyncWriteEquals(kMsg2, kLen2); AssertSyncWriteEquals(kMsg3, kLen3); AssertSyncWriteEquals(kMsg3, kLen3); AssertSyncWriteEquals(kMsg2, kLen2); AssertSyncWriteEquals(kMsg3, kLen3); AssertSyncWriteEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, SingleAsyncWrite) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), }; Initialize(nullptr, 0, writes, arraysize(writes)); AssertAsyncWriteEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, MultipleAsyncWrites) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(ASYNC, kMsg3, kLen3, 2), MockWrite(ASYNC, kMsg3, kLen3, 3), MockWrite(ASYNC, kMsg2, kLen2, 4), MockWrite(ASYNC, kMsg3, kLen3, 5), MockWrite(ASYNC, kMsg1, kLen1, 6), }; Initialize(nullptr, 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(SequencedSocketDataTest, MixedWrites) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), MockWrite(ASYNC, kMsg3, kLen3, 3), MockWrite(SYNCHRONOUS, kMsg2, kLen2, 4), MockWrite(ASYNC, kMsg3, kLen3, 5), MockWrite(SYNCHRONOUS, kMsg1, kLen1, 6), }; Initialize(nullptr, 0, writes, arraysize(writes)); AssertSyncWriteEquals(kMsg1, kLen1); AssertAsyncWriteEquals(kMsg2, kLen2); AssertSyncWriteEquals(kMsg3, kLen3); AssertAsyncWriteEquals(kMsg3, kLen3); AssertSyncWriteEquals(kMsg2, kLen2); AssertAsyncWriteEquals(kMsg3, kLen3); AssertSyncWriteEquals(kMsg1, kLen1); } TEST_F(SequencedSocketDataTest, SyncWriteFromCompletionCallback) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(SYNCHRONOUS, kMsg2, kLen2, 1), }; Initialize(nullptr, 0, writes, arraysize(writes)); scoped_refptr write_buf(new IOBuffer(kLen1)); memcpy(write_buf->data(), kMsg1, kLen1); ASSERT_EQ( ERR_IO_PENDING, sock_->Write( write_buf.get(), kLen1, base::Bind(&SequencedSocketDataTest::ReentrantWriteCallback, base::Unretained(this), kLen1, kMsg2, kLen2, kLen2))); base::MessageLoop::current()->RunUntilIdle(); } TEST_F(SequencedSocketDataTest, AsyncWriteFromCompletionCallback) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg2, kLen2, 1), }; Initialize(nullptr, 0, writes, arraysize(writes)); scoped_refptr write_buf(new IOBuffer(kLen1)); memcpy(write_buf->data(), kMsg1, kLen1); ASSERT_EQ( ERR_IO_PENDING, sock_->Write(write_buf.get(), kLen1, base::Bind(&SequencedSocketDataTest::ReentrantWriteCallback, base::Unretained(this), kLen1, kMsg2, kLen2, ERR_IO_PENDING))); ASSERT_FALSE(write_callback_.have_result()); ASSERT_EQ(kLen2, write_callback_.WaitForResult()); } TEST_F(SequencedSocketDataTest, ManyReentrantWrites) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(ASYNC, kMsg3, kLen3, 2), MockWrite(ASYNC, kMsg4, kLen4, 3), }; Initialize(nullptr, 0, writes, arraysize(writes)); ReentrantHelper helper3(sock_); helper3.SetExpectedWrite(kLen3); helper3.SetInvokeWrite(kMsg4, kLen4, ERR_IO_PENDING, write_callback_.callback()); ReentrantHelper helper2(sock_); helper2.SetExpectedWrite(kLen2); helper2.SetInvokeWrite(kMsg3, kLen3, ERR_IO_PENDING, helper3.callback()); ReentrantHelper helper(sock_); helper.SetExpectedWrite(kLen1); helper.SetInvokeWrite(kMsg2, kLen2, ERR_IO_PENDING, helper2.callback()); scoped_refptr write_buf(new IOBuffer(kLen1)); memcpy(write_buf->data(), kMsg1, kLen1); sock_->Write(write_buf.get(), kLen1, helper.callback()); ASSERT_EQ(kLen4, write_callback_.WaitForResult()); } // ----------- Mixed Reads and Writes TEST_F(SequencedSocketDataTest, MixedSyncOperations) { MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), MockRead(SYNCHRONOUS, kMsg2, kLen2, 3), }; MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg2, kLen2, 1), MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); AssertSyncReadEquals(kMsg1, kLen1); AssertSyncWriteEquals(kMsg2, kLen2); AssertSyncWriteEquals(kMsg3, kLen3); AssertSyncReadEquals(kMsg2, kLen2); } TEST_F(SequencedSocketDataTest, MixedAsyncOperations) { MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 3), }; MockWrite writes[] = { MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(ASYNC, kMsg3, kLen3, 2), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); AssertAsyncReadEquals(kMsg1, kLen1); AssertAsyncWriteEquals(kMsg2, kLen2); AssertAsyncWriteEquals(kMsg3, kLen3); AssertAsyncReadEquals(kMsg2, kLen2); } TEST_F(SequencedSocketDataTest, InterleavedAsyncOperations) { // Order of completion is read, write, write, read. MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 3), }; MockWrite writes[] = { MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(ASYNC, kMsg3, kLen3, 2), }; 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(kLen1, ERR_IO_PENDING); ASSERT_EQ(kLen1, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg1, kLen1); ASSERT_TRUE(write_callback_.have_result()); ASSERT_EQ(kLen2, write_callback_.WaitForResult()); // Issue the read, which will block until the write completes. AssertReadReturns(kLen2, ERR_IO_PENDING); // Issue the writes which will return first. AssertWriteReturns(kMsg3, kLen3, ERR_IO_PENDING); ASSERT_EQ(kLen3, write_callback_.WaitForResult()); ASSERT_EQ(kLen2, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg2, kLen2); } TEST_F(SequencedSocketDataTest, InterleavedMixedOperations) { // Order of completion is read, write, write, read. MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg2, kLen2, 3), MockRead(ASYNC, kMsg3, kLen3, 5), }; MockWrite writes[] = { MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(SYNCHRONOUS, kMsg3, kLen3, 2), MockWrite(SYNCHRONOUS, kMsg1, kLen1, 4), }; 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. AssertSyncReadEquals(kMsg1, kLen1); ASSERT_FALSE(write_callback_.have_result()); ASSERT_EQ(kLen2, write_callback_.WaitForResult()); // Issue the read, which will block until the write completes. AssertReadReturns(kLen2, ERR_IO_PENDING); // Issue the writes which will complete immediately. AssertSyncWriteEquals(kMsg3, kLen3); ASSERT_FALSE(read_callback_.have_result()); ASSERT_EQ(kLen2, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg2, kLen2); // Issue the read, which will block until the write completes. AssertReadReturns(kLen2, ERR_IO_PENDING); // Issue the writes which will complete immediately. AssertSyncWriteEquals(kMsg1, kLen1); ASSERT_FALSE(read_callback_.have_result()); ASSERT_EQ(kLen3, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg3, kLen3); } TEST_F(SequencedSocketDataTest, AsyncReadFromWriteCompletionCallback) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), }; MockRead reads[] = { MockRead(ASYNC, kMsg2, kLen2, 1), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); scoped_refptr write_buf(new IOBuffer(kLen1)); memcpy(write_buf->data(), kMsg1, kLen1); ASSERT_EQ(ERR_IO_PENDING, sock_->Write( write_buf.get(), kLen1, base::Bind(&SequencedSocketDataTest::ReentrantAsyncReadCallback, base::Unretained(this), kLen1, kLen2))); ASSERT_FALSE(read_callback_.have_result()); ASSERT_EQ(kLen2, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg2, kLen2); } TEST_F(SequencedSocketDataTest, AsyncWriteFromReadCompletionCallback) { MockWrite writes[] = { MockWrite(ASYNC, kMsg2, kLen2, 1), }; MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); scoped_refptr read_buf(new IOBuffer(kLen1)); ASSERT_EQ( ERR_IO_PENDING, sock_->Read( read_buf.get(), kLen1, base::Bind(&SequencedSocketDataTest::ReentrantAsyncWriteCallback, base::Unretained(this), kMsg2, kLen2, write_callback_.callback(), kLen1))); ASSERT_FALSE(write_callback_.have_result()); ASSERT_EQ(kLen2, write_callback_.WaitForResult()); } TEST_F(SequencedSocketDataTest, MixedReentrantOperations) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg3, kLen3, 2), }; MockRead reads[] = { MockRead(ASYNC, kMsg2, kLen2, 1), MockRead(ASYNC, kMsg4, kLen4, 3), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); read_buf_ = new IOBuffer(kLen4); ReentrantHelper helper3(sock_); helper3.SetExpectedWrite(kLen3); helper3.SetInvokeRead(read_buf_, kLen4, ERR_IO_PENDING, read_callback_.callback()); ReentrantHelper helper2(sock_); helper2.SetExpectedRead(kMsg2, kLen2); helper2.SetInvokeWrite(kMsg3, kLen3, ERR_IO_PENDING, helper3.callback()); ReentrantHelper helper(sock_); helper.SetExpectedWrite(kLen1); helper.SetInvokeRead(helper2.read_buf(), kLen2, ERR_IO_PENDING, helper2.callback()); scoped_refptr write_buf(new IOBuffer(kLen1)); memcpy(write_buf->data(), kMsg1, kLen1); sock_->Write(write_buf.get(), kLen1, helper.callback()); ASSERT_EQ(kLen4, read_callback_.WaitForResult()); } TEST_F(SequencedSocketDataTest, MixedReentrantOperationsThenSynchronousRead) { MockWrite writes[] = { MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg3, kLen3, 2), }; MockRead reads[] = { MockRead(ASYNC, kMsg2, kLen2, 1), MockRead(SYNCHRONOUS, kMsg4, kLen4, 3), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); read_buf_ = new IOBuffer(kLen4); ReentrantHelper helper3(sock_); helper3.SetExpectedWrite(kLen3); helper3.SetInvokeRead(read_buf_, kLen4, kLen4, failing_callback_); ReentrantHelper helper2(sock_); helper2.SetExpectedRead(kMsg2, kLen2); helper2.SetInvokeWrite(kMsg3, kLen3, ERR_IO_PENDING, helper3.callback()); ReentrantHelper helper(sock_); helper.SetExpectedWrite(kLen1); helper.SetInvokeRead(helper2.read_buf(), kLen2, ERR_IO_PENDING, helper2.callback()); scoped_refptr write_buf(new IOBuffer(kLen1)); memcpy(write_buf->data(), kMsg1, kLen1); ASSERT_EQ(ERR_IO_PENDING, sock_->Write(write_buf.get(), kLen1, helper.callback())); base::MessageLoop::current()->RunUntilIdle(); AssertReadBufferEquals(kMsg4, kLen4); } TEST_F(SequencedSocketDataTest, MixedReentrantOperationsThenSynchronousWrite) { MockWrite writes[] = { MockWrite(ASYNC, kMsg2, kLen2, 1), MockWrite(SYNCHRONOUS, kMsg4, kLen4, 3), }; MockRead reads[] = { MockRead(ASYNC, kMsg1, kLen1, 0), MockRead(ASYNC, kMsg3, kLen3, 2), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); read_buf_ = new IOBuffer(kLen4); ReentrantHelper helper3(sock_); helper3.SetExpectedRead(kMsg3, kLen3); helper3.SetInvokeWrite(kMsg4, kLen4, kLen4, failing_callback_); ReentrantHelper helper2(sock_); helper2.SetExpectedWrite(kLen2); helper2.SetInvokeRead(helper3.read_buf(), kLen3, ERR_IO_PENDING, helper3.callback()); ReentrantHelper helper(sock_); helper.SetExpectedRead(kMsg1, kLen1); helper.SetInvokeWrite(kMsg2, kLen2, ERR_IO_PENDING, helper2.callback()); ASSERT_EQ(ERR_IO_PENDING, sock_->Read(helper.read_buf().get(), kLen1, helper.callback())); base::MessageLoop::current()->RunUntilIdle(); } // Test the basic case where a read is paused. TEST_F(SequencedSocketDataTest, PauseAndResume_PauseRead) { MockRead reads[] = { MockRead(ASYNC, ERR_IO_PENDING, 0), MockRead(ASYNC, kMsg1, kLen1, 1), }; Initialize(reads, arraysize(reads), nullptr, 0); AssertReadReturns(kLen1, ERR_IO_PENDING); ASSERT_FALSE(read_callback_.have_result()); RunUntilPaused(); ASSERT_TRUE(IsPaused()); // Spinning the message loop should do nothing. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(read_callback_.have_result()); ASSERT_TRUE(IsPaused()); Resume(); ASSERT_FALSE(IsPaused()); ASSERT_TRUE(read_callback_.have_result()); ASSERT_EQ(kLen1, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg1, kLen1); } // Test the case where a read that will be paused is started before write that // completes before the pause. TEST_F(SequencedSocketDataTest, PauseAndResume_WritePauseRead) { MockWrite writes[] = { MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), }; MockRead reads[] = { MockRead(ASYNC, ERR_IO_PENDING, 1), MockRead(ASYNC, kMsg2, kLen2, 2), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); AssertReadReturns(kLen2, ERR_IO_PENDING); ASSERT_FALSE(read_callback_.have_result()); // Nothing should happen until the write starts. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(read_callback_.have_result()); ASSERT_FALSE(IsPaused()); AssertSyncWriteEquals(kMsg1, kLen1); RunUntilPaused(); ASSERT_FALSE(read_callback_.have_result()); ASSERT_TRUE(IsPaused()); // Spinning the message loop should do nothing. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(read_callback_.have_result()); ASSERT_TRUE(IsPaused()); Resume(); ASSERT_FALSE(IsPaused()); ASSERT_TRUE(read_callback_.have_result()); ASSERT_EQ(kLen2, read_callback_.WaitForResult()); AssertReadBufferEquals(kMsg2, kLen2); } // Test the basic case where a write is paused. TEST_F(SequencedSocketDataTest, PauseAndResume_PauseWrite) { MockWrite writes[] = { MockWrite(ASYNC, ERR_IO_PENDING, 0), MockWrite(ASYNC, kMsg1, kLen1, 1), }; Initialize(nullptr, 0, writes, arraysize(writes)); AssertWriteReturns(kMsg1, kLen1, ERR_IO_PENDING); ASSERT_FALSE(write_callback_.have_result()); RunUntilPaused(); ASSERT_TRUE(IsPaused()); // Spinning the message loop should do nothing. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(write_callback_.have_result()); ASSERT_TRUE(IsPaused()); Resume(); ASSERT_FALSE(IsPaused()); ASSERT_TRUE(write_callback_.have_result()); ASSERT_EQ(kLen1, write_callback_.WaitForResult()); } // Test the case where a write that will be paused is started before read that // completes before the pause. TEST_F(SequencedSocketDataTest, PauseAndResume_ReadPauseWrite) { MockWrite writes[] = { MockWrite(ASYNC, ERR_IO_PENDING, 1), MockWrite(ASYNC, kMsg2, kLen2, 2), }; MockRead reads[] = { MockRead(SYNCHRONOUS, kMsg1, kLen1, 0), }; Initialize(reads, arraysize(reads), writes, arraysize(writes)); AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING); ASSERT_FALSE(write_callback_.have_result()); // Nothing should happen until the write starts. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(write_callback_.have_result()); ASSERT_FALSE(IsPaused()); AssertSyncReadEquals(kMsg1, kLen1); RunUntilPaused(); ASSERT_FALSE(write_callback_.have_result()); ASSERT_TRUE(IsPaused()); // Spinning the message loop should do nothing. base::MessageLoop::current()->RunUntilIdle(); ASSERT_FALSE(write_callback_.have_result()); ASSERT_TRUE(IsPaused()); Resume(); ASSERT_FALSE(IsPaused()); ASSERT_TRUE(write_callback_.have_result()); ASSERT_EQ(kLen2, write_callback_.WaitForResult()); } } // namespace } // namespace net