Chromium Code Reviews| Index: net/http/bidirectional_stream_unittest.cc |
| diff --git a/net/http/bidirectional_stream_unittest.cc b/net/http/bidirectional_stream_unittest.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ffc57e280423bf64cb130ca9a5f8e203ead7eef0 |
| --- /dev/null |
| +++ b/net/http/bidirectional_stream_unittest.cc |
| @@ -0,0 +1,221 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "net/http/bidirectional_stream.h" |
| + |
| +#include <string> |
| + |
| +#include "base/memory/scoped_ptr.h" |
| +#include "base/run_loop.h" |
| +#include "base/stl_util.h" |
| +#include "base/strings/string_piece.h" |
| +#include "net/http/http_request_info.h" |
| +#include "net/http/http_response_headers.h" |
| +#include "net/http/http_response_info.h" |
| +#include "net/socket/socket_test_util.h" |
| +#include "net/spdy/spdy_read_queue.h" |
| +#include "net/spdy/spdy_session.h" |
| +#include "net/spdy/spdy_test_util_common.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| + |
| +namespace net { |
| + |
| +namespace { |
| + |
| +const char kBodyData[] = "Body data"; |
| +const size_t kBodyDataSize = arraysize(kBodyData); |
| +const base::StringPiece kBodyDataStringPiece(kBodyData, kBodyDataSize); |
| + |
| +class TestBidirectionalStreamDelegate : public BidirectionalStream::Delegate { |
| + public: |
| + TestBidirectionalStreamDelegate(base::WeakPtr<SpdySession> session) |
| + : loop_(new base::RunLoop), stream_(new BidirectionalStream(session)) {} |
| + |
| + ~TestBidirectionalStreamDelegate() override {} |
| + |
| + void OnFailed(int rv) override { loop_->Quit(); } |
| + |
| + void OnRequestHeadersSent() override {} |
| + |
| + void OnHeaders(const SpdyHeaderBlock& response_headers) override { |
| + response_headers_ = response_headers; |
| + } |
| + |
| + void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override { |
| + received_data_queue_.Enqueue(buffer.Pass()); |
| + } |
| + |
| + void OnDataSent() override {} |
| + |
| + void OnTrailers(const SpdyHeaderBlock& trailers) override { |
| + trailers_ = trailers; |
| + } |
| + |
| + void OnClose(int status) override { loop_->Quit(); } |
| + |
| + void Start(HttpRequestInfo* request) { |
| + stream_->Start(request, this); |
| + loop_->Run(); |
| + } |
| + |
| + void SendData(IOBuffer* data, int length, bool end_of_stream) { |
| + stream_->SendData(data, length, end_of_stream); |
| + } |
| + |
| + std::string TakeReceivedData() { |
| + size_t len = received_data_queue_.GetTotalSize(); |
| + std::string received_data(len, '\0'); |
| + if (len > 0) { |
| + EXPECT_EQ(len, received_data_queue_.Dequeue( |
| + string_as_array(&received_data), len)); |
| + } |
| + return received_data; |
| + } |
| + |
| + SpdyHeaderBlock response_headers_; |
| + SpdyHeaderBlock trailers_; |
| + |
| + private: |
| + scoped_ptr<base::RunLoop> loop_; |
| + scoped_ptr<BidirectionalStream> stream_; |
| + SpdyReadQueue received_data_queue_; |
| +}; |
| + |
| +// A delegate that sends data after request headers are sent. |
| +class SendDataDelegate : public TestBidirectionalStreamDelegate { |
| + public: |
| + SendDataDelegate(base::WeakPtr<SpdySession> session, base::StringPiece data) |
| + : TestBidirectionalStreamDelegate(session), data_(data) {} |
| + |
| + ~SendDataDelegate() override {} |
| + |
| + void OnRequestHeadersSent() override { |
| + TestBidirectionalStreamDelegate::OnRequestHeadersSent(); |
| + if (data_.data()) { |
| + scoped_refptr<StringIOBuffer> buf(new StringIOBuffer(data_.as_string())); |
| + SendData(buf.get(), buf->size(), NO_MORE_DATA_TO_SEND); |
| + } |
| + } |
| + |
| + private: |
| + base::StringPiece data_; |
| +}; |
| + |
| +} // namespace |
| + |
| +class BidirectionalStreamTest : public testing::Test { |
| + public: |
| + BidirectionalStreamTest() |
| + : spdy_util_(kProtoHTTP2), session_deps_(kProtoHTTP2) {} |
| + |
| + protected: |
| + void TearDown() override { |
| + EXPECT_TRUE(sequenced_data_->AllReadDataConsumed()); |
| + EXPECT_TRUE(sequenced_data_->AllWriteDataConsumed()); |
| + } |
| + |
| + // Initializes the session using SequencedSocketData. |
| + void InitSession(MockRead* reads, |
| + size_t reads_count, |
| + MockWrite* writes, |
| + size_t writes_count, |
| + const SpdySessionKey& key) { |
| + sequenced_data_.reset( |
| + new SequencedSocketData(reads, reads_count, writes, writes_count)); |
| + session_deps_.socket_factory->AddSocketDataProvider(sequenced_data_.get()); |
| + http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_); |
| + session_ = CreateInsecureSpdySession(http_session_, key, BoundNetLog()); |
| + } |
| + |
| + SpdyTestUtil spdy_util_; |
| + SpdySessionDependencies session_deps_; |
| + scoped_ptr<SequencedSocketData> sequenced_data_; |
| + scoped_refptr<HttpNetworkSession> http_session_; |
| + base::WeakPtr<SpdySession> session_; |
| + scoped_ptr<TestBidirectionalStreamDelegate> delegate_; |
| +}; |
| + |
| +TEST_F(BidirectionalStreamTest, SendGetRequest) { |
| + scoped_ptr<SpdyFrame> req( |
| + spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true)); |
| + MockWrite writes[] = { |
| + CreateMockWrite(*req.get(), 0), |
| + }; |
| + |
| + scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyGetSynReply(NULL, 0, 1)); |
|
Bence
2015/10/01 05:29:28
Consider passing some extra_headers to ConstructSp
xunjieli
2015/10/01 18:41:16
Done. Good idea. Thanks!
|
| + |
| + scoped_ptr<SpdyFrame> body(spdy_util_.ConstructSpdyBodyFrame(1, false)); |
| + |
| + const char* const kExtraHeaders[] = {"foo", "bar"}; |
| + scoped_ptr<SpdyFrame> trailers( |
| + spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true)); |
| + |
| + MockRead reads[] = { |
| + CreateMockRead(*resp, 1), CreateMockRead(*body, 2), |
| + CreateMockRead(*trailers, 3), MockRead(SYNCHRONOUS, 0, 4), |
| + }; |
| + |
| + HostPortPair host_port_pair("www.example.org", 80); |
| + SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
| + PRIVACY_MODE_DISABLED); |
| + InitSession(reads, arraysize(reads), writes, arraysize(writes), key); |
| + |
| + HttpRequestInfo request; |
| + request.method = "GET"; |
| + request.url = GURL("http://www.example.org/"); |
| + |
| + delegate_.reset(new TestBidirectionalStreamDelegate(session_)); |
| + delegate_->Start(&request); |
| + base::StringPiece status = delegate_->response_headers_[":status"]; |
| + EXPECT_EQ("200", status); |
| + EXPECT_EQ(kUploadData, delegate_->TakeReceivedData()); |
| + base::StringPiece trailer = delegate_->trailers_["foo"]; |
| + EXPECT_EQ("bar", trailer); |
| +} |
| + |
| +TEST_F(BidirectionalStreamTest, SendPostRequest) { |
| + BufferedSpdyFramer framer(spdy_util_.spdy_version(), false); |
| + |
| + scoped_ptr<SpdyFrame> req(spdy_util_.ConstructChunkedSpdyPost(NULL, 0)); |
| + scoped_ptr<SpdyFrame> body( |
| + framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_FIN)); |
| + MockWrite writes[] = { |
| + CreateMockWrite(*req, 0), // request |
| + CreateMockWrite(*body, 1), // POST upload frame |
| + }; |
| + scoped_ptr<SpdyFrame> resp(spdy_util_.ConstructSpdyPostSynReply(NULL, 0)); |
|
Bence
2015/10/01 05:29:28
Same thing here.
xunjieli
2015/10/01 18:41:16
Done.
|
| + |
| + scoped_ptr<SpdyFrame> resp_data( |
| + framer.CreateDataFrame(1, kBodyData, kBodyDataSize, DATA_FLAG_NONE)); |
| + |
| + const char* const kExtraHeaders[] = {"foo", "bar"}; |
| + scoped_ptr<SpdyFrame> trailers( |
| + spdy_util_.ConstructSpdyHeaderFrame(1, kExtraHeaders, 1, true)); |
| + |
| + MockRead reads[] = { |
| + CreateMockRead(*resp, 2), CreateMockRead(*resp_data, 3), |
| + CreateMockRead(*trailers, 4), MockRead(SYNCHRONOUS, 0, 5) // EOF |
| + }; |
| + |
| + HostPortPair host_port_pair("www.example.org", 80); |
| + SpdySessionKey key(host_port_pair, ProxyServer::Direct(), |
| + PRIVACY_MODE_DISABLED); |
| + InitSession(reads, arraysize(reads), writes, arraysize(writes), key); |
| + |
| + HttpRequestInfo request; |
| + request.method = "POST"; |
| + request.url = GURL("http://www.example.org/"); |
| + |
| + delegate_.reset(new SendDataDelegate(session_, kBodyDataStringPiece)); |
| + delegate_->Start(&request); |
| + |
| + base::StringPiece header = delegate_->response_headers_[":status"]; |
| + EXPECT_EQ("200", header); |
| + EXPECT_EQ(std::string(kBodyData, kBodyDataSize), |
| + delegate_->TakeReceivedData()); |
| + base::StringPiece trailer = delegate_->trailers_["foo"]; |
| + EXPECT_EQ("bar", trailer); |
| +} |
| + |
| +} // namespace net |