Index: net/spdy/spdy_session_pool_unittest.cc |
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc |
index 58002dcdea2f199779abe21ebe9ca6405051446d..1a29cc7aef2abf1869a4aa5eba37c7e8c942c41e 100644 |
--- a/net/spdy/spdy_session_pool_unittest.cc |
+++ b/net/spdy/spdy_session_pool_unittest.cc |
@@ -14,6 +14,7 @@ |
#include "net/socket/client_socket_handle.h" |
#include "net/socket/transport_client_socket_pool.h" |
#include "net/spdy/spdy_session.h" |
+#include "net/spdy/spdy_stream_test_util.h" |
#include "net/spdy/spdy_test_util_common.h" |
#include "testing/gtest/include/gtest/gtest.h" |
@@ -138,7 +139,7 @@ TEST_P(SpdySessionPoolTest, CloseCurrentSessions) { |
TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) { |
MockConnect connect_data(SYNCHRONOUS, OK); |
MockRead reads[] = { |
- MockRead(ASYNC, 0, 0) // EOF |
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
}; |
session_deps_.host_resolver->set_synchronous_mode(true); |
@@ -195,20 +196,20 @@ TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) { |
// All sessions are active and not closed |
EXPECT_TRUE(session1->is_active()); |
- EXPECT_FALSE(session1->IsClosed()); |
+ EXPECT_TRUE(session1->IsAvailable()); |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
EXPECT_TRUE(session3->is_active()); |
- EXPECT_FALSE(session3->IsClosed()); |
+ EXPECT_TRUE(session3->IsAvailable()); |
// Should not do anything, all are active |
spdy_session_pool_->CloseCurrentIdleSessions(); |
EXPECT_TRUE(session1->is_active()); |
- EXPECT_FALSE(session1->IsClosed()); |
+ EXPECT_TRUE(session1->IsAvailable()); |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
EXPECT_TRUE(session3->is_active()); |
- EXPECT_FALSE(session3->IsClosed()); |
+ EXPECT_TRUE(session3->IsAvailable()); |
// Make sessions 1 and 3 inactive, but keep them open. |
// Session 2 still open and active |
@@ -217,32 +218,40 @@ TEST_P(SpdySessionPoolTest, CloseCurrentIdleSessions) { |
session3->CloseCreatedStream(spdy_stream3, OK); |
EXPECT_EQ(NULL, spdy_stream3.get()); |
EXPECT_FALSE(session1->is_active()); |
- EXPECT_FALSE(session1->IsClosed()); |
+ EXPECT_TRUE(session1->IsAvailable()); |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
EXPECT_FALSE(session3->is_active()); |
- EXPECT_FALSE(session3->IsClosed()); |
+ EXPECT_TRUE(session3->IsAvailable()); |
// Should close session 1 and 3, 2 should be left open |
spdy_session_pool_->CloseCurrentIdleSessions(); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
EXPECT_TRUE(session1 == NULL); |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
EXPECT_TRUE(session3 == NULL); |
// Should not do anything |
spdy_session_pool_->CloseCurrentIdleSessions(); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
// Make 2 not active |
session2->CloseCreatedStream(spdy_stream2, OK); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
EXPECT_EQ(NULL, spdy_stream2.get()); |
EXPECT_FALSE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
// This should close session 2 |
spdy_session_pool_->CloseCurrentIdleSessions(); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ |
EXPECT_TRUE(session2 == NULL); |
} |
@@ -420,8 +429,9 @@ void SpdySessionPoolTest::RunIPPoolingTest( |
switch (close_sessions_type) { |
case SPDY_POOL_CLOSE_SESSIONS_MANUALLY: |
session->CloseSessionOnError(ERR_ABORTED, std::string()); |
- EXPECT_TRUE(session == NULL); |
session2->CloseSessionOnError(ERR_ABORTED, std::string()); |
+ base::MessageLoop::current()->RunUntilIdle(); |
+ EXPECT_TRUE(session == NULL); |
EXPECT_TRUE(session2 == NULL); |
break; |
case SPDY_POOL_CLOSE_CURRENT_SESSIONS: |
@@ -449,27 +459,30 @@ void SpdySessionPoolTest::RunIPPoolingTest( |
// Check spdy_session and spdy_session1 are not closed. |
EXPECT_FALSE(session->is_active()); |
- EXPECT_FALSE(session->IsClosed()); |
+ EXPECT_TRUE(session->IsAvailable()); |
EXPECT_FALSE(session1->is_active()); |
- EXPECT_FALSE(session1->IsClosed()); |
+ EXPECT_TRUE(session1->IsAvailable()); |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
// Test that calling CloseIdleSessions, does not cause a crash. |
// http://crbug.com/181400 |
spdy_session_pool_->CloseCurrentIdleSessions(); |
+ base::MessageLoop::current()->RunUntilIdle(); |
// Verify spdy_session and spdy_session1 are closed. |
EXPECT_TRUE(session == NULL); |
EXPECT_TRUE(session1 == NULL); |
EXPECT_TRUE(session2->is_active()); |
- EXPECT_FALSE(session2->IsClosed()); |
+ EXPECT_TRUE(session2->IsAvailable()); |
spdy_stream2->Cancel(); |
EXPECT_EQ(NULL, spdy_stream.get()); |
EXPECT_EQ(NULL, spdy_stream1.get()); |
EXPECT_EQ(NULL, spdy_stream2.get()); |
+ |
session2->CloseSessionOnError(ERR_ABORTED, std::string()); |
+ base::MessageLoop::current()->RunUntilIdle(); |
EXPECT_TRUE(session2 == NULL); |
break; |
} |
@@ -492,6 +505,93 @@ TEST_P(SpdySessionPoolTest, IPPoolingCloseIdleSessions) { |
RunIPPoolingTest(SPDY_POOL_CLOSE_IDLE_SESSIONS); |
} |
+// Construct a Pool with SpdySessions in various availability states. Simulate |
+// an IP address change. Ensure sessions gracefully shut down. Regression test |
+// for crbug.com/379469. |
+TEST_P(SpdySessionPoolTest, IPAddressChanged) { |
+ MockConnect connect_data(SYNCHRONOUS, OK); |
+ MockRead reads[] = { |
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. |
+ }; |
+ session_deps_.host_resolver->set_synchronous_mode(true); |
+ |
+ StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); |
+ data.set_connect_data(connect_data); |
+ session_deps_.socket_factory->AddSocketDataProvider(&data); |
+ |
+ SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
+ session_deps_.socket_factory->AddSSLSocketDataProvider(&ssl); |
+ |
+ CreateNetworkSession(); |
+ |
+ // Set up session 1: Available, but idle. |
+ const std::string kTestHost1("http://www.a.com"); |
+ HostPortPair test_host_port_pair1(kTestHost1, 80); |
+ SpdySessionKey key1( |
+ test_host_port_pair1, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); |
+ base::WeakPtr<SpdySession> session1 = |
+ CreateInsecureSpdySession(http_session_, key1, BoundNetLog()); |
+ EXPECT_TRUE(session1->IsAvailable()); |
+ |
+ // Set up session 2: Going away, but with an active stream. |
+ session_deps_.socket_factory->AddSocketDataProvider(&data); |
+ const std::string kTestHost2("http://www.b.com"); |
+ HostPortPair test_host_port_pair2(kTestHost2, 80); |
+ SpdySessionKey key2( |
+ test_host_port_pair2, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); |
+ base::WeakPtr<SpdySession> session2 = |
+ CreateInsecureSpdySession(http_session_, key2, BoundNetLog()); |
+ GURL url2(kTestHost2); |
+ base::WeakPtr<SpdyStream> spdy_stream2 = CreateStreamSynchronously( |
+ SPDY_BIDIRECTIONAL_STREAM, session2, url2, MEDIUM, BoundNetLog()); |
+ test::StreamDelegateDoNothing delegate2(spdy_stream2); |
+ spdy_stream2->SetDelegate(&delegate2); |
+ |
+ scoped_ptr<SpdyHeaderBlock> headers( |
+ SpdyTestUtil(GetParam()).ConstructGetHeaderBlock(url2.spec())); |
+ spdy_stream2->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND); |
+ EXPECT_TRUE(spdy_stream2->HasUrlFromHeaders()); |
+ |
+ session2->MakeUnavailable(); |
+ EXPECT_TRUE(session2->IsGoingAway()); |
+ |
+ // Set up session 3: Draining. |
+ session_deps_.socket_factory->AddSocketDataProvider(&data); |
+ const std::string kTestHost3("http://www.c.com"); |
+ HostPortPair test_host_port_pair3(kTestHost3, 80); |
+ SpdySessionKey key3( |
+ test_host_port_pair3, ProxyServer::Direct(), PRIVACY_MODE_DISABLED); |
+ base::WeakPtr<SpdySession> session3 = |
+ CreateInsecureSpdySession(http_session_, key3, BoundNetLog()); |
+ |
+ session3->CloseSessionOnError(ERR_SPDY_PROTOCOL_ERROR, "Error!"); |
+ EXPECT_TRUE(session3->IsDraining()); |
+ |
+ spdy_session_pool_->OnIPAddressChanged(); |
+ |
+#if defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) |
+ // TODO(jgraettinger): This should be draining when crbug.com/324653 is fixed. |
+ EXPECT_TRUE(session1->IsGoingAway()); |
+ EXPECT_TRUE(session2->IsGoingAway()); |
+ EXPECT_TRUE(session3->IsDraining()); |
+ |
+ EXPECT_FALSE(delegate2.StreamIsClosed()); |
+ |
+ session1->CloseSessionOnError(ERR_ABORTED, "Closing"); |
+ session2->CloseSessionOnError(ERR_ABORTED, "Closing"); |
+ |
+ EXPECT_TRUE(delegate2.StreamIsClosed()); |
+ EXPECT_EQ(ERR_ABORTED, delegate2.WaitForClose()); |
+#else |
+ EXPECT_TRUE(session1->IsDraining()); |
+ EXPECT_TRUE(session2->IsDraining()); |
+ EXPECT_TRUE(session3->IsDraining()); |
+ |
+ EXPECT_TRUE(delegate2.StreamIsClosed()); |
+ EXPECT_EQ(ERR_NETWORK_CHANGED, delegate2.WaitForClose()); |
+#endif // defined(OS_ANDROID) || defined(OS_WIN) || defined(OS_IOS) |
+} |
+ |
} // namespace |
} // namespace net |