| Index: net/spdy/spdy_session_unittest.cc
|
| diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
|
| index 5978f9384d9520b0eadd7ebad9f2036e0aa0fcf4..c435a57469ad590ec61c1acc00a1e1bc42584552 100644
|
| --- a/net/spdy/spdy_session_unittest.cc
|
| +++ b/net/spdy/spdy_session_unittest.cc
|
| @@ -920,6 +920,131 @@ TEST_P(SpdySessionTest, PingAndWriteLoop) {
|
| session->CloseSessionOnError(ERR_ABORTED, "Aborting");
|
| }
|
|
|
| +TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
|
| + const SpdyStreamId kLastStreamId = 0x7fffffff;
|
| + session_deps_.host_resolver->set_synchronous_mode(true);
|
| +
|
| + // Test setup: |stream_hi_water_mark_| and |max_concurrent_streams_| are
|
| + // fixed to allow for two stream ID assignments, and three concurrent
|
| + // streams. Four streams are started, and two are activated. Verify the
|
| + // session goes away, and that the created (but not activated) and
|
| + // stalled streams are aborted. Also verify the activated streams complete,
|
| + // at which point the session closes.
|
| +
|
| + scoped_ptr<SpdyFrame> req1(spdy_util_.ConstructSpdyGet(
|
| + NULL, 0, false, kLastStreamId - 2, MEDIUM, true));
|
| + scoped_ptr<SpdyFrame> req2(
|
| + spdy_util_.ConstructSpdyGet(NULL, 0, false, kLastStreamId, MEDIUM, true));
|
| +
|
| + MockWrite writes[] = {
|
| + CreateMockWrite(*req1, 0), CreateMockWrite(*req2, 1),
|
| + };
|
| +
|
| + scoped_ptr<SpdyFrame> resp1(
|
| + spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId - 2));
|
| + scoped_ptr<SpdyFrame> resp2(
|
| + spdy_util_.ConstructSpdyGetSynReply(NULL, 0, kLastStreamId));
|
| +
|
| + scoped_ptr<SpdyFrame> body1(
|
| + spdy_util_.ConstructSpdyBodyFrame(kLastStreamId - 2, true));
|
| + scoped_ptr<SpdyFrame> body2(
|
| + spdy_util_.ConstructSpdyBodyFrame(kLastStreamId, true));
|
| +
|
| + MockRead reads[] = {
|
| + CreateMockRead(*resp1, 2), CreateMockRead(*resp2, 3),
|
| + CreateMockRead(*body1, 4), CreateMockRead(*body2, 5),
|
| + MockRead(ASYNC, 0, 6) // EOF
|
| + };
|
| +
|
| + DeterministicSocketData data(
|
| + reads, arraysize(reads), writes, arraysize(writes));
|
| +
|
| + MockConnect connect_data(SYNCHRONOUS, OK);
|
| + data.set_connect_data(connect_data);
|
| + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
|
| +
|
| + CreateDeterministicNetworkSession();
|
| + base::WeakPtr<SpdySession> session =
|
| + CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
|
| +
|
| + // Fix stream_hi_water_mark_ to allow for two stream activations.
|
| + session->stream_hi_water_mark_ = kLastStreamId - 2;
|
| + // Fix max_concurrent_streams to allow for three stream creations.
|
| + session->max_concurrent_streams_ = 3;
|
| +
|
| + // Create three streams synchronously, and begin a fourth (which is stalled).
|
| + GURL url(kDefaultURL);
|
| + base::WeakPtr<SpdyStream> stream1 = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
|
| + test::StreamDelegateDoNothing delegate1(stream1);
|
| + stream1->SetDelegate(&delegate1);
|
| +
|
| + base::WeakPtr<SpdyStream> stream2 = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
|
| + test::StreamDelegateDoNothing delegate2(stream2);
|
| + stream2->SetDelegate(&delegate2);
|
| +
|
| + base::WeakPtr<SpdyStream> stream3 = CreateStreamSynchronously(
|
| + SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
|
| + test::StreamDelegateDoNothing delegate3(stream3);
|
| + stream3->SetDelegate(&delegate3);
|
| +
|
| + SpdyStreamRequest request4;
|
| + TestCompletionCallback callback4;
|
| + EXPECT_EQ(ERR_IO_PENDING,
|
| + request4.StartRequest(SPDY_REQUEST_RESPONSE_STREAM,
|
| + session,
|
| + url,
|
| + MEDIUM,
|
| + BoundNetLog(),
|
| + callback4.callback()));
|
| +
|
| + // Streams 1-3 were created. 4th is stalled. No streams are active yet.
|
| + EXPECT_EQ(0u, session->num_active_streams());
|
| + EXPECT_EQ(3u, session->num_created_streams());
|
| + EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
|
| +
|
| + // Activate stream 1. One ID remains available.
|
| + stream1->SendRequestHeaders(
|
| + scoped_ptr<SpdyHeaderBlock>(
|
| + spdy_util_.ConstructGetHeaderBlock(url.spec())),
|
| + NO_MORE_DATA_TO_SEND);
|
| + data.RunFor(1);
|
| +
|
| + EXPECT_EQ(kLastStreamId - 2u, stream1->stream_id());
|
| + EXPECT_EQ(1u, session->num_active_streams());
|
| + EXPECT_EQ(2u, session->num_created_streams());
|
| + EXPECT_EQ(1u, session->pending_create_stream_queue_size(MEDIUM));
|
| +
|
| + // Activate stream 2. ID space is exhausted.
|
| + stream2->SendRequestHeaders(
|
| + scoped_ptr<SpdyHeaderBlock>(
|
| + spdy_util_.ConstructGetHeaderBlock(url.spec())),
|
| + NO_MORE_DATA_TO_SEND);
|
| + data.RunFor(1);
|
| +
|
| + // Active streams remain active.
|
| + EXPECT_EQ(kLastStreamId, stream2->stream_id());
|
| + EXPECT_EQ(2u, session->num_active_streams());
|
| +
|
| + // Session is going away. Created and stalled streams were aborted.
|
| + EXPECT_EQ(SpdySession::STATE_GOING_AWAY, session->availability_state_);
|
| + EXPECT_EQ(ERR_ABORTED, delegate3.WaitForClose());
|
| + EXPECT_EQ(ERR_ABORTED, callback4.WaitForResult());
|
| + EXPECT_EQ(0u, session->num_created_streams());
|
| + EXPECT_EQ(0u, session->pending_create_stream_queue_size(MEDIUM));
|
| +
|
| + // Read responses on remaining active streams.
|
| + data.RunFor(4);
|
| + EXPECT_EQ(OK, delegate1.WaitForClose());
|
| + EXPECT_EQ(kUploadData, delegate1.TakeReceivedData());
|
| + EXPECT_EQ(OK, delegate2.WaitForClose());
|
| + EXPECT_EQ(kUploadData, delegate2.TakeReceivedData());
|
| +
|
| + // Session was destroyed.
|
| + EXPECT_FALSE(session.get());
|
| +}
|
| +
|
| TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
|
| session_deps_.host_resolver->set_synchronous_mode(true);
|
| session_deps_.time_func = TheNearFuture;
|
|
|