| // 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 <memory> |
| #include <string> |
| |
| #include "base/macros.h" |
| #include "base/memory/ref_counted.h" |
| #include "base/run_loop.h" |
| #include "net/base/completion_once_callback.h" |
| #include "net/base/io_buffer.h" |
| #include "net/base/test_completion_callback.h" |
| #include "net/log/net_log_with_source.h" |
| #include "net/socket/client_socket_handle.h" |
| #include "net/socket/socket_tag.h" |
| #include "net/socket/socket_test_util.h" |
| #include "net/socket/transport_client_socket_pool.h" |
| #include "net/test/gtest_util.h" |
| #include "net/test/test_with_scoped_task_environment.h" |
| #include "net/traffic_annotation/network_traffic_annotation_test_helper.h" |
| #include "starboard/memory.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest-spi.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "testing/platform_test.h" |
| |
| using net::test::IsError; |
| using net::test::IsOk; |
| |
| //----------------------------------------------------------------------------- |
| |
| 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_ = base::MakeRefCounted<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<IOBuffer> read_buf, |
| int read_len, |
| int second_rv, |
| CompletionOnceCallback callback) { |
| second_read_ = true; |
| second_read_buf_ = read_buf; |
| second_rv_ = second_rv; |
| second_callback_ = std::move(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, |
| CompletionOnceCallback callback) { |
| second_read_ = false; |
| second_rv_ = second_rv; |
| second_write_data_ = write_data; |
| second_callback_ = std::move(callback); |
| second_len_ = write_len; |
| } |
| |
| // Returns the OnIOComplete callback for this helper. |
| CompletionOnceCallback callback() { |
| return base::BindOnce(&ReentrantHelper::OnIOComplete, |
| base::Unretained(this)); |
| } |
| |
| // Retuns the buffer where data is expected to have been written, |
| // when checked by SetExpectRead() |
| scoped_refptr<IOBuffer> 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_, |
| std::move(second_callback_))); |
| } else { |
| scoped_refptr<IOBuffer> write_buf = |
| base::MakeRefCounted<IOBuffer>(second_len_); |
| memcpy(write_buf->data(), second_write_data_, second_len_); |
| ASSERT_EQ(second_rv_, socket_->Write(write_buf.get(), second_len_, |
| std::move(second_callback_), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| } |
| } |
| |
| StreamSocket* socket_; |
| |
| bool verify_read_; |
| scoped_refptr<IOBuffer> first_read_buf_; |
| const char* first_read_data_; |
| int first_len_; |
| |
| CompletionOnceCallback second_callback_; |
| bool second_read_; |
| int second_rv_; |
| scoped_refptr<IOBuffer> second_read_buf_; |
| const char* second_write_data_; |
| int second_len_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ReentrantHelper); |
| }; |
| |
| class SequencedSocketDataTest : public TestWithScopedTaskEnvironment { |
| 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, |
| CompletionOnceCallback callback, |
| int expected_rv, |
| int rv); |
| |
| // Callback which adds a failure if it's ever called. |
| void FailingCompletionCallback(int rv); |
| |
| protected: |
| void Initialize(base::span<const MockRead> reads, |
| base::span<const MockWrite> writes); |
| |
| 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; } |
| |
| CompletionOnceCallback failing_callback() { |
| return base::BindOnce(&SequencedSocketDataTest::FailingCompletionCallback, |
| base::Unretained(this)); |
| } |
| |
| TestCompletionCallback read_callback_; |
| scoped_refptr<IOBuffer> read_buf_; |
| TestCompletionCallback write_callback_; |
| StreamSocket* sock_; |
| |
| private: |
| MockConnect connect_data_; |
| std::unique_ptr<SequencedSocketData> data_; |
| |
| const HostPortPair endpoint_; |
| scoped_refptr<TransportSocketParams> tcp_params_; |
| MockClientSocketFactory socket_factory_; |
| MockTransportClientSocketPool socket_pool_; |
| ClientSocketHandle connection_; |
| bool expect_eof_; |
| |
| DISALLOW_COPY_AND_ASSIGN(SequencedSocketDataTest); |
| }; |
| |
| SequencedSocketDataTest::SequencedSocketDataTest() |
| : 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(base::span<const MockRead> reads, |
| base::span<const MockWrite> writes) { |
| data_.reset(new SequencedSocketData(reads, writes)); |
| data_->set_connect_data(connect_data_); |
| socket_factory_.AddSocketDataProvider(data_.get()); |
| |
| EXPECT_EQ(OK, connection_.Init( |
| endpoint_.ToString(), tcp_params_, LOWEST, SocketTag(), |
| ClientSocketPool::RespectLimits::ENABLED, |
| CompletionOnceCallback(), |
| reinterpret_cast<TransportClientSocketPool*>(&socket_pool_), |
| NetLogWithSource())); |
| 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_ = base::MakeRefCounted<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<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(len); |
| memcpy(buf->data(), data, len); |
| |
| if (rv == ERR_IO_PENDING) { |
| ASSERT_EQ(rv, sock_->Write(buf.get(), len, write_callback_.callback(), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| ASSERT_FALSE(write_callback_.have_result()); |
| } else { |
| ASSERT_EQ(rv, sock_->Write(buf.get(), len, failing_callback(), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| } |
| } |
| |
| 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, |
| CompletionOnceCallback callback, |
| int expected_rv, |
| int rv) { |
| EXPECT_EQ(expected_rv, rv); |
| scoped_refptr<IOBuffer> write_buf = base::MakeRefCounted<IOBuffer>(len); |
| memcpy(write_buf->data(), data, len); |
| EXPECT_THAT(sock_->Write(write_buf.get(), len, std::move(callback), |
| TRAFFIC_ANNOTATION_FOR_TESTS), |
| IsError(ERR_IO_PENDING)); |
| } |
| |
| 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, base::span<MockWrite>()); |
| 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, base::span<MockWrite>()); |
| |
| 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, base::span<MockWrite>()); |
| |
| 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, base::span<MockWrite>()); |
| |
| 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, base::span<MockWrite>()); |
| |
| 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, base::span<MockWrite>()); |
| |
| read_buf_ = base::MakeRefCounted<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::RunLoop().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, base::span<MockWrite>()); |
| |
| read_buf_ = base::MakeRefCounted<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, base::span<MockWrite>()); |
| |
| read_buf_ = base::MakeRefCounted<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, 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, base::span<MockWrite>()); |
| |
| // 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, base::span<MockWrite>()); |
| scoped_refptr<IOBuffer> read_buf = base::MakeRefCounted<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, base::span<MockWrite>()); |
| |
| scoped_refptr<IOBuffer> read_buf = base::MakeRefCounted<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, base::span<MockWrite>()); |
| |
| scoped_refptr<IOBuffer> read_buf = base::MakeRefCounted<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::RunLoop().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, writes); |
| |
| EXPECT_NONFATAL_FAILURE(AssertWriteReturns(kMsg1, kLen1, ERR_UNEXPECTED), |
| "Unable to perform synchronous IO while stopped"); |
| |
| set_expect_eof(false); |
| } |
| |
| // This tests rely on a specific version of gtest being available which is |
| // not guaranteed. |
| #if !defined(STARBOARD) |
| TEST_F(SequencedSocketDataTest, SingleSyncWriteTooSmall) { |
| MockWrite writes[] = { |
| MockWrite(SYNCHRONOUS, kMsg1, kLen1, 0), |
| }; |
| |
| Initialize(base::span<MockRead>(), 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 == expected_data\n Actual: false\nExpected: true", |
| "Expected equality of these values:\n rv"}; |
| ASSERT_EQ(arraysize(kExpectedFailures), |
| static_cast<size_t>(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); |
| } |
| #endif |
| |
| TEST_F(SequencedSocketDataTest, SingleSyncPartialWrite) { |
| MockWrite writes[] = { |
| MockWrite(SYNCHRONOUS, kMsg1, kLen1 - 1, 0), |
| MockWrite(SYNCHRONOUS, kMsg1 + kLen1 - 1, 1, 1), |
| }; |
| |
| Initialize(base::span<MockRead>(), 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(base::span<MockRead>(), 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(base::span<MockRead>(), 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(base::span<MockRead>(), 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(base::span<MockRead>(), 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(base::span<MockRead>(), 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(base::span<MockRead>(), writes); |
| |
| scoped_refptr<IOBuffer> write_buf = base::MakeRefCounted<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), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| base::RunLoop().RunUntilIdle(); |
| } |
| |
| TEST_F(SequencedSocketDataTest, AsyncWriteFromCompletionCallback) { |
| MockWrite writes[] = { |
| MockWrite(ASYNC, kMsg1, kLen1, 0), MockWrite(ASYNC, kMsg2, kLen2, 1), |
| }; |
| |
| Initialize(base::span<MockRead>(), writes); |
| |
| scoped_refptr<IOBuffer> write_buf = base::MakeRefCounted<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), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| 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(base::span<MockRead>(), 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<IOBuffer> write_buf = base::MakeRefCounted<IOBuffer>(kLen1); |
| memcpy(write_buf->data(), kMsg1, kLen1); |
| sock_->Write(write_buf.get(), kLen1, helper.callback(), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| |
| 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, 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, 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, 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); |
| |
| // Run posted OnWriteComplete(). |
| base::RunLoop().RunUntilIdle(); |
| |
| 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, 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, writes); |
| |
| scoped_refptr<IOBuffer> write_buf = base::MakeRefCounted<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), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| 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, writes); |
| |
| scoped_refptr<IOBuffer> read_buf = base::MakeRefCounted<IOBuffer>(kLen1); |
| ASSERT_EQ( |
| ERR_IO_PENDING, |
| sock_->Read( |
| read_buf.get(), kLen1, |
| base::BindOnce(&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, writes); |
| |
| read_buf_ = base::MakeRefCounted<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<IOBuffer> write_buf = base::MakeRefCounted<IOBuffer>(kLen1); |
| memcpy(write_buf->data(), kMsg1, kLen1); |
| sock_->Write(write_buf.get(), kLen1, helper.callback(), |
| TRAFFIC_ANNOTATION_FOR_TESTS); |
| |
| 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, writes); |
| |
| read_buf_ = base::MakeRefCounted<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<IOBuffer> write_buf = base::MakeRefCounted<IOBuffer>(kLen1); |
| memcpy(write_buf->data(), kMsg1, kLen1); |
| ASSERT_EQ(ERR_IO_PENDING, |
| sock_->Write(write_buf.get(), kLen1, helper.callback(), |
| TRAFFIC_ANNOTATION_FOR_TESTS)); |
| |
| base::RunLoop().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, writes); |
| |
| read_buf_ = base::MakeRefCounted<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::RunLoop().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, base::span<MockWrite>()); |
| |
| AssertReadReturns(kLen1, ERR_IO_PENDING); |
| ASSERT_FALSE(read_callback_.have_result()); |
| |
| RunUntilPaused(); |
| ASSERT_TRUE(IsPaused()); |
| |
| // Spinning the message loop should do nothing. |
| base::RunLoop().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, writes); |
| |
| AssertReadReturns(kLen2, ERR_IO_PENDING); |
| ASSERT_FALSE(read_callback_.have_result()); |
| |
| // Nothing should happen until the write starts. |
| base::RunLoop().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::RunLoop().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(base::span<MockRead>(), 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::RunLoop().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, writes); |
| |
| AssertWriteReturns(kMsg2, kLen2, ERR_IO_PENDING); |
| ASSERT_FALSE(write_callback_.have_result()); |
| |
| // Nothing should happen until the write starts. |
| base::RunLoop().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::RunLoop().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 |