| Index: net/base/client_socket_pool_unittest.cc
|
| diff --git a/net/base/client_socket_pool_unittest.cc b/net/base/client_socket_pool_unittest.cc
|
| index 73fc0e344dc93508e5c4e7cace238520f8166869..a889d9a7fa156a65e560b6d7fe2e908354a64351 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
|
|
|