Roll WebRTC 9745:9761, Libjingle 9742:9761
[chromium-blink-merge.git] / net / spdy / spdy_session_pool_unittest.cc
blob8f397eac8053e74e924db5ed85613cdbc5b27f1d
1 // Copyright (c) 2013 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.
5 #include "net/spdy/spdy_session_pool.h"
7 #include <cstddef>
8 #include <string>
10 #include "base/memory/ref_counted.h"
11 #include "base/memory/scoped_ptr.h"
12 #include "net/dns/host_cache.h"
13 #include "net/http/http_network_session.h"
14 #include "net/socket/client_socket_handle.h"
15 #include "net/socket/transport_client_socket_pool.h"
16 #include "net/spdy/spdy_session.h"
17 #include "net/spdy/spdy_stream_test_util.h"
18 #include "net/spdy/spdy_test_util_common.h"
19 #include "testing/gtest/include/gtest/gtest.h"
21 namespace net {
23 namespace {
25 class SpdySessionPoolTest : public ::testing::Test,
26 public ::testing::WithParamInterface<NextProto> {
27 protected:
28 // Used by RunIPPoolingTest().
29 enum SpdyPoolCloseSessionsType {
30 SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
31 SPDY_POOL_CLOSE_CURRENT_SESSIONS,
32 SPDY_POOL_CLOSE_IDLE_SESSIONS,
35 SpdySessionPoolTest()
36 : session_deps_(GetParam()),
37 spdy_session_pool_(NULL) {}
39 void CreateNetworkSession() {
40 http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
41 spdy_session_pool_ = http_session_->spdy_session_pool();
44 void RunIPPoolingTest(SpdyPoolCloseSessionsType close_sessions_type);
46 SpdySessionDependencies session_deps_;
47 scoped_refptr<HttpNetworkSession> http_session_;
48 SpdySessionPool* spdy_session_pool_;
51 INSTANTIATE_TEST_CASE_P(NextProto,
52 SpdySessionPoolTest,
53 testing::Values(kProtoSPDY31,
54 kProtoHTTP2_14,
55 kProtoHTTP2));
57 // A delegate that opens a new session when it is closed.
58 class SessionOpeningDelegate : public SpdyStream::Delegate {
59 public:
60 SessionOpeningDelegate(SpdySessionPool* spdy_session_pool,
61 const SpdySessionKey& key)
62 : spdy_session_pool_(spdy_session_pool),
63 key_(key) {}
65 ~SessionOpeningDelegate() override {}
67 void OnRequestHeadersSent() override {}
69 SpdyResponseHeadersStatus OnResponseHeadersUpdated(
70 const SpdyHeaderBlock& response_headers) override {
71 return RESPONSE_HEADERS_ARE_COMPLETE;
74 void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override {}
76 void OnDataSent() override {}
78 void OnTrailers(const SpdyHeaderBlock& trailers) override {}
80 void OnClose(int status) override {
81 ignore_result(CreateFakeSpdySession(spdy_session_pool_, key_));
84 private:
85 SpdySessionPool* const spdy_session_pool_;
86 const SpdySessionKey key_;
89 // Set up a SpdyStream to create a new session when it is closed.
90 // CloseCurrentSessions should not close the newly-created session.
91 TEST_P(SpdySessionPoolTest, CloseCurrentSessions) {
92 const char kTestHost[] = "www.foo.com";
93 const int kTestPort = 80;
95 session_deps_.host_resolver->set_synchronous_mode(true);
97 HostPortPair test_host_port_pair(kTestHost, kTestPort);
98 SpdySessionKey test_key =
99 SpdySessionKey(
100 test_host_port_pair, ProxyServer::Direct(),
101 PRIVACY_MODE_DISABLED);
103 MockConnect connect_data(SYNCHRONOUS, OK);
104 MockRead reads[] = {
105 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
108 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
109 data.set_connect_data(connect_data);
110 session_deps_.socket_factory->AddSocketDataProvider(&data);
112 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
113 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
115 CreateNetworkSession();
117 // Setup the first session to the first host.
118 base::WeakPtr<SpdySession> session =
119 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
121 // Flush the SpdySession::OnReadComplete() task.
122 base::MessageLoop::current()->RunUntilIdle();
124 // Verify that we have sessions for everything.
125 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
127 // Set the stream to create a new session when it is closed.
128 base::WeakPtr<SpdyStream> spdy_stream =
129 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
130 session, GURL("http://www.foo.com"),
131 MEDIUM, BoundNetLog());
132 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
133 spdy_stream->SetDelegate(&delegate);
135 // Close the current session.
136 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
138 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
141 TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) {
142 MockConnect connect_data(SYNCHRONOUS, OK);
143 MockRead reads[] = {
144 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
147 session_deps_.host_resolver->set_synchronous_mode(true);
149 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
150 data.set_connect_data(connect_data);
151 session_deps_.socket_factory->AddSocketDataProvider(&data);
153 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
154 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
156 CreateNetworkSession();
158 // Set up session 1
159 const std::string kTestHost1("http://www.a.com");
160 HostPortPair test_host_port_pair1(kTestHost1, 80);
161 SpdySessionKey key1(test_host_port_pair1, ProxyServer::Direct(),
162 PRIVACY_MODE_DISABLED);
163 base::WeakPtr<SpdySession> session1 =
164 CreateInsecureSpdySession(http_session_, key1, BoundNetLog());
165 GURL url1(kTestHost1);
166 base::WeakPtr<SpdyStream> spdy_stream1 =
167 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
168 session1, url1, MEDIUM, BoundNetLog());
169 ASSERT_TRUE(spdy_stream1.get() != NULL);
171 // Set up session 2
172 session_deps_.socket_factory->AddSocketDataProvider(&data);
173 const std::string kTestHost2("http://www.b.com");
174 HostPortPair test_host_port_pair2(kTestHost2, 80);
175 SpdySessionKey key2(test_host_port_pair2, ProxyServer::Direct(),
176 PRIVACY_MODE_DISABLED);
177 base::WeakPtr<SpdySession> session2 =
178 CreateInsecureSpdySession(http_session_, key2, BoundNetLog());
179 GURL url2(kTestHost2);
180 base::WeakPtr<SpdyStream> spdy_stream2 =
181 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
182 session2, url2, MEDIUM, BoundNetLog());
183 ASSERT_TRUE(spdy_stream2.get() != NULL);
185 // Set up session 3
186 session_deps_.socket_factory->AddSocketDataProvider(&data);
187 const std::string kTestHost3("http://www.c.com");
188 HostPortPair test_host_port_pair3(kTestHost3, 80);
189 SpdySessionKey key3(test_host_port_pair3, ProxyServer::Direct(),
190 PRIVACY_MODE_DISABLED);
191 base::WeakPtr<SpdySession> session3 =
192 CreateInsecureSpdySession(http_session_, key3, BoundNetLog());
193 GURL url3(kTestHost3);
194 base::WeakPtr<SpdyStream> spdy_stream3 =
195 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
196 session3, url3, MEDIUM, BoundNetLog());
197 ASSERT_TRUE(spdy_stream3.get() != NULL);
199 // All sessions are active and not closed
200 EXPECT_TRUE(session1->is_active());
201 EXPECT_TRUE(session1->IsAvailable());
202 EXPECT_TRUE(session2->is_active());
203 EXPECT_TRUE(session2->IsAvailable());
204 EXPECT_TRUE(session3->is_active());
205 EXPECT_TRUE(session3->IsAvailable());
207 // Should not do anything, all are active
208 spdy_session_pool_->CloseCurrentIdleSessions();
209 EXPECT_TRUE(session1->is_active());
210 EXPECT_TRUE(session1->IsAvailable());
211 EXPECT_TRUE(session2->is_active());
212 EXPECT_TRUE(session2->IsAvailable());
213 EXPECT_TRUE(session3->is_active());
214 EXPECT_TRUE(session3->IsAvailable());
216 // Make sessions 1 and 3 inactive, but keep them open.
217 // Session 2 still open and active
218 session1->CloseCreatedStream(spdy_stream1, OK);
219 EXPECT_EQ(NULL, spdy_stream1.get());
220 session3->CloseCreatedStream(spdy_stream3, OK);
221 EXPECT_EQ(NULL, spdy_stream3.get());
222 EXPECT_FALSE(session1->is_active());
223 EXPECT_TRUE(session1->IsAvailable());
224 EXPECT_TRUE(session2->is_active());
225 EXPECT_TRUE(session2->IsAvailable());
226 EXPECT_FALSE(session3->is_active());
227 EXPECT_TRUE(session3->IsAvailable());
229 // Should close session 1 and 3, 2 should be left open
230 spdy_session_pool_->CloseCurrentIdleSessions();
231 base::MessageLoop::current()->RunUntilIdle();
233 EXPECT_TRUE(session1 == NULL);
234 EXPECT_TRUE(session2->is_active());
235 EXPECT_TRUE(session2->IsAvailable());
236 EXPECT_TRUE(session3 == NULL);
238 // Should not do anything
239 spdy_session_pool_->CloseCurrentIdleSessions();
240 base::MessageLoop::current()->RunUntilIdle();
242 EXPECT_TRUE(session2->is_active());
243 EXPECT_TRUE(session2->IsAvailable());
245 // Make 2 not active
246 session2->CloseCreatedStream(spdy_stream2, OK);
247 base::MessageLoop::current()->RunUntilIdle();
249 EXPECT_EQ(NULL, spdy_stream2.get());
250 EXPECT_FALSE(session2->is_active());
251 EXPECT_TRUE(session2->IsAvailable());
253 // This should close session 2
254 spdy_session_pool_->CloseCurrentIdleSessions();
255 base::MessageLoop::current()->RunUntilIdle();
257 EXPECT_TRUE(session2 == NULL);
260 // Set up a SpdyStream to create a new session when it is closed.
261 // CloseAllSessions should close the newly-created session.
262 TEST_P(SpdySessionPoolTest, CloseAllSessions) {
263 const char kTestHost[] = "www.foo.com";
264 const int kTestPort = 80;
266 session_deps_.host_resolver->set_synchronous_mode(true);
268 HostPortPair test_host_port_pair(kTestHost, kTestPort);
269 SpdySessionKey test_key =
270 SpdySessionKey(
271 test_host_port_pair, ProxyServer::Direct(),
272 PRIVACY_MODE_DISABLED);
274 MockConnect connect_data(SYNCHRONOUS, OK);
275 MockRead reads[] = {
276 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
279 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
280 data.set_connect_data(connect_data);
281 session_deps_.socket_factory->AddSocketDataProvider(&data);
283 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
284 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
286 CreateNetworkSession();
288 // Setup the first session to the first host.
289 base::WeakPtr<SpdySession> session =
290 CreateInsecureSpdySession(http_session_, test_key, BoundNetLog());
292 // Flush the SpdySession::OnReadComplete() task.
293 base::MessageLoop::current()->RunUntilIdle();
295 // Verify that we have sessions for everything.
296 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_key));
298 // Set the stream to create a new session when it is closed.
299 base::WeakPtr<SpdyStream> spdy_stream =
300 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
301 session, GURL("http://www.foo.com"),
302 MEDIUM, BoundNetLog());
303 SessionOpeningDelegate delegate(spdy_session_pool_, test_key);
304 spdy_stream->SetDelegate(&delegate);
306 // Close the current session.
307 spdy_session_pool_->CloseAllSessions();
309 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_key));
312 // This test has three variants, one for each style of closing the connection.
313 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_SESSIONS_MANUALLY,
314 // the sessions are closed manually, calling SpdySessionPool::Remove() directly.
315 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_CURRENT_SESSIONS,
316 // sessions are closed with SpdySessionPool::CloseCurrentSessions().
317 // If |clean_via_close_current_sessions| is SPDY_POOL_CLOSE_IDLE_SESSIONS,
318 // sessions are closed with SpdySessionPool::CloseIdleSessions().
319 void SpdySessionPoolTest::RunIPPoolingTest(
320 SpdyPoolCloseSessionsType close_sessions_type) {
321 const int kTestPort = 80;
322 struct TestHosts {
323 std::string url;
324 std::string name;
325 std::string iplist;
326 SpdySessionKey key;
327 AddressList addresses;
328 } test_hosts[] = {
329 { "http:://www.foo.com",
330 "www.foo.com",
331 "192.0.2.33,192.168.0.1,192.168.0.5"
333 { "http://js.foo.com",
334 "js.foo.com",
335 "192.168.0.2,192.168.0.3,192.168.0.5,192.0.2.33"
337 { "http://images.foo.com",
338 "images.foo.com",
339 "192.168.0.4,192.168.0.3"
343 session_deps_.host_resolver->set_synchronous_mode(true);
344 for (size_t i = 0; i < arraysize(test_hosts); i++) {
345 session_deps_.host_resolver->rules()->AddIPLiteralRule(
346 test_hosts[i].name, test_hosts[i].iplist, std::string());
348 // This test requires that the HostResolver cache be populated. Normal
349 // code would have done this already, but we do it manually.
350 HostResolver::RequestInfo info(HostPortPair(test_hosts[i].name, kTestPort));
351 session_deps_.host_resolver->Resolve(info,
352 DEFAULT_PRIORITY,
353 &test_hosts[i].addresses,
354 CompletionCallback(),
355 NULL,
356 BoundNetLog());
358 // Setup a SpdySessionKey
359 test_hosts[i].key = SpdySessionKey(
360 HostPortPair(test_hosts[i].name, kTestPort), ProxyServer::Direct(),
361 PRIVACY_MODE_DISABLED);
364 MockConnect connect_data(SYNCHRONOUS, OK);
365 MockRead reads[] = {
366 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
369 StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
370 data.set_connect_data(connect_data);
371 session_deps_.socket_factory->AddSocketDataProvider(&data);
373 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
374 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
376 CreateNetworkSession();
378 // Setup the first session to the first host.
379 base::WeakPtr<SpdySession> session =
380 CreateInsecureSpdySession(
381 http_session_, test_hosts[0].key, BoundNetLog());
383 // Flush the SpdySession::OnReadComplete() task.
384 base::MessageLoop::current()->RunUntilIdle();
386 // The third host has no overlap with the first, so it can't pool IPs.
387 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
389 // The second host overlaps with the first, and should IP pool.
390 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
392 // Verify that the second host, through a proxy, won't share the IP.
393 SpdySessionKey proxy_key(test_hosts[1].key.host_port_pair(),
394 ProxyServer::FromPacString("HTTP http://proxy.foo.com/"),
395 PRIVACY_MODE_DISABLED);
396 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, proxy_key));
398 // Overlap between 2 and 3 does is not transitive to 1.
399 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
401 // Create a new session to host 2.
402 session_deps_.socket_factory->AddSocketDataProvider(&data);
403 base::WeakPtr<SpdySession> session2 =
404 CreateInsecureSpdySession(
405 http_session_, test_hosts[2].key, BoundNetLog());
407 // Verify that we have sessions for everything.
408 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
409 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
410 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
412 // Grab the session to host 1 and verify that it is the same session
413 // we got with host 0, and that is a different from host 2's session.
414 base::WeakPtr<SpdySession> session1 =
415 spdy_session_pool_->FindAvailableSession(
416 test_hosts[1].key, BoundNetLog());
417 EXPECT_EQ(session.get(), session1.get());
418 EXPECT_NE(session2.get(), session1.get());
420 // Remove the aliases and observe that we still have a session for host1.
421 SpdySessionPoolPeer pool_peer(spdy_session_pool_);
422 pool_peer.RemoveAliases(test_hosts[0].key);
423 pool_peer.RemoveAliases(test_hosts[1].key);
424 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
426 // Expire the host cache
427 session_deps_.host_resolver->GetHostCache()->clear();
428 EXPECT_TRUE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
430 // Cleanup the sessions.
431 switch (close_sessions_type) {
432 case SPDY_POOL_CLOSE_SESSIONS_MANUALLY:
433 session->CloseSessionOnError(ERR_ABORTED, std::string());
434 session2->CloseSessionOnError(ERR_ABORTED, std::string());
435 base::MessageLoop::current()->RunUntilIdle();
436 EXPECT_TRUE(session == NULL);
437 EXPECT_TRUE(session2 == NULL);
438 break;
439 case SPDY_POOL_CLOSE_CURRENT_SESSIONS:
440 spdy_session_pool_->CloseCurrentSessions(ERR_ABORTED);
441 break;
442 case SPDY_POOL_CLOSE_IDLE_SESSIONS:
443 GURL url(test_hosts[0].url);
444 base::WeakPtr<SpdyStream> spdy_stream =
445 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
446 session, url, MEDIUM, BoundNetLog());
447 GURL url1(test_hosts[1].url);
448 base::WeakPtr<SpdyStream> spdy_stream1 =
449 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
450 session1, url1, MEDIUM, BoundNetLog());
451 GURL url2(test_hosts[2].url);
452 base::WeakPtr<SpdyStream> spdy_stream2 =
453 CreateStreamSynchronously(SPDY_BIDIRECTIONAL_STREAM,
454 session2, url2, MEDIUM, BoundNetLog());
456 // Close streams to make spdy_session and spdy_session1 inactive.
457 session->CloseCreatedStream(spdy_stream, OK);
458 EXPECT_EQ(NULL, spdy_stream.get());
459 session1->CloseCreatedStream(spdy_stream1, OK);
460 EXPECT_EQ(NULL, spdy_stream1.get());
462 // Check spdy_session and spdy_session1 are not closed.
463 EXPECT_FALSE(session->is_active());
464 EXPECT_TRUE(session->IsAvailable());
465 EXPECT_FALSE(session1->is_active());
466 EXPECT_TRUE(session1->IsAvailable());
467 EXPECT_TRUE(session2->is_active());
468 EXPECT_TRUE(session2->IsAvailable());
470 // Test that calling CloseIdleSessions, does not cause a crash.
471 // http://crbug.com/181400
472 spdy_session_pool_->CloseCurrentIdleSessions();
473 base::MessageLoop::current()->RunUntilIdle();
475 // Verify spdy_session and spdy_session1 are closed.
476 EXPECT_TRUE(session == NULL);
477 EXPECT_TRUE(session1 == NULL);
478 EXPECT_TRUE(session2->is_active());
479 EXPECT_TRUE(session2->IsAvailable());
481 spdy_stream2->Cancel();
482 EXPECT_EQ(NULL, spdy_stream.get());
483 EXPECT_EQ(NULL, spdy_stream1.get());
484 EXPECT_EQ(NULL, spdy_stream2.get());
486 session2->CloseSessionOnError(ERR_ABORTED, std::string());
487 base::MessageLoop::current()->RunUntilIdle();
488 EXPECT_TRUE(session2 == NULL);
489 break;
492 // Verify that the map is all cleaned up.
493 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[0].key));
494 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[1].key));
495 EXPECT_FALSE(HasSpdySession(spdy_session_pool_, test_hosts[2].key));
498 TEST_P(SpdySessionPoolTest, IPPooling) {
499 RunIPPoolingTest(SPDY_POOL_CLOSE_SESSIONS_MANUALLY);
502 TEST_P(SpdySessionPoolTest, IPPoolingCloseCurrentSessions) {
503 RunIPPoolingTest(SPDY_POOL_CLOSE_CURRENT_SESSIONS);
506 TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) {
507 RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS);
510 // Construct a Pool with SpdySessions in various availability states. Simulate
511 // an IP address change. Ensure sessions gracefully shut down. Regression test
512 // for crbug.com/379469.
513 TEST_P(SpdySessionPoolTest, IPAddressChanged) {
514 MockConnect connect_data(SYNCHRONOUS, OK);
515 session_deps_.host_resolver->set_synchronous_mode(true);
516 SpdyTestUtil spdy_util(GetParam());
518 MockRead reads[] = {
519 MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
521 scoped_ptr<SpdyFrame> req(
522 spdy_util.ConstructSpdyGet("http://www.a.com", false, 1, MEDIUM));
523 MockWrite writes[] = {CreateMockWrite(*req, 1)};
525 StaticSocketDataProvider data(reads, arraysize(reads), writes,
526 arraysize(writes));
527 data.set_connect_data(connect_data);
528 session_deps_.socket_factory->AddSocketDataProvider(&data);
530 SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
531 session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl);
533 CreateNetworkSession();
535 // Set up session A: Going away, but with an active stream.
536 session_deps_.socket_factory->AddSocketDataProvider(&data);
537 const std::string kTestHostA("http://www.a.com");
538 HostPortPair test_host_port_pairA(kTestHostA, 80);
539 SpdySessionKey keyA(
540 test_host_port_pairA, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
541 base::WeakPtr<SpdySession> sessionA =
542 CreateInsecureSpdySession(http_session_, keyA, BoundNetLog());
544 GURL urlA(kTestHostA);
545 base::WeakPtr<SpdyStream> spdy_streamA = CreateStreamSynchronously(
546 SPDY_BIDIRECTIONAL_STREAM, sessionA, urlA, MEDIUM, BoundNetLog());
547 test::StreamDelegateDoNothing delegateA(spdy_streamA);
548 spdy_streamA->SetDelegate(&delegateA);
550 scoped_ptr<SpdyHeaderBlock> headers(
551 spdy_util.ConstructGetHeaderBlock(urlA.spec()));
552 spdy_streamA->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
553 EXPECT_TRUE(spdy_streamA->HasUrlFromHeaders());
555 base::MessageLoop::current()->RunUntilIdle(); // Allow headers to write.
556 EXPECT_TRUE(delegateA.send_headers_completed());
558 sessionA->MakeUnavailable();
559 EXPECT_TRUE(sessionA->IsGoingAway());
560 EXPECT_FALSE(delegateA.StreamIsClosed());
562 // Set up session B: Available, with a created stream.
563 const std::string kTestHostB("http://www.b.com");
564 HostPortPair test_host_port_pairB(kTestHostB, 80);
565 SpdySessionKey keyB(
566 test_host_port_pairB, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
567 base::WeakPtr<SpdySession> sessionB =
568 CreateInsecureSpdySession(http_session_, keyB, BoundNetLog());
569 EXPECT_TRUE(sessionB->IsAvailable());
571 GURL urlB(kTestHostB);
572 base::WeakPtr<SpdyStream> spdy_streamB = CreateStreamSynchronously(
573 SPDY_BIDIRECTIONAL_STREAM, sessionB, urlB, MEDIUM, BoundNetLog());
574 test::StreamDelegateDoNothing delegateB(spdy_streamB);
575 spdy_streamB->SetDelegate(&delegateB);
577 // Set up session C: Draining.
578 session_deps_.socket_factory->AddSocketDataProvider(&data);
579 const std::string kTestHostC("http://www.c.com");
580 HostPortPair test_host_port_pairC(kTestHostC, 80);
581 SpdySessionKey keyC(
582 test_host_port_pairC, ProxyServer::Direct(), PRIVACY_MODE_DISABLED);
583 base::WeakPtr<SpdySession> sessionC =
584 CreateInsecureSpdySession(http_session_, keyC, BoundNetLog());
586 sessionC->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error!");
587 EXPECT_TRUE(sessionC->IsDraining());
589 spdy_session_pool_->OnIPAddressChanged();
591 #if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
592 EXPECT_TRUE(sessionA->IsGoingAway());
593 EXPECT_TRUE(sessionB->IsDraining());
594 EXPECT_TRUE(sessionC->IsDraining());
596 EXPECT_EQ(1u,
597 sessionA->num_active_streams()); // Active stream is still active.
598 EXPECT_FALSE(delegateA.StreamIsClosed());
600 EXPECT_TRUE(delegateB.StreamIsClosed()); // Created stream was closed.
601 EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
603 sessionA->CloseSessionOnError(ERR_ABORTED, "Closing");
604 sessionB->CloseSessionOnError(ERR_ABORTED, "Closing");
606 EXPECT_TRUE(delegateA.StreamIsClosed());
607 EXPECT_EQ(ERR_ABORTED, delegateA.WaitForClose());
608 #else
609 EXPECT_TRUE(sessionA->IsDraining());
610 EXPECT_TRUE(sessionB->IsDraining());
611 EXPECT_TRUE(sessionC->IsDraining());
613 // Both streams were closed with an error.
614 EXPECT_TRUE(delegateA.StreamIsClosed());
615 EXPECT_EQ(ERR_NETWORK_CHANGED, delegateA.WaitForClose());
616 EXPECT_TRUE(delegateB.StreamIsClosed());
617 EXPECT_EQ(ERR_NETWORK_CHANGED, delegateB.WaitForClose());
618 #endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS)
621 } // namespace
623 } // namespace net