diff options
Diffstat (limited to 'net/base/client_socket_pool_unittest.cc')
-rw-r--r-- | net/base/client_socket_pool_unittest.cc | 274 |
1 files changed, 88 insertions, 186 deletions
diff --git a/net/base/client_socket_pool_unittest.cc b/net/base/client_socket_pool_unittest.cc index 73fc0e3..a889d9a 100644 --- a/net/base/client_socket_pool_unittest.cc +++ b/net/base/client_socket_pool_unittest.cc @@ -4,16 +4,11 @@ #include "base/message_loop.h" #include "net/base/client_socket.h" -#include "net/base/client_socket_factory.h" #include "net/base/client_socket_handle.h" #include "net/base/client_socket_pool.h" -#include "net/base/host_resolver_unittest.h" #include "net/base/net_errors.h" -#include "net/base/test_completion_callback.h" #include "testing/gtest/include/gtest/gtest.h" -namespace net { - namespace { const int kMaxSocketsPerGroup = 6; @@ -26,16 +21,16 @@ const int kPriorities[10] = { 1, 7, 9, 5, 6, 2, 8, 3, 4, 1 }; // available sockets in the socket group. const int kNumPendingRequests = arraysize(kPriorities); -const int kNumRequests = kMaxSocketsPerGroup + kNumPendingRequests; - -class MockClientSocket : public ClientSocket { +class MockClientSocket : public net::ClientSocket { public: - MockClientSocket() : connected_(false) {} + MockClientSocket() : connected_(false) { + allocation_count++; + } // ClientSocket methods: - virtual int Connect(CompletionCallback* callback) { + virtual int Connect(net::CompletionCallback* callback) { connected_ = true; - return OK; + return net::OK; } virtual void Disconnect() { connected_ = false; @@ -48,115 +43,51 @@ class MockClientSocket : public ClientSocket { } // Socket methods: - virtual int Read(IOBuffer* buf, int buf_len, - CompletionCallback* callback) { - return ERR_FAILED; + virtual int Read(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) { + return net::ERR_FAILED; } - virtual int Write(IOBuffer* buf, int buf_len, - CompletionCallback* callback) { - return ERR_FAILED; + virtual int Write(net::IOBuffer* buf, int buf_len, + net::CompletionCallback* callback) { + return net::ERR_FAILED; } + static int allocation_count; + private: bool connected_; }; -class MockFailingClientSocket : public ClientSocket { - public: - MockFailingClientSocket() {} - - // ClientSocket methods: - virtual int Connect(CompletionCallback* callback) { - return ERR_CONNECTION_FAILED; - } - - virtual void Disconnect() {} - - virtual bool IsConnected() const { - return false; - } - virtual bool IsConnectedAndIdle() const { - return false; - } - - // Socket methods: - virtual int Read(IOBuffer* buf, int buf_len, - CompletionCallback* callback) { - return ERR_FAILED; - } - - virtual int Write(IOBuffer* buf, int buf_len, - CompletionCallback* callback) { - return ERR_FAILED; - } -}; - -class MockClientSocketFactory : public ClientSocketFactory { - public: - enum ClientSocketType { - MOCK_CLIENT_SOCKET, - MOCK_FAILING_CLIENT_SOCKET, - }; - - MockClientSocketFactory() - : allocation_count_(0), client_socket_type_(MOCK_CLIENT_SOCKET) {} - - virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses) { - allocation_count_++; - switch (client_socket_type_) { - case MOCK_CLIENT_SOCKET: - return new MockClientSocket(); - case MOCK_FAILING_CLIENT_SOCKET: - return new MockFailingClientSocket(); - default: - NOTREACHED(); - return new MockClientSocket(); - } - } - - virtual SSLClientSocket* CreateSSLClientSocket( - ClientSocket* transport_socket, - const std::string& hostname, - const SSLConfig& ssl_config) { - NOTIMPLEMENTED(); - return NULL; - } - - int allocation_count() const { return allocation_count_; } - - void set_client_socket_type(ClientSocketType type) { - client_socket_type_ = type; - } - - private: - int allocation_count_; - ClientSocketType client_socket_type_; -}; +int MockClientSocket::allocation_count = 0; class TestSocketRequest : public CallbackRunner< Tuple1<int> > { public: TestSocketRequest( - ClientSocketPool* pool, + net::ClientSocketPool* pool, std::vector<TestSocketRequest*>* request_order) : handle(pool), request_order_(request_order) {} - ClientSocketHandle handle; + net::ClientSocketHandle handle; - int WaitForResult() { - return callback_.WaitForResult(); + void EnsureSocket() { + DCHECK(handle.is_initialized()); + request_order_->push_back(this); + if (!handle.socket()) { + handle.set_socket(new MockClientSocket()); + handle.socket()->Connect(NULL); + } } virtual void RunWithParams(const Tuple1<int>& params) { - callback_.RunWithParams(params); + DCHECK(params.a == net::OK); completion_count++; - request_order_->push_back(this); + EnsureSocket(); } static int completion_count; private: std::vector<TestSocketRequest*>* request_order_; - TestCompletionCallback callback_; }; int TestSocketRequest::completion_count = 0; @@ -164,76 +95,68 @@ int TestSocketRequest::completion_count = 0; class ClientSocketPoolTest : public testing::Test { protected: ClientSocketPoolTest() - : pool_(new ClientSocketPool(kMaxSocketsPerGroup, - &client_socket_factory_)) {} + : pool_(new net::ClientSocketPool(kMaxSocketsPerGroup)) {} virtual void SetUp() { + MockClientSocket::allocation_count = 0; TestSocketRequest::completion_count = 0; } - MockClientSocketFactory client_socket_factory_; - scoped_refptr<ClientSocketPool> pool_; + scoped_refptr<net::ClientSocketPool> pool_; std::vector<TestSocketRequest*> request_order_; }; TEST_F(ClientSocketPoolTest, Basic) { - TestCompletionCallback callback; - ClientSocketHandle handle(pool_.get()); - int rv = handle.Init("a", "www.google.com", 80, 0, &callback); - EXPECT_EQ(ERR_IO_PENDING, rv); - EXPECT_FALSE(handle.is_initialized()); - EXPECT_FALSE(handle.socket()); + TestSocketRequest r(pool_.get(), &request_order_); + int rv; - EXPECT_EQ(OK, callback.WaitForResult()); - EXPECT_TRUE(handle.is_initialized()); - EXPECT_TRUE(handle.socket()); + rv = r.handle.Init("a", 0, &r); + EXPECT_EQ(net::OK, rv); + EXPECT_TRUE(r.handle.is_initialized()); - handle.Reset(); + r.handle.Reset(); // The handle's Reset method may have posted a task. MessageLoop::current()->RunAllPending(); } -TEST_F(ClientSocketPoolTest, InitHostResolutionFailure) { - RuleBasedHostMapper* host_mapper = new RuleBasedHostMapper; - host_mapper->AddSimulatedFailure("unresolvable.host.name"); - ScopedHostMapper scoped_host_mapper(host_mapper); - TestSocketRequest req(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "unresolvable.host.name", 80, 5, &req)); - EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req.WaitForResult()); -} +TEST_F(ClientSocketPoolTest, WithIdleConnection) { + TestSocketRequest r(pool_.get(), &request_order_); + int rv; + + rv = r.handle.Init("a", 0, &r); + EXPECT_EQ(net::OK, rv); + EXPECT_TRUE(r.handle.is_initialized()); -TEST_F(ClientSocketPoolTest, InitConnectionFailure) { - client_socket_factory_.set_client_socket_type( - MockClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET); - TestSocketRequest req(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "unresolvable.host.name", 80, 5, &req)); - EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult()); + // Create a socket. + r.EnsureSocket(); + + // Release the socket. It should find its way into the idle list. We're + // testing that this does not trigger a crash. + r.handle.Reset(); + + // The handle's Reset method may have posted a task. + MessageLoop::current()->RunAllPending(); } TEST_F(ClientSocketPoolTest, PendingRequests) { int rv; - scoped_ptr<TestSocketRequest> reqs[kNumRequests]; + scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup + kNumPendingRequests]; for (size_t i = 0; i < arraysize(reqs); ++i) reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); // Create connections or queue up requests. for (int i = 0; i < kMaxSocketsPerGroup; ++i) { - EXPECT_EQ( - ERR_IO_PENDING, - reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get())); - EXPECT_EQ(OK, reqs[i]->WaitForResult()); + rv = reqs[i]->handle.Init("a", 5, reqs[i].get()); + EXPECT_EQ(net::OK, rv); + reqs[i]->EnsureSocket(); } - for (int i = 0; i < kNumPendingRequests; ++i) { rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( - "a", "www.google.com", 80, kPriorities[i], - reqs[kMaxSocketsPerGroup + i].get()); - EXPECT_EQ(ERR_IO_PENDING, rv); + "a", kPriorities[i], reqs[kMaxSocketsPerGroup + i].get()); + EXPECT_EQ(net::ERR_IO_PENDING, rv); } // Release any connections until we have no connections. @@ -249,8 +172,8 @@ TEST_F(ClientSocketPoolTest, PendingRequests) { } } while (released_one); - EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count()); - EXPECT_EQ(kNumRequests, TestSocketRequest::completion_count); + EXPECT_EQ(kMaxSocketsPerGroup, MockClientSocket::allocation_count); + EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count); for (int i = 0; i < kMaxSocketsPerGroup; ++i) { EXPECT_EQ(request_order_[i], reqs[i].get()) << @@ -271,77 +194,58 @@ TEST_F(ClientSocketPoolTest, PendingRequests) { } TEST_F(ClientSocketPoolTest, PendingRequests_NoKeepAlive) { - scoped_ptr<TestSocketRequest> reqs[kNumRequests]; + int rv; + + scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup + kNumPendingRequests]; for (size_t i = 0; i < arraysize(reqs); ++i) reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); // Create connections or queue up requests. - for (int i = 0; i < kMaxSocketsPerGroup; ++i) { - EXPECT_EQ( - ERR_IO_PENDING, - reqs[i]->handle.Init("a", "www.google.com", 80, 0, reqs[i].get())); - EXPECT_EQ(OK, reqs[i]->WaitForResult()); - } - - for (int i = 0; i < kNumPendingRequests; ++i) { - EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( - "a", "www.google.com", 80, 0, reqs[kMaxSocketsPerGroup + i].get())); + for (size_t i = 0; i < arraysize(reqs); ++i) { + rv = reqs[i]->handle.Init("a", 0, reqs[i].get()); + if (rv != net::ERR_IO_PENDING) { + EXPECT_EQ(net::OK, rv); + reqs[i]->EnsureSocket(); + } } // Release any connections until we have no connections. - - while (TestSocketRequest::completion_count < kNumRequests) { - int num_released = 0; + bool released_one; + do { + released_one = false; for (size_t i = 0; i < arraysize(reqs); ++i) { if (reqs[i]->handle.is_initialized()) { reqs[i]->handle.socket()->Disconnect(); reqs[i]->handle.Reset(); - num_released++; + MessageLoop::current()->RunAllPending(); + released_one = true; } } - int curr_num_completed = TestSocketRequest::completion_count; - for (int i = 0; - (i < num_released) && (i + curr_num_completed < kNumRequests); ++i) { - EXPECT_EQ(OK, reqs[i + curr_num_completed]->WaitForResult()); - } - } - - EXPECT_EQ(kNumRequests, client_socket_factory_.allocation_count()); - EXPECT_EQ(kNumRequests, TestSocketRequest::completion_count); -} + } while (released_one); -// This test will start up a RequestSocket() and then immediately Cancel() it. -// The pending host resolution will eventually complete, and destroy the -// ClientSocketPool which will crash if the group was not cleared properly. -TEST_F(ClientSocketPoolTest, CancelRequestClearGroup) { - TestSocketRequest req(pool_.get(), &request_order_); - EXPECT_EQ(ERR_IO_PENDING, - req.handle.Init("a", "www.google.com", 80, 5, &req)); - req.handle.Reset(); - // There is a race condition here. If the worker pool doesn't post the task - // before we get here, then this might not run ConnectingSocket::IOComplete - // and therefore leak the canceled ConnectingSocket. - MessageLoop::current()->RunAllPending(); + EXPECT_EQ(kMaxSocketsPerGroup + kNumPendingRequests, + MockClientSocket::allocation_count); + EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count); } TEST_F(ClientSocketPoolTest, CancelRequest) { - scoped_ptr<TestSocketRequest> reqs[kNumRequests]; + int rv; + + scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup + kNumPendingRequests]; for (size_t i = 0; i < arraysize(reqs); ++i) reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); // Create connections or queue up requests. for (int i = 0; i < kMaxSocketsPerGroup; ++i) { - EXPECT_EQ( - ERR_IO_PENDING, - reqs[i]->handle.Init("a", "www.google.com", 80, 5, reqs[i].get())); - EXPECT_EQ(OK, reqs[i]->WaitForResult()); + rv = reqs[i]->handle.Init("a", 5, reqs[i].get()); + EXPECT_EQ(net::OK, rv); + reqs[i]->EnsureSocket(); } - for (int i = 0; i < kNumPendingRequests; ++i) { - EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( - "a", "www.google.com", 80, kPriorities[i], - reqs[kMaxSocketsPerGroup + i].get())); + rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( + "a", kPriorities[i], reqs[kMaxSocketsPerGroup + i].get()); + EXPECT_EQ(net::ERR_IO_PENDING, rv); } // Cancel a request. @@ -362,8 +266,8 @@ TEST_F(ClientSocketPoolTest, CancelRequest) { } } while (released_one); - EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count()); - EXPECT_EQ(kNumRequests - 1, TestSocketRequest::completion_count); + EXPECT_EQ(kMaxSocketsPerGroup, MockClientSocket::allocation_count); + EXPECT_EQ(kNumPendingRequests - 1, TestSocketRequest::completion_count); for (int i = 0; i < kMaxSocketsPerGroup; ++i) { EXPECT_EQ(request_order_[i], reqs[i].get()) << "Request " << i << " was not in order."; @@ -386,5 +290,3 @@ TEST_F(ClientSocketPoolTest, CancelRequest) { } } // namespace - -} // namespace net |