Chromium Code Reviews| Index: net/spdy/spdy_session_spdy2_unittest.cc |
| =================================================================== |
| --- net/spdy/spdy_session_spdy2_unittest.cc (revision 181662) |
| +++ net/spdy/spdy_session_spdy2_unittest.cc (working copy) |
| @@ -1807,16 +1807,18 @@ |
| EXPECT_TRUE(data.at_read_eof()); |
| } |
| -// Test that SpdySession::DoRead yields while reading the data. This test makes |
| -// 4 reads of kMaxReadBytes / 4 (-spdy_data_frame_size), one read of |
| -// kMaxReadBytes (-spdy_data_frame_size), and some reads of kMaxReadBytes + 8k |
| -// (-spdy_data_frame_size), bytes of data available on the socket for reading. |
| -// It then verifies that DoRead has yielded even though there is data available |
| -// for it to read (i.e, socket()->Read didn't return ERR_IO_PENDING during |
| -// socket reads). Also verifies that SpdySession reads only |
| -// SpdySession::kReadBufferSize data from the underlying transport. |
| -// TODO(rtennti): Make this test work after fixes to DeterministicSocketData. |
| -TEST_F(SpdySessionSpdy2Test, DISABLED_TestYieldingDuringLargeReadData) { |
| +// Test that SpdySession::DoRead() tests interactions of yielding + async, |
| +// by doing the following MockReads. |
| +// |
| +// MockRead of SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K |
| +// ASYNC 6K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 8K, SYNCHRONOUS 2K. |
| +// |
| +// The above reads 26K synchronously. Since that is less that 32K, we will |
| +// attempt to read again. However, that DoRead() will return ERR_IO_PENDING |
| +// (because of async read), so DoRead() will yield. When we come back, DoRead() |
| +// will read the results from the async read, and rest of the data |
| +// synchronously. |
| +TEST_F(SpdySessionSpdy2Test, TestYieldingDuringAsyncReadData) { |
| MockConnect connect_data(SYNCHRONOUS, OK); |
| BufferedSpdyFramer framer(2, false); |
| @@ -1828,36 +1830,34 @@ |
| // Build buffer of size kMaxReadBytes / 4 (-spdy_data_frame_size). |
| ASSERT_EQ(32 * 1024, kMaxReadBytes); |
| TestDataStream test_stream; |
| - const int kSmallPayloadSize = kMaxReadBytes / 4 - SpdyDataFrame::size(); |
| - scoped_refptr<net::IOBuffer> small_payload( |
| - new net::IOBuffer(kSmallPayloadSize)); |
| - char* small_payload_data = small_payload->data(); |
| - test_stream.GetBytes(small_payload_data, kSmallPayloadSize); |
| + const int kEightKPayloadSize = kMaxReadBytes / 4 - SpdyDataFrame::size(); |
| + scoped_refptr<net::IOBuffer> eightk_payload( |
| + new net::IOBuffer(kEightKPayloadSize)); |
| + char* eightk_payload_data = eightk_payload->data(); |
| + test_stream.GetBytes(eightk_payload_data, kEightKPayloadSize); |
| - // Build buffer of size kMaxReadBytes - (-spdy_data_frame_size). |
| + // Build buffer of 6k size. |
| TestDataStream test_stream1; |
| - const int kMaxReadBytesPayloadSize = kMaxReadBytes - SpdyDataFrame::size(); |
| - scoped_refptr<net::IOBuffer> max_bytes_payload( |
| - new net::IOBuffer(kMaxReadBytesPayloadSize)); |
| - char* max_bytes_payload_data = max_bytes_payload->data(); |
| - test_stream1.GetBytes(max_bytes_payload_data, kMaxReadBytesPayloadSize); |
| + const int kSixKPayloadSize = kEightKPayloadSize - 2 * 1024; |
| + scoped_refptr<net::IOBuffer> sixk_bytes_payload( |
| + new net::IOBuffer(kSixKPayloadSize)); |
| + char* sixk_bytes_payload_data = sixk_bytes_payload->data(); |
| + test_stream1.GetBytes(sixk_bytes_payload_data, kSixKPayloadSize); |
| - // Build buffer of size kMaxReadBytes + kSmallPayloadSize |
| - // (-spdy_data_frame_size). |
| + // Build buffer of 2k size. |
| TestDataStream test_stream2; |
| - const int kLargePayloadSize = |
| - kMaxReadBytes + kSmallPayloadSize - SpdyDataFrame::size(); |
| - scoped_refptr<net::IOBuffer> large_payload( |
| - new net::IOBuffer(kLargePayloadSize)); |
| - char* large_payload_data = large_payload->data(); |
| - test_stream2.GetBytes(large_payload_data, kLargePayloadSize); |
| + const int kTwoKPayloadSize = kEightKPayloadSize - 6 * 1024; |
| + scoped_refptr<net::IOBuffer> twok_payload( |
| + new net::IOBuffer(kTwoKPayloadSize)); |
| + char* twok_payload_data = twok_payload->data(); |
| + test_stream2.GetBytes(twok_payload_data, kTwoKPayloadSize); |
| - scoped_ptr<SpdyFrame> small_data_frame(framer.CreateDataFrame( |
| - 1, small_payload_data, kSmallPayloadSize, DATA_FLAG_NONE)); |
| - scoped_ptr<SpdyFrame> max_bytes_data_frame(framer.CreateDataFrame( |
| - 1, max_bytes_payload_data, kMaxReadBytesPayloadSize, DATA_FLAG_NONE)); |
| - scoped_ptr<SpdyFrame> large_data_frame(framer.CreateDataFrame( |
| - 1, large_payload_data, kLargePayloadSize, DATA_FLAG_NONE)); |
| + scoped_ptr<SpdyFrame> eightk_data_frame(framer.CreateDataFrame( |
| + 1, eightk_payload_data, kEightKPayloadSize, DATA_FLAG_NONE)); |
| + scoped_ptr<SpdyFrame> sixk_bytes_data_frame(framer.CreateDataFrame( |
| + 1, sixk_bytes_payload_data, kSixKPayloadSize, DATA_FLAG_NONE)); |
| + scoped_ptr<SpdyFrame> twok_data_frame(framer.CreateDataFrame( |
| + 1, twok_payload_data, kTwoKPayloadSize, DATA_FLAG_NONE)); |
| scoped_ptr<SpdyFrame> finish_data_frame(framer.CreateDataFrame( |
| 1, "h", 1, DATA_FLAG_FIN)); |
| @@ -1865,14 +1865,17 @@ |
| MockRead reads[] = { |
| CreateMockRead(*resp1, 1), |
| - CreateMockRead(*small_data_frame, 2), |
| - CreateMockRead(*small_data_frame, 3, SYNCHRONOUS), |
| - CreateMockRead(*small_data_frame, 4, SYNCHRONOUS), |
| - CreateMockRead(*small_data_frame, 5, SYNCHRONOUS), |
| - CreateMockRead(*max_bytes_data_frame, 6), |
| - CreateMockRead(*large_data_frame, 7, SYNCHRONOUS), |
| - CreateMockRead(*finish_data_frame, 8, SYNCHRONOUS), |
| - MockRead(ASYNC, 0, 9) // EOF |
| + CreateMockRead(*eightk_data_frame, 2), |
| + CreateMockRead(*eightk_data_frame, 3, SYNCHRONOUS), |
| + CreateMockRead(*eightk_data_frame, 4, SYNCHRONOUS), |
| + CreateMockRead(*twok_data_frame, 5, SYNCHRONOUS), |
| + CreateMockRead(*sixk_bytes_data_frame, 6, ASYNC), |
|
Ryan Hamilton
2013/02/12 18:35:39
Can you make this return 8K?
ramant (doing other things)
2013/02/12 18:44:43
Done.
|
| + CreateMockRead(*eightk_data_frame, 7, SYNCHRONOUS), |
| + CreateMockRead(*eightk_data_frame, 8, SYNCHRONOUS), |
| + CreateMockRead(*eightk_data_frame, 9, SYNCHRONOUS), |
| + CreateMockRead(*twok_data_frame, 10, SYNCHRONOUS), |
| + CreateMockRead(*finish_data_frame, 11, SYNCHRONOUS), |
| + MockRead(ASYNC, 0, 12) // EOF |
| }; |
| // Create SpdySession and SpdyStream and send the request. |
| @@ -1907,7 +1910,7 @@ |
| EXPECT_TRUE(spdy_stream1->HasUrl()); |
| spdy_stream1->SendRequest(false); |
| - // Set up the TaskObserver to verify SpdySession::DoRead posts a task. |
| + // Set up the TaskObserver to monitor SpdySession::DoRead posting of tasks. |
| SpdySessionTestTaskObserver observer("spdy_session.cc", "DoRead"); |
| // Run until 1st read. |
| @@ -1917,7 +1920,7 @@ |
| EXPECT_EQ(0u, observer.executed_count()); |
| // Read all the data and verify SpdySession::DoRead has posted a task. |
| - data.RunFor(10); |
| + data.RunFor(12); |
| // Verify task observer's executed_count is 1, which indicates DoRead has |
| // posted only one task and thus yielded though there is data available for |
| @@ -1927,4 +1930,82 @@ |
| EXPECT_TRUE(data.at_read_eof()); |
| } |
| +// Send a GoAway frame when SpdySession is in DoLoop. If scoped_refptr to |
| +// <SpdySession> is deleted from SpdySession::DoLoop(), we get a crash because |
| +// GoAway could delete the SpdySession from the SpdySessionPool and the last |
| +// reference to SpdySession. |
| +TEST_F(SpdySessionSpdy2Test, GoAwayWhileInDoLoop) { |
| + MockConnect connect_data(SYNCHRONOUS, OK); |
| + BufferedSpdyFramer framer(2, false); |
| + |
| + scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, MEDIUM)); |
| + MockWrite writes[] = { |
| + CreateMockWrite(*req1, 0), |
| + }; |
| + |
| + scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); |
| + scoped_ptr<SpdyFrame> body1(ConstructSpdyBodyFrame(1, true)); |
| + scoped_ptr<SpdyFrame> goaway(ConstructSpdyGoAway()); |
| + |
| + MockRead reads[] = { |
| + CreateMockRead(*resp1, 1), |
| + CreateMockRead(*body1, 2), |
| + CreateMockRead(*goaway, 3), |
| + MockRead(ASYNC, 0, 4) // EOF |
| + }; |
| + |
| + // Create SpdySession and SpdyStream and send the request. |
| + DeterministicSocketData data(reads, arraysize(reads), |
| + writes, arraysize(writes)); |
| + data.set_connect_data(connect_data); |
| + session_deps_.host_resolver->set_synchronous_mode(true); |
| + session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data); |
| + |
| + SSLSocketDataProvider ssl(SYNCHRONOUS, OK); |
| + session_deps_.deterministic_socket_factory->AddSSLSocketDataProvider(&ssl); |
| + |
| + CreateDeterministicNetworkSession(); |
| + |
| + scoped_refptr<SpdySession> session = CreateInitializedSession(); |
| + |
| + scoped_refptr<SpdyStream> spdy_stream1; |
| + TestCompletionCallback callback1; |
| + GURL url1("http://www.google.com"); |
| + EXPECT_EQ(OK, session->CreateStream(url1, MEDIUM, &spdy_stream1, |
| + BoundNetLog(), callback1.callback())); |
| + EXPECT_EQ(0u, spdy_stream1->stream_id()); |
| + |
| + 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"; |
| + |
| + spdy_stream1->set_spdy_headers(headers.Pass()); |
| + EXPECT_TRUE(spdy_stream1->HasUrl()); |
| + spdy_stream1->SendRequest(false); |
| + |
| + // Run until 1st read. |
| + EXPECT_EQ(0u, spdy_stream1->stream_id()); |
| + data.RunFor(1); |
| + EXPECT_EQ(1u, spdy_stream1->stream_id()); |
| + |
| + // Drop the reference to the session. |
| + session = NULL; |
| + |
| + // Run until GoAway. |
| + data.RunFor(2); |
| + |
| + // Drop the reference to the stream which deletes its reference to the |
| + // SpdySession. Only references to SpdySession are held by DoLoop and |
| + // SpdySessionPool. If DoLoop doesn't hold the reference, we get a crash if |
| + // SpdySession is deleted from the SpdySessionPool. |
| + spdy_stream1 = NULL; |
| + |
| + data.RunFor(2); |
| + EXPECT_TRUE(data.at_write_eof()); |
| + EXPECT_TRUE(data.at_read_eof()); |
| +} |
| + |
| } // namespace net |