diff options
author | simonjam@chromium.org <simonjam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-10 01:13:58 +0000 |
---|---|---|
committer | simonjam@chromium.org <simonjam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-10 01:13:58 +0000 |
commit | a0dc711cd2cd69bdde091126fa7d941dc7fcc1dc (patch) | |
tree | 8dd8af62bd4de54ffb643d0e6c21bc6e32ef9ded /net | |
parent | 289dd736363cb662bd95b166de1fb3870b306b06 (diff) | |
download | chromium_src-a0dc711cd2cd69bdde091126fa7d941dc7fcc1dc.zip chromium_src-a0dc711cd2cd69bdde091126fa7d941dc7fcc1dc.tar.gz chromium_src-a0dc711cd2cd69bdde091126fa7d941dc7fcc1dc.tar.bz2 |
Integration tests for HTTP pipelining.
Added tests that exercise the code from HttpNetworkTransaction down to
HttpStreamParser with pipelining enabled.
BUG=None
TEST=net_unittests
Review URL: http://codereview.chromium.org/8457002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@109354 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/http/http_pipelined_connection_impl.cc | 1 | ||||
-rw-r--r-- | net/http/http_pipelined_network_transaction_unittest.cc | 470 | ||||
-rw-r--r-- | net/net.gyp | 1 |
3 files changed, 471 insertions, 1 deletions
diff --git a/net/http/http_pipelined_connection_impl.cc b/net/http/http_pipelined_connection_impl.cc index 8ed9e79..aa3d178 100644 --- a/net/http/http_pipelined_connection_impl.cc +++ b/net/http/http_pipelined_connection_impl.cc @@ -570,7 +570,6 @@ void HttpPipelinedConnectionImpl::GetSSLCertRequestInfo( void HttpPipelinedConnectionImpl::FireUserCallback(int pipeline_id, int result) { if (ContainsKey(stream_info_map_, pipeline_id)) { - CHECK(stream_info_map_[pipeline_id].pending_user_callback); stream_info_map_[pipeline_id].pending_user_callback->Run(result); } } diff --git a/net/http/http_pipelined_network_transaction_unittest.cc b/net/http/http_pipelined_network_transaction_unittest.cc new file mode 100644 index 0000000..8eba31a --- /dev/null +++ b/net/http/http_pipelined_network_transaction_unittest.cc @@ -0,0 +1,470 @@ +// 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 <string> + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_vector.h" +#include "base/stringprintf.h" +#include "base/utf_string_conversions.h" +#include "net/base/address_list.h" +#include "net/base/host_cache.h" +#include "net/base/io_buffer.h" +#include "net/base/mock_host_resolver.h" +#include "net/base/net_errors.h" +#include "net/base/net_util.h" +#include "net/base/request_priority.h" +#include "net/base/ssl_config_service_defaults.h" +#include "net/http/http_auth_handler_mock.h" +#include "net/http/http_network_session.h" +#include "net/http/http_network_transaction.h" +#include "net/http/http_request_info.h" +#include "net/http/http_server_properties_impl.h" +#include "net/proxy/proxy_service.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::StrEq; + +namespace net { + +namespace { + +class HttpPipelinedNetworkTransactionTest : public testing::Test { + public: + HttpPipelinedNetworkTransactionTest() + : histograms_("a"), + pool_(1, 1, &histograms_, &factory_) { + } + + virtual void SetUp() OVERRIDE { + default_pipelining_enabled_ = HttpStreamFactory::http_pipelining_enabled(); + HttpStreamFactory::set_http_pipelining_enabled(true); + } + + virtual void TearDown() OVERRIDE { + MessageLoop::current()->RunAllPending(); + HttpStreamFactory::set_http_pipelining_enabled(default_pipelining_enabled_); + } + + void Initialize() { + proxy_service_.reset(ProxyService::CreateDirect()); + ssl_config_ = new SSLConfigServiceDefaults; + auth_handler_factory_.reset(new HttpAuthHandlerMock::Factory()); + + HttpNetworkSession::Params session_params; + session_params.client_socket_factory = &factory_; + session_params.proxy_service = proxy_service_.get(); + session_params.host_resolver = &mock_resolver_; + session_params.ssl_config_service = ssl_config_.get(); + session_params.http_auth_handler_factory = auth_handler_factory_.get(); + session_params.http_server_properties = &http_server_properties_; + session_ = new HttpNetworkSession(session_params); + } + + void AddExpectedConnection(MockRead* reads, size_t reads_count, + MockWrite* writes, size_t writes_count) { + DeterministicSocketData* 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); + data_vector_.push_back(data); + } + + const HttpRequestInfo* GetRequestInfo(const char* filename) { + std::string url = StringPrintf("http://localhost/%s", filename); + HttpRequestInfo* request_info = new HttpRequestInfo; + request_info->url = GURL(url); + request_info->method = "GET"; + request_info_vector_.push_back(request_info); + return request_info; + } + + void ExpectResponse(const std::string& expected, + HttpNetworkTransaction& transaction) { + scoped_refptr<IOBuffer> buffer(new IOBuffer(expected.size())); + EXPECT_EQ(static_cast<int>(expected.size()), + transaction.Read(buffer.get(), expected.size(), &callback_)); + std::string actual(buffer->data(), expected.size()); + EXPECT_THAT(actual, StrEq(expected)); + EXPECT_EQ(OK, transaction.Read(buffer.get(), expected.size(), &callback_)); + } + + void CompleteTwoRequests() { + scoped_ptr<HttpNetworkTransaction> one_transaction( + new HttpNetworkTransaction(session_.get())); + TestOldCompletionCallback one_callback; + EXPECT_EQ(ERR_IO_PENDING, + one_transaction->Start(GetRequestInfo("one.html"), &one_callback, + BoundNetLog())); + EXPECT_EQ(OK, one_callback.WaitForResult()); + + HttpNetworkTransaction two_transaction(session_.get()); + TestOldCompletionCallback two_callback; + EXPECT_EQ(ERR_IO_PENDING, + two_transaction.Start(GetRequestInfo("two.html"), &two_callback, + BoundNetLog())); + + TestOldCompletionCallback one_read_callback; + scoped_refptr<IOBuffer> buffer(new IOBuffer(8)); + EXPECT_EQ(ERR_IO_PENDING, + one_transaction->Read(buffer.get(), 8, &one_read_callback)); + + data_vector_[0]->RunFor(2); + EXPECT_EQ(8, one_read_callback.WaitForResult()); + data_vector_[0]->SetStop(10); + std::string actual(buffer->data(), 8); + EXPECT_THAT(actual, StrEq("one.html")); + EXPECT_EQ(OK, one_transaction->Read(buffer.get(), 8, &one_read_callback)); + + EXPECT_EQ(OK, two_callback.WaitForResult()); + ExpectResponse("two.html", two_transaction); + } + + DeterministicMockClientSocketFactory factory_; + ClientSocketPoolHistograms histograms_; + MockTransportClientSocketPool pool_; + std::vector<scoped_refptr<DeterministicSocketData> > data_vector_; + TestOldCompletionCallback callback_; + ScopedVector<HttpRequestInfo> request_info_vector_; + bool default_pipelining_enabled_; + + scoped_ptr<ProxyService> proxy_service_; + MockHostResolver mock_resolver_; + scoped_refptr<SSLConfigService> ssl_config_; + scoped_ptr<HttpAuthHandlerMock::Factory> auth_handler_factory_; + HttpServerPropertiesImpl http_server_properties_; + scoped_refptr<HttpNetworkSession> session_; +}; + +TEST_F(HttpPipelinedNetworkTransactionTest, OneRequest) { + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /test.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 9\r\n\r\n"), + MockRead(false, 3, "test.html"), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + HttpNetworkTransaction transaction(session_.get()); + EXPECT_EQ(ERR_IO_PENDING, + transaction.Start(GetRequestInfo("test.html"), &callback_, + BoundNetLog())); + EXPECT_EQ(OK, callback_.WaitForResult()); + ExpectResponse("test.html", transaction); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, ReusePipeline) { + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 3, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(true, 4, "one.html"), + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 6, "Content-Length: 8\r\n\r\n"), + MockRead(false, 7, "two.html"), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + CompleteTwoRequests(); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, ReusesOnSpaceAvailable) { + int old_max_sockets = ClientSocketPoolManager::max_sockets_per_group(); + ClientSocketPoolManager::set_max_sockets_per_group(1); + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 4, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 7, "GET /three.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 12, "GET /four.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(false, 3, "one.html"), + MockRead(false, 5, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 6, "Content-Length: 8\r\n\r\n"), + MockRead(false, 8, "two.html"), + MockRead(false, 9, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 10, "Content-Length: 10\r\n\r\n"), + MockRead(false, 11, "three.html"), + MockRead(false, 13, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 14, "Content-Length: 9\r\n\r\n"), + MockRead(false, 15, "four.html"), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + scoped_ptr<HttpNetworkTransaction> one_transaction( + new HttpNetworkTransaction(session_.get())); + TestOldCompletionCallback one_callback; + EXPECT_EQ(ERR_IO_PENDING, + one_transaction->Start(GetRequestInfo("one.html"), &one_callback, + BoundNetLog())); + EXPECT_EQ(OK, one_callback.WaitForResult()); + + HttpNetworkTransaction two_transaction(session_.get()); + TestOldCompletionCallback two_callback; + EXPECT_EQ(ERR_IO_PENDING, + two_transaction.Start(GetRequestInfo("two.html"), &two_callback, + BoundNetLog())); + + HttpNetworkTransaction three_transaction(session_.get()); + TestOldCompletionCallback three_callback; + EXPECT_EQ(ERR_IO_PENDING, + three_transaction.Start(GetRequestInfo("three.html"), + &three_callback, BoundNetLog())); + + HttpNetworkTransaction four_transaction(session_.get()); + TestOldCompletionCallback four_callback; + EXPECT_EQ(ERR_IO_PENDING, + four_transaction.Start(GetRequestInfo("four.html"), &four_callback, + BoundNetLog())); + + ExpectResponse("one.html", *one_transaction.get()); + EXPECT_EQ(OK, two_callback.WaitForResult()); + ExpectResponse("two.html", two_transaction); + EXPECT_EQ(OK, three_callback.WaitForResult()); + ExpectResponse("three.html", three_transaction); + + one_transaction.reset(); + EXPECT_EQ(OK, four_callback.WaitForResult()); + ExpectResponse("four.html", four_transaction); + + ClientSocketPoolManager::set_max_sockets_per_group(old_max_sockets); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, UnknownSizeEvictsToNewPipeline) { + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 2, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n\r\n"), + MockRead(true, 3, "one.html"), + MockRead(false, OK, 4), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + MockWrite writes2[] = { + MockWrite(false, 0, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads2[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(false, 3, "two.html"), + }; + AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); + + CompleteTwoRequests(); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, ConnectionCloseEvictToNewPipeline) { + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 3, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(true, 4, "one.html"), + MockRead(false, ERR_SOCKET_NOT_CONNECTED, 5), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + MockWrite writes2[] = { + MockWrite(false, 0, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads2[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(false, 3, "two.html"), + }; + AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); + + CompleteTwoRequests(); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, ErrorEvictsToNewPipeline) { + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 3, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n\r\n"), + MockRead(false, ERR_FAILED, 2), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + MockWrite writes2[] = { + MockWrite(false, 0, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads2[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(false, 3, "two.html"), + }; + AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); + + HttpNetworkTransaction one_transaction(session_.get()); + TestOldCompletionCallback one_callback; + EXPECT_EQ(ERR_IO_PENDING, + one_transaction.Start(GetRequestInfo("one.html"), &one_callback, + BoundNetLog())); + EXPECT_EQ(OK, one_callback.WaitForResult()); + + HttpNetworkTransaction two_transaction(session_.get()); + TestOldCompletionCallback two_callback; + EXPECT_EQ(ERR_IO_PENDING, + two_transaction.Start(GetRequestInfo("two.html"), &two_callback, + BoundNetLog())); + + scoped_refptr<IOBuffer> buffer(new IOBuffer(1)); + EXPECT_EQ(ERR_FAILED, one_transaction.Read(buffer.get(), 1, &callback_)); + EXPECT_EQ(OK, two_callback.WaitForResult()); + ExpectResponse("two.html", two_transaction); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, SendErrorEvictsToNewPipeline) { + Initialize(); + + MockWrite writes[] = { + MockWrite(true, ERR_FAILED, 0), + }; + AddExpectedConnection(NULL, 0, writes, arraysize(writes)); + + MockWrite writes2[] = { + MockWrite(false, 0, "GET /two.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + }; + MockRead reads2[] = { + MockRead(false, 1, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 2, "Content-Length: 8\r\n\r\n"), + MockRead(false, 3, "two.html"), + }; + AddExpectedConnection(reads2, arraysize(reads2), writes2, arraysize(writes2)); + + HttpNetworkTransaction one_transaction(session_.get()); + TestOldCompletionCallback one_callback; + EXPECT_EQ(ERR_IO_PENDING, + one_transaction.Start(GetRequestInfo("one.html"), &one_callback, + BoundNetLog())); + + HttpNetworkTransaction two_transaction(session_.get()); + TestOldCompletionCallback two_callback; + EXPECT_EQ(ERR_IO_PENDING, + two_transaction.Start(GetRequestInfo("two.html"), &two_callback, + BoundNetLog())); + + data_vector_[0]->RunFor(1); + EXPECT_EQ(ERR_FAILED, one_callback.WaitForResult()); + + EXPECT_EQ(OK, two_callback.WaitForResult()); + ExpectResponse("two.html", two_transaction); +} + +TEST_F(HttpPipelinedNetworkTransactionTest, BasicHttpAuthentication) { + Initialize(); + + MockWrite writes[] = { + MockWrite(false, 0, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n\r\n"), + MockWrite(false, 5, "GET /one.html HTTP/1.1\r\n" + "Host: localhost\r\n" + "Connection: keep-alive\r\n" + "Authorization: auth_token\r\n\r\n"), + }; + MockRead reads[] = { + MockRead(false, 1, "HTTP/1.1 401 Authentication Required\r\n"), + MockRead(false, 2, "WWW-Authenticate: Basic realm=\"Secure Area\"\r\n"), + MockRead(false, 3, "Content-Length: 20\r\n\r\n"), + MockRead(false, 4, "needs authentication"), + MockRead(false, 6, "HTTP/1.1 200 OK\r\n"), + MockRead(false, 7, "Content-Length: 8\r\n\r\n"), + MockRead(false, 8, "one.html"), + }; + AddExpectedConnection(reads, arraysize(reads), writes, arraysize(writes)); + + HttpAuthHandlerMock* mock_auth = new HttpAuthHandlerMock; + std::string challenge_text = "Basic"; + HttpAuth::ChallengeTokenizer challenge(challenge_text.begin(), + challenge_text.end()); + GURL origin("localhost"); + EXPECT_TRUE(mock_auth->InitFromChallenge(&challenge, + HttpAuth::AUTH_SERVER, + origin, + BoundNetLog())); + auth_handler_factory_->AddMockHandler(mock_auth, HttpAuth::AUTH_SERVER); + + HttpNetworkTransaction transaction(session_.get()); + EXPECT_EQ( + ERR_IO_PENDING, + transaction.Start(GetRequestInfo("one.html"), &callback_, BoundNetLog())); + EXPECT_EQ(OK, callback_.WaitForResult()); + + AuthCredentials credentials(ASCIIToUTF16("user"), ASCIIToUTF16("pass")); + EXPECT_EQ(OK, transaction.RestartWithAuth(credentials, &callback_)); + + ExpectResponse("one.html", transaction); +} + +} // anonymous namespace + +} // namespace net diff --git a/net/net.gyp b/net/net.gyp index dd383c0..a5d69d3 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -1060,6 +1060,7 @@ 'http/http_network_transaction_unittest.cc', 'http/http_pipelined_connection_impl_unittest.cc', 'http/http_pipelined_host_unittest.cc', + 'http/http_pipelined_network_transaction_unittest.cc', 'http/http_proxy_client_socket_pool_unittest.cc', 'http/http_request_headers_unittest.cc', 'http/http_response_body_drainer_unittest.cc', |