Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(630)

Unified Diff: net/spdy/spdy_session_unittest.cc

Issue 305823003: Re-land: Defer SpdySession destruction to support closing writes (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Regression tests and fix for crbug.com/379469 Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/spdy/spdy_session_pool_unittest.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/spdy/spdy_session_unittest.cc
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 1f7ca60daf75cd4a5577812870b720fbd2408592..dd8679174efd403905fd7440e2e8340cb1ce6b44 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -282,8 +282,7 @@ TEST_P(SpdySessionTest, PendingStreamCancellingAnother) {
EXPECT_EQ(ERR_ABORTED, callback1.WaitForResult());
}
-// A session receiving a GOAWAY frame with no active streams should
-// immediately close.
+// A session receiving a GOAWAY frame with no active streams should close.
TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
session_deps_.host_resolver->set_synchronous_mode(true);
@@ -307,9 +306,8 @@ TEST_P(SpdySessionTest, GoAwayWithNoActiveStreams) {
// Read and process the GOAWAY frame.
data.RunFor(1);
-
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
-
+ base::RunLoop().RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -409,12 +407,13 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreams) {
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(session->IsStreamActive(1));
- EXPECT_FALSE(session->IsClosed());
+ EXPECT_TRUE(session->IsGoingAway());
// Should close the session.
spdy_stream1->Close();
EXPECT_EQ(NULL, spdy_stream1.get());
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -489,13 +488,12 @@ TEST_P(SpdySessionTest, GoAwayTwice) {
EXPECT_FALSE(session->IsStreamActive(3));
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(session->IsStreamActive(1));
-
- EXPECT_FALSE(session->IsClosed());
+ EXPECT_TRUE(session->IsGoingAway());
// Read and process the second GOAWAY frame, which should close the
// session.
data.RunFor(1);
-
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -568,12 +566,79 @@ TEST_P(SpdySessionTest, GoAwayWithActiveStreamsThenClose) {
EXPECT_FALSE(session->IsStreamActive(3));
EXPECT_EQ(NULL, spdy_stream2.get());
EXPECT_TRUE(session->IsStreamActive(1));
-
- EXPECT_FALSE(session->IsClosed());
+ EXPECT_TRUE(session->IsGoingAway());
session->CloseSessionOnError(ERR_ABORTED, "Aborting session");
-
EXPECT_EQ(NULL, spdy_stream1.get());
+
+ base::MessageLoop::current()->RunUntilIdle();
+ EXPECT_TRUE(session == NULL);
+}
+
+// Process a joint read buffer which causes the session to begin draining, and
+// then processes a GOAWAY. The session should gracefully drain. Regression test
+// for crbug.com/379469
+TEST_P(SpdySessionTest, GoAwayWhileDraining) {
+ session_deps_.host_resolver->set_synchronous_mode(true);
+
+ scoped_ptr<SpdyFrame> req(
+ spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+ MockWrite writes[] = {
+ CreateMockWrite(*req, 0),
+ };
+
+ scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1));
+ scoped_ptr<SpdyFrame> goaway(spdy_util_.ConstructSpdyGoAway(1));
+ scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, true));
+ size_t joint_size = goaway->size() * 2 + body->size();
+
+ // Compose interleaved |goaway| and |body| frames into a single read.
+ scoped_ptr<char[]> buffer(new char[joint_size]);
+ {
+ size_t out = 0;
+ memcpy(&buffer[out], goaway->data(), goaway->size());
+ out += goaway->size();
+ memcpy(&buffer[out], body->data(), body->size());
+ out += body->size();
+ memcpy(&buffer[out], goaway->data(), goaway->size());
+ out += goaway->size();
+ ASSERT_EQ(out, joint_size);
+ }
+ SpdyFrame joint_frames(buffer.get(), joint_size, false);
+
+ MockRead reads[] = {
+ CreateMockRead(*resp, 1), CreateMockRead(joint_frames, 2),
+ MockRead(ASYNC, 0, 3) // EOF
+ };
+
+ MockConnect connect_data(SYNCHRONOUS, OK);
+ DeterministicSocketData data(
+ reads, arraysize(reads), writes, arraysize(writes));
+ data.set_connect_data(connect_data);
+ session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+
+ CreateDeterministicNetworkSession();
+ base::WeakPtr<SpdySession> session =
+ CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
+
+ GURL url(kDefaultURL);
+ base::WeakPtr<SpdyStream> spdy_stream = CreateStreamSynchronously(
+ SPDY_REQUEST_RESPONSE_STREAM, session, url, MEDIUM, BoundNetLog());
+ test::StreamDelegateDoNothing delegate(spdy_stream);
+ spdy_stream->SetDelegate(&delegate);
+
+ scoped_ptr<SpdyHeaderBlock> headers(
+ spdy_util_.ConstructGetHeaderBlock(url.spec()));
+ spdy_stream->SendRequestHeaders(headers.Pass(), NO_MORE_DATA_TO_SEND);
+ EXPECT_TRUE(spdy_stream->HasUrlFromHeaders());
+
+ data.RunFor(3);
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Stream and session closed gracefully.
+ EXPECT_TRUE(delegate.StreamIsClosed());
+ EXPECT_EQ(OK, delegate.WaitForClose());
+ EXPECT_EQ(kUploadData, delegate.TakeReceivedData());
EXPECT_TRUE(session == NULL);
}
@@ -702,7 +767,7 @@ TEST_P(SpdySessionTest, SynStreamAfterGoAway) {
// Read and process the SYN_STREAM frame, the subsequent RST_STREAM,
// and EOF.
data.RunFor(3);
-
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -761,7 +826,7 @@ TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
// pre-existing stream is still active.
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
- EXPECT_FALSE(session->IsClosed());
+ EXPECT_TRUE(session->IsGoingAway());
EXPECT_TRUE(session->IsStreamActive(1));
@@ -770,6 +835,7 @@ TEST_P(SpdySessionTest, NetworkChangeWithActiveStreams) {
#endif
EXPECT_EQ(NULL, spdy_stream.get());
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -1042,6 +1108,7 @@ TEST_P(SpdySessionTest, StreamIdSpaceExhausted) {
EXPECT_EQ(kUploadData, delegate2.TakeReceivedData());
// Session was destroyed.
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_FALSE(session.get());
}
@@ -1195,6 +1262,7 @@ TEST_P(SpdySessionTest, DeleteExpiredPushStreams) {
// Read and process EOF.
data.RunFor(1);
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -1203,14 +1271,18 @@ TEST_P(SpdySessionTest, FailedPing) {
MockConnect connect_data(SYNCHRONOUS, OK);
MockRead reads[] = {
- MockRead(ASYNC, 0, 0, 0) // EOF
+ MockRead(SYNCHRONOUS, ERR_IO_PENDING) // Stall forever.
};
scoped_ptr<SpdyFrame> write_ping(spdy_util_.ConstructSpdyPing(1, false));
- DeterministicSocketData data(reads, arraysize(reads), NULL, 0);
+ MockWrite writes[] = {
+ CreateMockWrite(*write_ping),
+ };
+ StaticSocketDataProvider data(
+ reads, arraysize(reads), writes, arraysize(writes));
data.set_connect_data(connect_data);
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
- CreateDeterministicNetworkSession();
+ CreateNetworkSession();
base::WeakPtr<SpdySession> session =
CreateInsecureSpdySession(http_session_, key_, BoundNetLog());
@@ -1232,7 +1304,7 @@ TEST_P(SpdySessionTest, FailedPing) {
EXPECT_TRUE(session->check_ping_status_pending());
// Assert session is not closed.
- EXPECT_FALSE(session->IsClosed());
+ EXPECT_TRUE(session->IsAvailable());
EXPECT_LT(0u, session->num_active_streams() + session->num_created_streams());
EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
@@ -1241,6 +1313,7 @@ TEST_P(SpdySessionTest, FailedPing) {
base::TimeTicks now = base::TimeTicks::Now();
session->last_activity_time_ = now - base::TimeDelta::FromSeconds(1);
session->CheckPingStatus(now);
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
@@ -1304,6 +1377,11 @@ TEST_P(SpdySessionTest, OnSettings) {
EXPECT_EQ(OK, stream_releaser.WaitForResult());
data.RunFor(1);
+ if (spdy_util_.spdy_version() >= SPDY4) {
+ // Allow the SETTINGS+ACK to write, so the session finishes draining.
+ data.RunFor(1);
+ }
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -1583,7 +1661,7 @@ TEST_P(SpdySessionTest, Initialize) {
EXPECT_NE(log.bound().source().id, socket_source.id);
}
-TEST_P(SpdySessionTest, CloseSessionOnError) {
+TEST_P(SpdySessionTest, NetLogOnSessionGoaway) {
session_deps_.host_resolver->set_synchronous_mode(true);
MockConnect connect_data(SYNCHRONOUS, OK);
@@ -1625,6 +1703,53 @@ TEST_P(SpdySessionTest, CloseSessionOnError) {
CapturingNetLog::CapturedEntry entry = entries[pos];
int error_code = 0;
ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
+ EXPECT_EQ(OK, error_code);
+ } else {
+ ADD_FAILURE();
+ }
+}
+
+TEST_P(SpdySessionTest, NetLogOnSessionEOF) {
+ session_deps_.host_resolver->set_synchronous_mode(true);
+
+ MockConnect connect_data(SYNCHRONOUS, OK);
+ MockRead reads[] = {
+ MockRead(SYNCHRONOUS, 0, 0) // EOF
+ };
+
+ StaticSocketDataProvider data(reads, arraysize(reads), NULL, 0);
+ data.set_connect_data(connect_data);
+ session_deps_.socket_factory->AddSocketDataProvider(&data);
+
+ CreateNetworkSession();
+
+ CapturingBoundNetLog log;
+ base::WeakPtr<SpdySession> session =
+ CreateInsecureSpdySession(http_session_, key_, log.bound());
+ EXPECT_TRUE(HasSpdySession(spdy_session_pool_, key_));
+
+ // Flush the read completion task.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
+ EXPECT_TRUE(session == NULL);
+
+ // Check that the NetLog was filled reasonably.
+ net::CapturingNetLog::CapturedEntryList entries;
+ log.GetEntries(&entries);
+ EXPECT_LT(0u, entries.size());
+
+ // Check that we logged SPDY_SESSION_CLOSE correctly.
+ int pos =
+ net::ExpectLogContainsSomewhere(entries,
+ 0,
+ net::NetLog::TYPE_SPDY_SESSION_CLOSE,
+ net::NetLog::PHASE_NONE);
+
+ if (pos < static_cast<int>(entries.size())) {
+ CapturingNetLog::CapturedEntry entry = entries[pos];
+ int error_code = 0;
+ ASSERT_TRUE(entry.GetNetErrorCode(&error_code));
EXPECT_EQ(ERR_CONNECTION_CLOSED, error_code);
} else {
ADD_FAILURE();
@@ -1857,6 +1982,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedSelfClosingStreams) {
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -1930,6 +2056,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoCreatedMutuallyClosingStreams) {
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -2011,6 +2138,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedSelfClosingStreams) {
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -2094,6 +2222,7 @@ TEST_P(SpdySessionTest, CloseSessionWithTwoActivatedMutuallyClosingStreams) {
EXPECT_TRUE(delegate1.StreamIsClosed());
EXPECT_TRUE(delegate2.StreamIsClosed());
+ base::MessageLoop::current()->RunUntilIdle();
EXPECT_TRUE(session == NULL);
}
@@ -2124,12 +2253,14 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
scoped_ptr<SpdyFrame> req(
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, MEDIUM, true));
+ scoped_ptr<SpdyFrame> rst(
+ spdy_util_.ConstructSpdyRstStream(1, RST_STREAM_CANCEL));
MockWrite writes[] = {
- CreateMockWrite(*req, 0),
+ CreateMockWrite(*req, 0), CreateMockWrite(*rst, 1),
};
MockRead reads[] = {
- MockRead(ASYNC, 0, 1) // EOF
+ MockRead(ASYNC, 0, 2) // EOF
};
DeterministicSocketData data(reads, arraysize(reads),
writes, arraysize(writes));
@@ -2166,8 +2297,12 @@ TEST_P(SpdySessionTest, CloseActivatedStreamThatClosesSession) {
// session).
spdy_stream->Cancel();
+ data.RunFor(1);
+ base::MessageLoop::current()->RunUntilIdle();
+
EXPECT_EQ(NULL, spdy_stream.get());
EXPECT_TRUE(delegate.StreamIsClosed());
+
EXPECT_TRUE(session == NULL);
}
@@ -4308,6 +4443,7 @@ TEST_P(SpdySessionTest, SendWindowSizeIncreaseWithDeletedSession) {
// Close the session (since we can't do it from within the delegate
// method, since it's in the stream's loop).
session->CloseSessionOnError(ERR_CONNECTION_CLOSED, "Closing session");
+ base::RunLoop().RunUntilIdle();
EXPECT_TRUE(session == NULL);
EXPECT_FALSE(HasSpdySession(spdy_session_pool_, key_));
« no previous file with comments | « net/spdy/spdy_session_pool_unittest.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698