Index: net/spdy/spdy_session_spdy3_unittest.cc |
=================================================================== |
--- net/spdy/spdy_session_spdy3_unittest.cc (revision 180447) |
+++ net/spdy/spdy_session_spdy3_unittest.cc (working copy) |
@@ -4,11 +4,16 @@ |
#include "net/spdy/spdy_session.h" |
+#include "base/memory/scoped_ptr.h" |
+#include "base/memory/scoped_vector.h" |
+#include "base/string_util.h" |
#include "net/base/cert_test_util.h" |
#include "net/base/host_cache.h" |
+#include "net/base/io_buffer.h" |
#include "net/base/ip_endpoint.h" |
#include "net/base/net_log_unittest.h" |
#include "net/base/test_data_directory.h" |
+#include "net/base/test_data_stream.h" |
#include "net/spdy/spdy_io_buffer.h" |
#include "net/spdy/spdy_session_pool.h" |
#include "net/spdy/spdy_stream.h" |
@@ -168,6 +173,35 @@ |
HostPortProxyPair pair_; |
}; |
+class SpdySessionTaskObserver : public MessageLoop::TaskObserver { |
+ public: |
+ explicit SpdySessionTaskObserver(const std::string& function_name) |
+ : function_name_(function_name), |
+ posted_(false) { |
+ MessageLoop::current()->AddTaskObserver(this); |
+ } |
+ |
+ virtual ~SpdySessionTaskObserver() { |
+ MessageLoop::current()->RemoveTaskObserver(this); |
+ } |
+ |
+ virtual void WillProcessTask(const base::PendingTask& pending_task) OVERRIDE { |
+ } |
+ |
+ virtual void DidProcessTask(const base::PendingTask& pending_task) OVERRIDE { |
+ if (!posted_) { |
+ posted_ = EndsWith(pending_task.posted_from.function_name(), |
+ function_name_, true); |
+ } |
+ } |
+ |
+ bool posted() const { return posted_; } |
+ |
+ private: |
+ std::string function_name_; |
+ bool posted_; |
+}; |
+ |
// Test the SpdyIOBuffer class. |
TEST_F(SpdySessionSpdy3Test, SpdyIOBuffer) { |
std::priority_queue<SpdyIOBuffer> queue_; |
@@ -1748,4 +1782,167 @@ |
spdy_stream2 = NULL; |
} |
+TEST_F(SpdySessionSpdy3Test, SyncRead) { |
+ MockConnect connect_data(SYNCHRONOUS, OK); |
+ BufferedSpdyFramer framer(3, false); |
+ |
+ scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, MEDIUM)); |
+ MockWrite writes[] = { |
+ CreateMockWrite(*req1, 0), |
+ }; |
+ |
+ const int kPayloadSize = 1600; |
+ TestDataStream test_stream; |
+ scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize)); |
+ char* payload_data = payload->data(); |
+ test_stream.GetBytes(payload_data, kPayloadSize); |
+ |
+ scoped_ptr<SpdyFrame> data_frame1( |
+ framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE)); |
+ scoped_ptr<SpdyFrame> data_frame( |
+ framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_FIN)); |
+ |
+ scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); |
+ |
+ size_t num_reads = 6; |
+ scoped_array<MockRead> reads(new MockRead[num_reads]); |
+ size_t i = 0; |
+ reads[i] = CreateMockRead(*resp1, 1); |
+ i = 1; |
+ reads[i] = CreateMockRead(*data_frame1, 2); |
+ for (i = 2; i < num_reads - 2; ++i) |
+ reads[i] = CreateMockRead(*data_frame1, i + 1, SYNCHRONOUS); |
+ reads[i] = CreateMockRead(*data_frame, i + 1, SYNCHRONOUS); |
+ ++i; |
+ reads[i] = MockRead(ASYNC, 0, i + 1); // EOF |
+ |
+ DeterministicSocketData data(reads.get(), num_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)[":path"] = url1.path(); |
+ (*headers)[":version"] = "HTTP/1.1"; |
+ |
+ spdy_stream1->set_spdy_headers(headers.Pass()); |
+ EXPECT_TRUE(spdy_stream1->HasUrl()); |
+ spdy_stream1->SendRequest(false); |
+ |
+ SpdySessionTaskObserver observer("DoRead"); |
+ |
+ // Run until 1st read. |
+ EXPECT_EQ(0u, spdy_stream1->stream_id()); |
+ data.RunFor(2); |
+ EXPECT_EQ(1u, spdy_stream1->stream_id()); |
+ EXPECT_FALSE(observer.posted()); |
+ |
+ // Do 4 reads. |
+ data.RunFor(4); |
+ EXPECT_FALSE(observer.posted()); |
+ EXPECT_TRUE(data.at_write_eof()); |
+ EXPECT_TRUE(data.at_read_eof()); |
+} |
+ |
+TEST_F(SpdySessionSpdy3Test, ASyncRead) { |
+ MockConnect connect_data(SYNCHRONOUS, OK); |
+ BufferedSpdyFramer framer(3, false); |
+ |
+ scoped_ptr<SpdyFrame> req1(ConstructSpdyGet(NULL, 0, false, 1, MEDIUM)); |
+ MockWrite writes[] = { |
+ CreateMockWrite(*req1, 0), |
+ }; |
+ |
+ // Build buffers of size 8k. |
+ ASSERT_EQ(32 * 1024, kMaxReadBytes); |
+ const int kPayloadSize = (kMaxReadBytes / 4) - SpdyDataFrame::size(); |
+ TestDataStream test_stream; |
+ scoped_refptr<net::IOBuffer> payload(new net::IOBuffer(kPayloadSize)); |
+ char* payload_data = payload->data(); |
+ test_stream.GetBytes(payload_data, kPayloadSize); |
+ |
+ scoped_ptr<SpdyFrame> data_frame1( |
+ framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_NONE)); |
+ scoped_ptr<SpdyFrame> data_frame( |
+ framer.CreateDataFrame(1, payload_data, kPayloadSize, DATA_FLAG_FIN)); |
+ |
+ scoped_ptr<SpdyFrame> resp1(ConstructSpdyGetSynReply(NULL, 0, 1)); |
+ |
+ // Send twice as many bytes as kMaxReadBytes. |
+ size_t num_reads = 2 + (2 * kMaxReadBytes / kPayloadSize); |
+ scoped_array<MockRead> reads(new MockRead[num_reads]); |
+ size_t i = 0; |
+ reads[i] = CreateMockRead(*resp1, 1); |
+ i = 1; |
+ reads[i] = CreateMockRead(*data_frame1, i + 1); |
+ for (i = 2; i < num_reads - 2; ++i) |
+ reads[i] = CreateMockRead(*data_frame1, i + 1, SYNCHRONOUS); |
+ reads[i] = CreateMockRead(*data_frame, i + 1, SYNCHRONOUS); |
+ ++i; |
+ reads[i] = MockRead(ASYNC, 0, i + 1); // EOF |
+ |
+ DeterministicSocketData data(reads.get(), num_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)[":path"] = url1.path(); |
+ (*headers)[":version"] = "HTTP/1.1"; |
+ |
+ spdy_stream1->set_spdy_headers(headers.Pass()); |
+ EXPECT_TRUE(spdy_stream1->HasUrl()); |
+ spdy_stream1->SendRequest(false); |
+ |
+ SpdySessionTaskObserver observer("DoRead"); |
+ |
+ // Run until 1st read. |
+ EXPECT_EQ(0u, spdy_stream1->stream_id()); |
+ data.RunFor(2); |
+ EXPECT_EQ(1u, spdy_stream1->stream_id()); |
+ EXPECT_FALSE(observer.posted()); |
+ |
+ // Do 8 reads. |
+ data.RunFor(8); |
+ EXPECT_TRUE(observer.posted()); |
+ EXPECT_TRUE(data.at_write_eof()); |
+ EXPECT_TRUE(data.at_read_eof()); |
+} |
+ |
} // namespace net |