blob: 7bb5ae71eb5b6976e68bd39b8ddb1a365007ce90 [file] [log] [blame]
[email protected]f6d1d6eb2009-06-24 20:16:091// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
[email protected]ab838892009-06-30 18:49:055#include "net/socket/client_socket_pool_base.h"
[email protected]f6d1d6eb2009-06-24 20:16:096
7#include "base/compiler_specific.h"
8#include "base/message_loop.h"
9#include "net/base/host_resolver_unittest.h"
10#include "net/base/net_errors.h"
11#include "net/base/test_completion_callback.h"
12#include "net/socket/client_socket.h"
13#include "net/socket/client_socket_factory.h"
14#include "net/socket/client_socket_handle.h"
15#include "testing/gtest/include/gtest/gtest.h"
16
17namespace net {
18
19namespace {
20
[email protected]ab838892009-06-30 18:49:0521const int kMaxSocketsPerGroup = 2;
[email protected]f6d1d6eb2009-06-24 20:16:0922
23// Note that the first and the last are the same, the first should be handled
24// before the last, since it was inserted first.
[email protected]ab838892009-06-30 18:49:0525const int kPriorities[] = { 1, 3, 4, 2, 1 };
[email protected]f6d1d6eb2009-06-24 20:16:0926
27// This is the number of extra requests beyond the first few that use up all
28// available sockets in the socket group.
29const int kNumPendingRequests = arraysize(kPriorities);
30
31const int kNumRequests = kMaxSocketsPerGroup + kNumPendingRequests;
32
33class MockClientSocket : public ClientSocket {
34 public:
35 MockClientSocket() : connected_(false) {}
36
[email protected]ab838892009-06-30 18:49:0537 // Socket methods:
38 virtual int Read(
39 IOBuffer* /* buf */, int /* len */, CompletionCallback* /* callback */) {
40 return ERR_UNEXPECTED;
41 }
42
43 virtual int Write(
44 IOBuffer* /* buf */, int /* len */, CompletionCallback* /* callback */) {
45 return ERR_UNEXPECTED;
46 }
47
[email protected]f6d1d6eb2009-06-24 20:16:0948 // ClientSocket methods:
[email protected]ab838892009-06-30 18:49:0549
[email protected]f6d1d6eb2009-06-24 20:16:0950 virtual int Connect(CompletionCallback* callback) {
51 connected_ = true;
52 return OK;
53 }
[email protected]f6d1d6eb2009-06-24 20:16:0954
[email protected]ab838892009-06-30 18:49:0555 virtual void Disconnect() { connected_ = false; }
56 virtual bool IsConnected() const { return connected_; }
57 virtual bool IsConnectedAndIdle() const { return connected_; }
58
59#if defined(OS_LINUX)
60 virtual int GetPeerName(struct sockaddr* /* name */,
61 socklen_t* /* namelen */) {
62 return 0;
[email protected]f6d1d6eb2009-06-24 20:16:0963 }
[email protected]ab838892009-06-30 18:49:0564#endif
[email protected]f6d1d6eb2009-06-24 20:16:0965
66 private:
67 bool connected_;
[email protected]f6d1d6eb2009-06-24 20:16:0968
[email protected]ab838892009-06-30 18:49:0569 DISALLOW_COPY_AND_ASSIGN(MockClientSocket);
[email protected]f6d1d6eb2009-06-24 20:16:0970};
71
72class MockClientSocketFactory : public ClientSocketFactory {
73 public:
[email protected]ab838892009-06-30 18:49:0574 MockClientSocketFactory() : allocation_count_(0) {}
[email protected]f6d1d6eb2009-06-24 20:16:0975
76 virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses) {
77 allocation_count_++;
[email protected]ab838892009-06-30 18:49:0578 return NULL;
[email protected]f6d1d6eb2009-06-24 20:16:0979 }
80
81 virtual SSLClientSocket* CreateSSLClientSocket(
82 ClientSocket* transport_socket,
83 const std::string& hostname,
84 const SSLConfig& ssl_config) {
85 NOTIMPLEMENTED();
86 return NULL;
87 }
88
89 int allocation_count() const { return allocation_count_; }
90
[email protected]f6d1d6eb2009-06-24 20:16:0991 private:
92 int allocation_count_;
[email protected]f6d1d6eb2009-06-24 20:16:0993};
94
95class TestSocketRequest : public CallbackRunner< Tuple1<int> > {
96 public:
97 TestSocketRequest(
98 ClientSocketPool* pool,
99 std::vector<TestSocketRequest*>* request_order)
100 : handle(pool), request_order_(request_order) {}
101
102 ClientSocketHandle handle;
103
104 int WaitForResult() {
105 return callback_.WaitForResult();
106 }
107
108 virtual void RunWithParams(const Tuple1<int>& params) {
109 callback_.RunWithParams(params);
110 completion_count++;
111 request_order_->push_back(this);
112 }
113
114 static int completion_count;
115
116 private:
117 std::vector<TestSocketRequest*>* request_order_;
118 TestCompletionCallback callback_;
119};
120
121int TestSocketRequest::completion_count = 0;
122
[email protected]ab838892009-06-30 18:49:05123class TestConnectJob : public ConnectJob {
124 public:
125 enum JobType {
126 kMockJob,
127 kMockFailingJob,
128 kMockPendingJob,
129 kMockPendingFailingJob,
130 };
131
132 TestConnectJob(JobType job_type,
133 const std::string& group_name,
134 const ClientSocketPoolBase::Request& request,
135 ConnectJob::Delegate* delegate,
136 ClientSocketFactory* client_socket_factory)
[email protected]2ab05b52009-07-01 23:57:58137 : ConnectJob(group_name, request.handle, delegate),
138 job_type_(job_type),
[email protected]ab838892009-06-30 18:49:05139 client_socket_factory_(client_socket_factory),
[email protected]ab838892009-06-30 18:49:05140 method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {}
141
142 // ConnectJob methods:
143
144 virtual int Connect() {
145 AddressList ignored;
146 client_socket_factory_->CreateTCPClientSocket(ignored);
147 switch (job_type_) {
148 case kMockJob:
149 return DoConnect(true /* successful */, false /* sync */);
150 case kMockFailingJob:
151 return DoConnect(false /* error */, false /* sync */);
152 case kMockPendingJob:
153 MessageLoop::current()->PostTask(
154 FROM_HERE,
155 method_factory_.NewRunnableMethod(
156 &TestConnectJob::DoConnect,
157 true /* successful */,
158 true /* async */));
159 return ERR_IO_PENDING;
160 case kMockPendingFailingJob:
161 MessageLoop::current()->PostTask(
162 FROM_HERE,
163 method_factory_.NewRunnableMethod(
164 &TestConnectJob::DoConnect,
165 false /* error */,
166 true /* async */));
167 return ERR_IO_PENDING;
168 default:
169 NOTREACHED();
170 return ERR_FAILED;
171 }
172 }
173
174 private:
175 int DoConnect(bool succeed, bool was_async) {
176 int result = ERR_CONNECTION_FAILED;
[email protected]ab838892009-06-30 18:49:05177 if (succeed) {
178 result = OK;
[email protected]2ab05b52009-07-01 23:57:58179 set_socket(new MockClientSocket());
180 socket()->Connect(NULL);
[email protected]ab838892009-06-30 18:49:05181 }
[email protected]2ab05b52009-07-01 23:57:58182
183 if (was_async)
184 delegate()->OnConnectJobComplete(result, this);
[email protected]ab838892009-06-30 18:49:05185 return result;
186 }
187
188 const JobType job_type_;
[email protected]ab838892009-06-30 18:49:05189 ClientSocketFactory* const client_socket_factory_;
[email protected]ab838892009-06-30 18:49:05190 ScopedRunnableMethodFactory<TestConnectJob> method_factory_;
191
192 DISALLOW_COPY_AND_ASSIGN(TestConnectJob);
193};
194
195class TestConnectJobFactory : public ClientSocketPoolBase::ConnectJobFactory {
196 public:
197 explicit TestConnectJobFactory(ClientSocketFactory* client_socket_factory)
198 : job_type_(TestConnectJob::kMockJob),
199 client_socket_factory_(client_socket_factory) {}
200
201 virtual ~TestConnectJobFactory() {}
202
203 void set_job_type(TestConnectJob::JobType job_type) { job_type_ = job_type; }
204
205 // ConnectJobFactory methods:
206
207 virtual ConnectJob* NewConnectJob(
208 const std::string& group_name,
209 const ClientSocketPoolBase::Request& request,
210 ConnectJob::Delegate* delegate) const {
211 return new TestConnectJob(job_type_,
212 group_name,
213 request,
214 delegate,
215 client_socket_factory_);
216 }
217
218 private:
219 TestConnectJob::JobType job_type_;
220 ClientSocketFactory* const client_socket_factory_;
221
222 DISALLOW_COPY_AND_ASSIGN(TestConnectJobFactory);
223};
224
225class TestClientSocketPool : public ClientSocketPool {
226 public:
227 TestClientSocketPool(
228 int max_sockets_per_group,
229 ClientSocketPoolBase::ConnectJobFactory* connect_job_factory)
230 : base_(new ClientSocketPoolBase(
231 kMaxSocketsPerGroup, connect_job_factory)) {}
232
233 virtual int RequestSocket(
234 const std::string& group_name,
235 const HostResolver::RequestInfo& resolve_info,
236 int priority,
237 ClientSocketHandle* handle,
238 CompletionCallback* callback) {
239 return base_->RequestSocket(
240 group_name, resolve_info, priority, handle, callback);
241 }
242
243 virtual void CancelRequest(
244 const std::string& group_name,
245 const ClientSocketHandle* handle) {
246 base_->CancelRequest(group_name, handle);
247 }
248
249 virtual void ReleaseSocket(
250 const std::string& group_name,
251 ClientSocket* socket) {
252 base_->ReleaseSocket(group_name, socket);
253 }
254
255 virtual void CloseIdleSockets() {
256 base_->CloseIdleSockets();
257 }
258
259 virtual int IdleSocketCount() const { return base_->idle_socket_count(); }
260
261 virtual int IdleSocketCountInGroup(const std::string& group_name) const {
262 return base_->IdleSocketCountInGroup(group_name);
263 }
264
265 virtual LoadState GetLoadState(const std::string& group_name,
266 const ClientSocketHandle* handle) const {
267 return base_->GetLoadState(group_name, handle);
268 }
269
270 private:
271 const scoped_refptr<ClientSocketPoolBase> base_;
272
273 DISALLOW_COPY_AND_ASSIGN(TestClientSocketPool);
274};
275
276class ClientSocketPoolBaseTest : public testing::Test {
[email protected]f6d1d6eb2009-06-24 20:16:09277 protected:
[email protected]ab838892009-06-30 18:49:05278 ClientSocketPoolBaseTest()
279 : ignored_request_info_("ignored", 80),
280 connect_job_factory_(
281 new TestConnectJobFactory(&client_socket_factory_)),
282 pool_(new TestClientSocketPool(kMaxSocketsPerGroup,
283 connect_job_factory_)) {}
[email protected]f6d1d6eb2009-06-24 20:16:09284
285 virtual void SetUp() {
[email protected]f6d1d6eb2009-06-24 20:16:09286 TestSocketRequest::completion_count = 0;
287 }
288
289 virtual void TearDown() {
290 // The tests often call Reset() on handles at the end which may post
291 // DoReleaseSocket() tasks.
292 MessageLoop::current()->RunAllPending();
293 }
294
[email protected]ab838892009-06-30 18:49:05295 HostResolver::RequestInfo ignored_request_info_;
[email protected]f6d1d6eb2009-06-24 20:16:09296 MockClientSocketFactory client_socket_factory_;
[email protected]ab838892009-06-30 18:49:05297 TestConnectJobFactory* const connect_job_factory_;
[email protected]f6d1d6eb2009-06-24 20:16:09298 scoped_refptr<ClientSocketPool> pool_;
299 std::vector<TestSocketRequest*> request_order_;
300};
301
[email protected]ab838892009-06-30 18:49:05302TEST_F(ClientSocketPoolBaseTest, Basic) {
[email protected]f6d1d6eb2009-06-24 20:16:09303 TestCompletionCallback callback;
304 ClientSocketHandle handle(pool_.get());
[email protected]ab838892009-06-30 18:49:05305 int rv = handle.Init("a", ignored_request_info_, 0, &callback);
306 EXPECT_EQ(OK, rv);
[email protected]f6d1d6eb2009-06-24 20:16:09307 EXPECT_TRUE(handle.is_initialized());
308 EXPECT_TRUE(handle.socket());
[email protected]f6d1d6eb2009-06-24 20:16:09309 handle.Reset();
310}
311
[email protected]ab838892009-06-30 18:49:05312TEST_F(ClientSocketPoolBaseTest, InitConnectionFailure) {
313 connect_job_factory_->set_job_type(TestConnectJob::kMockFailingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09314 TestSocketRequest req(pool_.get(), &request_order_);
[email protected]3ae82302009-06-26 06:01:21315 EXPECT_EQ(ERR_CONNECTION_FAILED,
[email protected]ab838892009-06-30 18:49:05316 req.handle.Init("a", ignored_request_info_, 5, &req));
[email protected]f6d1d6eb2009-06-24 20:16:09317}
318
[email protected]ab838892009-06-30 18:49:05319TEST_F(ClientSocketPoolBaseTest, PendingRequests) {
[email protected]f6d1d6eb2009-06-24 20:16:09320 scoped_ptr<TestSocketRequest> reqs[kNumRequests];
321
322 for (size_t i = 0; i < arraysize(reqs); ++i)
323 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
324
325 // Create connections or queue up requests.
326
[email protected]ab838892009-06-30 18:49:05327 for (int i = 0; i < kMaxSocketsPerGroup; ++i) {
328 int rv = reqs[i]->handle.Init("a", ignored_request_info_, 5, reqs[i].get());
[email protected]f6d1d6eb2009-06-24 20:16:09329 EXPECT_EQ(OK, rv);
330 request_order_.push_back(reqs[i].get());
331 }
332
333 // The rest are pending since we've used all active sockets.
334 for (int i = 0; i < kNumPendingRequests; ++i) {
[email protected]ab838892009-06-30 18:49:05335 int rv = reqs[kMaxSocketsPerGroup + i]->handle.Init(
336 "a", ignored_request_info_, kPriorities[i],
337 reqs[kMaxSocketsPerGroup + i].get());
[email protected]f6d1d6eb2009-06-24 20:16:09338 EXPECT_EQ(ERR_IO_PENDING, rv);
339 }
340
341 // Release any connections until we have no connections.
342 bool released_one;
343 do {
344 released_one = false;
345 for (size_t i = 0; i < arraysize(reqs); ++i) {
346 if (reqs[i]->handle.is_initialized()) {
347 reqs[i]->handle.Reset();
348 MessageLoop::current()->RunAllPending();
349 released_one = true;
350 }
351 }
352 } while (released_one);
353
354 EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count());
[email protected]ab838892009-06-30 18:49:05355 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count);
[email protected]f6d1d6eb2009-06-24 20:16:09356
357 for (int i = 0; i < kMaxSocketsPerGroup; ++i) {
358 EXPECT_EQ(request_order_[i], reqs[i].get()) <<
359 "Request " << i << " was not in order.";
360 }
361
362 for (int i = 0; i < kNumPendingRequests - 1; ++i) {
363 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i];
364 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue],
365 reqs[kMaxSocketsPerGroup + i].get()) <<
366 "Request " << kMaxSocketsPerGroup + i << " was not in order.";
367 }
368
369 EXPECT_EQ(request_order_[arraysize(reqs) - 1],
370 reqs[arraysize(reqs) - 1].get()) <<
371 "The last request with priority 1 should not have been inserted "
372 "earlier into the queue.";
373}
374
[email protected]ab838892009-06-30 18:49:05375TEST_F(ClientSocketPoolBaseTest, PendingRequests_NoKeepAlive) {
[email protected]f6d1d6eb2009-06-24 20:16:09376 scoped_ptr<TestSocketRequest> reqs[kNumRequests];
377 for (size_t i = 0; i < arraysize(reqs); ++i)
378 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
379
380 // Create connections or queue up requests.
[email protected]ab838892009-06-30 18:49:05381 for (int i = 0; i < kMaxSocketsPerGroup; ++i) {
382 int rv = reqs[i]->handle.Init("a", ignored_request_info_, 5, reqs[i].get());
[email protected]f6d1d6eb2009-06-24 20:16:09383 EXPECT_EQ(OK, rv);
384 request_order_.push_back(reqs[i].get());
385 }
386
387 // The rest are pending since we've used all active sockets.
388 for (int i = 0; i < kNumPendingRequests; ++i) {
[email protected]ab838892009-06-30 18:49:05389 int rv = reqs[kMaxSocketsPerGroup + i]->handle.Init(
390 "a", ignored_request_info_, kPriorities[i],
391 reqs[kMaxSocketsPerGroup + i].get());
392 EXPECT_EQ(ERR_IO_PENDING, rv);
[email protected]f6d1d6eb2009-06-24 20:16:09393 }
394
395 // Release any connections until we have no connections.
396 bool released_one;
397 do {
398 released_one = false;
399 for (size_t i = 0; i < arraysize(reqs); ++i) {
400 if (reqs[i]->handle.is_initialized()) {
401 reqs[i]->handle.socket()->Disconnect(); // No keep alive.
402 reqs[i]->handle.Reset();
403 MessageLoop::current()->RunAllPending();
404 released_one = true;
405 }
406 }
407 } while (released_one);
408
409 for (int i = kMaxSocketsPerGroup; i < kNumRequests; ++i)
410 EXPECT_EQ(OK, reqs[i]->WaitForResult());
411
412 EXPECT_EQ(kNumRequests, client_socket_factory_.allocation_count());
[email protected]ab838892009-06-30 18:49:05413 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count);
[email protected]f6d1d6eb2009-06-24 20:16:09414}
415
416// This test will start up a RequestSocket() and then immediately Cancel() it.
[email protected]ab838892009-06-30 18:49:05417// The pending connect job will be cancelled and should not call back into
418// ClientSocketPoolBase.
419TEST_F(ClientSocketPoolBaseTest, CancelRequestClearGroup) {
420 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09421 TestSocketRequest req(pool_.get(), &request_order_);
[email protected]ab838892009-06-30 18:49:05422 EXPECT_EQ(ERR_IO_PENDING,
423 req.handle.Init("a", ignored_request_info_, 5, &req));
[email protected]f6d1d6eb2009-06-24 20:16:09424 req.handle.Reset();
[email protected]f6d1d6eb2009-06-24 20:16:09425}
426
[email protected]ab838892009-06-30 18:49:05427TEST_F(ClientSocketPoolBaseTest, TwoRequestsCancelOne) {
428 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09429 TestSocketRequest req(pool_.get(), &request_order_);
430 TestSocketRequest req2(pool_.get(), &request_order_);
431
[email protected]ab838892009-06-30 18:49:05432 EXPECT_EQ(ERR_IO_PENDING,
433 req.handle.Init("a", ignored_request_info_, 5, &req));
434 EXPECT_EQ(ERR_IO_PENDING,
435 req2.handle.Init("a", ignored_request_info_, 5, &req2));
[email protected]f6d1d6eb2009-06-24 20:16:09436
437 req.handle.Reset();
438
439 EXPECT_EQ(OK, req2.WaitForResult());
440 req2.handle.Reset();
441}
442
[email protected]ab838892009-06-30 18:49:05443TEST_F(ClientSocketPoolBaseTest, ConnectCancelConnect) {
444 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09445 ClientSocketHandle handle(pool_.get());
446 TestCompletionCallback callback;
447 TestSocketRequest req(pool_.get(), &request_order_);
448
[email protected]ab838892009-06-30 18:49:05449 EXPECT_EQ(ERR_IO_PENDING,
450 handle.Init("a", ignored_request_info_, 5, &callback));
[email protected]f6d1d6eb2009-06-24 20:16:09451
452 handle.Reset();
453
454 TestCompletionCallback callback2;
[email protected]ab838892009-06-30 18:49:05455 EXPECT_EQ(ERR_IO_PENDING,
456 handle.Init("a", ignored_request_info_, 5, &callback2));
[email protected]f6d1d6eb2009-06-24 20:16:09457
458 EXPECT_EQ(OK, callback2.WaitForResult());
459 EXPECT_FALSE(callback.have_result());
460
461 handle.Reset();
462}
463
[email protected]ab838892009-06-30 18:49:05464TEST_F(ClientSocketPoolBaseTest, CancelRequest) {
[email protected]f6d1d6eb2009-06-24 20:16:09465 scoped_ptr<TestSocketRequest> reqs[kNumRequests];
466
467 for (size_t i = 0; i < arraysize(reqs); ++i)
468 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
469
470 // Create connections or queue up requests.
[email protected]ab838892009-06-30 18:49:05471 for (int i = 0; i < kMaxSocketsPerGroup; ++i) {
472 int rv = reqs[i]->handle.Init("a", ignored_request_info_, 5, reqs[i].get());
[email protected]f6d1d6eb2009-06-24 20:16:09473 EXPECT_EQ(OK, rv);
474 request_order_.push_back(reqs[i].get());
475 }
476
477 // The rest are pending since we've used all active sockets.
478 for (int i = 0; i < kNumPendingRequests; ++i) {
479 EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init(
[email protected]ab838892009-06-30 18:49:05480 "a", ignored_request_info_, kPriorities[i],
481 reqs[kMaxSocketsPerGroup + i].get()));
[email protected]f6d1d6eb2009-06-24 20:16:09482 }
483
484 // Cancel a request.
485 size_t index_to_cancel = kMaxSocketsPerGroup + 2;
486 EXPECT_TRUE(!reqs[index_to_cancel]->handle.is_initialized());
487 reqs[index_to_cancel]->handle.Reset();
488
489 // Release any connections until we have no connections.
490 bool released_one;
491 do {
492 released_one = false;
493 for (size_t i = 0; i < arraysize(reqs); ++i) {
494 if (reqs[i]->handle.is_initialized()) {
495 reqs[i]->handle.Reset();
496 MessageLoop::current()->RunAllPending();
497 released_one = true;
498 }
499 }
500 } while (released_one);
501
502 EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count());
[email protected]ab838892009-06-30 18:49:05503 EXPECT_EQ(kNumPendingRequests - 1, TestSocketRequest::completion_count);
[email protected]f6d1d6eb2009-06-24 20:16:09504
505 for (int i = 0; i < kMaxSocketsPerGroup; ++i) {
506 EXPECT_EQ(request_order_[i], reqs[i].get()) <<
507 "Request " << i << " was not in order.";
508 }
509
510 for (int i = 0; i < kNumPendingRequests - 1; ++i) {
511 if (i == 2) continue;
512 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i];
513 if (kPriorities[i] < kPriorities[index_to_cancel - kMaxSocketsPerGroup])
514 index_in_queue--;
515 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue],
516 reqs[kMaxSocketsPerGroup + i].get()) <<
517 "Request " << kMaxSocketsPerGroup + i << " was not in order.";
518 }
519
520 EXPECT_EQ(request_order_[arraysize(reqs) - 2],
521 reqs[arraysize(reqs) - 1].get()) <<
522 "The last request with priority 1 should not have been inserted "
523 "earlier into the queue.";
524}
525
526class RequestSocketCallback : public CallbackRunner< Tuple1<int> > {
527 public:
[email protected]2ab05b52009-07-01 23:57:58528 RequestSocketCallback(ClientSocketHandle* handle,
529 TestConnectJobFactory* test_connect_job_factory,
530 TestConnectJob::JobType next_job_type)
[email protected]f6d1d6eb2009-06-24 20:16:09531 : handle_(handle),
[email protected]2ab05b52009-07-01 23:57:58532 within_callback_(false),
533 test_connect_job_factory_(test_connect_job_factory),
534 next_job_type_(next_job_type) {}
[email protected]f6d1d6eb2009-06-24 20:16:09535
536 virtual void RunWithParams(const Tuple1<int>& params) {
537 callback_.RunWithParams(params);
538 ASSERT_EQ(OK, params.a);
539
540 if (!within_callback_) {
[email protected]2ab05b52009-07-01 23:57:58541 test_connect_job_factory_->set_job_type(next_job_type_);
[email protected]f6d1d6eb2009-06-24 20:16:09542 handle_->Reset();
543 within_callback_ = true;
544 int rv = handle_->Init(
545 "a", HostResolver::RequestInfo("www.google.com", 80), 0, this);
[email protected]2ab05b52009-07-01 23:57:58546 switch (next_job_type_) {
547 case TestConnectJob::kMockJob:
548 EXPECT_EQ(OK, rv);
549 break;
550 case TestConnectJob::kMockPendingJob:
551 EXPECT_EQ(ERR_IO_PENDING, rv);
552 break;
553 default:
554 FAIL() << "Unexpected job type: " << next_job_type_;
555 break;
556 }
[email protected]f6d1d6eb2009-06-24 20:16:09557 }
558 }
559
560 int WaitForResult() {
561 return callback_.WaitForResult();
562 }
563
564 private:
565 ClientSocketHandle* const handle_;
566 bool within_callback_;
[email protected]2ab05b52009-07-01 23:57:58567 TestConnectJobFactory* const test_connect_job_factory_;
568 TestConnectJob::JobType next_job_type_;
[email protected]f6d1d6eb2009-06-24 20:16:09569 TestCompletionCallback callback_;
570};
571
[email protected]2ab05b52009-07-01 23:57:58572TEST_F(ClientSocketPoolBaseTest, RequestPendingJobTwice) {
[email protected]ab838892009-06-30 18:49:05573 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09574 ClientSocketHandle handle(pool_.get());
[email protected]2ab05b52009-07-01 23:57:58575 RequestSocketCallback callback(
576 &handle, connect_job_factory_, TestConnectJob::kMockPendingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09577 int rv = handle.Init(
[email protected]ab838892009-06-30 18:49:05578 "a", ignored_request_info_, 0, &callback);
[email protected]f6d1d6eb2009-06-24 20:16:09579 ASSERT_EQ(ERR_IO_PENDING, rv);
580
581 EXPECT_EQ(OK, callback.WaitForResult());
[email protected]2ab05b52009-07-01 23:57:58582 handle.Reset();
583}
[email protected]f6d1d6eb2009-06-24 20:16:09584
[email protected]2ab05b52009-07-01 23:57:58585TEST_F(ClientSocketPoolBaseTest, RequestPendingJobThenSynchronous) {
586 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
587 ClientSocketHandle handle(pool_.get());
588 RequestSocketCallback callback(
589 &handle, connect_job_factory_, TestConnectJob::kMockJob);
590 int rv = handle.Init(
591 "a", ignored_request_info_, 0, &callback);
592 ASSERT_EQ(ERR_IO_PENDING, rv);
593
594 EXPECT_EQ(OK, callback.WaitForResult());
[email protected]f6d1d6eb2009-06-24 20:16:09595 handle.Reset();
596}
597
598// Make sure that pending requests get serviced after active requests get
599// cancelled.
[email protected]ab838892009-06-30 18:49:05600TEST_F(ClientSocketPoolBaseTest, CancelActiveRequestWithPendingRequests) {
601 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09602
603 scoped_ptr<TestSocketRequest> reqs[kNumRequests];
604
605 // Queue up all the requests
[email protected]f6d1d6eb2009-06-24 20:16:09606 for (size_t i = 0; i < arraysize(reqs); ++i) {
607 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
[email protected]ab838892009-06-30 18:49:05608 int rv = reqs[i]->handle.Init("a", ignored_request_info_, 5, reqs[i].get());
[email protected]f6d1d6eb2009-06-24 20:16:09609 EXPECT_EQ(ERR_IO_PENDING, rv);
610 }
611
612 // Now, kMaxSocketsPerGroup requests should be active. Let's cancel them.
613 for (int i = 0; i < kMaxSocketsPerGroup; ++i)
614 reqs[i]->handle.Reset();
615
616 // Let's wait for the rest to complete now.
617
618 for (size_t i = kMaxSocketsPerGroup; i < arraysize(reqs); ++i) {
619 EXPECT_EQ(OK, reqs[i]->WaitForResult());
620 reqs[i]->handle.Reset();
621 }
622
623 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count);
624}
625
626// Make sure that pending requests get serviced after active requests fail.
[email protected]ab838892009-06-30 18:49:05627TEST_F(ClientSocketPoolBaseTest, FailingActiveRequestWithPendingRequests) {
628 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
[email protected]f6d1d6eb2009-06-24 20:16:09629
630 scoped_ptr<TestSocketRequest> reqs[kMaxSocketsPerGroup * 2 + 1];
631
632 // Queue up all the requests
[email protected]f6d1d6eb2009-06-24 20:16:09633 for (size_t i = 0; i < arraysize(reqs); ++i) {
634 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_));
[email protected]ab838892009-06-30 18:49:05635 int rv = reqs[i]->handle.Init("a", ignored_request_info_, 5, reqs[i].get());
[email protected]f6d1d6eb2009-06-24 20:16:09636 EXPECT_EQ(ERR_IO_PENDING, rv);
637 }
638
639 for (size_t i = 0; i < arraysize(reqs); ++i)
640 EXPECT_EQ(ERR_CONNECTION_FAILED, reqs[i]->WaitForResult());
641}
642
[email protected]2ab05b52009-07-01 23:57:58643// A pending asynchronous job completes, which will free up a socket slot. The
644// next job finishes synchronously. The callback for the asynchronous job
645// should be first though.
646TEST_F(ClientSocketPoolBaseTest, PendingJobCompletionOrder) {
647 // First two jobs are async.
648 connect_job_factory_->set_job_type(TestConnectJob::kMockPendingFailingJob);
649
650 // Start job 1 (async error).
651 TestSocketRequest req1(pool_.get(), &request_order_);
652 int rv = req1.handle.Init("a", ignored_request_info_, 5, &req1);
653 EXPECT_EQ(ERR_IO_PENDING, rv);
654
655 // Start job 2 (async error).
656 TestSocketRequest req2(pool_.get(), &request_order_);
657 rv = req2.handle.Init("a", ignored_request_info_, 5, &req2);
658 EXPECT_EQ(ERR_IO_PENDING, rv);
659
660 // The pending job is sync.
661 connect_job_factory_->set_job_type(TestConnectJob::kMockJob);
662
663 // Request 3 does not have a ConnectJob yet. It's just pending.
664 TestSocketRequest req3(pool_.get(), &request_order_);
665 rv = req3.handle.Init("a", ignored_request_info_, 5, &req3);
666 EXPECT_EQ(ERR_IO_PENDING, rv);
667
668 EXPECT_EQ(ERR_CONNECTION_FAILED, req1.WaitForResult());
669 EXPECT_EQ(ERR_CONNECTION_FAILED, req2.WaitForResult());
670 EXPECT_EQ(OK, req3.WaitForResult());
671
672 ASSERT_EQ(3U, request_order_.size());
673
674 // After job 1 finishes unsuccessfully, it will try to process the pending
675 // requests queue, so it starts up job 3 for request 3. This job
676 // synchronously succeeds, so the request order is 1, 3, 2.
677 EXPECT_EQ(&req1, request_order_[0]);
678 EXPECT_EQ(&req2, request_order_[2]);
679 EXPECT_EQ(&req3, request_order_[1]);
680}
681
[email protected]f6d1d6eb2009-06-24 20:16:09682} // namespace
683
684} // namespace net