Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Unified Diff: net/socket/client_socket_pool_base_unittest.cc

Issue 992733002: Remove //net (except for Android test stuff) and sdch (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/socket/client_socket_pool_base.cc ('k') | net/socket/client_socket_pool_histograms.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/socket/client_socket_pool_base_unittest.cc
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
deleted file mode 100644
index c4a28459a1ebd717cb97cdac07e63fa7e86659e7..0000000000000000000000000000000000000000
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ /dev/null
@@ -1,4103 +0,0 @@
-// Copyright (c) 2012 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/socket/client_socket_pool_base.h"
-
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
-#include "base/memory/weak_ptr.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/platform_thread.h"
-#include "base/values.h"
-#include "net/base/load_timing_info.h"
-#include "net/base/load_timing_info_test_util.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/base/net_log_unittest.h"
-#include "net/base/request_priority.h"
-#include "net/base/test_completion_callback.h"
-#include "net/http/http_response_headers.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/client_socket_handle.h"
-#include "net/socket/client_socket_pool_histograms.h"
-#include "net/socket/socket_test_util.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/socket/stream_socket.h"
-#include "net/udp/datagram_client_socket.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-using ::testing::Invoke;
-using ::testing::Return;
-
-namespace net {
-
-namespace {
-
-const int kDefaultMaxSockets = 4;
-const int kDefaultMaxSocketsPerGroup = 2;
-
-// Make sure |handle| sets load times correctly when it has been assigned a
-// reused socket.
-void TestLoadTimingInfoConnectedReused(const ClientSocketHandle& handle) {
- LoadTimingInfo load_timing_info;
- // Only pass true in as |is_reused|, as in general, HttpStream types should
- // have stricter concepts of reuse than socket pools.
- EXPECT_TRUE(handle.GetLoadTimingInfo(true, &load_timing_info));
-
- EXPECT_EQ(true, load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
-
- ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
- ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
-}
-
-// Make sure |handle| sets load times correctly when it has been assigned a
-// fresh socket. Also runs TestLoadTimingInfoConnectedReused, since the owner
-// of a connection where |is_reused| is false may consider the connection
-// reused.
-void TestLoadTimingInfoConnectedNotReused(const ClientSocketHandle& handle) {
- EXPECT_FALSE(handle.is_reused());
-
- LoadTimingInfo load_timing_info;
- EXPECT_TRUE(handle.GetLoadTimingInfo(false, &load_timing_info));
-
- EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_NE(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
-
- ExpectConnectTimingHasTimes(load_timing_info.connect_timing,
- CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY);
- ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
-
- TestLoadTimingInfoConnectedReused(handle);
-}
-
-// Make sure |handle| sets load times correctly, in the case that it does not
-// currently have a socket.
-void TestLoadTimingInfoNotConnected(const ClientSocketHandle& handle) {
- // Should only be set to true once a socket is assigned, if at all.
- EXPECT_FALSE(handle.is_reused());
-
- LoadTimingInfo load_timing_info;
- EXPECT_FALSE(handle.GetLoadTimingInfo(false, &load_timing_info));
-
- EXPECT_FALSE(load_timing_info.socket_reused);
- EXPECT_EQ(NetLog::Source::kInvalidId, load_timing_info.socket_log_id);
-
- ExpectConnectTimingHasNoTimes(load_timing_info.connect_timing);
- ExpectLoadTimingHasOnlyConnectionTimes(load_timing_info);
-}
-
-class TestSocketParams : public base::RefCounted<TestSocketParams> {
- public:
- explicit TestSocketParams(bool ignore_limits)
- : ignore_limits_(ignore_limits) {}
-
- bool ignore_limits() { return ignore_limits_; }
-
- private:
- friend class base::RefCounted<TestSocketParams>;
- ~TestSocketParams() {}
-
- const bool ignore_limits_;
-};
-typedef ClientSocketPoolBase<TestSocketParams> TestClientSocketPoolBase;
-
-class MockClientSocket : public StreamSocket {
- public:
- explicit MockClientSocket(net::NetLog* net_log)
- : connected_(false),
- has_unread_data_(false),
- net_log_(BoundNetLog::Make(net_log, net::NetLog::SOURCE_SOCKET)),
- was_used_to_convey_data_(false) {
- }
-
- // Sets whether the socket has unread data. If true, the next call to Read()
- // will return 1 byte and IsConnectedAndIdle() will return false.
- void set_has_unread_data(bool has_unread_data) {
- has_unread_data_ = has_unread_data;
- }
-
- // Socket implementation.
- int Read(IOBuffer* /* buf */,
- int len,
- const CompletionCallback& /* callback */) override {
- if (has_unread_data_ && len > 0) {
- has_unread_data_ = false;
- was_used_to_convey_data_ = true;
- return 1;
- }
- return ERR_UNEXPECTED;
- }
-
- int Write(IOBuffer* /* buf */,
- int len,
- const CompletionCallback& /* callback */) override {
- was_used_to_convey_data_ = true;
- return len;
- }
- int SetReceiveBufferSize(int32 size) override { return OK; }
- int SetSendBufferSize(int32 size) override { return OK; }
-
- // StreamSocket implementation.
- int Connect(const CompletionCallback& callback) override {
- connected_ = true;
- return OK;
- }
-
- void Disconnect() override { connected_ = false; }
- bool IsConnected() const override { return connected_; }
- bool IsConnectedAndIdle() const override {
- return connected_ && !has_unread_data_;
- }
-
- int GetPeerAddress(IPEndPoint* /* address */) const override {
- return ERR_UNEXPECTED;
- }
-
- int GetLocalAddress(IPEndPoint* /* address */) const override {
- return ERR_UNEXPECTED;
- }
-
- const BoundNetLog& NetLog() const override { return net_log_; }
-
- void SetSubresourceSpeculation() override {}
- void SetOmniboxSpeculation() override {}
- bool WasEverUsed() const override { return was_used_to_convey_data_; }
- bool UsingTCPFastOpen() const override { return false; }
- bool WasNpnNegotiated() const override { return false; }
- NextProto GetNegotiatedProtocol() const override { return kProtoUnknown; }
- bool GetSSLInfo(SSLInfo* ssl_info) override { return false; }
-
- private:
- bool connected_;
- bool has_unread_data_;
- BoundNetLog net_log_;
- bool was_used_to_convey_data_;
-
- DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
-};
-
-class TestConnectJob;
-
-class MockClientSocketFactory : public ClientSocketFactory {
- public:
- MockClientSocketFactory() : allocation_count_(0) {}
-
- scoped_ptr<DatagramClientSocket> CreateDatagramClientSocket(
- DatagramSocket::BindType bind_type,
- const RandIntCallback& rand_int_cb,
- NetLog* net_log,
- const NetLog::Source& source) override {
- NOTREACHED();
- return scoped_ptr<DatagramClientSocket>();
- }
-
- scoped_ptr<StreamSocket> CreateTransportClientSocket(
- const AddressList& addresses,
- NetLog* /* net_log */,
- const NetLog::Source& /*source*/) override {
- allocation_count_++;
- return scoped_ptr<StreamSocket>();
- }
-
- scoped_ptr<SSLClientSocket> CreateSSLClientSocket(
- scoped_ptr<ClientSocketHandle> transport_socket,
- const HostPortPair& host_and_port,
- const SSLConfig& ssl_config,
- const SSLClientSocketContext& context) override {
- NOTIMPLEMENTED();
- return scoped_ptr<SSLClientSocket>();
- }
-
- void ClearSSLSessionCache() override { NOTIMPLEMENTED(); }
-
- void WaitForSignal(TestConnectJob* job) { waiting_jobs_.push_back(job); }
-
- void SignalJobs();
-
- void SignalJob(size_t job);
-
- void SetJobLoadState(size_t job, LoadState load_state);
-
- int allocation_count() const { return allocation_count_; }
-
- private:
- int allocation_count_;
- std::vector<TestConnectJob*> waiting_jobs_;
-};
-
-class TestConnectJob : public ConnectJob {
- public:
- enum JobType {
- kMockJob,
- kMockFailingJob,
- kMockPendingJob,
- kMockPendingFailingJob,
- kMockWaitingJob,
- kMockRecoverableJob,
- kMockPendingRecoverableJob,
- kMockAdditionalErrorStateJob,
- kMockPendingAdditionalErrorStateJob,
- kMockUnreadDataJob,
- };
-
- // The kMockPendingJob uses a slight delay before allowing the connect
- // to complete.
- static const int kPendingConnectDelay = 2;
-
- TestConnectJob(JobType job_type,
- const std::string& group_name,
- const TestClientSocketPoolBase::Request& request,
- base::TimeDelta timeout_duration,
- ConnectJob::Delegate* delegate,
- MockClientSocketFactory* client_socket_factory,
- NetLog* net_log)
- : ConnectJob(group_name, timeout_duration, request.priority(), delegate,
- BoundNetLog::Make(net_log, NetLog::SOURCE_CONNECT_JOB)),
- job_type_(job_type),
- client_socket_factory_(client_socket_factory),
- load_state_(LOAD_STATE_IDLE),
- store_additional_error_state_(false),
- weak_factory_(this) {
- }
-
- void Signal() {
- DoConnect(waiting_success_, true /* async */, false /* recoverable */);
- }
-
- void set_load_state(LoadState load_state) { load_state_ = load_state; }
-
- // From ConnectJob:
-
- LoadState GetLoadState() const override { return load_state_; }
-
- void GetAdditionalErrorState(ClientSocketHandle* handle) override {
- if (store_additional_error_state_) {
- // Set all of the additional error state fields in some way.
- handle->set_is_ssl_error(true);
- HttpResponseInfo info;
- info.headers = new HttpResponseHeaders(std::string());
- handle->set_ssl_error_response_info(info);
- }
- }
-
- private:
- // From ConnectJob:
-
- int ConnectInternal() override {
- AddressList ignored;
- client_socket_factory_->CreateTransportClientSocket(
- ignored, NULL, net::NetLog::Source());
- SetSocket(
- scoped_ptr<StreamSocket>(new MockClientSocket(net_log().net_log())));
- switch (job_type_) {
- case kMockJob:
- return DoConnect(true /* successful */, false /* sync */,
- false /* recoverable */);
- case kMockFailingJob:
- return DoConnect(false /* error */, false /* sync */,
- false /* recoverable */);
- case kMockPendingJob:
- set_load_state(LOAD_STATE_CONNECTING);
-
- // Depending on execution timings, posting a delayed task can result
- // in the task getting executed the at the earliest possible
- // opportunity or only after returning once from the message loop and
- // then a second call into the message loop. In order to make behavior
- // more deterministic, we change the default delay to 2ms. This should
- // always require us to wait for the second call into the message loop.
- //
- // N.B. The correct fix for this and similar timing problems is to
- // abstract time for the purpose of unittests. Unfortunately, we have
- // a lot of third-party components that directly call the various
- // time functions, so this change would be rather invasive.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
- weak_factory_.GetWeakPtr(),
- true /* successful */,
- true /* async */,
- false /* recoverable */),
- base::TimeDelta::FromMilliseconds(kPendingConnectDelay));
- return ERR_IO_PENDING;
- case kMockPendingFailingJob:
- set_load_state(LOAD_STATE_CONNECTING);
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
- weak_factory_.GetWeakPtr(),
- false /* error */,
- true /* async */,
- false /* recoverable */),
- base::TimeDelta::FromMilliseconds(2));
- return ERR_IO_PENDING;
- case kMockWaitingJob:
- set_load_state(LOAD_STATE_CONNECTING);
- client_socket_factory_->WaitForSignal(this);
- waiting_success_ = true;
- return ERR_IO_PENDING;
- case kMockRecoverableJob:
- return DoConnect(false /* error */, false /* sync */,
- true /* recoverable */);
- case kMockPendingRecoverableJob:
- set_load_state(LOAD_STATE_CONNECTING);
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
- weak_factory_.GetWeakPtr(),
- false /* error */,
- true /* async */,
- true /* recoverable */),
- base::TimeDelta::FromMilliseconds(2));
- return ERR_IO_PENDING;
- case kMockAdditionalErrorStateJob:
- store_additional_error_state_ = true;
- return DoConnect(false /* error */, false /* sync */,
- false /* recoverable */);
- case kMockPendingAdditionalErrorStateJob:
- set_load_state(LOAD_STATE_CONNECTING);
- store_additional_error_state_ = true;
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(base::IgnoreResult(&TestConnectJob::DoConnect),
- weak_factory_.GetWeakPtr(),
- false /* error */,
- true /* async */,
- false /* recoverable */),
- base::TimeDelta::FromMilliseconds(2));
- return ERR_IO_PENDING;
- case kMockUnreadDataJob: {
- int ret = DoConnect(true /* successful */, false /* sync */,
- false /* recoverable */);
- static_cast<MockClientSocket*>(socket())->set_has_unread_data(true);
- return ret;
- }
- default:
- NOTREACHED();
- SetSocket(scoped_ptr<StreamSocket>());
- return ERR_FAILED;
- }
- }
-
- int DoConnect(bool succeed, bool was_async, bool recoverable) {
- int result = OK;
- if (succeed) {
- socket()->Connect(CompletionCallback());
- } else if (recoverable) {
- result = ERR_PROXY_AUTH_REQUESTED;
- } else {
- result = ERR_CONNECTION_FAILED;
- SetSocket(scoped_ptr<StreamSocket>());
- }
-
- if (was_async)
- NotifyDelegateOfCompletion(result);
- return result;
- }
-
- bool waiting_success_;
- const JobType job_type_;
- MockClientSocketFactory* const client_socket_factory_;
- LoadState load_state_;
- bool store_additional_error_state_;
-
- base::WeakPtrFactory<TestConnectJob> weak_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(TestConnectJob);
-};
-
-class TestConnectJobFactory
- : public TestClientSocketPoolBase::ConnectJobFactory {
- public:
- TestConnectJobFactory(MockClientSocketFactory* client_socket_factory,
- NetLog* net_log)
- : job_type_(TestConnectJob::kMockJob),
- job_types_(NULL),
- client_socket_factory_(client_socket_factory),
- net_log_(net_log) {
- }
-
- ~TestConnectJobFactory() override {}
-
- void set_job_type(TestConnectJob::JobType job_type) { job_type_ = job_type; }
-
- void set_job_types(std::list<TestConnectJob::JobType>* job_types) {
- job_types_ = job_types;
- CHECK(!job_types_->empty());
- }
-
- void set_timeout_duration(base::TimeDelta timeout_duration) {
- timeout_duration_ = timeout_duration;
- }
-
- // ConnectJobFactory implementation.
-
- scoped_ptr<ConnectJob> NewConnectJob(
- const std::string& group_name,
- const TestClientSocketPoolBase::Request& request,
- ConnectJob::Delegate* delegate) const override {
- EXPECT_TRUE(!job_types_ || !job_types_->empty());
- TestConnectJob::JobType job_type = job_type_;
- if (job_types_ && !job_types_->empty()) {
- job_type = job_types_->front();
- job_types_->pop_front();
- }
- return scoped_ptr<ConnectJob>(new TestConnectJob(job_type,
- group_name,
- request,
- timeout_duration_,
- delegate,
- client_socket_factory_,
- net_log_));
- }
-
- base::TimeDelta ConnectionTimeout() const override {
- return timeout_duration_;
- }
-
- private:
- TestConnectJob::JobType job_type_;
- std::list<TestConnectJob::JobType>* job_types_;
- base::TimeDelta timeout_duration_;
- MockClientSocketFactory* const client_socket_factory_;
- NetLog* net_log_;
-
- DISALLOW_COPY_AND_ASSIGN(TestConnectJobFactory);
-};
-
-class TestClientSocketPool : public ClientSocketPool {
- public:
- typedef TestSocketParams SocketParams;
-
- TestClientSocketPool(
- int max_sockets,
- int max_sockets_per_group,
- ClientSocketPoolHistograms* histograms,
- base::TimeDelta unused_idle_socket_timeout,
- base::TimeDelta used_idle_socket_timeout,
- TestClientSocketPoolBase::ConnectJobFactory* connect_job_factory)
- : base_(NULL, max_sockets, max_sockets_per_group, histograms,
- unused_idle_socket_timeout, used_idle_socket_timeout,
- connect_job_factory) {}
-
- ~TestClientSocketPool() override {}
-
- int RequestSocket(const std::string& group_name,
- const void* params,
- net::RequestPriority priority,
- ClientSocketHandle* handle,
- const CompletionCallback& callback,
- const BoundNetLog& net_log) override {
- const scoped_refptr<TestSocketParams>* casted_socket_params =
- static_cast<const scoped_refptr<TestSocketParams>*>(params);
- return base_.RequestSocket(group_name, *casted_socket_params, priority,
- handle, callback, net_log);
- }
-
- void RequestSockets(const std::string& group_name,
- const void* params,
- int num_sockets,
- const BoundNetLog& net_log) override {
- const scoped_refptr<TestSocketParams>* casted_params =
- static_cast<const scoped_refptr<TestSocketParams>*>(params);
-
- base_.RequestSockets(group_name, *casted_params, num_sockets, net_log);
- }
-
- void CancelRequest(const std::string& group_name,
- ClientSocketHandle* handle) override {
- base_.CancelRequest(group_name, handle);
- }
-
- void ReleaseSocket(const std::string& group_name,
- scoped_ptr<StreamSocket> socket,
- int id) override {
- base_.ReleaseSocket(group_name, socket.Pass(), id);
- }
-
- void FlushWithError(int error) override { base_.FlushWithError(error); }
-
- bool IsStalled() const override { return base_.IsStalled(); }
-
- void CloseIdleSockets() override { base_.CloseIdleSockets(); }
-
- int IdleSocketCount() const override { return base_.idle_socket_count(); }
-
- int IdleSocketCountInGroup(const std::string& group_name) const override {
- return base_.IdleSocketCountInGroup(group_name);
- }
-
- LoadState GetLoadState(const std::string& group_name,
- const ClientSocketHandle* handle) const override {
- return base_.GetLoadState(group_name, handle);
- }
-
- void AddHigherLayeredPool(HigherLayeredPool* higher_pool) override {
- base_.AddHigherLayeredPool(higher_pool);
- }
-
- void RemoveHigherLayeredPool(HigherLayeredPool* higher_pool) override {
- base_.RemoveHigherLayeredPool(higher_pool);
- }
-
- base::DictionaryValue* GetInfoAsValue(
- const std::string& name,
- const std::string& type,
- bool include_nested_pools) const override {
- return base_.GetInfoAsValue(name, type);
- }
-
- base::TimeDelta ConnectionTimeout() const override {
- return base_.ConnectionTimeout();
- }
-
- ClientSocketPoolHistograms* histograms() const override {
- return base_.histograms();
- }
-
- const TestClientSocketPoolBase* base() const { return &base_; }
-
- int NumUnassignedConnectJobsInGroup(const std::string& group_name) const {
- return base_.NumUnassignedConnectJobsInGroup(group_name);
- }
-
- int NumConnectJobsInGroup(const std::string& group_name) const {
- return base_.NumConnectJobsInGroup(group_name);
- }
-
- int NumActiveSocketsInGroup(const std::string& group_name) const {
- return base_.NumActiveSocketsInGroup(group_name);
- }
-
- bool HasGroup(const std::string& group_name) const {
- return base_.HasGroup(group_name);
- }
-
- void CleanupTimedOutIdleSockets() { base_.CleanupIdleSockets(false); }
-
- void EnableConnectBackupJobs() { base_.EnableConnectBackupJobs(); }
-
- bool CloseOneIdleConnectionInHigherLayeredPool() {
- return base_.CloseOneIdleConnectionInHigherLayeredPool();
- }
-
- private:
- TestClientSocketPoolBase base_;
-
- DISALLOW_COPY_AND_ASSIGN(TestClientSocketPool);
-};
-
-} // namespace
-
-namespace {
-
-void MockClientSocketFactory::SignalJobs() {
- for (std::vector<TestConnectJob*>::iterator it = waiting_jobs_.begin();
- it != waiting_jobs_.end(); ++it) {
- (*it)->Signal();
- }
- waiting_jobs_.clear();
-}
-
-void MockClientSocketFactory::SignalJob(size_t job) {
- ASSERT_LT(job, waiting_jobs_.size());
- waiting_jobs_[job]->Signal();
- waiting_jobs_.erase(waiting_jobs_.begin() + job);
-}
-
-void MockClientSocketFactory::SetJobLoadState(size_t job,
- LoadState load_state) {
- ASSERT_LT(job, waiting_jobs_.size());
- waiting_jobs_[job]->set_load_state(load_state);
-}
-
-class TestConnectJobDelegate : public ConnectJob::Delegate {
- public:
- TestConnectJobDelegate()
- : have_result_(false), waiting_for_result_(false), result_(OK) {}
- ~TestConnectJobDelegate() override {}
-
- void OnConnectJobComplete(int result, ConnectJob* job) override {
- result_ = result;
- scoped_ptr<ConnectJob> owned_job(job);
- scoped_ptr<StreamSocket> socket = owned_job->PassSocket();
- // socket.get() should be NULL iff result != OK
- EXPECT_EQ(socket == NULL, result != OK);
- have_result_ = true;
- if (waiting_for_result_)
- base::MessageLoop::current()->Quit();
- }
-
- int WaitForResult() {
- DCHECK(!waiting_for_result_);
- while (!have_result_) {
- waiting_for_result_ = true;
- base::MessageLoop::current()->Run();
- waiting_for_result_ = false;
- }
- have_result_ = false; // auto-reset for next callback
- return result_;
- }
-
- private:
- bool have_result_;
- bool waiting_for_result_;
- int result_;
-};
-
-class ClientSocketPoolBaseTest : public testing::Test {
- protected:
- ClientSocketPoolBaseTest()
- : params_(new TestSocketParams(false /* ignore_limits */)),
- histograms_("ClientSocketPoolTest") {
- connect_backup_jobs_enabled_ =
- internal::ClientSocketPoolBaseHelper::connect_backup_jobs_enabled();
- internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(true);
- cleanup_timer_enabled_ =
- internal::ClientSocketPoolBaseHelper::cleanup_timer_enabled();
- }
-
- ~ClientSocketPoolBaseTest() override {
- internal::ClientSocketPoolBaseHelper::set_connect_backup_jobs_enabled(
- connect_backup_jobs_enabled_);
- internal::ClientSocketPoolBaseHelper::set_cleanup_timer_enabled(
- cleanup_timer_enabled_);
- }
-
- void CreatePool(int max_sockets, int max_sockets_per_group) {
- CreatePoolWithIdleTimeouts(
- max_sockets,
- max_sockets_per_group,
- ClientSocketPool::unused_idle_socket_timeout(),
- ClientSocketPool::used_idle_socket_timeout());
- }
-
- void CreatePoolWithIdleTimeouts(
- int max_sockets, int max_sockets_per_group,
- base::TimeDelta unused_idle_socket_timeout,
- base::TimeDelta used_idle_socket_timeout) {
- DCHECK(!pool_.get());
- connect_job_factory_ = new TestConnectJobFactory(&client_socket_factory_,
- &net_log_);
- pool_.reset(new TestClientSocketPool(max_sockets,
- max_sockets_per_group,
- &histograms_,
- unused_idle_socket_timeout,
- used_idle_socket_timeout,
- connect_job_factory_));
- }
-
- int StartRequestWithParams(
- const std::string& group_name,
- RequestPriority priority,
- const scoped_refptr<TestSocketParams>& params) {
- return test_base_.StartRequestUsingPool(
- pool_.get(), group_name, priority, params);
- }
-
- int StartRequest(const std::string& group_name, RequestPriority priority) {
- return StartRequestWithParams(group_name, priority, params_);
- }
-
- int GetOrderOfRequest(size_t index) const {
- return test_base_.GetOrderOfRequest(index);
- }
-
- bool ReleaseOneConnection(ClientSocketPoolTest::KeepAlive keep_alive) {
- return test_base_.ReleaseOneConnection(keep_alive);
- }
-
- void ReleaseAllConnections(ClientSocketPoolTest::KeepAlive keep_alive) {
- test_base_.ReleaseAllConnections(keep_alive);
- }
-
- TestSocketRequest* request(int i) { return test_base_.request(i); }
- size_t requests_size() const { return test_base_.requests_size(); }
- ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
- size_t completion_count() const { return test_base_.completion_count(); }
-
- CapturingNetLog net_log_;
- bool connect_backup_jobs_enabled_;
- bool cleanup_timer_enabled_;
- MockClientSocketFactory client_socket_factory_;
- TestConnectJobFactory* connect_job_factory_;
- scoped_refptr<TestSocketParams> params_;
- ClientSocketPoolHistograms histograms_;
- scoped_ptr<TestClientSocketPool> pool_;
- ClientSocketPoolTest test_base_;
-};
-
-// Even though a timeout is specified, it doesn't time out on a synchronous
-// completion.
-TEST_F(ClientSocketPoolBaseTest, ConnectJob_NoTimeoutOnSynchronousCompletion) {
- TestConnectJobDelegate delegate;
- ClientSocketHandle ignored;
- TestClientSocketPoolBase::Request request(
- &ignored, CompletionCallback(), DEFAULT_PRIORITY,
- internal::ClientSocketPoolBaseHelper::NORMAL,
- false, params_, BoundNetLog());
- scoped_ptr<TestConnectJob> job(
- new TestConnectJob(TestConnectJob::kMockJob,
- "a",
- request,
- base::TimeDelta::FromMicroseconds(1),
- &delegate,
- &client_socket_factory_,
- NULL));
- EXPECT_EQ(OK, job->Connect());
-}
-
-TEST_F(ClientSocketPoolBaseTest, ConnectJob_TimedOut) {
- TestConnectJobDelegate delegate;
- ClientSocketHandle ignored;
- CapturingNetLog log;
-
- TestClientSocketPoolBase::Request request(
- &ignored, CompletionCallback(), DEFAULT_PRIORITY,
- internal::ClientSocketPoolBaseHelper::NORMAL,
- false, params_, BoundNetLog());
- // Deleted by TestConnectJobDelegate.
- TestConnectJob* job =
- new TestConnectJob(TestConnectJob::kMockPendingJob,
- "a",
- request,
- base::TimeDelta::FromMicroseconds(1),
- &delegate,
- &client_socket_factory_,
- &log);
- ASSERT_EQ(ERR_IO_PENDING, job->Connect());
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(1));
- EXPECT_EQ(ERR_TIMED_OUT, delegate.WaitForResult());
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
-
- EXPECT_EQ(6u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
- EXPECT_TRUE(LogContainsEvent(
- entries, 2, NetLog::TYPE_CONNECT_JOB_SET_SOCKET,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- entries, 3, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_TIMED_OUT,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 4, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB_CONNECT));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 5, NetLog::TYPE_SOCKET_POOL_CONNECT_JOB));
-}
-
-TEST_F(ClientSocketPoolBaseTest, BasicSynchronous) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- TestCompletionCallback callback;
- ClientSocketHandle handle;
- CapturingBoundNetLog log;
- TestLoadTimingInfoNotConnected(handle);
-
- EXPECT_EQ(OK,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- log.bound()));
- EXPECT_TRUE(handle.is_initialized());
- EXPECT_TRUE(handle.socket());
- TestLoadTimingInfoConnectedNotReused(handle);
-
- handle.Reset();
- TestLoadTimingInfoNotConnected(handle);
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
-
- EXPECT_EQ(4u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
- EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_SOCKET_POOL));
-}
-
-TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
- CapturingBoundNetLog log;
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- // Set the additional error state members to ensure that they get cleared.
- handle.set_is_ssl_error(true);
- HttpResponseInfo info;
- info.headers = new HttpResponseHeaders(std::string());
- handle.set_ssl_error_response_info(info);
- EXPECT_EQ(ERR_CONNECTION_FAILED,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- log.bound()));
- EXPECT_FALSE(handle.socket());
- EXPECT_FALSE(handle.is_ssl_error());
- EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
- TestLoadTimingInfoNotConnected(handle);
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
-
- EXPECT_EQ(3u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
- EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL));
-}
-
-TEST_F(ClientSocketPoolBaseTest, TotalLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- // TODO(eroman): Check that the NetLog contains this event.
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("c", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("d", DEFAULT_PRIORITY));
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("f", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("g", DEFAULT_PRIORITY));
-
- ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
-
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(3, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
- EXPECT_EQ(5, GetOrderOfRequest(5));
- EXPECT_EQ(6, GetOrderOfRequest(6));
- EXPECT_EQ(7, GetOrderOfRequest(7));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(8));
-}
-
-TEST_F(ClientSocketPoolBaseTest, TotalLimitReachedNewGroup) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- // TODO(eroman): Check that the NetLog contains this event.
-
- // Reach all limits: max total sockets, and max sockets per group.
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
-
- // Now create a new group and verify that we don't starve it.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", DEFAULT_PRIORITY));
-
- ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
-
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(3, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
- EXPECT_EQ(5, GetOrderOfRequest(5));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(6));
-}
-
-TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsPriority) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("b", LOWEST));
- EXPECT_EQ(OK, StartRequest("a", MEDIUM));
- EXPECT_EQ(OK, StartRequest("b", HIGHEST));
- EXPECT_EQ(OK, StartRequest("a", LOWEST));
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", HIGHEST));
-
- ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
-
- EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
-
- // First 4 requests don't have to wait, and finish in order.
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(3, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
-
- // Request ("b", HIGHEST) has the highest priority, then ("a", MEDIUM),
- // and then ("c", LOWEST).
- EXPECT_EQ(7, GetOrderOfRequest(5));
- EXPECT_EQ(6, GetOrderOfRequest(6));
- EXPECT_EQ(5, GetOrderOfRequest(7));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(9));
-}
-
-TEST_F(ClientSocketPoolBaseTest, TotalLimitRespectsGroupLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("a", LOWEST));
- EXPECT_EQ(OK, StartRequest("a", LOW));
- EXPECT_EQ(OK, StartRequest("b", HIGHEST));
- EXPECT_EQ(OK, StartRequest("b", MEDIUM));
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", HIGHEST));
-
- ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSockets, completion_count());
-
- // First 4 requests don't have to wait, and finish in order.
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(3, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
-
- // Request ("b", 7) has the highest priority, but we can't make new socket for
- // group "b", because it has reached the per-group limit. Then we make
- // socket for ("c", 6), because it has higher priority than ("a", 4),
- // and we still can't make a socket for group "b".
- EXPECT_EQ(5, GetOrderOfRequest(5));
- EXPECT_EQ(6, GetOrderOfRequest(6));
- EXPECT_EQ(7, GetOrderOfRequest(7));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(8));
-}
-
-// Make sure that we count connecting sockets against the total limit.
-TEST_F(ClientSocketPoolBaseTest, TotalLimitCountsConnectingSockets) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("c", DEFAULT_PRIORITY));
-
- // Create one asynchronous request.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("d", DEFAULT_PRIORITY));
-
- // We post all of our delayed tasks with a 2ms delay. I.e. they don't
- // actually become pending until 2ms after they have been created. In order
- // to flush all tasks, we need to wait so that we know there are no
- // soon-to-be-pending tasks waiting.
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- base::MessageLoop::current()->RunUntilIdle();
-
- // The next synchronous request should wait for its turn.
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("e", DEFAULT_PRIORITY));
-
- ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
-
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(3, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
- EXPECT_EQ(5, GetOrderOfRequest(5));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(6));
-}
-
-TEST_F(ClientSocketPoolBaseTest, CorrectlyCountStalledGroups) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", DEFAULT_PRIORITY));
-
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
-
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
- EXPECT_EQ(kDefaultMaxSockets + 1, client_socket_factory_.allocation_count());
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
- EXPECT_EQ(kDefaultMaxSockets + 2, client_socket_factory_.allocation_count());
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
- EXPECT_EQ(kDefaultMaxSockets + 2, client_socket_factory_.allocation_count());
-}
-
-TEST_F(ClientSocketPoolBaseTest, StallAndThenCancelAndTriggerAvailableSocket) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ClientSocketHandle handles[4];
- for (size_t i = 0; i < arraysize(handles); ++i) {
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handles[i].Init("b",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- // One will be stalled, cancel all the handles now.
- // This should hit the OnAvailableSocketSlot() code where we previously had
- // stalled groups, but no longer have any.
- for (size_t i = 0; i < arraysize(handles); ++i)
- handles[i].Reset();
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelStalledSocketAtSocketLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- {
- ClientSocketHandle handles[kDefaultMaxSockets];
- TestCompletionCallback callbacks[kDefaultMaxSockets];
- for (int i = 0; i < kDefaultMaxSockets; ++i) {
- EXPECT_EQ(OK, handles[i].Init(base::IntToString(i),
- params_,
- DEFAULT_PRIORITY,
- callbacks[i].callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- // Force a stalled group.
- ClientSocketHandle stalled_handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- // Cancel the stalled request.
- stalled_handle.Reset();
-
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
- EXPECT_EQ(0, pool_->IdleSocketCount());
-
- // Dropping out of scope will close all handles and return them to idle.
- }
-
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
- EXPECT_EQ(kDefaultMaxSockets, pool_->IdleSocketCount());
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelPendingSocketAtSocketLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- {
- ClientSocketHandle handles[kDefaultMaxSockets];
- for (int i = 0; i < kDefaultMaxSockets; ++i) {
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handles[i].Init(base::IntToString(i),
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- // Force a stalled group.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle stalled_handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- // Since it is stalled, it should have no connect jobs.
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("foo"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("foo"));
-
- // Cancel the stalled request.
- handles[0].Reset();
-
- // Now we should have a connect job.
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("foo"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("foo"));
-
- // The stalled socket should connect.
- EXPECT_EQ(OK, callback.WaitForResult());
-
- EXPECT_EQ(kDefaultMaxSockets + 1,
- client_socket_factory_.allocation_count());
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("foo"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("foo"));
-
- // Dropping out of scope will close all handles and return them to idle.
- }
-
- EXPECT_EQ(1, pool_->IdleSocketCount());
-}
-
-TEST_F(ClientSocketPoolBaseTest, WaitForStalledSocketAtSocketLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- ClientSocketHandle stalled_handle;
- TestCompletionCallback callback;
- {
- EXPECT_FALSE(pool_->IsStalled());
- ClientSocketHandle handles[kDefaultMaxSockets];
- for (int i = 0; i < kDefaultMaxSockets; ++i) {
- TestCompletionCallback callback;
- EXPECT_EQ(OK, handles[i].Init(base::StringPrintf(
- "Take 2: %d", i),
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_FALSE(pool_->IsStalled());
-
- // Now we will hit the socket limit.
- EXPECT_EQ(ERR_IO_PENDING, stalled_handle.Init("foo",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_TRUE(pool_->IsStalled());
-
- // Dropping out of scope will close all handles and return them to idle.
- }
-
- // But if we wait for it, the released idle sockets will be closed in
- // preference of the waiting request.
- EXPECT_EQ(OK, callback.WaitForResult());
-
- EXPECT_EQ(kDefaultMaxSockets + 1, client_socket_factory_.allocation_count());
- EXPECT_EQ(3, pool_->IdleSocketCount());
-}
-
-// Regression test for http://crbug.com/40952.
-TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketAtSocketLimitDeleteGroup) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- pool_->EnableConnectBackupJobs();
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- for (int i = 0; i < kDefaultMaxSockets; ++i) {
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init(base::IntToString(i),
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- // Flush all the DoReleaseSocket tasks.
- base::MessageLoop::current()->RunUntilIdle();
-
- // Stall a group. Set a pending job so it'll trigger a backup job if we don't
- // reuse a socket.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
-
- // "0" is special here, since it should be the first entry in the sorted map,
- // which is the one which we would close an idle socket for. We shouldn't
- // close an idle socket though, since we should reuse the idle socket.
- EXPECT_EQ(OK, handle.Init("0",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
- EXPECT_EQ(kDefaultMaxSockets - 1, pool_->IdleSocketCount());
-}
-
-TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", IDLE));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
-
- ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
-
- EXPECT_EQ(kDefaultMaxSocketsPerGroup,
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup,
- completion_count());
-
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(8, GetOrderOfRequest(3));
- EXPECT_EQ(6, GetOrderOfRequest(4));
- EXPECT_EQ(4, GetOrderOfRequest(5));
- EXPECT_EQ(3, GetOrderOfRequest(6));
- EXPECT_EQ(5, GetOrderOfRequest(7));
- EXPECT_EQ(7, GetOrderOfRequest(8));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(9));
-}
-
-TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
-
- ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE);
-
- for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_size(); ++i)
- EXPECT_EQ(OK, request(i)->WaitForResult());
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup,
- completion_count());
-}
-
-// This test will start up a RequestSocket() and then immediately Cancel() it.
-// The pending connect job will be cancelled and should not call back into
-// ClientSocketPoolBase.
-TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- handle.Reset();
-}
-
-TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
-
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- handle.Reset();
-
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_FALSE(callback.have_result());
-
- handle.Reset();
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelRequest) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
-
- // Cancel a request.
- size_t index_to_cancel = kDefaultMaxSocketsPerGroup + 2;
- EXPECT_FALSE((*requests())[index_to_cancel]->handle()->is_initialized());
- (*requests())[index_to_cancel]->handle()->Reset();
-
- ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE);
-
- EXPECT_EQ(kDefaultMaxSocketsPerGroup,
- client_socket_factory_.allocation_count());
- EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup - 1,
- completion_count());
-
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(5, GetOrderOfRequest(3));
- EXPECT_EQ(3, GetOrderOfRequest(4));
- EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound,
- GetOrderOfRequest(5)); // Canceled request.
- EXPECT_EQ(4, GetOrderOfRequest(6));
- EXPECT_EQ(6, GetOrderOfRequest(7));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(8));
-}
-
-class RequestSocketCallback : public TestCompletionCallbackBase {
- public:
- RequestSocketCallback(ClientSocketHandle* handle,
- TestClientSocketPool* pool,
- TestConnectJobFactory* test_connect_job_factory,
- TestConnectJob::JobType next_job_type)
- : handle_(handle),
- pool_(pool),
- within_callback_(false),
- test_connect_job_factory_(test_connect_job_factory),
- next_job_type_(next_job_type),
- callback_(base::Bind(&RequestSocketCallback::OnComplete,
- base::Unretained(this))) {
- }
-
- ~RequestSocketCallback() override {}
-
- const CompletionCallback& callback() const { return callback_; }
-
- private:
- void OnComplete(int result) {
- SetResult(result);
- ASSERT_EQ(OK, result);
-
- if (!within_callback_) {
- test_connect_job_factory_->set_job_type(next_job_type_);
-
- // Don't allow reuse of the socket. Disconnect it and then release it and
- // run through the MessageLoop once to get it completely released.
- handle_->socket()->Disconnect();
- handle_->Reset();
- {
- // TODO: Resolve conflicting intentions of stopping recursion with the
- // |!within_callback_| test (above) and the call to |RunUntilIdle()|
- // below. http://crbug.com/114130.
- base::MessageLoop::ScopedNestableTaskAllower allow(
- base::MessageLoop::current());
- base::MessageLoop::current()->RunUntilIdle();
- }
- within_callback_ = true;
- TestCompletionCallback next_job_callback;
- scoped_refptr<TestSocketParams> params(
- new TestSocketParams(false /* ignore_limits */));
- int rv = handle_->Init("a",
- params,
- DEFAULT_PRIORITY,
- next_job_callback.callback(),
- pool_,
- BoundNetLog());
- switch (next_job_type_) {
- case TestConnectJob::kMockJob:
- EXPECT_EQ(OK, rv);
- break;
- case TestConnectJob::kMockPendingJob:
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // For pending jobs, wait for new socket to be created. This makes
- // sure there are no more pending operations nor any unclosed sockets
- // when the test finishes.
- // We need to give it a little bit of time to run, so that all the
- // operations that happen on timers (e.g. cleanup of idle
- // connections) can execute.
- {
- base::MessageLoop::ScopedNestableTaskAllower allow(
- base::MessageLoop::current());
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- EXPECT_EQ(OK, next_job_callback.WaitForResult());
- }
- break;
- default:
- FAIL() << "Unexpected job type: " << next_job_type_;
- break;
- }
- }
- }
-
- ClientSocketHandle* const handle_;
- TestClientSocketPool* const pool_;
- bool within_callback_;
- TestConnectJobFactory* const test_connect_job_factory_;
- TestConnectJob::JobType next_job_type_;
- CompletionCallback callback_;
-};
-
-TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- RequestSocketCallback callback(
- &handle, pool_.get(), connect_job_factory_,
- TestConnectJob::kMockPendingJob);
- int rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
-
- EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- RequestSocketCallback callback(
- &handle, pool_.get(), connect_job_factory_, TestConnectJob::kMockJob);
- int rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
-
- EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-// Make sure that pending requests get serviced after active requests get
-// cancelled.
-TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
-
- // Now, kDefaultMaxSocketsPerGroup requests should be active.
- // Let's cancel them.
- for (int i = 0; i < kDefaultMaxSocketsPerGroup; ++i) {
- ASSERT_FALSE(request(i)->handle()->is_initialized());
- request(i)->handle()->Reset();
- }
-
- // Let's wait for the rest to complete now.
- for (size_t i = kDefaultMaxSocketsPerGroup; i < requests_size(); ++i) {
- EXPECT_EQ(OK, request(i)->WaitForResult());
- request(i)->handle()->Reset();
- }
-
- EXPECT_EQ(requests_size() - kDefaultMaxSocketsPerGroup,
- completion_count());
-}
-
-// Make sure that pending requests get serviced after active requests fail.
-TEST_F(ClientSocketPoolBaseTest, FailingActiveRequestWithPendingRequests) {
- const size_t kMaxSockets = 5;
- CreatePool(kMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
-
- const size_t kNumberOfRequests = 2 * kDefaultMaxSocketsPerGroup + 1;
- ASSERT_LE(kNumberOfRequests, kMaxSockets); // Otherwise the test will hang.
-
- // Queue up all the requests
- for (size_t i = 0; i < kNumberOfRequests; ++i)
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
-
- for (size_t i = 0; i < kNumberOfRequests; ++i)
- EXPECT_EQ(ERR_CONNECTION_FAILED, request(i)->WaitForResult());
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestThenRequestSocket) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Cancel the active request.
- handle.Reset();
-
- rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback.WaitForResult());
-
- EXPECT_FALSE(handle.is_reused());
- TestLoadTimingInfoConnectedNotReused(handle);
- EXPECT_EQ(2, client_socket_factory_.allocation_count());
-}
-
-// Regression test for http://crbug.com/17985.
-TEST_F(ClientSocketPoolBaseTest, GroupWithPendingRequestsIsNotEmpty) {
- const int kMaxSockets = 3;
- const int kMaxSocketsPerGroup = 2;
- CreatePool(kMaxSockets, kMaxSocketsPerGroup);
-
- const RequestPriority kHighPriority = HIGHEST;
-
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
-
- // This is going to be a pending request in an otherwise empty group.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
-
- // Reach the maximum socket limit.
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
-
- // Create a stalled group with high priorities.
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kHighPriority));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("c", kHighPriority));
-
- // Release the first two sockets from "a". Because this is a keepalive,
- // the first release will unblock the pending request for "a". The
- // second release will unblock a request for "c", becaue it is the next
- // high priority socket.
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::KEEP_ALIVE));
-
- // Closing idle sockets should not get us into trouble, but in the bug
- // we were hitting a CHECK here.
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- pool_->CloseIdleSockets();
-
- // Run the released socket wakeups.
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-TEST_F(ClientSocketPoolBaseTest, BasicAsynchronous) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- CapturingBoundNetLog log;
- int rv = handle.Init("a",
- params_,
- LOWEST,
- callback.callback(),
- pool_.get(),
- log.bound());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- TestLoadTimingInfoNotConnected(handle);
-
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_TRUE(handle.is_initialized());
- EXPECT_TRUE(handle.socket());
- TestLoadTimingInfoConnectedNotReused(handle);
-
- handle.Reset();
- TestLoadTimingInfoNotConnected(handle);
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
-
- EXPECT_EQ(4u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
- EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 3, NetLog::TYPE_SOCKET_POOL));
-}
-
-TEST_F(ClientSocketPoolBaseTest,
- InitConnectionAsynchronousFailure) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- CapturingBoundNetLog log;
- // Set the additional error state members to ensure that they get cleared.
- handle.set_is_ssl_error(true);
- HttpResponseInfo info;
- info.headers = new HttpResponseHeaders(std::string());
- handle.set_ssl_error_response_info(info);
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- log.bound()));
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
- EXPECT_FALSE(handle.is_ssl_error());
- EXPECT_TRUE(handle.ssl_error_response_info().headers.get() == NULL);
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
-
- EXPECT_EQ(3u, entries.size());
- EXPECT_TRUE(LogContainsBeginEvent(
- entries, 0, NetLog::TYPE_SOCKET_POOL));
- EXPECT_TRUE(LogContainsEvent(
- entries, 1, NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB,
- NetLog::PHASE_NONE));
- EXPECT_TRUE(LogContainsEndEvent(
- entries, 2, NetLog::TYPE_SOCKET_POOL));
-}
-
-TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
- // TODO(eroman): Add back the log expectations! Removed them because the
- // ordering is difficult, and some may fire during destructor.
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
-
- EXPECT_EQ(ERR_IO_PENDING,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- CapturingBoundNetLog log2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- handle.Reset();
-
-
- // At this point, request 2 is just waiting for the connect job to finish.
-
- EXPECT_EQ(OK, callback2.WaitForResult());
- handle2.Reset();
-
- // Now request 2 has actually finished.
- // TODO(eroman): Add back log expectations.
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelRequestLimitsJobs) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOWEST));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", LOW));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", MEDIUM));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", HIGHEST));
-
- EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
- (*requests())[2]->handle()->Reset();
- (*requests())[3]->handle()->Reset();
- EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
-
- (*requests())[1]->handle()->Reset();
- EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
-
- (*requests())[0]->handle()->Reset();
- EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->NumConnectJobsInGroup("a"));
-}
-
-// When requests and ConnectJobs are not coupled, the request will get serviced
-// by whatever comes first.
-TEST_F(ClientSocketPoolBaseTest, ReleaseSockets) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- // Start job 1 (async OK)
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- std::vector<TestSocketRequest*> request_order;
- size_t completion_count; // unused
- TestSocketRequest req1(&request_order, &completion_count);
- int rv = req1.handle()->Init("a",
- params_,
- DEFAULT_PRIORITY,
- req1.callback(), pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, req1.WaitForResult());
-
- // Job 1 finished OK. Start job 2 (also async OK). Request 3 is pending
- // without a job.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- TestSocketRequest req2(&request_order, &completion_count);
- rv = req2.handle()->Init("a",
- params_,
- DEFAULT_PRIORITY,
- req2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- TestSocketRequest req3(&request_order, &completion_count);
- rv = req3.handle()->Init("a",
- params_,
- DEFAULT_PRIORITY,
- req3.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Both Requests 2 and 3 are pending. We release socket 1 which should
- // service request 2. Request 3 should still be waiting.
- req1.handle()->Reset();
- // Run the released socket wakeups.
- base::MessageLoop::current()->RunUntilIdle();
- ASSERT_TRUE(req2.handle()->socket());
- EXPECT_EQ(OK, req2.WaitForResult());
- EXPECT_FALSE(req3.handle()->socket());
-
- // Signal job 2, which should service request 3.
-
- client_socket_factory_.SignalJobs();
- EXPECT_EQ(OK, req3.WaitForResult());
-
- ASSERT_EQ(3U, request_order.size());
- EXPECT_EQ(&req1, request_order[0]);
- EXPECT_EQ(&req2, request_order[1]);
- EXPECT_EQ(&req3, request_order[2]);
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-}
-
-// The requests are not coupled to the jobs. So, the requests should finish in
-// their priority / insertion order.
-TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- // First two jobs are async.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
-
- std::vector<TestSocketRequest*> request_order;
- size_t completion_count; // unused
- TestSocketRequest req1(&request_order, &completion_count);
- int rv = req1.handle()->Init("a",
- params_,
- DEFAULT_PRIORITY,
- req1.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- TestSocketRequest req2(&request_order, &completion_count);
- rv = req2.handle()->Init("a",
- params_,
- DEFAULT_PRIORITY,
- req2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // The pending job is sync.
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- TestSocketRequest req3(&request_order, &completion_count);
- rv = req3.handle()->Init("a",
- params_,
- DEFAULT_PRIORITY,
- req3.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- EXPECT_EQ(ERR_CONNECTION_FAILED, req1.WaitForResult());
- EXPECT_EQ(OK, req2.WaitForResult());
- EXPECT_EQ(ERR_CONNECTION_FAILED, req3.WaitForResult());
-
- ASSERT_EQ(3U, request_order.size());
- EXPECT_EQ(&req1, request_order[0]);
- EXPECT_EQ(&req2, request_order[1]);
- EXPECT_EQ(&req3, request_order[2]);
-}
-
-// Test GetLoadState in the case there's only one socket request.
-TEST_F(ClientSocketPoolBaseTest, LoadStateOneRequest) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
-
- client_socket_factory_.SetJobLoadState(0, LOAD_STATE_SSL_HANDSHAKE);
- EXPECT_EQ(LOAD_STATE_SSL_HANDSHAKE, handle.GetLoadState());
-
- // No point in completing the connection, since ClientSocketHandles only
- // expect the LoadState to be checked while connecting.
-}
-
-// Test GetLoadState in the case there are two socket requests.
-TEST_F(ClientSocketPoolBaseTest, LoadStateTwoRequests) {
- CreatePool(2, 2);
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- rv = handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // If the first Job is in an earlier state than the second, the state of
- // the second job should be used for both handles.
- client_socket_factory_.SetJobLoadState(0, LOAD_STATE_RESOLVING_HOST);
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle2.GetLoadState());
-
- // If the second Job is in an earlier state than the second, the state of
- // the first job should be used for both handles.
- client_socket_factory_.SetJobLoadState(0, LOAD_STATE_SSL_HANDSHAKE);
- // One request is farther
- EXPECT_EQ(LOAD_STATE_SSL_HANDSHAKE, handle.GetLoadState());
- EXPECT_EQ(LOAD_STATE_SSL_HANDSHAKE, handle2.GetLoadState());
-
- // Farthest along job connects and the first request gets the socket. The
- // second handle switches to the state of the remaining ConnectJob.
- client_socket_factory_.SignalJob(0);
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle2.GetLoadState());
-}
-
-// Test GetLoadState in the case the per-group limit is reached.
-TEST_F(ClientSocketPoolBaseTest, LoadStateGroupLimit) {
- CreatePool(2, 1);
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- MEDIUM,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
-
- // Request another socket from the same pool, buth with a higher priority.
- // The first request should now be stalled at the socket group limit.
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- rv = handle2.Init("a",
- params_,
- HIGHEST,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET, handle.GetLoadState());
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle2.GetLoadState());
-
- // The first handle should remain stalled as the other socket goes through
- // the connect process.
-
- client_socket_factory_.SetJobLoadState(0, LOAD_STATE_SSL_HANDSHAKE);
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET, handle.GetLoadState());
- EXPECT_EQ(LOAD_STATE_SSL_HANDSHAKE, handle2.GetLoadState());
-
- client_socket_factory_.SignalJob(0);
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET, handle.GetLoadState());
-
- // Closing the second socket should cause the stalled handle to finally get a
- // ConnectJob.
- handle2.socket()->Disconnect();
- handle2.Reset();
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
-}
-
-// Test GetLoadState in the case the per-pool limit is reached.
-TEST_F(ClientSocketPoolBaseTest, LoadStatePoolLimit) {
- CreatePool(2, 2);
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Request for socket from another pool.
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- rv = handle2.Init("b",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Request another socket from the first pool. Request should stall at the
- // socket pool limit.
- ClientSocketHandle handle3;
- TestCompletionCallback callback3;
- rv = handle3.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // The third handle should remain stalled as the other sockets in its group
- // goes through the connect process.
-
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle.GetLoadState());
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL, handle3.GetLoadState());
-
- client_socket_factory_.SetJobLoadState(0, LOAD_STATE_SSL_HANDSHAKE);
- EXPECT_EQ(LOAD_STATE_SSL_HANDSHAKE, handle.GetLoadState());
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL, handle3.GetLoadState());
-
- client_socket_factory_.SignalJob(0);
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_EQ(LOAD_STATE_WAITING_FOR_STALLED_SOCKET_POOL, handle3.GetLoadState());
-
- // Closing a socket should allow the stalled handle to finally get a new
- // ConnectJob.
- handle.socket()->Disconnect();
- handle.Reset();
- EXPECT_EQ(LOAD_STATE_CONNECTING, handle3.GetLoadState());
-}
-
-TEST_F(ClientSocketPoolBaseTest, Recoverable) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockRecoverableJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED,
- handle.Init("a", params_, DEFAULT_PRIORITY, callback.callback(),
- pool_.get(), BoundNetLog()));
- EXPECT_TRUE(handle.is_initialized());
- EXPECT_TRUE(handle.socket());
-}
-
-TEST_F(ClientSocketPoolBaseTest, AsyncRecoverable) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(
- TestConnectJob::kMockPendingRecoverableJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- EXPECT_EQ(ERR_PROXY_AUTH_REQUESTED, callback.WaitForResult());
- EXPECT_TRUE(handle.is_initialized());
- EXPECT_TRUE(handle.socket());
-}
-
-TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateSynchronous) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(
- TestConnectJob::kMockAdditionalErrorStateJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_CONNECTION_FAILED,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
- EXPECT_TRUE(handle.is_ssl_error());
- EXPECT_FALSE(handle.ssl_error_response_info().headers.get() == NULL);
-}
-
-TEST_F(ClientSocketPoolBaseTest, AdditionalErrorStateAsynchronous) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(
- TestConnectJob::kMockPendingAdditionalErrorStateJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult());
- EXPECT_FALSE(handle.is_initialized());
- EXPECT_FALSE(handle.socket());
- EXPECT_TRUE(handle.is_ssl_error());
- EXPECT_FALSE(handle.ssl_error_response_info().headers.get() == NULL);
-}
-
-// Make sure we can reuse sockets when the cleanup timer is disabled.
-TEST_F(ClientSocketPoolBaseTest, DisableCleanupTimerReuse) {
- // Disable cleanup timer.
- internal::ClientSocketPoolBaseHelper::set_cleanup_timer_enabled(false);
-
- CreatePoolWithIdleTimeouts(
- kDefaultMaxSockets, kDefaultMaxSocketsPerGroup,
- base::TimeDelta(), // Time out unused sockets immediately.
- base::TimeDelta::FromDays(1)); // Don't time out used sockets.
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- LOWEST,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
- ASSERT_EQ(OK, callback.WaitForResult());
-
- // Use and release the socket.
- EXPECT_EQ(1, handle.socket()->Write(NULL, 1, CompletionCallback()));
- TestLoadTimingInfoConnectedNotReused(handle);
- handle.Reset();
-
- // Should now have one idle socket.
- ASSERT_EQ(1, pool_->IdleSocketCount());
-
- // Request a new socket. This should reuse the old socket and complete
- // synchronously.
- CapturingBoundNetLog log;
- rv = handle.Init("a",
- params_,
- LOWEST,
- CompletionCallback(),
- pool_.get(),
- log.bound());
- ASSERT_EQ(OK, rv);
- EXPECT_TRUE(handle.is_reused());
- TestLoadTimingInfoConnectedReused(handle);
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEntryWithType(
- entries, 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
-}
-
-// Make sure we cleanup old unused sockets when the cleanup timer is disabled.
-TEST_F(ClientSocketPoolBaseTest, DisableCleanupTimerNoReuse) {
- // Disable cleanup timer.
- internal::ClientSocketPoolBaseHelper::set_cleanup_timer_enabled(false);
-
- CreatePoolWithIdleTimeouts(
- kDefaultMaxSockets, kDefaultMaxSocketsPerGroup,
- base::TimeDelta(), // Time out unused sockets immediately
- base::TimeDelta()); // Time out used sockets immediately
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- // Startup two mock pending connect jobs, which will sit in the MessageLoop.
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- LOWEST,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- rv = handle2.Init("a",
- params_,
- LOWEST,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- ASSERT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle2));
-
- // Cancel one of the requests. Wait for the other, which will get the first
- // job. Release the socket. Run the loop again to make sure the second
- // socket is sitting idle and the first one is released (since ReleaseSocket()
- // just posts a DoReleaseSocket() task).
-
- handle.Reset();
- ASSERT_EQ(OK, callback2.WaitForResult());
- // Use the socket.
- EXPECT_EQ(1, handle2.socket()->Write(NULL, 1, CompletionCallback()));
- handle2.Reset();
-
- // We post all of our delayed tasks with a 2ms delay. I.e. they don't
- // actually become pending until 2ms after they have been created. In order
- // to flush all tasks, we need to wait so that we know there are no
- // soon-to-be-pending tasks waiting.
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- base::MessageLoop::current()->RunUntilIdle();
-
- // Both sockets should now be idle.
- ASSERT_EQ(2, pool_->IdleSocketCount());
-
- // Request a new socket. This should cleanup the unused and timed out ones.
- // A new socket will be created rather than reusing the idle one.
- CapturingBoundNetLog log;
- TestCompletionCallback callback3;
- rv = handle.Init("a",
- params_,
- LOWEST,
- callback3.callback(),
- pool_.get(),
- log.bound());
- ASSERT_EQ(ERR_IO_PENDING, rv);
- ASSERT_EQ(OK, callback3.WaitForResult());
- EXPECT_FALSE(handle.is_reused());
-
- // Make sure the idle socket is closed.
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
- EXPECT_FALSE(LogContainsEntryWithType(
- entries, 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
-}
-
-TEST_F(ClientSocketPoolBaseTest, CleanupTimedOutIdleSockets) {
- CreatePoolWithIdleTimeouts(
- kDefaultMaxSockets, kDefaultMaxSocketsPerGroup,
- base::TimeDelta(), // Time out unused sockets immediately.
- base::TimeDelta::FromDays(1)); // Don't time out used sockets.
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- // Startup two mock pending connect jobs, which will sit in the MessageLoop.
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- LOWEST,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle));
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- rv = handle2.Init("a",
- params_,
- LOWEST,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(LOAD_STATE_CONNECTING, pool_->GetLoadState("a", &handle2));
-
- // Cancel one of the requests. Wait for the other, which will get the first
- // job. Release the socket. Run the loop again to make sure the second
- // socket is sitting idle and the first one is released (since ReleaseSocket()
- // just posts a DoReleaseSocket() task).
-
- handle.Reset();
- EXPECT_EQ(OK, callback2.WaitForResult());
- // Use the socket.
- EXPECT_EQ(1, handle2.socket()->Write(NULL, 1, CompletionCallback()));
- handle2.Reset();
-
- // We post all of our delayed tasks with a 2ms delay. I.e. they don't
- // actually become pending until 2ms after they have been created. In order
- // to flush all tasks, we need to wait so that we know there are no
- // soon-to-be-pending tasks waiting.
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(10));
- base::MessageLoop::current()->RunUntilIdle();
-
- ASSERT_EQ(2, pool_->IdleSocketCount());
-
- // Invoke the idle socket cleanup check. Only one socket should be left, the
- // used socket. Request it to make sure that it's used.
-
- pool_->CleanupTimedOutIdleSockets();
- CapturingBoundNetLog log;
- rv = handle.Init("a",
- params_,
- LOWEST,
- callback.callback(),
- pool_.get(),
- log.bound());
- EXPECT_EQ(OK, rv);
- EXPECT_TRUE(handle.is_reused());
-
- CapturingNetLog::CapturedEntryList entries;
- log.GetEntries(&entries);
- EXPECT_TRUE(LogContainsEntryWithType(
- entries, 1, NetLog::TYPE_SOCKET_POOL_REUSED_AN_EXISTING_SOCKET));
-}
-
-// Make sure that we process all pending requests even when we're stalling
-// because of multiple releasing disconnected sockets.
-TEST_F(ClientSocketPoolBaseTest, MultipleReleasingDisconnectedSockets) {
- CreatePoolWithIdleTimeouts(
- kDefaultMaxSockets, kDefaultMaxSocketsPerGroup,
- base::TimeDelta(), // Time out unused sockets immediately.
- base::TimeDelta::FromDays(1)); // Don't time out used sockets.
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- // Startup 4 connect jobs. Two of them will be pending.
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- int rv = handle.Init("a",
- params_,
- LOWEST,
- callback.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(OK, rv);
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- rv = handle2.Init("a",
- params_,
- LOWEST,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(OK, rv);
-
- ClientSocketHandle handle3;
- TestCompletionCallback callback3;
- rv = handle3.Init("a",
- params_,
- LOWEST,
- callback3.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- ClientSocketHandle handle4;
- TestCompletionCallback callback4;
- rv = handle4.Init("a",
- params_,
- LOWEST,
- callback4.callback(),
- pool_.get(),
- BoundNetLog());
- EXPECT_EQ(ERR_IO_PENDING, rv);
-
- // Release two disconnected sockets.
-
- handle.socket()->Disconnect();
- handle.Reset();
- handle2.socket()->Disconnect();
- handle2.Reset();
-
- EXPECT_EQ(OK, callback3.WaitForResult());
- EXPECT_FALSE(handle3.is_reused());
- EXPECT_EQ(OK, callback4.WaitForResult());
- EXPECT_FALSE(handle4.is_reused());
-}
-
-// Regression test for http://crbug.com/42267.
-// When DoReleaseSocket() is processed for one socket, it is blocked because the
-// other stalled groups all have releasing sockets, so no progress can be made.
-TEST_F(ClientSocketPoolBaseTest, SocketLimitReleasingSockets) {
- CreatePoolWithIdleTimeouts(
- 4 /* socket limit */, 4 /* socket limit per group */,
- base::TimeDelta(), // Time out unused sockets immediately.
- base::TimeDelta::FromDays(1)); // Don't time out used sockets.
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- // Max out the socket limit with 2 per group.
-
- ClientSocketHandle handle_a[4];
- TestCompletionCallback callback_a[4];
- ClientSocketHandle handle_b[4];
- TestCompletionCallback callback_b[4];
-
- for (int i = 0; i < 2; ++i) {
- EXPECT_EQ(OK, handle_a[i].Init("a",
- params_,
- LOWEST,
- callback_a[i].callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, handle_b[i].Init("b",
- params_,
- LOWEST,
- callback_b[i].callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- // Make 4 pending requests, 2 per group.
-
- for (int i = 2; i < 4; ++i) {
- EXPECT_EQ(ERR_IO_PENDING,
- handle_a[i].Init("a",
- params_,
- LOWEST,
- callback_a[i].callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(ERR_IO_PENDING,
- handle_b[i].Init("b",
- params_,
- LOWEST,
- callback_b[i].callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- // Release b's socket first. The order is important, because in
- // DoReleaseSocket(), we'll process b's released socket, and since both b and
- // a are stalled, but 'a' is lower lexicographically, we'll process group 'a'
- // first, which has a releasing socket, so it refuses to start up another
- // ConnectJob. So, we used to infinite loop on this.
- handle_b[0].socket()->Disconnect();
- handle_b[0].Reset();
- handle_a[0].socket()->Disconnect();
- handle_a[0].Reset();
-
- // Used to get stuck here.
- base::MessageLoop::current()->RunUntilIdle();
-
- handle_b[1].socket()->Disconnect();
- handle_b[1].Reset();
- handle_a[1].socket()->Disconnect();
- handle_a[1].Reset();
-
- for (int i = 2; i < 4; ++i) {
- EXPECT_EQ(OK, callback_b[i].WaitForResult());
- EXPECT_EQ(OK, callback_a[i].WaitForResult());
- }
-}
-
-TEST_F(ClientSocketPoolBaseTest,
- ReleasingDisconnectedSocketsMaintainsPriorityOrder) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", DEFAULT_PRIORITY));
-
- EXPECT_EQ(OK, (*requests())[0]->WaitForResult());
- EXPECT_EQ(OK, (*requests())[1]->WaitForResult());
- EXPECT_EQ(2u, completion_count());
-
- // Releases one connection.
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE));
- EXPECT_EQ(OK, (*requests())[2]->WaitForResult());
-
- EXPECT_TRUE(ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE));
- EXPECT_EQ(OK, (*requests())[3]->WaitForResult());
- EXPECT_EQ(4u, completion_count());
-
- EXPECT_EQ(1, GetOrderOfRequest(1));
- EXPECT_EQ(2, GetOrderOfRequest(2));
- EXPECT_EQ(3, GetOrderOfRequest(3));
- EXPECT_EQ(4, GetOrderOfRequest(4));
-
- // Make sure we test order of all requests made.
- EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(5));
-}
-
-class TestReleasingSocketRequest : public TestCompletionCallbackBase {
- public:
- TestReleasingSocketRequest(TestClientSocketPool* pool,
- int expected_result,
- bool reset_releasing_handle)
- : pool_(pool),
- expected_result_(expected_result),
- reset_releasing_handle_(reset_releasing_handle),
- callback_(base::Bind(&TestReleasingSocketRequest::OnComplete,
- base::Unretained(this))) {
- }
-
- ~TestReleasingSocketRequest() override {}
-
- ClientSocketHandle* handle() { return &handle_; }
-
- const CompletionCallback& callback() const { return callback_; }
-
- private:
- void OnComplete(int result) {
- SetResult(result);
- if (reset_releasing_handle_)
- handle_.Reset();
-
- scoped_refptr<TestSocketParams> con_params(
- new TestSocketParams(false /* ignore_limits */));
- EXPECT_EQ(expected_result_,
- handle2_.Init("a", con_params, DEFAULT_PRIORITY,
- callback2_.callback(), pool_, BoundNetLog()));
- }
-
- TestClientSocketPool* const pool_;
- int expected_result_;
- bool reset_releasing_handle_;
- ClientSocketHandle handle_;
- ClientSocketHandle handle2_;
- CompletionCallback callback_;
- TestCompletionCallback callback2_;
-};
-
-
-TEST_F(ClientSocketPoolBaseTest, AdditionalErrorSocketsDontUseSlot) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("a", DEFAULT_PRIORITY));
- EXPECT_EQ(OK, StartRequest("b", DEFAULT_PRIORITY));
-
- EXPECT_EQ(static_cast<int>(requests_size()),
- client_socket_factory_.allocation_count());
-
- connect_job_factory_->set_job_type(
- TestConnectJob::kMockPendingAdditionalErrorStateJob);
- TestReleasingSocketRequest req(pool_.get(), OK, false);
- EXPECT_EQ(ERR_IO_PENDING,
- req.handle()->Init("a", params_, DEFAULT_PRIORITY, req.callback(),
- pool_.get(), BoundNetLog()));
- // The next job should complete synchronously
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult());
- EXPECT_FALSE(req.handle()->is_initialized());
- EXPECT_FALSE(req.handle()->socket());
- EXPECT_TRUE(req.handle()->is_ssl_error());
- EXPECT_FALSE(req.handle()->ssl_error_response_info().headers.get() == NULL);
-}
-
-// http://crbug.com/44724 regression test.
-// We start releasing the pool when we flush on network change. When that
-// happens, the only active references are in the ClientSocketHandles. When a
-// ConnectJob completes and calls back into the last ClientSocketHandle, that
-// callback can release the last reference and delete the pool. After the
-// callback finishes, we go back to the stack frame within the now-deleted pool.
-// Executing any code that refers to members of the now-deleted pool can cause
-// crashes.
-TEST_F(ClientSocketPoolBaseTest, CallbackThatReleasesPool) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- pool_->FlushWithError(ERR_NETWORK_CHANGED);
-
- // We'll call back into this now.
- callback.WaitForResult();
-}
-
-TEST_F(ClientSocketPoolBaseTest, DoNotReuseSocketAfterFlush) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
-
- pool_->FlushWithError(ERR_NETWORK_CHANGED);
-
- handle.Reset();
- base::MessageLoop::current()->RunUntilIdle();
-
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
- EXPECT_EQ(ClientSocketHandle::UNUSED, handle.reuse_type());
-}
-
-class ConnectWithinCallback : public TestCompletionCallbackBase {
- public:
- ConnectWithinCallback(
- const std::string& group_name,
- const scoped_refptr<TestSocketParams>& params,
- TestClientSocketPool* pool)
- : group_name_(group_name),
- params_(params),
- pool_(pool),
- callback_(base::Bind(&ConnectWithinCallback::OnComplete,
- base::Unretained(this))) {
- }
-
- ~ConnectWithinCallback() override {}
-
- int WaitForNestedResult() {
- return nested_callback_.WaitForResult();
- }
-
- const CompletionCallback& callback() const { return callback_; }
-
- private:
- void OnComplete(int result) {
- SetResult(result);
- EXPECT_EQ(ERR_IO_PENDING,
- handle_.Init(group_name_,
- params_,
- DEFAULT_PRIORITY,
- nested_callback_.callback(),
- pool_,
- BoundNetLog()));
- }
-
- const std::string group_name_;
- const scoped_refptr<TestSocketParams> params_;
- TestClientSocketPool* const pool_;
- ClientSocketHandle handle_;
- CompletionCallback callback_;
- TestCompletionCallback nested_callback_;
-
- DISALLOW_COPY_AND_ASSIGN(ConnectWithinCallback);
-};
-
-TEST_F(ClientSocketPoolBaseTest, AbortAllRequestsOnFlush) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
-
- // First job will be waiting until it gets aborted.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
-
- ClientSocketHandle handle;
- ConnectWithinCallback callback("a", params_, pool_.get());
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- // Second job will be started during the first callback, and will
- // asynchronously complete with OK.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- pool_->FlushWithError(ERR_NETWORK_CHANGED);
- EXPECT_EQ(ERR_NETWORK_CHANGED, callback.WaitForResult());
- EXPECT_EQ(OK, callback.WaitForNestedResult());
-}
-
-// Cancel a pending socket request while we're at max sockets,
-// and verify that the backup socket firing doesn't cause a crash.
-TEST_F(ClientSocketPoolBaseTest, BackupSocketCancelAtMaxSockets) {
- // Max 4 sockets globally, max 4 sockets per group.
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- pool_->EnableConnectBackupJobs();
-
- // Create the first socket and set to ERR_IO_PENDING. This starts the backup
- // timer.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- // Start (MaxSockets - 1) connected sockets to reach max sockets.
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- ClientSocketHandle handles[kDefaultMaxSockets];
- for (int i = 1; i < kDefaultMaxSockets; ++i) {
- TestCompletionCallback callback;
- EXPECT_EQ(OK, handles[i].Init("bar",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- }
-
- base::MessageLoop::current()->RunUntilIdle();
-
- // Cancel the pending request.
- handle.Reset();
-
- // Wait for the backup timer to fire (add some slop to ensure it fires)
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
- ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3));
-
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kDefaultMaxSockets, client_socket_factory_.allocation_count());
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterCancelingAllRequests) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- pool_->EnableConnectBackupJobs();
-
- // Create the first socket and set to ERR_IO_PENDING. This starts the backup
- // timer.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- ASSERT_TRUE(pool_->HasGroup("bar"));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("bar"));
-
- // Cancel the socket request. This should cancel the backup timer. Wait for
- // the backup time to see if it indeed got canceled.
- handle.Reset();
- // Wait for the backup timer to fire (add some slop to ensure it fires)
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
- ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3));
- base::MessageLoop::current()->RunUntilIdle();
- ASSERT_TRUE(pool_->HasGroup("bar"));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("bar"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, CancelBackupSocketAfterFinishingAllRequests) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- pool_->EnableConnectBackupJobs();
-
- // Create the first socket and set to ERR_IO_PENDING. This starts the backup
- // timer.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("bar",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("bar",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
- ASSERT_TRUE(pool_->HasGroup("bar"));
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("bar"));
-
- // Cancel request 1 and then complete request 2. With the requests finished,
- // the backup timer should be cancelled.
- handle.Reset();
- EXPECT_EQ(OK, callback2.WaitForResult());
- // Wait for the backup timer to fire (add some slop to ensure it fires)
- base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(
- ClientSocketPool::kMaxConnectRetryIntervalMs / 2 * 3));
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-// Test delayed socket binding for the case where we have two connects,
-// and while one is waiting on a connect, the other frees up.
-// The socket waiting on a connect should switch immediately to the freed
-// up socket.
-TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingWaitingForConnect) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // No idle sockets, no pending jobs.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- // Create a second socket to the same host, but this one will wait.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- ClientSocketHandle handle2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- // No idle sockets, and one connecting job.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Return the first handle to the pool. This will initiate the delayed
- // binding.
- handle1.Reset();
-
- base::MessageLoop::current()->RunUntilIdle();
-
- // Still no idle sockets, still one pending connect job.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // The second socket connected, even though it was a Waiting Job.
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // And we can see there is still one job waiting.
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Finally, signal the waiting Connect.
- client_socket_factory_.SignalJobs();
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-// Test delayed socket binding when a group is at capacity and one
-// of the group's sockets frees up.
-TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtGroupCapacity) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // No idle sockets, no pending jobs.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- // Create a second socket to the same host, but this one will wait.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- ClientSocketHandle handle2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- // No idle sockets, and one connecting job.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Return the first handle to the pool. This will initiate the delayed
- // binding.
- handle1.Reset();
-
- base::MessageLoop::current()->RunUntilIdle();
-
- // Still no idle sockets, still one pending connect job.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // The second socket connected, even though it was a Waiting Job.
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // And we can see there is still one job waiting.
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Finally, signal the waiting Connect.
- client_socket_factory_.SignalJobs();
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-// Test out the case where we have one socket connected, one
-// connecting, when the first socket finishes and goes idle.
-// Although the second connection is pending, the second request
-// should complete, by taking the first socket's idle socket.
-TEST_F(ClientSocketPoolBaseTest, DelayedSocketBindingAtStall) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // No idle sockets, no pending jobs.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- // Create a second socket to the same host, but this one will wait.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- ClientSocketHandle handle2;
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- // No idle sockets, and one connecting job.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Return the first handle to the pool. This will initiate the delayed
- // binding.
- handle1.Reset();
-
- base::MessageLoop::current()->RunUntilIdle();
-
- // Still no idle sockets, still one pending connect job.
- EXPECT_EQ(0, pool_->IdleSocketCount());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // The second socket connected, even though it was a Waiting Job.
- EXPECT_EQ(OK, callback.WaitForResult());
-
- // And we can see there is still one job waiting.
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Finally, signal the waiting Connect.
- client_socket_factory_.SignalJobs();
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- base::MessageLoop::current()->RunUntilIdle();
-}
-
-// Cover the case where on an available socket slot, we have one pending
-// request that completes synchronously, thereby making the Group empty.
-TEST_F(ClientSocketPoolBaseTest, SynchronouslyProcessOnePendingRequest) {
- const int kUnlimitedSockets = 100;
- const int kOneSocketPerGroup = 1;
- CreatePool(kUnlimitedSockets, kOneSocketPerGroup);
-
- // Make the first request asynchronous fail.
- // This will free up a socket slot later.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING,
- handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Make the second request synchronously fail. This should make the Group
- // empty.
- connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- // It'll be ERR_IO_PENDING now, but the TestConnectJob will synchronously fail
- // when created.
- EXPECT_EQ(ERR_IO_PENDING,
- handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback1.WaitForResult());
- EXPECT_EQ(ERR_CONNECTION_FAILED, callback2.WaitForResult());
- EXPECT_FALSE(pool_->HasGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, PreferUsedSocketToUnusedSocket) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
- ClientSocketHandle handle3;
- TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING, handle3.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback3.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(OK, callback3.WaitForResult());
-
- // Use the socket.
- EXPECT_EQ(1, handle1.socket()->Write(NULL, 1, CompletionCallback()));
- EXPECT_EQ(1, handle3.socket()->Write(NULL, 1, CompletionCallback()));
-
- handle1.Reset();
- handle2.Reset();
- handle3.Reset();
-
- EXPECT_EQ(OK, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, handle3.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback3.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_TRUE(handle1.socket()->WasEverUsed());
- EXPECT_TRUE(handle2.socket()->WasEverUsed());
- EXPECT_FALSE(handle3.socket()->WasEverUsed());
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSockets) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
- handle1.Reset();
- handle2.Reset();
-
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsWhenAlreadyHaveAConnectJob) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
-
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
- handle1.Reset();
- handle2.Reset();
-
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest,
- RequestSocketsWhenAlreadyHaveMultipleConnectJob) {
- CreatePool(4, 4);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ClientSocketHandle handle3;
- TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING, handle3.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback3.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
-
- EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- EXPECT_EQ(OK, callback1.WaitForResult());
- EXPECT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(OK, callback3.WaitForResult());
- handle1.Reset();
- handle2.Reset();
- handle3.Reset();
-
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(3, pool_->IdleSocketCountInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsAtMaxSocketLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ASSERT_FALSE(pool_->HasGroup("a"));
-
- pool_->RequestSockets("a", &params_, kDefaultMaxSockets,
- BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(kDefaultMaxSockets, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(kDefaultMaxSockets, pool_->NumUnassignedConnectJobsInGroup("a"));
-
- ASSERT_FALSE(pool_->HasGroup("b"));
-
- pool_->RequestSockets("b", &params_, kDefaultMaxSockets,
- BoundNetLog());
-
- ASSERT_FALSE(pool_->HasGroup("b"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsHitMaxSocketLimit) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSockets);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ASSERT_FALSE(pool_->HasGroup("a"));
-
- pool_->RequestSockets("a", &params_, kDefaultMaxSockets - 1,
- BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(kDefaultMaxSockets - 1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(kDefaultMaxSockets - 1,
- pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_FALSE(pool_->IsStalled());
-
- ASSERT_FALSE(pool_->HasGroup("b"));
-
- pool_->RequestSockets("b", &params_, kDefaultMaxSockets,
- BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("b"));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("b"));
- EXPECT_FALSE(pool_->IsStalled());
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountIdleSockets) {
- CreatePool(4, 4);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
- ASSERT_EQ(OK, callback1.WaitForResult());
- handle1.Reset();
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
-
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsCountActiveSockets) {
- CreatePool(4, 4);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
- ASSERT_EQ(OK, callback1.WaitForResult());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
-
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronous) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("b", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
-
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("b"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("b"));
- EXPECT_EQ(kDefaultMaxSocketsPerGroup, pool_->IdleSocketCountInGroup("b"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsSynchronousError) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
-
- pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
-
- ASSERT_FALSE(pool_->HasGroup("a"));
-
- connect_job_factory_->set_job_type(
- TestConnectJob::kMockAdditionalErrorStateJob);
- pool_->RequestSockets("a", &params_, kDefaultMaxSocketsPerGroup,
- BoundNetLog());
-
- ASSERT_FALSE(pool_->HasGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsMultipleTimesDoesNothing) {
- CreatePool(4, 4);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
- ASSERT_EQ(OK, callback1.WaitForResult());
-
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- int rv = handle2.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog());
- if (rv != OK) {
- EXPECT_EQ(ERR_IO_PENDING, rv);
- EXPECT_EQ(OK, callback2.WaitForResult());
- }
-
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->NumActiveSocketsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- handle1.Reset();
- handle2.Reset();
-
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->IdleSocketCountInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, RequestSocketsDifferentNumSockets) {
- CreatePool(4, 4);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
- EXPECT_EQ(2, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(2, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 3, BoundNetLog());
- EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(3, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
- EXPECT_EQ(3, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(3, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, PreconnectJobsTakenByNormalRequests) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- ASSERT_EQ(OK, callback1.WaitForResult());
-
- // Make sure if a preconnected socket is not fully connected when a request
- // starts, it has a connect start time.
- TestLoadTimingInfoConnectedNotReused(handle1);
- handle1.Reset();
-
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-}
-
-// Checks that fully connected preconnect jobs have no connect times, and are
-// marked as reused.
-TEST_F(ClientSocketPoolBaseTest, ConnectedPreconnectJobsHaveNoConnectTimes) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- // Make sure the idle socket was used.
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- TestLoadTimingInfoConnectedReused(handle);
- handle.Reset();
- TestLoadTimingInfoNotConnected(handle);
-}
-
-// http://crbug.com/64940 regression test.
-TEST_F(ClientSocketPoolBaseTest, PreconnectClosesIdleSocketRemovesGroup) {
- const int kMaxTotalSockets = 3;
- const int kMaxSocketsPerGroup = 2;
- CreatePool(kMaxTotalSockets, kMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- // Note that group name ordering matters here. "a" comes before "b", so
- // CloseOneIdleSocket() will try to close "a"'s idle socket.
-
- // Set up one idle socket in "a".
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ASSERT_EQ(OK, callback1.WaitForResult());
- handle1.Reset();
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-
- // Set up two active sockets in "b".
- ClientSocketHandle handle2;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle1.Init("b",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(ERR_IO_PENDING, handle2.Init("b",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ASSERT_EQ(OK, callback1.WaitForResult());
- ASSERT_EQ(OK, callback2.WaitForResult());
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("b"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("b"));
- EXPECT_EQ(2, pool_->NumActiveSocketsInGroup("b"));
-
- // Now we have 1 idle socket in "a" and 2 active sockets in "b". This means
- // we've maxed out on sockets, since we set |kMaxTotalSockets| to 3.
- // Requesting 2 preconnected sockets for "a" should fail to allocate any more
- // sockets for "a", and "b" should still have 2 active sockets.
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("b"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("b"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("b"));
- EXPECT_EQ(2, pool_->NumActiveSocketsInGroup("b"));
-
- // Now release the 2 active sockets for "b". This will give us 1 idle socket
- // in "a" and 2 idle sockets in "b". Requesting 2 preconnected sockets for
- // "a" should result in closing 1 for "b".
- handle1.Reset();
- handle2.Reset();
- EXPECT_EQ(2, pool_->IdleSocketCountInGroup("b"));
- EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("b"));
-
- pool_->RequestSockets("a", &params_, 2, BoundNetLog());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("b"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("b"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("b"));
- EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("b"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, PreconnectWithoutBackupJob) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- pool_->EnableConnectBackupJobs();
-
- // Make the ConnectJob hang until it times out, shorten the timeout.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- connect_job_factory_->set_timeout_duration(
- base::TimeDelta::FromMilliseconds(500));
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- // Verify the backup timer doesn't create a backup job, by making
- // the backup job a pending job instead of a waiting job, so it
- // *would* complete if it were created.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::MessageLoop::QuitClosure(),
- base::TimeDelta::FromSeconds(1));
- base::MessageLoop::current()->Run();
- EXPECT_FALSE(pool_->HasGroup("a"));
-}
-
-TEST_F(ClientSocketPoolBaseTest, PreconnectWithBackupJob) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- pool_->EnableConnectBackupJobs();
-
- // Make the ConnectJob hang forever.
- connect_job_factory_->set_job_type(TestConnectJob::kMockWaitingJob);
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- base::MessageLoop::current()->RunUntilIdle();
-
- // Make the backup job be a pending job, so it completes normally.
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- // Timer has started, but the backup connect job shouldn't be created yet.
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(0, pool_->NumActiveSocketsInGroup("a"));
- ASSERT_EQ(OK, callback.WaitForResult());
-
- // The hung connect job should still be there, but everything else should be
- // complete.
- EXPECT_EQ(1, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
- EXPECT_EQ(1, pool_->NumActiveSocketsInGroup("a"));
-}
-
-// Tests that a preconnect that starts out with unread data can still be used.
-// http://crbug.com/334467
-TEST_F(ClientSocketPoolBaseTest, PreconnectWithUnreadData) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockUnreadDataJob);
-
- pool_->RequestSockets("a", &params_, 1, BoundNetLog());
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-
- // Fail future jobs to be sure that handle receives the preconnected socket
- // rather than closing it and making a new one.
- connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(OK, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
-
- ASSERT_TRUE(pool_->HasGroup("a"));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->NumUnassignedConnectJobsInGroup("a"));
- EXPECT_EQ(0, pool_->IdleSocketCountInGroup("a"));
-
- // Drain the pending read.
- EXPECT_EQ(1, handle.socket()->Read(NULL, 1, CompletionCallback()));
-
- TestLoadTimingInfoConnectedReused(handle);
- handle.Reset();
-
- // The socket should be usable now that it's idle again.
- EXPECT_EQ(1, pool_->IdleSocketCountInGroup("a"));
-}
-
-class MockLayeredPool : public HigherLayeredPool {
- public:
- MockLayeredPool(TestClientSocketPool* pool,
- const std::string& group_name)
- : pool_(pool),
- group_name_(group_name),
- can_release_connection_(true) {
- pool_->AddHigherLayeredPool(this);
- }
-
- ~MockLayeredPool() {
- pool_->RemoveHigherLayeredPool(this);
- }
-
- int RequestSocket(TestClientSocketPool* pool) {
- scoped_refptr<TestSocketParams> params(
- new TestSocketParams(false /* ignore_limits */));
- return handle_.Init(group_name_, params, DEFAULT_PRIORITY,
- callback_.callback(), pool, BoundNetLog());
- }
-
- int RequestSocketWithoutLimits(TestClientSocketPool* pool) {
- scoped_refptr<TestSocketParams> params(
- new TestSocketParams(true /* ignore_limits */));
- return handle_.Init(group_name_, params, MAXIMUM_PRIORITY,
- callback_.callback(), pool, BoundNetLog());
- }
-
- bool ReleaseOneConnection() {
- if (!handle_.is_initialized() || !can_release_connection_) {
- return false;
- }
- handle_.socket()->Disconnect();
- handle_.Reset();
- return true;
- }
-
- void set_can_release_connection(bool can_release_connection) {
- can_release_connection_ = can_release_connection;
- }
-
- MOCK_METHOD0(CloseOneIdleConnection, bool());
-
- private:
- TestClientSocketPool* const pool_;
- ClientSocketHandle handle_;
- TestCompletionCallback callback_;
- const std::string group_name_;
- bool can_release_connection_;
-};
-
-TEST_F(ClientSocketPoolBaseTest, FailToCloseIdleSocketsNotHeldByLayeredPool) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- MockLayeredPool mock_layered_pool(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
- .WillOnce(Return(false));
- EXPECT_FALSE(pool_->CloseOneIdleConnectionInHigherLayeredPool());
-}
-
-TEST_F(ClientSocketPoolBaseTest, ForciblyCloseIdleSocketsHeldByLayeredPool) {
- CreatePool(kDefaultMaxSockets, kDefaultMaxSocketsPerGroup);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- MockLayeredPool mock_layered_pool(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
- .WillOnce(Invoke(&mock_layered_pool,
- &MockLayeredPool::ReleaseOneConnection));
- EXPECT_TRUE(pool_->CloseOneIdleConnectionInHigherLayeredPool());
-}
-
-// Tests the basic case of closing an idle socket in a higher layered pool when
-// a new request is issued and the lower layer pool is stalled.
-TEST_F(ClientSocketPoolBaseTest, CloseIdleSocketsHeldByLayeredPoolWhenNeeded) {
- CreatePool(1, 1);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- MockLayeredPool mock_layered_pool(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
- .WillOnce(Invoke(&mock_layered_pool,
- &MockLayeredPool::ReleaseOneConnection));
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-// Same as above, but the idle socket is in the same group as the stalled
-// socket, and closes the only other request in its group when closing requests
-// in higher layered pools. This generally shouldn't happen, but it may be
-// possible if a higher level pool issues a request and the request is
-// subsequently cancelled. Even if it's not possible, best not to crash.
-TEST_F(ClientSocketPoolBaseTest,
- CloseIdleSocketsHeldByLayeredPoolWhenNeededSameGroup) {
- CreatePool(2, 2);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- // Need a socket in another group for the pool to be stalled (If a group
- // has the maximum number of connections already, it's not stalled).
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(OK, handle1.Init("group1",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- MockLayeredPool mock_layered_pool(pool_.get(), "group2");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
- .WillOnce(Invoke(&mock_layered_pool,
- &MockLayeredPool::ReleaseOneConnection));
- ClientSocketHandle handle;
- TestCompletionCallback callback2;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("group2",
- params_,
- DEFAULT_PRIORITY,
- callback2.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback2.WaitForResult());
-}
-
-// Tests the case when an idle socket can be closed when a new request is
-// issued, and the new request belongs to a group that was previously stalled.
-TEST_F(ClientSocketPoolBaseTest,
- CloseIdleSocketsHeldByLayeredPoolInSameGroupWhenNeeded) {
- CreatePool(2, 2);
- std::list<TestConnectJob::JobType> job_types;
- job_types.push_back(TestConnectJob::kMockJob);
- job_types.push_back(TestConnectJob::kMockJob);
- job_types.push_back(TestConnectJob::kMockJob);
- job_types.push_back(TestConnectJob::kMockJob);
- connect_job_factory_->set_job_types(&job_types);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(OK, handle1.Init("group1",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- MockLayeredPool mock_layered_pool(pool_.get(), "group2");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
- .WillRepeatedly(Invoke(&mock_layered_pool,
- &MockLayeredPool::ReleaseOneConnection));
- mock_layered_pool.set_can_release_connection(false);
-
- // The third request is made when the socket pool is in a stalled state.
- ClientSocketHandle handle3;
- TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING, handle3.Init("group3",
- params_,
- DEFAULT_PRIORITY,
- callback3.callback(),
- pool_.get(),
- BoundNetLog()));
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(callback3.have_result());
-
- // The fourth request is made when the pool is no longer stalled. The third
- // request should be serviced first, since it was issued first and has the
- // same priority.
- mock_layered_pool.set_can_release_connection(true);
- ClientSocketHandle handle4;
- TestCompletionCallback callback4;
- EXPECT_EQ(ERR_IO_PENDING, handle4.Init("group3",
- params_,
- DEFAULT_PRIORITY,
- callback4.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback3.WaitForResult());
- EXPECT_FALSE(callback4.have_result());
-
- // Closing a handle should free up another socket slot.
- handle1.Reset();
- EXPECT_EQ(OK, callback4.WaitForResult());
-}
-
-// Tests the case when an idle socket can be closed when a new request is
-// issued, and the new request belongs to a group that was previously stalled.
-//
-// The two differences from the above test are that the stalled requests are not
-// in the same group as the layered pool's request, and the the fourth request
-// has a higher priority than the third one, so gets a socket first.
-TEST_F(ClientSocketPoolBaseTest,
- CloseIdleSocketsHeldByLayeredPoolInSameGroupWhenNeeded2) {
- CreatePool(2, 2);
- std::list<TestConnectJob::JobType> job_types;
- job_types.push_back(TestConnectJob::kMockJob);
- job_types.push_back(TestConnectJob::kMockJob);
- job_types.push_back(TestConnectJob::kMockJob);
- job_types.push_back(TestConnectJob::kMockJob);
- connect_job_factory_->set_job_types(&job_types);
-
- ClientSocketHandle handle1;
- TestCompletionCallback callback1;
- EXPECT_EQ(OK, handle1.Init("group1",
- params_,
- DEFAULT_PRIORITY,
- callback1.callback(),
- pool_.get(),
- BoundNetLog()));
-
- MockLayeredPool mock_layered_pool(pool_.get(), "group2");
- EXPECT_EQ(OK, mock_layered_pool.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool, CloseOneIdleConnection())
- .WillRepeatedly(Invoke(&mock_layered_pool,
- &MockLayeredPool::ReleaseOneConnection));
- mock_layered_pool.set_can_release_connection(false);
-
- // The third request is made when the socket pool is in a stalled state.
- ClientSocketHandle handle3;
- TestCompletionCallback callback3;
- EXPECT_EQ(ERR_IO_PENDING, handle3.Init("group3",
- params_,
- MEDIUM,
- callback3.callback(),
- pool_.get(),
- BoundNetLog()));
-
- base::RunLoop().RunUntilIdle();
- EXPECT_FALSE(callback3.have_result());
-
- // The fourth request is made when the pool is no longer stalled. This
- // request has a higher priority than the third request, so is serviced first.
- mock_layered_pool.set_can_release_connection(true);
- ClientSocketHandle handle4;
- TestCompletionCallback callback4;
- EXPECT_EQ(ERR_IO_PENDING, handle4.Init("group3",
- params_,
- HIGHEST,
- callback4.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback4.WaitForResult());
- EXPECT_FALSE(callback3.have_result());
-
- // Closing a handle should free up another socket slot.
- handle1.Reset();
- EXPECT_EQ(OK, callback3.WaitForResult());
-}
-
-TEST_F(ClientSocketPoolBaseTest,
- CloseMultipleIdleSocketsHeldByLayeredPoolWhenNeeded) {
- CreatePool(1, 1);
- connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
-
- MockLayeredPool mock_layered_pool1(pool_.get(), "foo");
- EXPECT_EQ(OK, mock_layered_pool1.RequestSocket(pool_.get()));
- EXPECT_CALL(mock_layered_pool1, CloseOneIdleConnection())
- .WillRepeatedly(Invoke(&mock_layered_pool1,
- &MockLayeredPool::ReleaseOneConnection));
- MockLayeredPool mock_layered_pool2(pool_.get(), "bar");
- EXPECT_EQ(OK, mock_layered_pool2.RequestSocketWithoutLimits(pool_.get()));
- EXPECT_CALL(mock_layered_pool2, CloseOneIdleConnection())
- .WillRepeatedly(Invoke(&mock_layered_pool2,
- &MockLayeredPool::ReleaseOneConnection));
- ClientSocketHandle handle;
- TestCompletionCallback callback;
- EXPECT_EQ(ERR_IO_PENDING, handle.Init("a",
- params_,
- DEFAULT_PRIORITY,
- callback.callback(),
- pool_.get(),
- BoundNetLog()));
- EXPECT_EQ(OK, callback.WaitForResult());
-}
-
-// Test that when a socket pool and group are at their limits, a request
-// with |ignore_limits| triggers creation of a new socket, and gets the socket
-// instead of a request with the same priority that was issued earlier, but
-// that does not have |ignore_limits| set.
-TEST_F(ClientSocketPoolBaseTest, IgnoreLimits) {
- scoped_refptr<TestSocketParams> params_ignore_limits(
- new TestSocketParams(true /* ignore_limits */));
- CreatePool(1, 1);
-
- // Issue a request to reach the socket pool limit.
- EXPECT_EQ(OK, StartRequestWithParams("a", MAXIMUM_PRIORITY, params_));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequestWithParams("a", MAXIMUM_PRIORITY,
- params_));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequestWithParams("a", MAXIMUM_PRIORITY,
- params_ignore_limits));
- ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- EXPECT_EQ(OK, request(2)->WaitForResult());
- EXPECT_FALSE(request(1)->have_result());
-}
-
-// Test that when a socket pool and group are at their limits, a ConnectJob
-// issued for a request with |ignore_limits| set is not cancelled when a request
-// without |ignore_limits| issued to the same group is cancelled.
-TEST_F(ClientSocketPoolBaseTest, IgnoreLimitsCancelOtherJob) {
- scoped_refptr<TestSocketParams> params_ignore_limits(
- new TestSocketParams(true /* ignore_limits */));
- CreatePool(1, 1);
-
- // Issue a request to reach the socket pool limit.
- EXPECT_EQ(OK, StartRequestWithParams("a", MAXIMUM_PRIORITY, params_));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequestWithParams("a", MAXIMUM_PRIORITY,
- params_));
- EXPECT_EQ(0, pool_->NumConnectJobsInGroup("a"));
-
- EXPECT_EQ(ERR_IO_PENDING, StartRequestWithParams("a", MAXIMUM_PRIORITY,
- params_ignore_limits));
- ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- // Cancel the pending request without ignore_limits set. The ConnectJob
- // should not be cancelled.
- request(1)->handle()->Reset();
- ASSERT_EQ(1, pool_->NumConnectJobsInGroup("a"));
-
- EXPECT_EQ(OK, request(2)->WaitForResult());
- EXPECT_FALSE(request(1)->have_result());
-}
-
-} // namespace
-
-} // namespace net
« no previous file with comments | « net/socket/client_socket_pool_base.cc ('k') | net/socket/client_socket_pool_histograms.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698