diff options
author | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-23 02:43:25 +0000 |
---|---|---|
committer | rtenneti@chromium.org <rtenneti@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-23 02:43:25 +0000 |
commit | 49769d31820e00ee35c4a554e9e557023d8948ce (patch) | |
tree | dd1987b66d80668fc41f1d826264c429b6248a71 /net/spdy/spdy_session_spdy2_unittest.cc | |
parent | 089df8eba039306e50da494446c5ea7ee5cdbb54 (diff) | |
download | chromium_src-49769d31820e00ee35c4a554e9e557023d8948ce.zip chromium_src-49769d31820e00ee35c4a554e9e557023d8948ce.tar.gz chromium_src-49769d31820e00ee35c4a554e9e557023d8948ce.tar.bz2 |
SPDY - handle stalled spdy streams properly when number of concurrent
streams go over 100.
Changed create_stream_queues_ to pending_create_stream_queues_ for readability (jar).
When a spdy_stream is closed or a created stream which didn't have stream_id
is cancelled, handle how many streams get unstalled (or new streams
that are created) properly. Fix is not to go over the max concurrent
streams limit.
Bug=170491
R=rch@chromium.org,jar@chromium.org
TESTS=network unit tests
Review URL: https://chromiumcodereview.appspot.com/12033016
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178218 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/spdy/spdy_session_spdy2_unittest.cc')
-rw-r--r-- | net/spdy/spdy_session_spdy2_unittest.cc | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/net/spdy/spdy_session_spdy2_unittest.cc b/net/spdy/spdy_session_spdy2_unittest.cc index d9401c8..54b8722 100644 --- a/net/spdy/spdy_session_spdy2_unittest.cc +++ b/net/spdy/spdy_session_spdy2_unittest.cc @@ -1586,4 +1586,286 @@ TEST_F(SpdySessionSpdy2Test, CloseSessionWithTwoCreatedStreams) { spdy_stream2 = NULL; } +TEST_F(SpdySessionSpdy2Test, CloseTwoStalledCreateStream) { + // TODO(rtenneti): Define a helper class/methods and move the common code in + // this file. + MockConnect connect_data(SYNCHRONOUS, OK); + + SettingsMap new_settings; + const SpdySettingsIds kSpdySettingsIds1 = SETTINGS_MAX_CONCURRENT_STREAMS; + const uint32 max_concurrent_streams = 1; + new_settings[kSpdySettingsIds1] = + SettingsFlagsAndValue(SETTINGS_FLAG_NONE, max_concurrent_streams); + + scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, LOWEST)); + scoped_ptr<SpdyFrame> req2(ConstructSpdyGet(NULL, 0, false, 3, LOWEST)); + scoped_ptr<SpdyFrame> req3(ConstructSpdyGet(NULL, 0, false, 5, LOWEST)); + MockWrite writes[] = { + CreateMockWrite(*req1, 1), + CreateMockWrite(*req2, 4), + CreateMockWrite(*req3, 7), + }; + + // Set up the socket so we read a SETTINGS frame that sets max concurrent + // streams to 1. + scoped_ptr<SpdyFrame> settings_frame(ConstructSpdySettings(new_settings)); + + scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); + scoped_ptr<SpdyFrame> body1(ConstructSpdyBodyFrame(1, true)); + + scoped_ptr<SpdyFrame> resp2(ConstructSpdyGetSynReply(NULL, 0, 3)); + scoped_ptr<SpdyFrame> body2(ConstructSpdyBodyFrame(3, true)); + + scoped_ptr<SpdyFrame> resp3(ConstructSpdyGetSynReply(NULL, 0, 5)); + scoped_ptr<SpdyFrame> body3(ConstructSpdyBodyFrame(5, true)); + + MockRead reads[] = { + CreateMockRead(*settings_frame), + CreateMockRead(*resp1, 2), + CreateMockRead(*body1, 3), + CreateMockRead(*resp2, 5), + CreateMockRead(*body2, 6), + CreateMockRead(*resp3, 8), + CreateMockRead(*body3, 9), + MockRead(ASYNC, 0, 10) // EOF + }; + + SpdySessionDependencies session_deps; + session_deps.host_resolver->set_synchronous_mode(true); + + DeterministicSocketData data(reads, arraysize(reads), + writes, arraysize(writes)); + data.set_connect_data(connect_data); + session_deps.deterministic_socket_factory->AddSocketDataProvider(&data); + + SSLSocketDataProvider ssl(SYNCHRONOUS, OK); + session_deps.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); + + scoped_refptr<HttpNetworkSession> http_session( + SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps)); + + const std::string kTestHost("www.foo.com"); + const int kTestPort = 80; + HostPortPair test_host_port_pair(kTestHost, kTestPort); + HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); + + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); + + // Create a session. + EXPECT_FALSE(spdy_session_pool->HasSession(pair)); + scoped_refptr<SpdySession> session = + spdy_session_pool->Get(pair, BoundNetLog()); + ASSERT_TRUE(spdy_session_pool->HasSession(pair)); + + scoped_refptr<TransportSocketParams> transport_params( + new TransportSocketParams(test_host_port_pair, + LOWEST, + false, + false, + OnHostResolutionCallback())); + scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), + transport_params, LOWEST, CompletionCallback(), + http_session->GetTransportSocketPool( + HttpNetworkSession::NORMAL_SOCKET_POOL), + BoundNetLog())); + EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); + + // Read the settings frame. + data.RunFor(1); + + scoped_refptr<SpdyStream> spdy_stream1; + TestCompletionCallback callback1; + GURL url1("http://www.google.com"); + EXPECT_EQ(OK, session->CreateStream(url1, + LOWEST, + &spdy_stream1, + BoundNetLog(), + callback1.callback())); + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + scoped_refptr<SpdyStream> spdy_stream2; + TestCompletionCallback callback2; + GURL url2("http://www.google.com"); + EXPECT_EQ(ERR_IO_PENDING, + session->CreateStream(url2, + LOWEST, + &spdy_stream2, + BoundNetLog(), + callback2.callback())); + + scoped_refptr<SpdyStream> spdy_stream3; + TestCompletionCallback callback3; + GURL url3("http://www.google.com"); + EXPECT_EQ(ERR_IO_PENDING, + session->CreateStream(url3, + LOWEST, + &spdy_stream3, + BoundNetLog(), + callback3.callback())); + + EXPECT_EQ(1u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(2u, session->pending_create_stream_queues(LOWEST)); + + scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock); + (*headers)["method"] = "GET"; + (*headers)["scheme"] = url1.scheme(); + (*headers)["host"] = url1.host(); + (*headers)["url"] = url1.path(); + (*headers)["version"] = "HTTP/1.1"; + scoped_ptr<SpdyHeaderBlock> headers2(new SpdyHeaderBlock); + *headers2 = *headers; + scoped_ptr<SpdyHeaderBlock> headers3(new SpdyHeaderBlock); + *headers3 = *headers; + + spdy_stream1->set_spdy_headers(headers.Pass()); + EXPECT_TRUE(spdy_stream1->HasUrl()); + spdy_stream1->SendRequest(false); + + // Run until 1st stream is closed. + EXPECT_EQ(0u, spdy_stream1->stream_id()); + data.RunFor(3); + EXPECT_EQ(1u, spdy_stream1->stream_id()); + EXPECT_EQ(1u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(1u, session->pending_create_stream_queues(LOWEST)); + + EXPECT_TRUE(spdy_stream2.get() != NULL); + spdy_stream2->set_spdy_headers(headers2.Pass()); + EXPECT_TRUE(spdy_stream2->HasUrl()); + spdy_stream2->SendRequest(false); + + // Run until 2nd stream is closed. + EXPECT_EQ(0u, spdy_stream2->stream_id()); + data.RunFor(3); + EXPECT_EQ(3u, spdy_stream2->stream_id()); + EXPECT_EQ(1u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(0u, session->pending_create_stream_queues(LOWEST)); + + EXPECT_TRUE(spdy_stream3.get() != NULL); + spdy_stream3->set_spdy_headers(headers3.Pass()); + EXPECT_TRUE(spdy_stream3->HasUrl()); + spdy_stream3->SendRequest(false); + + EXPECT_EQ(0u, spdy_stream3->stream_id()); + data.RunFor(4); + EXPECT_EQ(5u, spdy_stream3->stream_id()); + EXPECT_EQ(0u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(0u, session->pending_create_stream_queues(LOWEST)); +} + +TEST_F(SpdySessionSpdy2Test, CancelTwoStalledCreateStream) { + SpdySessionDependencies session_deps; + session_deps.host_resolver->set_synchronous_mode(true); + + MockRead reads[] = { + MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever. + }; + + StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0); + MockConnect connect_data(SYNCHRONOUS, OK); + + data.set_connect_data(connect_data); + session_deps.socket_factory->AddSocketDataProvider(&data); + + SSLSocketDataProvider ssl(SYNCHRONOUS, OK); + session_deps.socket_factory->AddSSLSocketDataProvider(&ssl); + + scoped_refptr<HttpNetworkSession> http_session( + SpdySessionDependencies::SpdyCreateSession(&session_deps)); + + const std::string kTestHost("www.foo.com"); + const int kTestPort = 80; + HostPortPair test_host_port_pair(kTestHost, kTestPort); + HostPortProxyPair pair(test_host_port_pair, ProxyServer::Direct()); + + SpdySessionPool* spdy_session_pool(http_session->spdy_session_pool()); + + // Initialize the SpdySetting with 1 max concurrent streams. + spdy_session_pool->http_server_properties()->SetSpdySetting( + test_host_port_pair, + SETTINGS_MAX_CONCURRENT_STREAMS, + SETTINGS_FLAG_PLEASE_PERSIST, + 1); + + // Create a session. + EXPECT_FALSE(spdy_session_pool->HasSession(pair)); + scoped_refptr<SpdySession> session = + spdy_session_pool->Get(pair, BoundNetLog()); + ASSERT_TRUE(spdy_session_pool->HasSession(pair)); + + scoped_refptr<TransportSocketParams> transport_params( + new TransportSocketParams(test_host_port_pair, + LOWEST, + false, + false, + OnHostResolutionCallback())); + scoped_ptr<ClientSocketHandle> connection(new ClientSocketHandle); + EXPECT_EQ(OK, connection->Init(test_host_port_pair.ToString(), + transport_params, + LOWEST, + CompletionCallback(), + http_session->GetTransportSocketPool( + HttpNetworkSession::NORMAL_SOCKET_POOL), + BoundNetLog())); + EXPECT_EQ(OK, session->InitializeWithSocket(connection.release(), false, OK)); + + scoped_refptr<SpdyStream> spdy_stream1; + TestCompletionCallback callback1; + GURL url1("http://www.google.com"); + ASSERT_EQ(OK, + session->CreateStream(url1, + LOWEST, + &spdy_stream1, + BoundNetLog(), + callback1.callback())); + EXPECT_EQ(0u, spdy_stream1->stream_id()); + + scoped_refptr<SpdyStream> spdy_stream2; + TestCompletionCallback callback2; + GURL url2("http://www.google.com"); + ASSERT_EQ(ERR_IO_PENDING, + session->CreateStream(url2, + LOWEST, + &spdy_stream2, + BoundNetLog(), + callback2.callback())); + + scoped_refptr<SpdyStream> spdy_stream3; + TestCompletionCallback callback3; + GURL url3("http://www.google.com"); + ASSERT_EQ(ERR_IO_PENDING, + session->CreateStream(url3, + LOWEST, + &spdy_stream3, + BoundNetLog(), + callback3.callback())); + + EXPECT_EQ(1u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(2u, session->pending_create_stream_queues(LOWEST)); + + // Cancel the first stream, this will allow the second stream to be created. + EXPECT_TRUE(spdy_stream1.get() != NULL); + spdy_stream1->Cancel(); + spdy_stream1 = NULL; + session->CancelPendingCreateStreams(&spdy_stream1); + EXPECT_EQ(1u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(1u, session->pending_create_stream_queues(LOWEST)); + + // Cancel the second stream, this will allow the third stream to be created. + EXPECT_TRUE(spdy_stream2.get() != NULL); + spdy_stream2->Cancel(); + spdy_stream2 = NULL; + session->CancelPendingCreateStreams(&spdy_stream2); + EXPECT_EQ(1u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(0u, session->pending_create_stream_queues(LOWEST)); + + // Cancel the third stream. + EXPECT_TRUE(spdy_stream3.get() != NULL); + spdy_stream3->Cancel(); + spdy_stream3 = NULL; + session->CancelPendingCreateStreams(&spdy_stream3); + EXPECT_EQ(0u, session->num_active_streams() + session->num_created_streams()); + EXPECT_EQ(0u, session->pending_create_stream_queues(LOWEST)); +} + } // namespace net |