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