Chromium Code Reviews| Index: net/http/http_pipelined_connection_impl_unittest.cc |
| diff --git a/net/http/http_pipelined_connection_impl_unittest.cc b/net/http/http_pipelined_connection_impl_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..d73ce77e1fd961512a891ba8619a356fdfc73b26 |
| --- /dev/null |
| +++ b/net/http/http_pipelined_connection_impl_unittest.cc |
| @@ -0,0 +1,740 @@ |
| +// Copyright (c) 2011 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/http/http_pipelined_connection_impl.h" |
| + |
| +#include <string> |
|
mmenke
2011/08/23 19:05:25
nit: Add blank link.
James Simonsen
2011/08/26 22:19:07
Done.
|
| +#include "base/memory/ref_counted.h" |
| +#include "base/memory/scoped_vector.h" |
| +#include "net/base/io_buffer.h" |
| +#include "net/base/net_errors.h" |
| +#include "net/base/request_priority.h" |
| +#include "net/http/http_pipelined_stream.h" |
| +#include "net/socket/client_socket_handle.h" |
| +#include "net/socket/client_socket_pool_histograms.h" |
| +#include "net/socket/socket_test_util.h" |
| +#include "testing/gmock/include/gmock/gmock.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +using testing::NiceMock; |
| +using testing::Ref; |
| +using testing::StrEq; |
| + |
| +namespace net { |
| + |
| +class DummySocketParams : public base::RefCounted<DummySocketParams> { |
| + private: |
| + friend class base::RefCounted<DummySocketParams>; |
| +}; |
| + |
| +REGISTER_SOCKET_PARAMS_FOR_POOL(MockTransportClientSocketPool, |
| + DummySocketParams); |
| + |
| +class MockPipelineOwner : public HttpPipelinedConnectionImpl::Owner { |
| + public: |
| + MOCK_METHOD1(OnPipelineHasCapacity, void(HttpPipelinedConnection* pipeline)); |
| +}; |
| + |
| +class HttpPipelinedConnectionImplTest : public testing::Test { |
| + public: |
| + HttpPipelinedConnectionImplTest() |
| + : histograms_("a"), |
| + pool_(1, 1, &histograms_, &factory_) { |
| + } |
| + |
| + void 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(MockConnect(false, 0)); |
| + if (reads_count || writes_count) { |
| + data_->StopAfter(reads_count + writes_count); |
| + } |
| + factory_.AddSocketDataProvider(data_.get()); |
| + scoped_refptr<DummySocketParams> params; |
| + ClientSocketHandle* connection = new ClientSocketHandle; |
| + connection->Init("a", params, MEDIUM, NULL, &pool_, BoundNetLog()); |
| + pipeline_.reset(new HttpPipelinedConnectionImpl(connection, &owner_, |
| + ssl_config_, proxy_info_, |
| + BoundNetLog(), false)); |
| + } |
| + |
| + HttpRequestInfo* GetRequestInfo(const std::string& filename) { |
| + HttpRequestInfo* request_info = new HttpRequestInfo; |
| + request_info->url = GURL("http://localhost/" + filename); |
| + request_info->method = "GET"; |
| + request_info_vector_.push_back(request_info); |
| + return request_info; |
| + } |
| + |
| + HttpStream* NewTestStream(const std::string& filename) { |
| + HttpStream* stream = pipeline_->CreateNewStream(); |
| + HttpRequestInfo* request_info = GetRequestInfo(filename); |
| + int rv = stream->InitializeStream(request_info, BoundNetLog(), NULL); |
| + DCHECK_EQ(OK, rv); |
| + return stream; |
| + } |
| + |
| + void ExpectResponse(const std::string& expected, |
| + scoped_ptr<HttpStream>& stream, bool async) { |
| + scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size())); |
| + |
| + if (async) { |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream->ReadResponseBody(buffer.get(), expected.size(), |
| + &callback_)); |
| + data_->RunFor(1); |
| + EXPECT_EQ(static_cast<int>(expected.size()), callback_.WaitForResult()); |
| + } else { |
| + EXPECT_EQ(static_cast<int>(expected.size()), |
| + stream->ReadResponseBody(buffer.get(), expected.size(), |
| + &callback_)); |
| + } |
| + std::string actual(buffer->data(), expected.size()); |
| + EXPECT_THAT(actual, StrEq(expected)); |
| + } |
| + |
| + void TestSyncRequest(scoped_ptr<HttpStream>& stream, |
| + const std::string& filename) { |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(OK, stream->SendRequest(headers, NULL, &response, &callback_)); |
| + EXPECT_EQ(OK, stream->ReadResponseHeaders(&callback_)); |
| + ExpectResponse(filename, stream, false); |
| + |
| + stream->Close(false); |
| + } |
| + |
| + DeterministicMockClientSocketFactory factory_; |
| + ClientSocketPoolHistograms histograms_; |
| + MockTransportClientSocketPool pool_; |
| + scoped_refptr<DeterministicSocketData> data_; |
| + |
| + SSLConfig ssl_config_; |
| + ProxyInfo proxy_info_; |
| + NiceMock<MockPipelineOwner> owner_; |
| + TestCompletionCallback callback_; |
| + scoped_ptr<HttpPipelinedConnectionImpl> pipeline_; |
| + ScopedVector<HttpRequestInfo> request_info_vector_; |
| +}; |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, SyncSingleRequest) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 3, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); |
| + TestSyncRequest(stream, "ok.html"); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, AsyncSingleRequest) { |
| + MockWrite writes[] = { |
| + MockWrite(true, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(true, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(true, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(true, 3, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); |
| + |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream->SendRequest(headers, NULL, &response, &callback_)); |
| + data_->RunFor(1); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(&callback_)); |
| + data_->RunFor(2); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + ExpectResponse("ok.html", stream, true); |
| + |
| + stream->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, LockStepAsyncRequests) { |
| + MockWrite writes[] = { |
| + MockWrite(true, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(true, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(true, 2, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(true, 3, "Content-Length: 7\r\n\r\n"), |
| + MockRead(true, 4, "ok.html"), |
| + MockRead(true, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(true, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(true, 7, "ko.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + HttpRequestHeaders headers1; |
| + HttpResponseInfo response1; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream1->SendRequest(headers1, NULL, &response1, &callback_)); |
| + |
| + HttpRequestHeaders headers2; |
| + HttpResponseInfo response2; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream2->SendRequest(headers2, NULL, &response2, &callback_)); |
| + |
| + data_->RunFor(1); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + data_->RunFor(1); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + EXPECT_EQ(ERR_IO_PENDING, stream1->ReadResponseHeaders(&callback_)); |
| + EXPECT_EQ(ERR_IO_PENDING, stream2->ReadResponseHeaders(&callback_)); |
| + |
| + data_->RunFor(2); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + ExpectResponse("ok.html", stream1, true); |
| + |
| + stream1->Close(false); |
| + |
| + data_->RunFor(2); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + ExpectResponse("ko.html", stream2, true); |
| + |
| + stream2->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, TwoResponsesInOnePacket) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 2, |
| + "HTTP/1.1 200 OK\r\n" |
| + "Content-Length: 7\r\n\r\n" |
| + "ok.html" |
| + "HTTP/1.1 200 OK\r\n" |
| + "Content-Length: 7\r\n\r\n" |
| + "ko.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + HttpRequestHeaders headers1; |
| + HttpResponseInfo response1; |
| + EXPECT_EQ(OK, stream1->SendRequest(headers1, NULL, &response1, &callback_)); |
| + HttpRequestHeaders headers2; |
| + HttpResponseInfo response2; |
| + EXPECT_EQ(OK, stream2->SendRequest(headers2, NULL, &response2, &callback_)); |
| + |
| + EXPECT_EQ(OK, stream1->ReadResponseHeaders(&callback_)); |
| + ExpectResponse("ok.html", stream1, false); |
| + stream1->Close(false); |
| + |
| + EXPECT_EQ(OK, stream2->ReadResponseHeaders(&callback_)); |
| + ExpectResponse("ko.html", stream2, false); |
| + stream2->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, InitializeOrderSwapped) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 4, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 3, "ko.html"), |
| + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 7, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + TestSyncRequest(stream2, "ko.html"); |
| + TestSyncRequest(stream1, "ok.html"); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, SendOrderSwapped) { |
|
mmenke
2011/08/23 19:05:25
How is this different from the previous test?
James Simonsen
2011/08/26 22:19:07
Hmm. It was different at one point, but I oversimp
|
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 4, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 3, "ko.html"), |
| + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 7, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + HttpRequestHeaders headers2; |
| + HttpResponseInfo response2; |
| + EXPECT_EQ(OK, stream2->SendRequest(headers2, NULL, &response2, &callback_)); |
| + EXPECT_EQ(OK, stream2->ReadResponseHeaders(&callback_)); |
| + ExpectResponse("ko.html", stream2, false); |
| + |
| + stream2->Close(false); |
| + |
| + HttpRequestHeaders headers1; |
| + HttpResponseInfo response1; |
| + EXPECT_EQ(OK, stream1->SendRequest(headers1, NULL, &response1, &callback_)); |
| + EXPECT_EQ(OK, stream1->ReadResponseHeaders(&callback_)); |
| + ExpectResponse("ok.html", stream1, false); |
| + |
| + stream1->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, ReadOrderSwapped) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 1, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 2, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 3, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 4, "ok.html"), |
| + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 7, "ko.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + HttpRequestHeaders headers1; |
| + HttpResponseInfo response1; |
| + EXPECT_EQ(OK, stream1->SendRequest(headers1, NULL, &response1, &callback_)); |
| + |
| + HttpRequestHeaders headers2; |
| + HttpResponseInfo response2; |
| + EXPECT_EQ(OK, stream2->SendRequest(headers2, NULL, &response2, &callback_)); |
| + |
| + EXPECT_EQ(ERR_IO_PENDING, stream2->ReadResponseHeaders(&callback_)); |
| + |
| + EXPECT_EQ(OK, stream1->ReadResponseHeaders(&callback_)); |
| + ExpectResponse("ok.html", stream1, false); |
| + |
| + stream1->Close(false); |
| + |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + ExpectResponse("ko.html", stream2, false); |
| + |
| + stream2->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, SendWhileReading) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 3, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 4, "ok.html"), |
| + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 7, "ko.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + HttpRequestHeaders headers1; |
| + HttpResponseInfo response1; |
| + EXPECT_EQ(OK, stream1->SendRequest(headers1, NULL, &response1, &callback_)); |
| + EXPECT_EQ(OK, stream1->ReadResponseHeaders(&callback_)); |
| + |
| + HttpRequestHeaders headers2; |
| + HttpResponseInfo response2; |
| + EXPECT_EQ(OK, stream2->SendRequest(headers2, NULL, &response2, &callback_)); |
| + |
| + ExpectResponse("ok.html", stream1, false); |
| + stream1->Close(false); |
| + |
| + EXPECT_EQ(OK, stream2->ReadResponseHeaders(&callback_)); |
| + ExpectResponse("ko.html", stream2, false); |
| + stream2->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, AsyncSendWhileAsyncReadBlocked) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(true, 3, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(true, 4, "ok.html"), |
| + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 7, "ko.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream1(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> stream2(NewTestStream("ko.html")); |
| + |
| + HttpRequestHeaders headers1; |
| + HttpResponseInfo response1; |
| + EXPECT_EQ(OK, stream1->SendRequest(headers1, NULL, &response1, &callback_)); |
| + EXPECT_EQ(OK, stream1->ReadResponseHeaders(&callback_)); |
| + TestCompletionCallback callback1; |
| + std::string expected = "ok.html"; |
| + scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size())); |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream1->ReadResponseBody(buffer.get(), expected.size(), |
| + &callback1)); |
| + |
| + HttpRequestHeaders headers2; |
| + HttpResponseInfo response2; |
| + TestCompletionCallback callback2; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream2->SendRequest(headers2, NULL, &response2, &callback2)); |
| + |
| + data_->RunFor(1); |
| + EXPECT_LE(OK, callback2.WaitForResult()); |
| + EXPECT_EQ(ERR_IO_PENDING, stream2->ReadResponseHeaders(&callback2)); |
| + |
| + data_->RunFor(1); |
| + EXPECT_EQ(static_cast<int>(expected.size()), callback1.WaitForResult()); |
| + std::string actual(buffer->data(), expected.size()); |
| + EXPECT_THAT(actual, StrEq(expected)); |
| + stream1->Close(false); |
| + |
| + data_->StopAfter(8); |
| + EXPECT_LE(OK, callback2.WaitForResult()); |
| + ExpectResponse("ko.html", stream2, false); |
| + stream2->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, PipelineNotUsed) { |
|
mmenke
2011/08/23 19:05:25
nit: Might want to put this test as well as the n
James Simonsen
2011/08/26 22:19:07
Done.
|
| + MockWrite writes[] = {}; |
|
mmenke
2011/08/23 19:05:25
MSVC doesn't like 0-length arrays like this.
James Simonsen
2011/08/26 22:19:07
Lame. Fixed.
|
| + MockRead reads[] = {}; |
| + Initialize(reads, 0, writes, 0); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, StreamNotUsed) { |
| + MockWrite writes[] = {}; |
| + MockRead reads[] = {}; |
| + Initialize(reads, 0, writes, 0); |
| + |
| + scoped_ptr<HttpStream> stream(pipeline_->CreateNewStream()); |
| + |
| + stream->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, StreamBoundButNotUsed) { |
| + MockWrite writes[] = {}; |
| + MockRead reads[] = {}; |
| + Initialize(reads, 0, writes, 0); |
| + |
| + scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); |
| + |
| + stream->Close(false); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, UnusedStreamAllowsLaterUse) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 3, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> unused_stream(NewTestStream("unused.html")); |
| + unused_stream->Close(false); |
| + |
| + scoped_ptr<HttpStream> later_stream(NewTestStream("ok.html")); |
| + TestSyncRequest(later_stream, "ok.html"); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, UnsentStreamAllowsLaterUse) { |
| + MockWrite writes[] = { |
| + MockWrite(true, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 4, "GET /ko.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(true, 1, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(true, 2, "Content-Length: 7\r\n\r\n"), |
| + MockRead(true, 3, "ok.html"), |
| + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 6, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 7, "ko.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); |
| + |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + stream->SendRequest(headers, NULL, &response, &callback_)); |
| + |
| + scoped_ptr<HttpStream> unsent_stream(NewTestStream("unsent.html")); |
| + HttpRequestHeaders unsent_headers; |
| + HttpResponseInfo unsent_response; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + unsent_stream->SendRequest(unsent_headers, NULL, &unsent_response, |
| + &callback_)); |
| + unsent_stream->Close(false); |
| + |
| + data_->RunFor(1); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + EXPECT_EQ(ERR_IO_PENDING, stream->ReadResponseHeaders(&callback_)); |
| + data_->RunFor(2); |
| + EXPECT_LE(OK, callback_.WaitForResult()); |
| + |
| + ExpectResponse("ok.html", stream, true); |
| + |
| + stream->Close(false); |
| + |
| + data_->StopAfter(8); |
| + scoped_ptr<HttpStream> later_stream(NewTestStream("ko.html")); |
| + TestSyncRequest(later_stream, "ko.html"); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, FailedSend) { |
| + MockWrite writes[] = { |
| + MockWrite(true, ERR_FAILED), |
| + }; |
| + MockRead reads[] = {}; |
| + Initialize(reads, 0, writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> failed_stream(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); |
| + scoped_ptr<HttpStream> closed_stream(NewTestStream("closed.html")); |
| + scoped_ptr<HttpStream> rejected_stream(NewTestStream("rejected.html")); |
| + |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + TestCompletionCallback failed_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + failed_stream->SendRequest(headers, NULL, &response, |
| + &failed_callback)); |
| + TestCompletionCallback evicted_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + evicted_stream->SendRequest(headers, NULL, &response, |
| + &evicted_callback)); |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + closed_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + closed_stream->Close(false); |
| + |
| + data_->RunFor(1); |
| + EXPECT_EQ(ERR_FAILED, failed_callback.WaitForResult()); |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, |
| + rejected_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + |
| + failed_stream->Close(true); |
| + evicted_stream->Close(true); |
| + rejected_stream->Close(true); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, ConnectionSuddenlyClosedAfterResponse) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 1, "GET /read_evicted.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 2, "GET /read_rejected.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(true, ERR_SOCKET_NOT_CONNECTED, 5), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 3, "HTTP/1.1 200 OK\r\n\r\n"), |
| + MockRead(false, 4, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> closed_stream(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> read_evicted_stream( |
| + NewTestStream("read_evicted.html")); |
| + scoped_ptr<HttpStream> read_rejected_stream( |
| + NewTestStream("read_rejected.html")); |
| + scoped_ptr<HttpStream> send_closed_stream( |
| + NewTestStream("send_closed.html")); |
| + scoped_ptr<HttpStream> send_evicted_stream( |
| + NewTestStream("send_evicted.html")); |
| + scoped_ptr<HttpStream> send_rejected_stream( |
| + NewTestStream("send_rejected.html")); |
| + |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(OK, closed_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + EXPECT_EQ(OK, read_evicted_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + EXPECT_EQ(OK, read_rejected_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + TestCompletionCallback send_closed_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + send_closed_stream->SendRequest(headers, NULL, &response, |
| + &send_closed_callback)); |
| + TestCompletionCallback send_evicted_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + send_evicted_stream->SendRequest(headers, NULL, &response, |
| + &send_evicted_callback)); |
| + |
| + TestCompletionCallback read_evicted_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + read_evicted_stream->ReadResponseHeaders(&read_evicted_callback)); |
| + |
| + EXPECT_EQ(OK, closed_stream->ReadResponseHeaders(&callback_)); |
| + std::string expected = "ok.html"; |
| + scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size() + 10)); |
| + EXPECT_EQ(static_cast<int>(expected.size()), |
| + closed_stream->ReadResponseBody(buffer.get(), expected.size() + 10, |
| + &callback_)); |
| + std::string actual(buffer->data(), expected.size()); |
| + EXPECT_THAT(actual, StrEq(expected)); |
|
mmenke
2011/08/23 19:05:25
nit: Instead of the above lines, could just use:
James Simonsen
2011/08/26 22:19:07
Good eye. Fixed.
|
| + closed_stream->Close(true); |
| + |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, read_evicted_callback.WaitForResult()); |
| + read_evicted_stream->Close(true); |
| + |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, |
| + read_rejected_stream->ReadResponseHeaders(&callback_)); |
| + read_rejected_stream->Close(true); |
| + |
| + data_->RunFor(1); |
| + EXPECT_EQ(ERR_SOCKET_NOT_CONNECTED, send_closed_callback.WaitForResult()); |
| + send_closed_stream->Close(true); |
| + |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, send_evicted_callback.WaitForResult()); |
| + send_evicted_stream->Close(true); |
| + |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, |
| + send_rejected_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + send_rejected_stream->Close(true); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, AbortWhileReadingHeaders) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /aborts.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 1, "GET /evicted.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(true, ERR_FAILED, 2), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> aborted_stream(NewTestStream("aborts.html")); |
| + scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); |
| + scoped_ptr<HttpStream> rejected_stream(NewTestStream( |
| + "rejected.html")); |
| + |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(OK, aborted_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + EXPECT_EQ(OK, evicted_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + |
| + EXPECT_EQ(ERR_IO_PENDING, aborted_stream->ReadResponseHeaders(&callback_)); |
| + TestCompletionCallback evicted_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + evicted_stream->ReadResponseHeaders(&evicted_callback)); |
| + |
| + aborted_stream->Close(true); |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); |
| + evicted_stream->Close(true); |
| + |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, |
| + rejected_stream->SendRequest(headers, NULL, &response, &callback_)); |
| + rejected_stream->Close(true); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, PendingResponseAbandoned) { |
|
mmenke
2011/08/23 19:05:25
Out of general paranoia, should also have tests wh
James Simonsen
2011/08/26 22:19:07
Nice. Caught a bug too.
|
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 1, "GET /abandoned.html HTTP/1.1\r\n\r\n"), |
| + MockWrite(false, 2, "GET /evicted.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = { |
| + MockRead(false, 3, "HTTP/1.1 200 OK\r\n"), |
| + MockRead(false, 4, "Content-Length: 7\r\n\r\n"), |
| + MockRead(false, 5, "ok.html"), |
| + }; |
| + Initialize(reads, arraysize(reads), writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> ok_stream(NewTestStream("ok.html")); |
| + scoped_ptr<HttpStream> abandoned_stream( |
| + NewTestStream("abandoned.html")); |
| + scoped_ptr<HttpStream> evicted_stream(NewTestStream("evicted.html")); |
| + |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(OK, ok_stream->SendRequest(headers, NULL, &response, &callback_)); |
| + EXPECT_EQ(OK, abandoned_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + EXPECT_EQ(OK, evicted_stream->SendRequest(headers, NULL, &response, |
| + &callback_)); |
| + |
| + EXPECT_EQ(OK, ok_stream->ReadResponseHeaders(&callback_)); |
| + TestCompletionCallback abandoned_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + abandoned_stream->ReadResponseHeaders(&abandoned_callback)); |
| + TestCompletionCallback evicted_callback; |
| + EXPECT_EQ(ERR_IO_PENDING, |
| + evicted_stream->ReadResponseHeaders(&evicted_callback)); |
| + |
| + abandoned_stream->Close(false); |
| + |
| + ExpectResponse("ok.html", ok_stream, false); |
| + ok_stream->Close(false); |
| + |
| + EXPECT_EQ(ERR_PIPELINE_EVICTION, evicted_callback.WaitForResult()); |
| + evicted_stream->Close(true); |
| + EXPECT_FALSE(evicted_stream->IsConnectionReusable()); |
| +} |
| + |
| +TEST_F(HttpPipelinedConnectionImplTest, OnPipelineHasCapacity) { |
| + MockWrite writes[] = { |
| + MockWrite(false, 0, "GET /ok.html HTTP/1.1\r\n\r\n"), |
| + }; |
| + MockRead reads[] = {}; |
| + Initialize(reads, 0, writes, arraysize(writes)); |
| + |
| + scoped_ptr<HttpStream> stream(NewTestStream("ok.html")); |
| + |
| + EXPECT_CALL(owner_, OnPipelineHasCapacity(pipeline_.get())).Times(1); |
| + HttpRequestHeaders headers; |
| + HttpResponseInfo response; |
| + EXPECT_EQ(OK, stream->SendRequest(headers, NULL, &response, &callback_)); |
| + MessageLoop::current()->RunAllPending(); |
| + |
| + stream->Close(false); |
| + EXPECT_CALL(owner_, OnPipelineHasCapacity(pipeline_.get())).Times(1); |
| + stream.reset(NULL); |
| + MessageLoop::current()->RunAllPending(); |
| +} |
| + |
| +} // namespace net |