OLD | NEW |
| (Empty) |
1 // 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 | |
5 #include "net/base/tcp_client_socket_pool.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/message_loop.h" | |
9 #include "net/base/client_socket.h" | |
10 #include "net/base/client_socket_factory.h" | |
11 #include "net/base/client_socket_handle.h" | |
12 #include "net/base/host_resolver_unittest.h" | |
13 #include "net/base/net_errors.h" | |
14 #include "net/base/test_completion_callback.h" | |
15 #include "testing/gtest/include/gtest/gtest.h" | |
16 | |
17 namespace net { | |
18 | |
19 namespace { | |
20 | |
21 const int kMaxSocketsPerGroup = 6; | |
22 | |
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. | |
25 const int kPriorities[10] = { 1, 7, 9, 5, 6, 2, 8, 3, 4, 1 }; | |
26 | |
27 // This is the number of extra requests beyond the first few that use up all | |
28 // available sockets in the socket group. | |
29 const int kNumPendingRequests = arraysize(kPriorities); | |
30 | |
31 const int kNumRequests = kMaxSocketsPerGroup + kNumPendingRequests; | |
32 | |
33 class MockClientSocket : public ClientSocket { | |
34 public: | |
35 MockClientSocket() : connected_(false) {} | |
36 | |
37 // ClientSocket methods: | |
38 virtual int Connect(CompletionCallback* callback) { | |
39 connected_ = true; | |
40 return OK; | |
41 } | |
42 virtual void Disconnect() { | |
43 connected_ = false; | |
44 } | |
45 virtual bool IsConnected() const { | |
46 return connected_; | |
47 } | |
48 virtual bool IsConnectedAndIdle() const { | |
49 return connected_; | |
50 } | |
51 | |
52 // Socket methods: | |
53 virtual int Read(IOBuffer* buf, int buf_len, | |
54 CompletionCallback* callback) { | |
55 return ERR_FAILED; | |
56 } | |
57 virtual int Write(IOBuffer* buf, int buf_len, | |
58 CompletionCallback* callback) { | |
59 return ERR_FAILED; | |
60 } | |
61 | |
62 private: | |
63 bool connected_; | |
64 }; | |
65 | |
66 class MockFailingClientSocket : public ClientSocket { | |
67 public: | |
68 MockFailingClientSocket() {} | |
69 | |
70 // ClientSocket methods: | |
71 virtual int Connect(CompletionCallback* callback) { | |
72 return ERR_CONNECTION_FAILED; | |
73 } | |
74 | |
75 virtual void Disconnect() {} | |
76 | |
77 virtual bool IsConnected() const { | |
78 return false; | |
79 } | |
80 virtual bool IsConnectedAndIdle() const { | |
81 return false; | |
82 } | |
83 | |
84 // Socket methods: | |
85 virtual int Read(IOBuffer* buf, int buf_len, | |
86 CompletionCallback* callback) { | |
87 return ERR_FAILED; | |
88 } | |
89 | |
90 virtual int Write(IOBuffer* buf, int buf_len, | |
91 CompletionCallback* callback) { | |
92 return ERR_FAILED; | |
93 } | |
94 }; | |
95 | |
96 class MockPendingClientSocket : public ClientSocket { | |
97 public: | |
98 MockPendingClientSocket() | |
99 : method_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {} | |
100 | |
101 // ClientSocket methods: | |
102 virtual int Connect(CompletionCallback* callback) { | |
103 MessageLoop::current()->PostTask( | |
104 FROM_HERE, | |
105 method_factory_.NewRunnableMethod( | |
106 &MockPendingClientSocket::DoCallback, callback)); | |
107 return ERR_IO_PENDING; | |
108 } | |
109 | |
110 virtual void Disconnect() {} | |
111 | |
112 virtual bool IsConnected() const { | |
113 return false; | |
114 } | |
115 virtual bool IsConnectedAndIdle() const { | |
116 return false; | |
117 } | |
118 | |
119 // Socket methods: | |
120 virtual int Read(IOBuffer* buf, int buf_len, | |
121 CompletionCallback* callback) { | |
122 return ERR_FAILED; | |
123 } | |
124 | |
125 virtual int Write(IOBuffer* buf, int buf_len, | |
126 CompletionCallback* callback) { | |
127 return ERR_FAILED; | |
128 } | |
129 | |
130 private: | |
131 void DoCallback(CompletionCallback* callback) { | |
132 callback->Run(OK); | |
133 } | |
134 | |
135 ScopedRunnableMethodFactory<MockPendingClientSocket> method_factory_; | |
136 }; | |
137 | |
138 class MockClientSocketFactory : public ClientSocketFactory { | |
139 public: | |
140 enum ClientSocketType { | |
141 MOCK_CLIENT_SOCKET, | |
142 MOCK_FAILING_CLIENT_SOCKET, | |
143 MOCK_PENDING_CLIENT_SOCKET, | |
144 }; | |
145 | |
146 MockClientSocketFactory() | |
147 : allocation_count_(0), client_socket_type_(MOCK_CLIENT_SOCKET) {} | |
148 | |
149 virtual ClientSocket* CreateTCPClientSocket(const AddressList& addresses) { | |
150 allocation_count_++; | |
151 switch (client_socket_type_) { | |
152 case MOCK_CLIENT_SOCKET: | |
153 return new MockClientSocket(); | |
154 case MOCK_FAILING_CLIENT_SOCKET: | |
155 return new MockFailingClientSocket(); | |
156 case MOCK_PENDING_CLIENT_SOCKET: | |
157 return new MockPendingClientSocket(); | |
158 default: | |
159 NOTREACHED(); | |
160 return new MockClientSocket(); | |
161 } | |
162 } | |
163 | |
164 virtual SSLClientSocket* CreateSSLClientSocket( | |
165 ClientSocket* transport_socket, | |
166 const std::string& hostname, | |
167 const SSLConfig& ssl_config) { | |
168 NOTIMPLEMENTED(); | |
169 return NULL; | |
170 } | |
171 | |
172 int allocation_count() const { return allocation_count_; } | |
173 | |
174 void set_client_socket_type(ClientSocketType type) { | |
175 client_socket_type_ = type; | |
176 } | |
177 | |
178 private: | |
179 int allocation_count_; | |
180 ClientSocketType client_socket_type_; | |
181 }; | |
182 | |
183 class TestSocketRequest : public CallbackRunner< Tuple1<int> > { | |
184 public: | |
185 TestSocketRequest( | |
186 ClientSocketPool* pool, | |
187 std::vector<TestSocketRequest*>* request_order) | |
188 : handle(pool), request_order_(request_order) {} | |
189 | |
190 ClientSocketHandle handle; | |
191 | |
192 int WaitForResult() { | |
193 return callback_.WaitForResult(); | |
194 } | |
195 | |
196 virtual void RunWithParams(const Tuple1<int>& params) { | |
197 callback_.RunWithParams(params); | |
198 completion_count++; | |
199 request_order_->push_back(this); | |
200 } | |
201 | |
202 static int completion_count; | |
203 | |
204 private: | |
205 std::vector<TestSocketRequest*>* request_order_; | |
206 TestCompletionCallback callback_; | |
207 }; | |
208 | |
209 int TestSocketRequest::completion_count = 0; | |
210 | |
211 class TCPClientSocketPoolTest : public testing::Test { | |
212 protected: | |
213 TCPClientSocketPoolTest() | |
214 : pool_(new TCPClientSocketPool(kMaxSocketsPerGroup, | |
215 &host_resolver_, | |
216 &client_socket_factory_)) {} | |
217 | |
218 virtual void SetUp() { | |
219 RuleBasedHostMapper *host_mapper = new RuleBasedHostMapper(); | |
220 host_mapper->AddRule("*", "127.0.0.1"); | |
221 scoped_host_mapper_.Init(host_mapper); | |
222 TestSocketRequest::completion_count = 0; | |
223 } | |
224 | |
225 virtual void TearDown() { | |
226 // The tests often call Reset() on handles at the end which may post | |
227 // DoReleaseSocket() tasks. | |
228 MessageLoop::current()->RunAllPending(); | |
229 } | |
230 | |
231 ScopedHostMapper scoped_host_mapper_; | |
232 HostResolver host_resolver_; | |
233 MockClientSocketFactory client_socket_factory_; | |
234 scoped_refptr<ClientSocketPool> pool_; | |
235 std::vector<TestSocketRequest*> request_order_; | |
236 }; | |
237 | |
238 TEST_F(TCPClientSocketPoolTest, Basic) { | |
239 TestCompletionCallback callback; | |
240 ClientSocketHandle handle(pool_.get()); | |
241 HostResolver::RequestInfo info("www.google.com", 80); | |
242 int rv = handle.Init("a", info, 0, &callback); | |
243 EXPECT_EQ(ERR_IO_PENDING, rv); | |
244 EXPECT_FALSE(handle.is_initialized()); | |
245 EXPECT_FALSE(handle.socket()); | |
246 | |
247 EXPECT_EQ(OK, callback.WaitForResult()); | |
248 EXPECT_TRUE(handle.is_initialized()); | |
249 EXPECT_TRUE(handle.socket()); | |
250 | |
251 handle.Reset(); | |
252 } | |
253 | |
254 TEST_F(TCPClientSocketPoolTest, InitHostResolutionFailure) { | |
255 RuleBasedHostMapper* host_mapper = new RuleBasedHostMapper; | |
256 host_mapper->AddSimulatedFailure("unresolvable.host.name"); | |
257 ScopedHostMapper scoped_host_mapper(host_mapper); | |
258 TestSocketRequest req(pool_.get(), &request_order_); | |
259 HostResolver::RequestInfo info("unresolvable.host.name", 80); | |
260 EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req)); | |
261 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, req.WaitForResult()); | |
262 } | |
263 | |
264 TEST_F(TCPClientSocketPoolTest, InitConnectionFailure) { | |
265 client_socket_factory_.set_client_socket_type( | |
266 MockClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET); | |
267 TestSocketRequest req(pool_.get(), &request_order_); | |
268 HostResolver::RequestInfo info("unresolvable.host.name", 80); | |
269 EXPECT_EQ(ERR_IO_PENDING, | |
270 req.handle.Init("a", info, 5, &req)); | |
271 EXPECT_EQ(ERR_CONNECTION_FAILED, req.WaitForResult()); | |
272 } | |
273 | |
274 TEST_F(TCPClientSocketPoolTest, PendingRequests) { | |
275 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; | |
276 | |
277 for (size_t i = 0; i < arraysize(reqs); ++i) | |
278 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | |
279 | |
280 // Create connections or queue up requests. | |
281 | |
282 // First request finishes asynchronously. | |
283 HostResolver::RequestInfo info("www.google.com", 80); | |
284 int rv = reqs[0]->handle.Init("a", info, 5, reqs[0].get()); | |
285 EXPECT_EQ(ERR_IO_PENDING, rv); | |
286 EXPECT_EQ(OK, reqs[0]->WaitForResult()); | |
287 | |
288 // Rest of them finish synchronously, since they're in the HostCache. | |
289 for (int i = 1; i < kMaxSocketsPerGroup; ++i) { | |
290 rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); | |
291 EXPECT_EQ(OK, rv); | |
292 request_order_.push_back(reqs[i].get()); | |
293 } | |
294 | |
295 // The rest are pending since we've used all active sockets. | |
296 for (int i = 0; i < kNumPendingRequests; ++i) { | |
297 rv = reqs[kMaxSocketsPerGroup + i]->handle.Init( | |
298 "a", info, kPriorities[i], reqs[kMaxSocketsPerGroup + i].get()); | |
299 EXPECT_EQ(ERR_IO_PENDING, rv); | |
300 } | |
301 | |
302 // Release any connections until we have no connections. | |
303 bool released_one; | |
304 do { | |
305 released_one = false; | |
306 for (size_t i = 0; i < arraysize(reqs); ++i) { | |
307 if (reqs[i]->handle.is_initialized()) { | |
308 reqs[i]->handle.Reset(); | |
309 MessageLoop::current()->RunAllPending(); | |
310 released_one = true; | |
311 } | |
312 } | |
313 } while (released_one); | |
314 | |
315 EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count()); | |
316 EXPECT_EQ(kNumPendingRequests + 1, TestSocketRequest::completion_count); | |
317 | |
318 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { | |
319 EXPECT_EQ(request_order_[i], reqs[i].get()) << | |
320 "Request " << i << " was not in order."; | |
321 } | |
322 | |
323 for (int i = 0; i < kNumPendingRequests - 1; ++i) { | |
324 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i]; | |
325 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue], | |
326 reqs[kMaxSocketsPerGroup + i].get()) << | |
327 "Request " << kMaxSocketsPerGroup + i << " was not in order."; | |
328 } | |
329 | |
330 EXPECT_EQ(request_order_[arraysize(reqs) - 1], | |
331 reqs[arraysize(reqs) - 1].get()) << | |
332 "The last request with priority 1 should not have been inserted " | |
333 "earlier into the queue."; | |
334 } | |
335 | |
336 TEST_F(TCPClientSocketPoolTest, PendingRequests_NoKeepAlive) { | |
337 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; | |
338 for (size_t i = 0; i < arraysize(reqs); ++i) | |
339 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | |
340 | |
341 // Create connections or queue up requests. | |
342 | |
343 // First request finishes asynchronously. | |
344 HostResolver::RequestInfo info("www.google.com", 80); | |
345 int rv = reqs[0]->handle.Init("a", info, 5, reqs[0].get()); | |
346 EXPECT_EQ(ERR_IO_PENDING, rv); | |
347 EXPECT_EQ(OK, reqs[0]->WaitForResult()); | |
348 | |
349 // Rest of them finish synchronously, since they're in the HostCache. | |
350 for (int i = 1; i < kMaxSocketsPerGroup; ++i) { | |
351 rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); | |
352 EXPECT_EQ(OK, rv); | |
353 request_order_.push_back(reqs[i].get()); | |
354 } | |
355 | |
356 // The rest are pending since we've used all active sockets. | |
357 for (int i = 0; i < kNumPendingRequests; ++i) { | |
358 EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( | |
359 "a", info, 0, reqs[kMaxSocketsPerGroup + i].get())); | |
360 } | |
361 | |
362 // Release any connections until we have no connections. | |
363 bool released_one; | |
364 do { | |
365 released_one = false; | |
366 for (size_t i = 0; i < arraysize(reqs); ++i) { | |
367 if (reqs[i]->handle.is_initialized()) { | |
368 reqs[i]->handle.socket()->Disconnect(); // No keep alive. | |
369 reqs[i]->handle.Reset(); | |
370 MessageLoop::current()->RunAllPending(); | |
371 released_one = true; | |
372 } | |
373 } | |
374 } while (released_one); | |
375 | |
376 for (int i = kMaxSocketsPerGroup; i < kNumRequests; ++i) | |
377 EXPECT_EQ(OK, reqs[i]->WaitForResult()); | |
378 | |
379 EXPECT_EQ(kNumRequests, client_socket_factory_.allocation_count()); | |
380 EXPECT_EQ(kNumPendingRequests + 1, TestSocketRequest::completion_count); | |
381 } | |
382 | |
383 // This test will start up a RequestSocket() and then immediately Cancel() it. | |
384 // The pending host resolution will eventually complete, and destroy the | |
385 // ClientSocketPool which will crash if the group was not cleared properly. | |
386 TEST_F(TCPClientSocketPoolTest, CancelRequestClearGroup) { | |
387 TestSocketRequest req(pool_.get(), &request_order_); | |
388 HostResolver::RequestInfo info("www.google.com", 80); | |
389 EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req)); | |
390 req.handle.Reset(); | |
391 | |
392 PlatformThread::Sleep(100); | |
393 | |
394 // There is a race condition here. If the worker pool doesn't post the task | |
395 // before we get here, then this might not run ConnectingSocket::OnIOComplete | |
396 // and therefore leak the canceled ConnectingSocket. However, other tests | |
397 // after this will call MessageLoop::RunAllPending() which should prevent a | |
398 // leak, unless the worker thread takes longer than all of them. | |
399 MessageLoop::current()->RunAllPending(); | |
400 } | |
401 | |
402 TEST_F(TCPClientSocketPoolTest, TwoRequestsCancelOne) { | |
403 TestSocketRequest req(pool_.get(), &request_order_); | |
404 TestSocketRequest req2(pool_.get(), &request_order_); | |
405 | |
406 HostResolver::RequestInfo info("www.google.com", 80); | |
407 EXPECT_EQ(ERR_IO_PENDING, req.handle.Init("a", info, 5, &req)); | |
408 EXPECT_EQ(ERR_IO_PENDING, req2.handle.Init("a", info, 5, &req2)); | |
409 | |
410 req.handle.Reset(); | |
411 | |
412 EXPECT_EQ(OK, req2.WaitForResult()); | |
413 req2.handle.Reset(); | |
414 } | |
415 | |
416 TEST_F(TCPClientSocketPoolTest, ConnectCancelConnect) { | |
417 client_socket_factory_.set_client_socket_type( | |
418 MockClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET); | |
419 ClientSocketHandle handle(pool_.get()); | |
420 TestCompletionCallback callback; | |
421 TestSocketRequest req(pool_.get(), &request_order_); | |
422 | |
423 HostResolver::RequestInfo info("www.google.com", 80); | |
424 EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", info, 5, &callback)); | |
425 | |
426 handle.Reset(); | |
427 | |
428 TestCompletionCallback callback2; | |
429 EXPECT_EQ(ERR_IO_PENDING, handle.Init("a", info, 5, &callback2)); | |
430 | |
431 // At this point, handle has two ConnectingSockets out for it. Due to the | |
432 // host cache, the host resolution for both will return in the same loop of | |
433 // the MessageLoop. The client socket is a pending socket, so the Connect() | |
434 // will asynchronously complete on the next loop of the MessageLoop. That | |
435 // means that the first ConnectingSocket will enter OnIOComplete, and then the | |
436 // second one will. If the first one is not cancelled, it will advance the | |
437 // load state, and then the second one will crash. | |
438 | |
439 EXPECT_EQ(OK, callback2.WaitForResult()); | |
440 EXPECT_FALSE(callback.have_result()); | |
441 | |
442 handle.Reset(); | |
443 } | |
444 | |
445 TEST_F(TCPClientSocketPoolTest, CancelRequest) { | |
446 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; | |
447 | |
448 for (size_t i = 0; i < arraysize(reqs); ++i) | |
449 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | |
450 | |
451 // Create connections or queue up requests. | |
452 HostResolver::RequestInfo info("www.google.com", 80); | |
453 | |
454 // First request finishes asynchronously. | |
455 int rv = reqs[0]->handle.Init("a", info, 5, reqs[0].get()); | |
456 EXPECT_EQ(ERR_IO_PENDING, rv); | |
457 EXPECT_EQ(OK, reqs[0]->WaitForResult()); | |
458 | |
459 // Rest of them finish synchronously, since they're in the HostCache. | |
460 for (int i = 1; i < kMaxSocketsPerGroup; ++i) { | |
461 rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); | |
462 EXPECT_EQ(OK, rv); | |
463 request_order_.push_back(reqs[i].get()); | |
464 } | |
465 | |
466 // The rest are pending since we've used all active sockets. | |
467 for (int i = 0; i < kNumPendingRequests; ++i) { | |
468 EXPECT_EQ(ERR_IO_PENDING, reqs[kMaxSocketsPerGroup + i]->handle.Init( | |
469 "a", info, kPriorities[i], reqs[kMaxSocketsPerGroup + i].get())); | |
470 } | |
471 | |
472 // Cancel a request. | |
473 size_t index_to_cancel = kMaxSocketsPerGroup + 2; | |
474 EXPECT_TRUE(!reqs[index_to_cancel]->handle.is_initialized()); | |
475 reqs[index_to_cancel]->handle.Reset(); | |
476 | |
477 // Release any connections until we have no connections. | |
478 bool released_one; | |
479 do { | |
480 released_one = false; | |
481 for (size_t i = 0; i < arraysize(reqs); ++i) { | |
482 if (reqs[i]->handle.is_initialized()) { | |
483 reqs[i]->handle.Reset(); | |
484 MessageLoop::current()->RunAllPending(); | |
485 released_one = true; | |
486 } | |
487 } | |
488 } while (released_one); | |
489 | |
490 EXPECT_EQ(kMaxSocketsPerGroup, client_socket_factory_.allocation_count()); | |
491 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count); | |
492 | |
493 for (int i = 0; i < kMaxSocketsPerGroup; ++i) { | |
494 EXPECT_EQ(request_order_[i], reqs[i].get()) << | |
495 "Request " << i << " was not in order."; | |
496 } | |
497 | |
498 for (int i = 0; i < kNumPendingRequests - 1; ++i) { | |
499 if (i == 2) continue; | |
500 int index_in_queue = (kNumPendingRequests - 1) - kPriorities[i]; | |
501 if (kPriorities[i] < kPriorities[index_to_cancel - kMaxSocketsPerGroup]) | |
502 index_in_queue--; | |
503 EXPECT_EQ(request_order_[kMaxSocketsPerGroup + index_in_queue], | |
504 reqs[kMaxSocketsPerGroup + i].get()) << | |
505 "Request " << kMaxSocketsPerGroup + i << " was not in order."; | |
506 } | |
507 | |
508 EXPECT_EQ(request_order_[arraysize(reqs) - 2], | |
509 reqs[arraysize(reqs) - 1].get()) << | |
510 "The last request with priority 1 should not have been inserted " | |
511 "earlier into the queue."; | |
512 } | |
513 | |
514 class RequestSocketCallback : public CallbackRunner< Tuple1<int> > { | |
515 public: | |
516 RequestSocketCallback(ClientSocketHandle* handle) | |
517 : handle_(handle), | |
518 within_callback_(false) {} | |
519 | |
520 virtual void RunWithParams(const Tuple1<int>& params) { | |
521 callback_.RunWithParams(params); | |
522 ASSERT_EQ(OK, params.a); | |
523 | |
524 if (!within_callback_) { | |
525 handle_->Reset(); | |
526 within_callback_ = true; | |
527 int rv = handle_->Init( | |
528 "a", HostResolver::RequestInfo("www.google.com", 80), 0, this); | |
529 EXPECT_EQ(OK, rv); | |
530 } | |
531 } | |
532 | |
533 int WaitForResult() { | |
534 return callback_.WaitForResult(); | |
535 } | |
536 | |
537 private: | |
538 ClientSocketHandle* const handle_; | |
539 bool within_callback_; | |
540 TestCompletionCallback callback_; | |
541 }; | |
542 | |
543 TEST_F(TCPClientSocketPoolTest, RequestTwice) { | |
544 ClientSocketHandle handle(pool_.get()); | |
545 RequestSocketCallback callback(&handle); | |
546 int rv = handle.Init( | |
547 "a", HostResolver::RequestInfo("www.google.com", 80), 0, &callback); | |
548 ASSERT_EQ(ERR_IO_PENDING, rv); | |
549 | |
550 EXPECT_EQ(OK, callback.WaitForResult()); | |
551 | |
552 handle.Reset(); | |
553 } | |
554 | |
555 // Make sure that pending requests get serviced after active requests get | |
556 // cancelled. | |
557 TEST_F(TCPClientSocketPoolTest, CancelActiveRequestWithPendingRequests) { | |
558 client_socket_factory_.set_client_socket_type( | |
559 MockClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET); | |
560 | |
561 scoped_ptr<TestSocketRequest> reqs[kNumRequests]; | |
562 | |
563 // Queue up all the requests | |
564 | |
565 HostResolver::RequestInfo info("www.google.com", 80); | |
566 for (size_t i = 0; i < arraysize(reqs); ++i) { | |
567 reqs[i].reset(new TestSocketRequest(pool_.get(), &request_order_)); | |
568 int rv = reqs[i]->handle.Init("a", info, 5, reqs[i].get()); | |
569 EXPECT_EQ(ERR_IO_PENDING, rv); | |
570 } | |
571 | |
572 // Now, kMaxSocketsPerGroup requests should be active. Let's cancel them. | |
573 for (int i = 0; i < kMaxSocketsPerGroup; ++i) | |
574 reqs[i]->handle.Reset(); | |
575 | |
576 // Let's wait for the rest to complete now. | |
577 | |
578 for (size_t i = kMaxSocketsPerGroup; i < arraysize(reqs); ++i) { | |
579 EXPECT_EQ(OK, reqs[i]->WaitForResult()); | |
580 reqs[i]->handle.Reset(); | |
581 } | |
582 | |
583 EXPECT_EQ(kNumPendingRequests, TestSocketRequest::completion_count); | |
584 } | |
585 | |
586 } // namespace | |
587 | |
588 } // namespace net | |
OLD | NEW |