1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/quic/quic_reliable_client_stream.h"
7 #include "net/base/net_errors.h"
8 #include "net/base/test_completion_callback.h"
9 #include "net/quic/quic_chromium_client_session.h"
10 #include "net/quic/quic_utils.h"
11 #include "net/quic/spdy_utils.h"
12 #include "net/quic/test_tools/quic_test_utils.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gmock_mutant.h"
16 using testing::AnyNumber
;
17 using testing::CreateFunctor
;
18 using testing::Invoke
;
19 using testing::Return
;
27 const QuicStreamId kTestStreamId
= 5u;
29 class MockDelegate
: public QuicReliableClientStream::Delegate
{
33 MOCK_METHOD0(OnSendData
, int());
34 MOCK_METHOD2(OnSendDataComplete
, int(int, bool*));
35 MOCK_METHOD1(OnHeadersAvailable
, void(const SpdyHeaderBlock
&));
36 MOCK_METHOD2(OnDataReceived
, int(const char*, int));
37 MOCK_METHOD0(OnDataAvailable
, void());
38 MOCK_METHOD1(OnClose
, void(QuicErrorCode
));
39 MOCK_METHOD1(OnError
, void(int));
40 MOCK_METHOD0(HasSendHeadersComplete
, bool());
43 DISALLOW_COPY_AND_ASSIGN(MockDelegate
);
46 class QuicReliableClientStreamTest
47 : public ::testing::TestWithParam
<QuicVersion
> {
49 QuicReliableClientStreamTest()
50 : session_(new MockConnection(Perspective::IS_CLIENT
,
51 SupportedVersions(GetParam()))) {
53 new QuicReliableClientStream(kTestStreamId
, &session_
, BoundNetLog());
54 session_
.ActivateStream(stream_
);
55 stream_
->SetDelegate(&delegate_
);
58 void InitializeHeaders() {
59 headers_
[":host"] = "www.google.com";
60 headers_
[":path"] = "/index.hml";
61 headers_
[":scheme"] = "https";
63 "__utma=208381060.1228362404.1372200928.1372200928.1372200928.1; "
65 "GX=DQAAAOEAAACWJYdewdE9rIrW6qw3PtVi2-d729qaa-74KqOsM1NVQblK4VhX"
66 "hoALMsy6HOdDad2Sz0flUByv7etmo3mLMidGrBoljqO9hSVA40SLqpG_iuKKSHX"
67 "RW3Np4bq0F0SDGDNsW0DSmTS9ufMRrlpARJDS7qAI6M3bghqJp4eABKZiRqebHT"
68 "pMU-RXvTI5D5oCF1vYxYofH_l1Kviuiy3oQ1kS1enqWgbhJ2t61_SNdv-1XJIS0"
69 "O3YeHLmVCs62O6zp89QwakfAWK9d3IDQvVSJzCQsvxvNIvaZFa567MawWlXg0Rh"
70 "1zFMi5vzcns38-8_Sns; "
71 "GA=v*2%2Fmem*57968640*47239936%2Fmem*57968640*47114716%2Fno-nm-"
72 "yj*15%2Fno-cc-yj*5%2Fpc-ch*133685%2Fpc-s-cr*133947%2Fpc-s-t*1339"
73 "47%2Fno-nm-yj*4%2Fno-cc-yj*1%2Fceft-as*1%2Fceft-nqas*0%2Fad-ra-c"
74 "v_p%2Fad-nr-cv_p-f*1%2Fad-v-cv_p*859%2Fad-ns-cv_p-f*1%2Ffn-v-ad%"
75 "2Fpc-t*250%2Fpc-cm*461%2Fpc-s-cr*722%2Fpc-s-t*722%2Fau_p*4"
76 "SICAID=AJKiYcHdKgxum7KMXG0ei2t1-W4OD1uW-ecNsCqC0wDuAXiDGIcT_HA2o1"
77 "3Rs1UKCuBAF9g8rWNOFbxt8PSNSHFuIhOo2t6bJAVpCsMU5Laa6lewuTMYI8MzdQP"
78 "ARHKyW-koxuhMZHUnGBJAM1gJODe0cATO_KGoX4pbbFxxJ5IicRxOrWK_5rU3cdy6"
79 "edlR9FsEdH6iujMcHkbE5l18ehJDwTWmBKBzVD87naobhMMrF6VvnDGxQVGp9Ir_b"
80 "Rgj3RWUoPumQVCxtSOBdX0GlJOEcDTNCzQIm9BSfetog_eP_TfYubKudt5eMsXmN6"
81 "QnyXHeGeK2UINUzJ-D30AFcpqYgH9_1BvYSpi7fc7_ydBU8TaD8ZRxvtnzXqj0RfG"
82 "tuHghmv3aD-uzSYJ75XDdzKdizZ86IG6Fbn1XFhYZM-fbHhm3mVEXnyRW4ZuNOLFk"
83 "Fas6LMcVC6Q8QLlHYbXBpdNFuGbuZGUnav5C-2I_-46lL0NGg3GewxGKGHvHEfoyn"
84 "EFFlEYHsBQ98rXImL8ySDycdLEFvBPdtctPmWCfTxwmoSMLHU2SCVDhbqMWU5b0yr"
85 "JBCScs_ejbKaqBDoB7ZGxTvqlrB__2ZmnHHjCr8RgMRtKNtIeuZAo ";
88 void ReadData(StringPiece expected_data
) {
89 scoped_refptr
<IOBuffer
> buffer(new IOBuffer(expected_data
.length() + 1));
90 EXPECT_EQ(static_cast<int>(expected_data
.length()),
91 stream_
->Read(buffer
.get(), expected_data
.length() + 1));
92 EXPECT_EQ(expected_data
,
93 StringPiece(buffer
->data(), expected_data
.length()));
96 testing::StrictMock
<MockDelegate
> delegate_
;
97 MockQuicSpdySession session_
;
98 QuicReliableClientStream
* stream_
;
99 QuicCryptoClientConfig crypto_config_
;
100 SpdyHeaderBlock headers_
;
103 INSTANTIATE_TEST_CASE_P(Version
, QuicReliableClientStreamTest
,
104 ::testing::ValuesIn(QuicSupportedVersions()));
106 TEST_P(QuicReliableClientStreamTest
, OnFinRead
) {
108 std::string uncompressed_headers
=
109 SpdyUtils::SerializeUncompressedHeaders(headers_
, GetParam());
110 QuicStreamOffset offset
= 0;
111 stream_
->OnStreamHeaders(uncompressed_headers
);
112 stream_
->OnStreamHeadersComplete(false, uncompressed_headers
.length());
114 EXPECT_CALL(delegate_
, OnHeadersAvailable(headers_
));
115 base::MessageLoop::current()->RunUntilIdle();
116 EXPECT_TRUE(stream_
->decompressed_headers().empty());
118 QuicStreamFrame
frame2(kTestStreamId
, true, offset
, StringPiece());
119 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
120 stream_
->OnStreamFrame(frame2
);
123 TEST_P(QuicReliableClientStreamTest
, OnDataAvailableBeforeHeaders
) {
124 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
126 EXPECT_CALL(delegate_
, OnDataAvailable()).Times(0);
127 stream_
->OnDataAvailable();
130 TEST_P(QuicReliableClientStreamTest
, OnDataAvailable
) {
132 std::string uncompressed_headers
=
133 SpdyUtils::SerializeUncompressedHeaders(headers_
, GetParam());
134 stream_
->OnStreamHeaders(uncompressed_headers
);
135 stream_
->OnStreamHeadersComplete(false, uncompressed_headers
.length());
137 EXPECT_CALL(delegate_
, OnHeadersAvailable(headers_
));
138 base::MessageLoop::current()->RunUntilIdle();
139 EXPECT_TRUE(stream_
->decompressed_headers().empty());
141 const char data
[] = "hello world!";
142 stream_
->OnStreamFrame(QuicStreamFrame(kTestStreamId
, /*fin=*/false,
143 /*offset=*/0, data
));
145 EXPECT_CALL(delegate_
, OnDataAvailable())
146 .WillOnce(testing::Invoke(
147 CreateFunctor(this, &QuicReliableClientStreamTest::ReadData
,
148 StringPiece(data
, arraysize(data
) - 1))));
149 base::MessageLoop::current()->RunUntilIdle();
151 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
154 TEST_P(QuicReliableClientStreamTest
, ProcessHeadersWithError
) {
155 std::string bad_headers
= "...";
156 stream_
->OnStreamHeaders(StringPiece(bad_headers
));
157 stream_
->OnStreamHeadersComplete(false, bad_headers
.length());
159 EXPECT_CALL(session_
,
160 SendRstStream(kTestStreamId
, QUIC_BAD_APPLICATION_PAYLOAD
, 0));
161 base::MessageLoop::current()->RunUntilIdle();
163 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
166 TEST_P(QuicReliableClientStreamTest
, OnDataAvailableWithError
) {
168 std::string uncompressed_headers
=
169 SpdyUtils::SerializeUncompressedHeaders(headers_
, GetParam());
170 stream_
->OnStreamHeaders(uncompressed_headers
);
171 stream_
->OnStreamHeadersComplete(false, uncompressed_headers
.length());
173 EXPECT_CALL(delegate_
, OnHeadersAvailable(headers_
));
174 base::MessageLoop::current()->RunUntilIdle();
175 EXPECT_TRUE(stream_
->decompressed_headers().empty());
177 const char data
[] = "hello world!";
178 stream_
->OnStreamFrame(QuicStreamFrame(kTestStreamId
, /*fin=*/false,
179 /*offset=*/0, data
));
180 EXPECT_CALL(delegate_
, OnDataAvailable())
181 .WillOnce(testing::Invoke(CreateFunctor(
182 stream_
, &QuicReliableClientStream::Reset
, QUIC_STREAM_CANCELLED
)));
183 base::MessageLoop::current()->RunUntilIdle();
185 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
188 TEST_P(QuicReliableClientStreamTest
, OnError
) {
189 EXPECT_CALL(delegate_
, OnError(ERR_INTERNET_DISCONNECTED
));
191 stream_
->OnError(ERR_INTERNET_DISCONNECTED
);
192 EXPECT_FALSE(stream_
->GetDelegate());
195 TEST_P(QuicReliableClientStreamTest
, WriteStreamData
) {
196 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
198 const char kData1
[] = "hello world";
199 const size_t kDataLen
= arraysize(kData1
);
202 EXPECT_CALL(session_
, WritevData(stream_
->id(), _
, _
, _
, _
, _
)).WillOnce(
203 Return(QuicConsumedData(kDataLen
, true)));
204 TestCompletionCallback callback
;
205 EXPECT_EQ(OK
, stream_
->WriteStreamData(base::StringPiece(kData1
, kDataLen
),
206 true, callback
.callback()));
209 TEST_P(QuicReliableClientStreamTest
, WriteStreamDataAsync
) {
210 EXPECT_CALL(delegate_
, HasSendHeadersComplete()).Times(AnyNumber());
211 EXPECT_CALL(delegate_
, OnClose(QUIC_NO_ERROR
));
213 const char kData1
[] = "hello world";
214 const size_t kDataLen
= arraysize(kData1
);
217 EXPECT_CALL(session_
, WritevData(stream_
->id(), _
, _
, _
, _
, _
)).WillOnce(
218 Return(QuicConsumedData(0, false)));
219 TestCompletionCallback callback
;
220 EXPECT_EQ(ERR_IO_PENDING
,
221 stream_
->WriteStreamData(base::StringPiece(kData1
, kDataLen
),
222 true, callback
.callback()));
223 ASSERT_FALSE(callback
.have_result());
226 EXPECT_CALL(session_
, WritevData(stream_
->id(), _
, _
, _
, _
, _
)).WillOnce(
227 Return(QuicConsumedData(kDataLen
, true)));
228 stream_
->OnCanWrite();
229 ASSERT_TRUE(callback
.have_result());
230 EXPECT_EQ(OK
, callback
.WaitForResult());