OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 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/socket/websocket_transport_client_socket_pool.h" | |
6 | |
7 #include <queue> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/bind_helpers.h" | |
11 #include "base/callback.h" | |
12 #include "base/macros.h" | |
13 #include "base/message_loop/message_loop.h" | |
14 #include "base/run_loop.h" | |
15 #include "base/strings/stringprintf.h" | |
16 #include "base/time/time.h" | |
17 #include "net/base/capturing_net_log.h" | |
18 #include "net/base/ip_endpoint.h" | |
19 #include "net/base/load_timing_info.h" | |
20 #include "net/base/load_timing_info_test_util.h" | |
21 #include "net/base/net_errors.h" | |
22 #include "net/base/net_util.h" | |
23 #include "net/base/test_completion_callback.h" | |
24 #include "net/dns/mock_host_resolver.h" | |
25 #include "net/socket/client_socket_handle.h" | |
26 #include "net/socket/client_socket_pool_histograms.h" | |
27 #include "net/socket/socket_test_util.h" | |
28 #include "net/socket/stream_socket.h" | |
29 #include "net/socket/transport_client_socket_pool_test_util.h" | |
30 #include "net/socket/websocket_endpoint_lock_manager.h" | |
31 #include "testing/gtest/include/gtest/gtest.h" | |
32 | |
33 namespace net { | |
34 | |
35 namespace { | |
36 | |
37 const int kMaxSockets = 32; | |
38 const int kMaxSocketsPerGroup = 6; | |
39 const net::RequestPriority kDefaultPriority = LOW; | |
40 | |
41 // RunLoop doesn't support this natively but it is easy to emulate. | |
42 void RunLoopForTimePeriod(base::TimeDelta period) { | |
43 base::RunLoop run_loop; | |
44 base::Closure quit_closure(run_loop.QuitClosure()); | |
45 base::MessageLoop::current()->PostDelayedTask( | |
46 FROM_HERE, quit_closure, period); | |
47 run_loop.Run(); | |
48 } | |
49 | |
50 class WebSocketTransportClientSocketPoolTest : public testing::Test { | |
51 protected: | |
52 WebSocketTransportClientSocketPoolTest() | |
53 : params_(new TransportSocketParams(HostPortPair("www.google.com", 80), | |
54 false, | |
55 false, | |
56 OnHostResolutionCallback())), | |
57 histograms_(new ClientSocketPoolHistograms("TCPUnitTest")), | |
58 host_resolver_(new MockHostResolver), | |
59 client_socket_factory_(&net_log_), | |
60 pool_(kMaxSockets, | |
61 kMaxSocketsPerGroup, | |
62 histograms_.get(), | |
63 host_resolver_.get(), | |
64 &client_socket_factory_, | |
65 NULL) {} | |
66 | |
67 virtual ~WebSocketTransportClientSocketPoolTest() { | |
68 ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE); | |
69 EXPECT_TRUE(WebSocketEndpointLockManager::GetInstance()->IsEmpty()); | |
70 } | |
71 | |
72 int StartRequest(const std::string& group_name, RequestPriority priority) { | |
73 scoped_refptr<TransportSocketParams> params( | |
74 new TransportSocketParams(HostPortPair("www.google.com", 80), | |
75 false, | |
76 false, | |
77 OnHostResolutionCallback())); | |
78 return test_base_.StartRequestUsingPool( | |
79 &pool_, group_name, priority, params); | |
80 } | |
81 | |
82 int GetOrderOfRequest(size_t index) { | |
83 return test_base_.GetOrderOfRequest(index); | |
84 } | |
85 | |
86 bool ReleaseOneConnection(ClientSocketPoolTest::KeepAlive keep_alive) { | |
87 return test_base_.ReleaseOneConnection(keep_alive); | |
88 } | |
89 | |
90 void ReleaseAllConnections(ClientSocketPoolTest::KeepAlive keep_alive) { | |
91 test_base_.ReleaseAllConnections(keep_alive); | |
92 } | |
93 | |
94 TestSocketRequest* request(int i) { return test_base_.request(i); } | |
95 | |
96 ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); } | |
97 size_t completion_count() const { return test_base_.completion_count(); } | |
98 | |
99 CapturingNetLog net_log_; | |
100 scoped_refptr<TransportSocketParams> params_; | |
101 scoped_ptr<ClientSocketPoolHistograms> histograms_; | |
102 scoped_ptr<MockHostResolver> host_resolver_; | |
103 MockTransportClientSocketFactory client_socket_factory_; | |
104 WebSocketTransportClientSocketPool pool_; | |
105 ClientSocketPoolTest test_base_; | |
106 | |
107 private: | |
108 DISALLOW_COPY_AND_ASSIGN(WebSocketTransportClientSocketPoolTest); | |
109 }; | |
110 | |
111 TEST_F(WebSocketTransportClientSocketPoolTest, Basic) { | |
112 TestCompletionCallback callback; | |
113 ClientSocketHandle handle; | |
114 int rv = handle.Init( | |
115 "a", params_, LOW, callback.callback(), &pool_, BoundNetLog()); | |
116 EXPECT_EQ(ERR_IO_PENDING, rv); | |
117 EXPECT_FALSE(handle.is_initialized()); | |
118 EXPECT_FALSE(handle.socket()); | |
119 | |
120 EXPECT_EQ(OK, callback.WaitForResult()); | |
121 EXPECT_TRUE(handle.is_initialized()); | |
122 EXPECT_TRUE(handle.socket()); | |
123 TestLoadTimingInfoConnectedNotReused(handle); | |
124 } | |
125 | |
126 // Make sure that WebSocketTransportConnectJob passes on its priority to its | |
127 // HostResolver request on Init. | |
128 TEST_F(WebSocketTransportClientSocketPoolTest, SetResolvePriorityOnInit) { | |
129 for (int i = MINIMUM_PRIORITY; i <= MAXIMUM_PRIORITY; ++i) { | |
130 RequestPriority priority = static_cast<RequestPriority>(i); | |
131 TestCompletionCallback callback; | |
132 ClientSocketHandle handle; | |
133 EXPECT_EQ(ERR_IO_PENDING, | |
134 handle.Init("a", | |
135 params_, | |
136 priority, | |
137 callback.callback(), | |
138 &pool_, | |
139 BoundNetLog())); | |
140 EXPECT_EQ(priority, host_resolver_->last_request_priority()); | |
141 } | |
142 } | |
143 | |
144 TEST_F(WebSocketTransportClientSocketPoolTest, InitHostResolutionFailure) { | |
145 host_resolver_->rules()->AddSimulatedFailure("unresolvable.host.name"); | |
146 TestCompletionCallback callback; | |
147 ClientSocketHandle handle; | |
148 HostPortPair host_port_pair("unresolvable.host.name", 80); | |
149 scoped_refptr<TransportSocketParams> dest(new TransportSocketParams( | |
150 host_port_pair, false, false, OnHostResolutionCallback())); | |
151 EXPECT_EQ(ERR_IO_PENDING, | |
152 handle.Init("a", | |
153 dest, | |
154 kDefaultPriority, | |
155 callback.callback(), | |
156 &pool_, | |
157 BoundNetLog())); | |
158 EXPECT_EQ(ERR_NAME_NOT_RESOLVED, callback.WaitForResult()); | |
159 } | |
160 | |
161 TEST_F(WebSocketTransportClientSocketPoolTest, InitConnectionFailure) { | |
162 client_socket_factory_.set_client_socket_type( | |
163 MockTransportClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET); | |
164 TestCompletionCallback callback; | |
165 ClientSocketHandle handle; | |
166 EXPECT_EQ(ERR_IO_PENDING, | |
167 handle.Init("a", | |
168 params_, | |
169 kDefaultPriority, | |
170 callback.callback(), | |
171 &pool_, | |
172 BoundNetLog())); | |
173 EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult()); | |
174 | |
175 // Make the host resolutions complete synchronously this time. | |
176 host_resolver_->set_synchronous_mode(true); | |
177 EXPECT_EQ(ERR_CONNECTION_FAILED, | |
178 handle.Init("a", | |
179 params_, | |
180 kDefaultPriority, | |
181 callback.callback(), | |
182 &pool_, | |
183 BoundNetLog())); | |
184 } | |
185 | |
186 TEST_F(WebSocketTransportClientSocketPoolTest, PendingRequestsFinishFifo) { | |
187 // First request finishes asynchronously. | |
188 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
189 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
190 | |
191 // Make all subsequent host resolutions complete synchronously. | |
192 host_resolver_->set_synchronous_mode(true); | |
193 | |
194 // Rest of them wait for the first socket to be released. | |
195 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
196 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
197 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
198 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
199 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
200 | |
201 ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE); | |
202 | |
203 EXPECT_EQ(6, client_socket_factory_.allocation_count()); | |
204 | |
205 // One initial asynchronous request and then 5 pending requests. | |
206 EXPECT_EQ(6U, completion_count()); | |
207 | |
208 // The requests finish in FIFO order. | |
209 EXPECT_EQ(1, GetOrderOfRequest(1)); | |
210 EXPECT_EQ(2, GetOrderOfRequest(2)); | |
211 EXPECT_EQ(3, GetOrderOfRequest(3)); | |
212 EXPECT_EQ(4, GetOrderOfRequest(4)); | |
213 EXPECT_EQ(5, GetOrderOfRequest(5)); | |
214 EXPECT_EQ(6, GetOrderOfRequest(6)); | |
215 | |
216 // Make sure we test order of all requests made. | |
217 EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(7)); | |
218 } | |
219 | |
220 TEST_F(WebSocketTransportClientSocketPoolTest, PendingRequests_NoKeepAlive) { | |
221 // First request finishes asynchronously. | |
222 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
223 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
224 | |
225 // Make all subsequent host resolutions complete synchronously. | |
226 host_resolver_->set_synchronous_mode(true); | |
227 | |
228 // Rest of them wait foe the first socket to be released. | |
tyoshino (SeeGerritForStatus)
2014/06/24 05:46:52
foe -> for
Adam Rice
2014/06/24 06:28:37
Done.
| |
229 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
230 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
231 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
232 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
233 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
234 | |
235 ReleaseAllConnections(ClientSocketPoolTest::NO_KEEP_ALIVE); | |
236 | |
237 // The pending requests should finish successfully. | |
238 EXPECT_EQ(OK, request(1)->WaitForResult()); | |
239 EXPECT_EQ(OK, request(2)->WaitForResult()); | |
240 EXPECT_EQ(OK, request(3)->WaitForResult()); | |
241 EXPECT_EQ(OK, request(4)->WaitForResult()); | |
242 EXPECT_EQ(OK, request(5)->WaitForResult()); | |
243 | |
244 EXPECT_EQ(static_cast<int>(requests()->size()), | |
245 client_socket_factory_.allocation_count()); | |
246 | |
247 // First asynchronous request, and then last 5 pending requests. | |
248 EXPECT_EQ(6U, completion_count()); | |
249 } | |
250 | |
251 // This test will start up a RequestSocket() and then immediately Cancel() it. | |
252 // The pending host resolution will eventually complete, and destroy the | |
253 // ClientSocketPool which will crash if the group was not cleared properly. | |
254 TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequestClearGroup) { | |
255 TestCompletionCallback callback; | |
256 ClientSocketHandle handle; | |
257 EXPECT_EQ(ERR_IO_PENDING, | |
258 handle.Init("a", | |
259 params_, | |
260 kDefaultPriority, | |
261 callback.callback(), | |
262 &pool_, | |
263 BoundNetLog())); | |
264 handle.Reset(); | |
265 } | |
266 | |
267 TEST_F(WebSocketTransportClientSocketPoolTest, TwoRequestsCancelOne) { | |
268 ClientSocketHandle handle; | |
269 TestCompletionCallback callback; | |
270 ClientSocketHandle handle2; | |
271 TestCompletionCallback callback2; | |
272 | |
273 EXPECT_EQ(ERR_IO_PENDING, | |
274 handle.Init("a", | |
275 params_, | |
276 kDefaultPriority, | |
277 callback.callback(), | |
278 &pool_, | |
279 BoundNetLog())); | |
280 EXPECT_EQ(ERR_IO_PENDING, | |
281 handle2.Init("a", | |
282 params_, | |
283 kDefaultPriority, | |
284 callback2.callback(), | |
285 &pool_, | |
286 BoundNetLog())); | |
287 | |
288 handle.Reset(); | |
289 | |
290 EXPECT_EQ(OK, callback2.WaitForResult()); | |
291 handle2.Reset(); | |
292 } | |
293 | |
294 TEST_F(WebSocketTransportClientSocketPoolTest, ConnectCancelConnect) { | |
295 client_socket_factory_.set_client_socket_type( | |
296 MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET); | |
297 ClientSocketHandle handle; | |
298 TestCompletionCallback callback; | |
299 EXPECT_EQ(ERR_IO_PENDING, | |
300 handle.Init("a", | |
301 params_, | |
302 kDefaultPriority, | |
303 callback.callback(), | |
304 &pool_, | |
305 BoundNetLog())); | |
306 | |
307 handle.Reset(); | |
308 | |
309 TestCompletionCallback callback2; | |
310 EXPECT_EQ(ERR_IO_PENDING, | |
311 handle.Init("a", | |
312 params_, | |
313 kDefaultPriority, | |
314 callback2.callback(), | |
315 &pool_, | |
316 BoundNetLog())); | |
317 | |
318 host_resolver_->set_synchronous_mode(true); | |
319 // At this point, handle has two ConnectingSockets out for it. Due to the | |
320 // setting the mock resolver into synchronous mode, the host resolution for | |
321 // both will return in the same loop of the MessageLoop. The client socket | |
322 // is a pending socket, so the Connect() will asynchronously complete on the | |
323 // next loop of the MessageLoop. That means that the first | |
324 // ConnectingSocket will enter OnIOComplete, and then the second one will. | |
325 // If the first one is not cancelled, it will advance the load state, and | |
326 // then the second one will crash. | |
327 | |
328 EXPECT_EQ(OK, callback2.WaitForResult()); | |
329 EXPECT_FALSE(callback.have_result()); | |
330 | |
331 handle.Reset(); | |
332 } | |
333 | |
334 TEST_F(WebSocketTransportClientSocketPoolTest, CancelRequest) { | |
335 // First request finishes asynchronously. | |
336 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
337 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
338 | |
339 // Make all subsequent host resolutions complete synchronously. | |
340 host_resolver_->set_synchronous_mode(true); | |
341 | |
342 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
343 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
344 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
345 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
346 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
347 | |
348 // Cancel a request. | |
349 const size_t index_to_cancel = 2; | |
350 EXPECT_FALSE(request(index_to_cancel)->handle()->is_initialized()); | |
351 request(index_to_cancel)->handle()->Reset(); | |
352 | |
353 ReleaseAllConnections(ClientSocketPoolTest::KEEP_ALIVE); | |
354 | |
355 EXPECT_EQ(5, client_socket_factory_.allocation_count()); | |
356 | |
357 EXPECT_EQ(1, GetOrderOfRequest(1)); | |
358 EXPECT_EQ(2, GetOrderOfRequest(2)); | |
359 EXPECT_EQ(ClientSocketPoolTest::kRequestNotFound, | |
360 GetOrderOfRequest(3)); // Canceled request. | |
361 EXPECT_EQ(3, GetOrderOfRequest(4)); | |
362 EXPECT_EQ(4, GetOrderOfRequest(5)); | |
363 EXPECT_EQ(5, GetOrderOfRequest(6)); | |
364 | |
365 // Make sure we test order of all requests made. | |
366 EXPECT_EQ(ClientSocketPoolTest::kIndexOutOfBounds, GetOrderOfRequest(7)); | |
367 } | |
368 | |
369 class RequestSocketCallback : public TestCompletionCallbackBase { | |
370 public: | |
371 RequestSocketCallback(ClientSocketHandle* handle, | |
372 WebSocketTransportClientSocketPool* pool) | |
373 : handle_(handle), | |
374 pool_(pool), | |
375 within_callback_(false), | |
376 callback_(base::Bind(&RequestSocketCallback::OnComplete, | |
377 base::Unretained(this))) {} | |
378 | |
379 virtual ~RequestSocketCallback() {} | |
380 | |
381 const CompletionCallback& callback() const { return callback_; } | |
382 | |
383 private: | |
384 void OnComplete(int result) { | |
385 SetResult(result); | |
386 ASSERT_EQ(OK, result); | |
387 | |
388 if (!within_callback_) { | |
389 // Don't allow reuse of the socket. Disconnect it and then release it and | |
390 // run through the MessageLoop once to get it completely released. | |
391 handle_->socket()->Disconnect(); | |
392 handle_->Reset(); | |
393 { | |
394 base::MessageLoop::ScopedNestableTaskAllower allow( | |
395 base::MessageLoop::current()); | |
396 base::MessageLoop::current()->RunUntilIdle(); | |
397 } | |
398 within_callback_ = true; | |
399 scoped_refptr<TransportSocketParams> dest( | |
400 new TransportSocketParams(HostPortPair("www.google.com", 80), | |
401 false, | |
402 false, | |
403 OnHostResolutionCallback())); | |
404 int rv = | |
405 handle_->Init("a", dest, LOWEST, callback(), pool_, BoundNetLog()); | |
406 EXPECT_EQ(OK, rv); | |
407 } | |
408 } | |
409 | |
410 ClientSocketHandle* const handle_; | |
411 WebSocketTransportClientSocketPool* const pool_; | |
412 bool within_callback_; | |
413 CompletionCallback callback_; | |
414 | |
415 DISALLOW_COPY_AND_ASSIGN(RequestSocketCallback); | |
416 }; | |
417 | |
418 TEST_F(WebSocketTransportClientSocketPoolTest, RequestTwice) { | |
419 ClientSocketHandle handle; | |
420 RequestSocketCallback callback(&handle, &pool_); | |
421 scoped_refptr<TransportSocketParams> dest( | |
422 new TransportSocketParams(HostPortPair("www.google.com", 80), | |
423 false, | |
424 false, | |
425 OnHostResolutionCallback())); | |
426 int rv = handle.Init( | |
427 "a", dest, LOWEST, callback.callback(), &pool_, BoundNetLog()); | |
428 ASSERT_EQ(ERR_IO_PENDING, rv); | |
429 | |
430 // The callback is going to request "www.google.com". We want it to complete | |
431 // synchronously this time. | |
432 host_resolver_->set_synchronous_mode(true); | |
433 | |
434 EXPECT_EQ(OK, callback.WaitForResult()); | |
435 | |
436 handle.Reset(); | |
437 } | |
438 | |
439 // Make sure that pending requests get serviced after active requests get | |
440 // cancelled. | |
441 TEST_F(WebSocketTransportClientSocketPoolTest, | |
442 CancelActiveRequestWithPendingRequests) { | |
443 client_socket_factory_.set_client_socket_type( | |
444 MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET); | |
445 | |
446 // Queue up all the requests | |
447 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
448 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
449 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
450 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
451 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
452 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
453 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
454 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
455 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
456 | |
457 // Now, kMaxSocketsPerGroup requests should be active. Let's cancel them. | |
458 ASSERT_LE(kMaxSocketsPerGroup, static_cast<int>(requests()->size())); | |
459 for (int i = 0; i < kMaxSocketsPerGroup; i++) | |
460 request(i)->handle()->Reset(); | |
461 | |
462 // Let's wait for the rest to complete now. | |
463 for (size_t i = kMaxSocketsPerGroup; i < requests()->size(); ++i) { | |
464 EXPECT_EQ(OK, request(i)->WaitForResult()); | |
465 request(i)->handle()->Reset(); | |
466 } | |
467 | |
468 EXPECT_EQ(requests()->size() - kMaxSocketsPerGroup, completion_count()); | |
469 } | |
470 | |
471 // Make sure that pending requests get serviced after active requests fail. | |
472 TEST_F(WebSocketTransportClientSocketPoolTest, | |
473 FailingActiveRequestWithPendingRequests) { | |
474 client_socket_factory_.set_client_socket_type( | |
475 MockTransportClientSocketFactory::MOCK_PENDING_FAILING_CLIENT_SOCKET); | |
476 | |
477 const int kNumRequests = 2 * kMaxSocketsPerGroup + 1; | |
478 ASSERT_LE(kNumRequests, kMaxSockets); // Otherwise the test will hang. | |
479 | |
480 // Queue up all the requests | |
481 for (int i = 0; i < kNumRequests; i++) | |
482 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
483 | |
484 for (int i = 0; i < kNumRequests; i++) | |
485 EXPECT_EQ(ERR_CONNECTION_FAILED, request(i)->WaitForResult()); | |
486 } | |
487 | |
488 // The lock on the endpoint is released when a ClientSocketHandle is reset. | |
489 TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleReset) { | |
490 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
491 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
492 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
493 EXPECT_FALSE(request(1)->handle()->is_initialized()); | |
494 request(0)->handle()->Reset(); | |
495 base::RunLoop().RunUntilIdle(); | |
496 EXPECT_TRUE(request(1)->handle()->is_initialized()); | |
497 } | |
498 | |
499 // The lock on the endpoint is released when a ClientSocketHandle is deleted. | |
500 TEST_F(WebSocketTransportClientSocketPoolTest, LockReleasedOnHandleDelete) { | |
501 TestCompletionCallback callback; | |
502 scoped_ptr<ClientSocketHandle> handle(new ClientSocketHandle); | |
503 int rv = handle->Init( | |
504 "a", params_, LOW, callback.callback(), &pool_, BoundNetLog()); | |
505 EXPECT_EQ(ERR_IO_PENDING, rv); | |
506 | |
507 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
508 EXPECT_EQ(OK, callback.WaitForResult()); | |
509 EXPECT_FALSE(request(0)->handle()->is_initialized()); | |
510 handle.reset(); | |
511 base::RunLoop().RunUntilIdle(); | |
512 EXPECT_TRUE(request(0)->handle()->is_initialized()); | |
513 } | |
514 | |
515 // A new connection is performed when the lock on the previous connection is | |
516 // explicity released. | |
517 TEST_F(WebSocketTransportClientSocketPoolTest, | |
518 ConnectionProceedsOnExplicitRelease) { | |
519 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
520 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
521 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
522 EXPECT_FALSE(request(1)->handle()->is_initialized()); | |
523 WebSocketTransportClientSocketPool::UnlockEndpoint(request(0)->handle()); | |
524 base::RunLoop().RunUntilIdle(); | |
525 EXPECT_TRUE(request(1)->handle()->is_initialized()); | |
526 } | |
527 | |
528 // A connection which is cancelled before completion does not block subsequent | |
529 // connections. | |
530 TEST_F(WebSocketTransportClientSocketPoolTest, | |
531 CancelDuringConnectionReleasesLock) { | |
532 MockTransportClientSocketFactory::ClientSocketType case_types[] = { | |
533 MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET, | |
534 MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET}; | |
535 | |
536 client_socket_factory_.set_client_socket_types(case_types, | |
537 arraysize(case_types)); | |
538 | |
539 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
540 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
541 base::RunLoop().RunUntilIdle(); | |
542 pool_.CancelRequest("a", (request(0))->handle()); | |
543 EXPECT_EQ(OK, request(1)->WaitForResult()); | |
544 } | |
545 | |
546 // Test the case of the IPv6 address stalling, and falling back to the IPv4 | |
547 // socket which finishes first. | |
548 TEST_F(WebSocketTransportClientSocketPoolTest, | |
549 IPv6FallbackSocketIPv4FinishesFirst) { | |
550 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
551 kMaxSocketsPerGroup, | |
552 histograms_.get(), | |
553 host_resolver_.get(), | |
554 &client_socket_factory_, | |
555 NULL); | |
556 | |
557 MockTransportClientSocketFactory::ClientSocketType case_types[] = { | |
558 // This is the IPv6 socket. | |
559 MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET, | |
560 // This is the IPv4 socket. | |
561 MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET}; | |
562 | |
563 client_socket_factory_.set_client_socket_types(case_types, 2); | |
564 | |
565 // Resolve an AddressList with a IPv6 address first and then a IPv4 address. | |
566 host_resolver_->rules()->AddIPLiteralRule( | |
567 "*", "2:abcd::3:4:ff,2.2.2.2", std::string()); | |
568 | |
569 TestCompletionCallback callback; | |
570 ClientSocketHandle handle; | |
571 int rv = | |
572 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
573 EXPECT_EQ(ERR_IO_PENDING, rv); | |
574 EXPECT_FALSE(handle.is_initialized()); | |
575 EXPECT_FALSE(handle.socket()); | |
576 | |
577 EXPECT_EQ(OK, callback.WaitForResult()); | |
578 EXPECT_TRUE(handle.is_initialized()); | |
579 EXPECT_TRUE(handle.socket()); | |
580 IPEndPoint endpoint; | |
581 handle.socket()->GetLocalAddress(&endpoint); | |
582 EXPECT_EQ(kIPv4AddressSize, endpoint.address().size()); | |
583 EXPECT_EQ(2, client_socket_factory_.allocation_count()); | |
584 } | |
585 | |
586 // Test the case of the IPv6 address being slow, thus falling back to trying to | |
587 // connect to the IPv4 address, but having the connect to the IPv6 address | |
588 // finish first. | |
589 TEST_F(WebSocketTransportClientSocketPoolTest, | |
590 IPv6FallbackSocketIPv6FinishesFirst) { | |
591 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
592 kMaxSocketsPerGroup, | |
593 histograms_.get(), | |
594 host_resolver_.get(), | |
595 &client_socket_factory_, | |
596 NULL); | |
597 | |
598 MockTransportClientSocketFactory::ClientSocketType case_types[] = { | |
599 // This is the IPv6 socket. | |
600 MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET, | |
601 // This is the IPv4 socket. | |
602 MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET}; | |
603 | |
604 client_socket_factory_.set_client_socket_types(case_types, 2); | |
605 client_socket_factory_.set_delay(base::TimeDelta::FromMilliseconds( | |
606 TransportConnectJobHelper::kIPv6FallbackTimerInMs + 50)); | |
607 | |
608 // Resolve an AddressList with a IPv6 address first and then a IPv4 address. | |
609 host_resolver_->rules()->AddIPLiteralRule( | |
610 "*", "2:abcd::3:4:ff,2.2.2.2", std::string()); | |
611 | |
612 TestCompletionCallback callback; | |
613 ClientSocketHandle handle; | |
614 int rv = | |
615 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
616 EXPECT_EQ(ERR_IO_PENDING, rv); | |
617 EXPECT_FALSE(handle.is_initialized()); | |
618 EXPECT_FALSE(handle.socket()); | |
619 | |
620 EXPECT_EQ(OK, callback.WaitForResult()); | |
621 EXPECT_TRUE(handle.is_initialized()); | |
622 EXPECT_TRUE(handle.socket()); | |
623 IPEndPoint endpoint; | |
624 handle.socket()->GetLocalAddress(&endpoint); | |
625 EXPECT_EQ(kIPv6AddressSize, endpoint.address().size()); | |
626 EXPECT_EQ(2, client_socket_factory_.allocation_count()); | |
627 } | |
628 | |
629 TEST_F(WebSocketTransportClientSocketPoolTest, | |
630 IPv6NoIPv4AddressesToFallbackTo) { | |
631 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
632 kMaxSocketsPerGroup, | |
633 histograms_.get(), | |
634 host_resolver_.get(), | |
635 &client_socket_factory_, | |
636 NULL); | |
637 | |
638 client_socket_factory_.set_client_socket_type( | |
639 MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET); | |
640 | |
641 // Resolve an AddressList with only IPv6 addresses. | |
642 host_resolver_->rules()->AddIPLiteralRule( | |
643 "*", "2:abcd::3:4:ff,3:abcd::3:4:ff", std::string()); | |
644 | |
645 TestCompletionCallback callback; | |
646 ClientSocketHandle handle; | |
647 int rv = | |
648 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
649 EXPECT_EQ(ERR_IO_PENDING, rv); | |
650 EXPECT_FALSE(handle.is_initialized()); | |
651 EXPECT_FALSE(handle.socket()); | |
652 | |
653 EXPECT_EQ(OK, callback.WaitForResult()); | |
654 EXPECT_TRUE(handle.is_initialized()); | |
655 EXPECT_TRUE(handle.socket()); | |
656 IPEndPoint endpoint; | |
657 handle.socket()->GetLocalAddress(&endpoint); | |
658 EXPECT_EQ(kIPv6AddressSize, endpoint.address().size()); | |
659 EXPECT_EQ(1, client_socket_factory_.allocation_count()); | |
660 } | |
661 | |
662 TEST_F(WebSocketTransportClientSocketPoolTest, IPv4HasNoFallback) { | |
663 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
664 kMaxSocketsPerGroup, | |
665 histograms_.get(), | |
666 host_resolver_.get(), | |
667 &client_socket_factory_, | |
668 NULL); | |
669 | |
670 client_socket_factory_.set_client_socket_type( | |
671 MockTransportClientSocketFactory::MOCK_DELAYED_CLIENT_SOCKET); | |
672 | |
673 // Resolve an AddressList with only IPv4 addresses. | |
674 host_resolver_->rules()->AddIPLiteralRule("*", "1.1.1.1", std::string()); | |
675 | |
676 TestCompletionCallback callback; | |
677 ClientSocketHandle handle; | |
678 int rv = | |
679 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
680 EXPECT_EQ(ERR_IO_PENDING, rv); | |
681 EXPECT_FALSE(handle.is_initialized()); | |
682 EXPECT_FALSE(handle.socket()); | |
683 | |
684 EXPECT_EQ(OK, callback.WaitForResult()); | |
685 EXPECT_TRUE(handle.is_initialized()); | |
686 EXPECT_TRUE(handle.socket()); | |
687 IPEndPoint endpoint; | |
688 handle.socket()->GetLocalAddress(&endpoint); | |
689 EXPECT_EQ(kIPv4AddressSize, endpoint.address().size()); | |
690 EXPECT_EQ(1, client_socket_factory_.allocation_count()); | |
691 } | |
692 | |
693 // If all IPv6 addresses fail to connect synchronously, then IPv4 connections | |
694 // proceeed immediately. | |
695 TEST_F(WebSocketTransportClientSocketPoolTest, IPv6InstantFail) { | |
696 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
697 kMaxSocketsPerGroup, | |
698 histograms_.get(), | |
699 host_resolver_.get(), | |
700 &client_socket_factory_, | |
701 NULL); | |
702 | |
703 MockTransportClientSocketFactory::ClientSocketType case_types[] = { | |
704 // First IPv6 socket. | |
705 MockTransportClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET, | |
706 // Second IPv6 socket. | |
707 MockTransportClientSocketFactory::MOCK_FAILING_CLIENT_SOCKET, | |
708 // This is the IPv4 socket. | |
709 MockTransportClientSocketFactory::MOCK_CLIENT_SOCKET}; | |
710 | |
711 client_socket_factory_.set_client_socket_types(case_types, | |
712 arraysize(case_types)); | |
713 | |
714 // Resolve an AddressList with two IPv6 addresses and then a IPv4 address. | |
715 host_resolver_->rules()->AddIPLiteralRule( | |
716 "*", "2:abcd::3:4:ff,2:abcd::3:5:ff,2.2.2.2", std::string()); | |
717 host_resolver_->set_synchronous_mode(true); | |
718 TestCompletionCallback callback; | |
719 ClientSocketHandle handle; | |
720 int rv = | |
721 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
722 EXPECT_EQ(OK, rv); | |
723 ASSERT_TRUE(handle.socket()); | |
724 | |
725 IPEndPoint endpoint; | |
726 handle.socket()->GetPeerAddress(&endpoint); | |
727 EXPECT_EQ("2.2.2.2", endpoint.ToStringWithoutPort()); | |
728 } | |
729 | |
730 // If all IPv6 addresses fail before the IPv4 fallback timeout, then the IPv4 | |
731 // connections proceed immediately. | |
732 TEST_F(WebSocketTransportClientSocketPoolTest, IPv6RapidFail) { | |
733 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
734 kMaxSocketsPerGroup, | |
735 histograms_.get(), | |
736 host_resolver_.get(), | |
737 &client_socket_factory_, | |
738 NULL); | |
739 | |
740 MockTransportClientSocketFactory::ClientSocketType case_types[] = { | |
741 // First IPv6 socket. | |
742 MockTransportClientSocketFactory::MOCK_PENDING_FAILING_CLIENT_SOCKET, | |
743 // Second IPv6 socket. | |
744 MockTransportClientSocketFactory::MOCK_PENDING_FAILING_CLIENT_SOCKET, | |
745 // This is the IPv4 socket. | |
746 MockTransportClientSocketFactory::MOCK_CLIENT_SOCKET}; | |
747 | |
748 client_socket_factory_.set_client_socket_types(case_types, | |
749 arraysize(case_types)); | |
750 | |
751 // Resolve an AddressList with two IPv6 addresses and then a IPv4 address. | |
752 host_resolver_->rules()->AddIPLiteralRule( | |
753 "*", "2:abcd::3:4:ff,2:abcd::3:5:ff,2.2.2.2", std::string()); | |
754 | |
755 TestCompletionCallback callback; | |
756 ClientSocketHandle handle; | |
757 int rv = | |
758 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
759 EXPECT_EQ(ERR_IO_PENDING, rv); | |
760 EXPECT_FALSE(handle.socket()); | |
761 | |
762 base::Time start(base::Time::NowFromSystemTime()); | |
763 EXPECT_EQ(OK, callback.WaitForResult()); | |
764 EXPECT_LT(base::Time::NowFromSystemTime() - start, | |
765 base::TimeDelta::FromMilliseconds( | |
766 TransportConnectJobHelper::kIPv6FallbackTimerInMs)); | |
767 ASSERT_TRUE(handle.socket()); | |
768 | |
769 IPEndPoint endpoint; | |
770 handle.socket()->GetPeerAddress(&endpoint); | |
771 EXPECT_EQ("2.2.2.2", endpoint.ToStringWithoutPort()); | |
772 } | |
773 | |
774 // If two sockets connect successfully, the one which connected first wins (this | |
775 // can only happen if the sockets are different types, since sockets of the same | |
776 // type do not race). | |
777 TEST_F(WebSocketTransportClientSocketPoolTest, FirstSuccessWins) { | |
778 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
779 kMaxSocketsPerGroup, | |
780 histograms_.get(), | |
781 host_resolver_.get(), | |
782 &client_socket_factory_, | |
783 NULL); | |
784 | |
785 client_socket_factory_.set_client_socket_type( | |
786 MockTransportClientSocketFactory::MOCK_TRIGGERABLE_CLIENT_SOCKET); | |
787 | |
788 // Resolve an AddressList with an IPv6 addresses and an IPv4 address. | |
789 host_resolver_->rules()->AddIPLiteralRule( | |
790 "*", "2:abcd::3:4:ff,2.2.2.2", std::string()); | |
791 | |
792 TestCompletionCallback callback; | |
793 ClientSocketHandle handle; | |
794 int rv = | |
795 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
796 EXPECT_EQ(ERR_IO_PENDING, rv); | |
797 ASSERT_FALSE(handle.socket()); | |
798 | |
799 base::Closure ipv6_connect_trigger = | |
800 client_socket_factory_.WaitForTriggerableSocketCreation(); | |
801 base::Closure ipv4_connect_trigger = | |
802 client_socket_factory_.WaitForTriggerableSocketCreation(); | |
803 | |
804 ipv4_connect_trigger.Run(); | |
805 ipv6_connect_trigger.Run(); | |
806 | |
807 EXPECT_EQ(OK, callback.WaitForResult()); | |
808 ASSERT_TRUE(handle.socket()); | |
809 | |
810 IPEndPoint endpoint; | |
811 handle.socket()->GetPeerAddress(&endpoint); | |
812 EXPECT_EQ("2.2.2.2", endpoint.ToStringWithoutPort()); | |
813 } | |
814 | |
815 // We should not report failure until all connections have failed. | |
816 TEST_F(WebSocketTransportClientSocketPoolTest, LastFailureWins) { | |
817 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
818 kMaxSocketsPerGroup, | |
819 histograms_.get(), | |
820 host_resolver_.get(), | |
821 &client_socket_factory_, | |
822 NULL); | |
823 | |
824 client_socket_factory_.set_client_socket_type( | |
825 MockTransportClientSocketFactory::MOCK_DELAYED_FAILING_CLIENT_SOCKET); | |
826 base::TimeDelta delay = base::TimeDelta::FromMilliseconds( | |
827 TransportConnectJobHelper::kIPv6FallbackTimerInMs / 3); | |
828 client_socket_factory_.set_delay(delay); | |
829 | |
830 // Resolve an AddressList with 4 IPv6 addresses and 2 IPv4 address. | |
831 host_resolver_->rules()->AddIPLiteralRule("*", | |
832 "1:abcd::3:4:ff,2:abcd::3:4:ff," | |
833 "3:abcd::3:4:ff,4:abcd::3:4:ff," | |
834 "1.1.1.1,2.2.2.2", | |
835 std::string()); | |
836 | |
837 // Expected order of events: | |
838 // After 100ms: Connect to 1:abcd::3:4:ff times out | |
839 // After 200ms: Connect to 2:abcd::3:4:ff times out | |
840 // After 300ms: Connect to 3:abcd::3:4:ff times out, IPv4 fallback starts | |
841 // After 400ms: Connect to 4:abcd::3:4:ff and 1.1.1.1 time out | |
842 // After 500ms: Connect to 2.2.2.2 times out | |
843 | |
844 TestCompletionCallback callback; | |
845 ClientSocketHandle handle; | |
846 base::Time start(base::Time::NowFromSystemTime()); | |
847 int rv = | |
848 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
849 EXPECT_EQ(ERR_IO_PENDING, rv); | |
850 | |
851 EXPECT_EQ(ERR_CONNECTION_FAILED, callback.WaitForResult()); | |
852 | |
853 EXPECT_GE(base::Time::NowFromSystemTime() - start, delay * 5); | |
854 } | |
855 | |
856 // Global timeout for all connects applies. This test is disabled by default | |
857 // because it takes 4 minutes. Run with --gtest_also_run_disabled_tests if you | |
858 // want to run it. | |
859 TEST_F(WebSocketTransportClientSocketPoolTest, DISABLED_OverallTimeoutApplies) { | |
860 WebSocketTransportClientSocketPool pool(kMaxSockets, | |
861 kMaxSocketsPerGroup, | |
862 histograms_.get(), | |
863 host_resolver_.get(), | |
864 &client_socket_factory_, | |
865 NULL); | |
866 const base::TimeDelta connect_job_timeout = pool.ConnectionTimeout(); | |
867 | |
868 client_socket_factory_.set_client_socket_type( | |
869 MockTransportClientSocketFactory::MOCK_DELAYED_FAILING_CLIENT_SOCKET); | |
870 client_socket_factory_.set_delay(base::TimeDelta::FromSeconds(1) + | |
871 connect_job_timeout / 6); | |
872 | |
873 // Resolve an AddressList with 6 IPv6 addresses and 6 IPv4 address. | |
874 host_resolver_->rules()->AddIPLiteralRule("*", | |
875 "1:abcd::3:4:ff,2:abcd::3:4:ff," | |
876 "3:abcd::3:4:ff,4:abcd::3:4:ff," | |
877 "5:abcd::3:4:ff,6:abcd::3:4:ff," | |
878 "1.1.1.1,2.2.2.2,3.3.3.3," | |
879 "4.4.4.4,5.5.5.5,6.6.6.6", | |
880 std::string()); | |
881 | |
882 TestCompletionCallback callback; | |
883 ClientSocketHandle handle; | |
884 | |
885 int rv = | |
886 handle.Init("a", params_, LOW, callback.callback(), &pool, BoundNetLog()); | |
887 EXPECT_EQ(ERR_IO_PENDING, rv); | |
888 | |
889 EXPECT_EQ(ERR_TIMED_OUT, callback.WaitForResult()); | |
890 } | |
891 | |
892 TEST_F(WebSocketTransportClientSocketPoolTest, MaxSocketsEnforced) { | |
893 host_resolver_->set_synchronous_mode(true); | |
894 for (int i = 0; i < kMaxSockets; ++i) { | |
895 EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); | |
896 WebSocketTransportClientSocketPool::UnlockEndpoint(request(i)->handle()); | |
897 } | |
898 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
899 } | |
900 | |
901 TEST_F(WebSocketTransportClientSocketPoolTest, MaxSocketsEnforcedWhenPending) { | |
902 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
903 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
904 } | |
905 // Now there are 32 sockets waiting to connect, and one stalled. | |
906 for (int i = 0; i < kMaxSockets; ++i) { | |
907 base::RunLoop().RunUntilIdle(); | |
908 EXPECT_TRUE(request(i)->handle()->is_initialized()); | |
909 EXPECT_TRUE(request(i)->handle()->socket()); | |
910 WebSocketTransportClientSocketPool::UnlockEndpoint(request(i)->handle()); | |
911 } | |
912 // Now there are 32 sockets connected, and one stalled. | |
913 base::RunLoop().RunUntilIdle(); | |
914 EXPECT_FALSE(request(kMaxSockets)->handle()->is_initialized()); | |
915 EXPECT_FALSE(request(kMaxSockets)->handle()->socket()); | |
916 } | |
917 | |
918 TEST_F(WebSocketTransportClientSocketPoolTest, StalledSocketReleased) { | |
919 host_resolver_->set_synchronous_mode(true); | |
920 for (int i = 0; i < kMaxSockets; ++i) { | |
921 EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); | |
922 WebSocketTransportClientSocketPool::UnlockEndpoint(request(i)->handle()); | |
923 } | |
924 | |
925 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
926 ReleaseOneConnection(ClientSocketPoolTest::NO_KEEP_ALIVE); | |
927 EXPECT_TRUE(request(kMaxSockets)->handle()->is_initialized()); | |
928 EXPECT_TRUE(request(kMaxSockets)->handle()->socket()); | |
929 } | |
930 | |
931 TEST_F(WebSocketTransportClientSocketPoolTest, IsStalledTrueWhenStalled) { | |
932 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
933 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
934 } | |
935 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
936 EXPECT_TRUE(pool_.IsStalled()); | |
937 } | |
938 | |
939 TEST_F(WebSocketTransportClientSocketPoolTest, | |
940 CancellingPendingSocketUnstallsStalledSocket) { | |
941 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
942 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
943 } | |
944 EXPECT_EQ(OK, request(0)->WaitForResult()); | |
945 request(1)->handle()->Reset(); | |
946 base::RunLoop().RunUntilIdle(); | |
947 EXPECT_FALSE(pool_.IsStalled()); | |
948 } | |
949 | |
950 TEST_F(WebSocketTransportClientSocketPoolTest, | |
951 LoadStateOfStalledSocketIsWaitingForAvailableSocket) { | |
952 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
953 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
954 } | |
955 EXPECT_EQ(LOAD_STATE_WAITING_FOR_AVAILABLE_SOCKET, | |
956 pool_.GetLoadState("a", request(kMaxSockets)->handle())); | |
957 } | |
958 | |
959 TEST_F(WebSocketTransportClientSocketPoolTest, | |
960 CancellingStalledSocketUnstallsPool) { | |
961 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
962 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
963 } | |
964 request(kMaxSockets)->handle()->Reset(); | |
965 EXPECT_FALSE(pool_.IsStalled()); | |
966 } | |
967 | |
968 TEST_F(WebSocketTransportClientSocketPoolTest, | |
969 FlushWithErrorFlushesPendingConnections) { | |
970 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
971 pool_.FlushWithError(ERR_FAILED); | |
972 EXPECT_EQ(ERR_FAILED, request(0)->WaitForResult()); | |
973 } | |
974 | |
975 TEST_F(WebSocketTransportClientSocketPoolTest, | |
976 FlushWithErrorFlushesStalledConnections) { | |
977 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
978 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
979 } | |
980 pool_.FlushWithError(ERR_FAILED); | |
981 EXPECT_EQ(ERR_FAILED, request(kMaxSockets)->WaitForResult()); | |
982 } | |
983 | |
984 TEST_F(WebSocketTransportClientSocketPoolTest, | |
985 AfterFlushWithErrorCanMakeNewConnections) { | |
986 for (int i = 0; i < kMaxSockets + 1; ++i) { | |
987 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
988 } | |
989 pool_.FlushWithError(ERR_FAILED); | |
990 host_resolver_->set_synchronous_mode(true); | |
991 EXPECT_EQ(OK, StartRequest("a", kDefaultPriority)); | |
992 } | |
993 | |
994 // Deleting pending connections can release the lock on the endpoint, which can | |
995 // in principle lead to other pending connections succeeding. However, when we | |
996 // call FlushWithError(), everything should fail. | |
997 TEST_F(WebSocketTransportClientSocketPoolTest, | |
998 FlushWithErrorDoesNotCauseSuccessfulConnections) { | |
999 host_resolver_->set_synchronous_mode(true); | |
1000 MockTransportClientSocketFactory::ClientSocketType first_type[] = { | |
1001 // First socket | |
1002 MockTransportClientSocketFactory::MOCK_PENDING_CLIENT_SOCKET | |
1003 }; | |
1004 client_socket_factory_.set_client_socket_types(first_type, | |
1005 arraysize(first_type)); | |
1006 // The rest of the sockets will connect synchronously. | |
1007 client_socket_factory_.set_client_socket_type( | |
1008 MockTransportClientSocketFactory::MOCK_CLIENT_SOCKET); | |
1009 for (int i = 0; i < kMaxSockets; ++i) { | |
1010 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
1011 } | |
1012 // Now we have one socket in STATE_TRANSPORT_CONNECT and the rest in | |
1013 // STATE_OBTAIN_LOCK. If any of the sockets in STATE_OBTAIN_LOCK is given the | |
1014 // lock, they will synchronously connect. | |
1015 pool_.FlushWithError(ERR_FAILED); | |
1016 for (int i = 0; i < kMaxSockets; ++i) { | |
1017 EXPECT_EQ(ERR_FAILED, request(i)->WaitForResult()); | |
1018 } | |
1019 } | |
1020 | |
1021 // This is a regression test for the first attempted fix for | |
1022 // FlushWithErrorDoesNotCauseSuccessfulConnections. Because a ConnectJob can | |
1023 // have both IPv4 and IPv6 subjobs, it can be both connecting and waiting for | |
1024 // the lock at the same time. | |
1025 TEST_F(WebSocketTransportClientSocketPoolTest, | |
1026 FlushWithErrorDoesNotCauseSuccessfulConnectionsMultipleAddressTypes) { | |
1027 host_resolver_->set_synchronous_mode(true); | |
1028 // The first |kMaxSockets| sockets to connect will be IPv6. Then we will have | |
1029 // one IPv4. | |
1030 std::vector<MockTransportClientSocketFactory::ClientSocketType> socket_types( | |
1031 kMaxSockets + 1, | |
1032 MockTransportClientSocketFactory::MOCK_STALLED_CLIENT_SOCKET); | |
1033 client_socket_factory_.set_client_socket_types(&socket_types[0], | |
1034 socket_types.size()); | |
1035 // The rest of the sockets will connect synchronously. | |
1036 client_socket_factory_.set_client_socket_type( | |
1037 MockTransportClientSocketFactory::MOCK_CLIENT_SOCKET); | |
1038 for (int i = 0; i < kMaxSockets; ++i) { | |
1039 host_resolver_->rules()->ClearRules(); | |
1040 // Each connect job has a different IPv6 address but the same IPv4 address. | |
1041 // So the IPv6 connections happen in parallel but the IPv4 ones are | |
1042 // serialised. | |
1043 host_resolver_->rules()->AddIPLiteralRule("*", | |
1044 base::StringPrintf( | |
1045 "%x:abcd::3:4:ff," | |
1046 "1.1.1.1", | |
1047 i + 1), | |
1048 std::string()); | |
1049 EXPECT_EQ(ERR_IO_PENDING, StartRequest("a", kDefaultPriority)); | |
1050 } | |
1051 // Now we have |kMaxSockets| IPv6 sockets stalled in connect. No IPv4 sockets | |
1052 // are started yet. | |
1053 RunLoopForTimePeriod(base::TimeDelta::FromMilliseconds( | |
1054 TransportConnectJobHelper::kIPv6FallbackTimerInMs)); | |
1055 // Now we have |kMaxSockets| IPv6 sockets and one IPv4 socket stalled in | |
1056 // connect, and |kMaxSockets - 1| IPv4 sockets waiting for the endpoint lock. | |
1057 pool_.FlushWithError(ERR_FAILED); | |
1058 for (int i = 0; i < kMaxSockets; ++i) { | |
1059 EXPECT_EQ(ERR_FAILED, request(i)->WaitForResult()); | |
1060 } | |
1061 } | |
1062 | |
1063 } // namespace | |
1064 | |
1065 } // namespace net | |
OLD | NEW |