1 // Copyright (c) 2019 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.
4
5 #include "net/third_party/quiche/src/quic/qbone/qbone_stream.h"
6
7 #include <utility>
8
9 #include "net/third_party/quiche/src/quic/core/crypto/quic_random.h"
10 #include "net/third_party/quiche/src/quic/core/quic_session.h"
11 #include "net/third_party/quiche/src/quic/core/quic_simple_buffer_allocator.h"
12 #include "net/third_party/quiche/src/quic/core/quic_utils.h"
13 #include "net/third_party/quiche/src/quic/platform/api/quic_test.h"
14 #include "net/third_party/quiche/src/quic/platform/api/quic_test_loopback.h"
15 #include "net/third_party/quiche/src/quic/qbone/qbone_constants.h"
16 #include "net/third_party/quiche/src/quic/qbone/qbone_session_base.h"
17 #include "net/third_party/quiche/src/quic/test_tools/mock_clock.h"
18 #include "net/third_party/quiche/src/quic/test_tools/quic_test_utils.h"
19 #include "net/third_party/quiche/src/common/platform/api/quiche_string_piece.h"
20 #include "net/third_party/quiche/src/spdy/core/spdy_protocol.h"
21
22 namespace quic {
23
24 namespace {
25
26 using ::testing::_;
27 using ::testing::StrictMock;
28
29 // MockQuicSession that does not create streams and writes data from
30 // QuicStream to a string.
31 class MockQuicSession : public QboneSessionBase {
32 public:
MockQuicSession(QuicConnection * connection,const QuicConfig & config)33 MockQuicSession(QuicConnection* connection, const QuicConfig& config)
34 : QboneSessionBase(connection,
35 nullptr /*visitor*/,
36 config,
37 CurrentSupportedVersions(),
38 nullptr /*writer*/) {}
39
~MockQuicSession()40 ~MockQuicSession() override {}
41
42 // Writes outgoing data from QuicStream to a string.
WritevData(QuicStreamId id,size_t write_length,QuicStreamOffset offset,StreamSendingState state,TransmissionType type,quiche::QuicheOptional<EncryptionLevel> level)43 QuicConsumedData WritevData(
44 QuicStreamId id,
45 size_t write_length,
46 QuicStreamOffset offset,
47 StreamSendingState state,
48 TransmissionType type,
49 quiche::QuicheOptional<EncryptionLevel> level) override {
50 if (!writable_) {
51 return QuicConsumedData(0, false);
52 }
53
54 return QuicConsumedData(write_length, state != StreamSendingState::NO_FIN);
55 }
56
CreateIncomingStream(QuicStreamId id)57 QboneReadOnlyStream* CreateIncomingStream(QuicStreamId id) override {
58 return nullptr;
59 }
60
GetCryptoStream() const61 const QuicCryptoStream* GetCryptoStream() const override { return nullptr; }
GetMutableCryptoStream()62 QuicCryptoStream* GetMutableCryptoStream() override { return nullptr; }
63
64 // Called by QuicStream when they want to close stream.
65 MOCK_METHOD3(SendRstStream,
66 void(QuicStreamId, QuicRstStreamErrorCode, QuicStreamOffset));
67
68 // Sets whether data is written to buffer, or else if this is write blocked.
set_writable(bool writable)69 void set_writable(bool writable) { writable_ = writable; }
70
71 // Tracks whether the stream is write blocked and its priority.
RegisterReliableStream(QuicStreamId stream_id)72 void RegisterReliableStream(QuicStreamId stream_id) {
73 // The priority effectively does not matter. Put all streams on the same
74 // priority.
75 write_blocked_streams()->RegisterStream(
76 stream_id,
77 /*is_static_stream=*/false,
78 /* precedence= */ spdy::SpdyStreamPrecedence(3));
79 }
80
81 // The session take ownership of the stream.
ActivateReliableStream(std::unique_ptr<QuicStream> stream)82 void ActivateReliableStream(std::unique_ptr<QuicStream> stream) {
83 ActivateStream(std::move(stream));
84 }
85
CreateCryptoStream()86 std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override {
87 return nullptr;
88 }
89
90 MOCK_METHOD1(ProcessPacketFromPeer, void(quiche::QuicheStringPiece));
91 MOCK_METHOD1(ProcessPacketFromNetwork, void(quiche::QuicheStringPiece));
92
93 private:
94 // Whether data is written to write_buffer_.
95 bool writable_ = true;
96 };
97
98 // Packet writer that does nothing. This is required for QuicConnection but
99 // isn't used for writing data.
100 class DummyPacketWriter : public QuicPacketWriter {
101 public:
DummyPacketWriter()102 DummyPacketWriter() {}
103
104 // QuicPacketWriter overrides.
WritePacket(const char * buffer,size_t buf_len,const QuicIpAddress & self_address,const QuicSocketAddress & peer_address,PerPacketOptions * options)105 WriteResult WritePacket(const char* buffer,
106 size_t buf_len,
107 const QuicIpAddress& self_address,
108 const QuicSocketAddress& peer_address,
109 PerPacketOptions* options) override {
110 return WriteResult(WRITE_STATUS_ERROR, 0);
111 }
112
IsWriteBlocked() const113 bool IsWriteBlocked() const override { return false; };
114
SetWritable()115 void SetWritable() override {}
116
GetMaxPacketSize(const QuicSocketAddress & peer_address) const117 QuicByteCount GetMaxPacketSize(
118 const QuicSocketAddress& peer_address) const override {
119 return 0;
120 }
121
SupportsReleaseTime() const122 bool SupportsReleaseTime() const override { return false; }
123
IsBatchMode() const124 bool IsBatchMode() const override { return false; }
125
GetNextWriteLocation(const QuicIpAddress & self_address,const QuicSocketAddress & peer_address)126 char* GetNextWriteLocation(const QuicIpAddress& self_address,
127 const QuicSocketAddress& peer_address) override {
128 return nullptr;
129 }
130
Flush()131 WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); }
132 };
133
134 class QboneReadOnlyStreamTest : public ::testing::Test,
135 public QuicConnectionHelperInterface {
136 public:
CreateReliableQuicStream()137 void CreateReliableQuicStream() {
138 // Arbitrary values for QuicConnection.
139 Perspective perspective = Perspective::IS_SERVER;
140 bool owns_writer = true;
141
142 alarm_factory_ = std::make_unique<test::MockAlarmFactory>();
143
144 connection_.reset(new QuicConnection(
145 test::TestConnectionId(0), QuicSocketAddress(TestLoopback(), 0),
146 this /*QuicConnectionHelperInterface*/, alarm_factory_.get(),
147 new DummyPacketWriter(), owns_writer, perspective,
148 ParsedVersionOfIndex(CurrentSupportedVersions(), 0)));
149 clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
150 session_ = std::make_unique<StrictMock<MockQuicSession>>(connection_.get(),
151 QuicConfig());
152 stream_ = new QboneReadOnlyStream(kStreamId, session_.get());
153 session_->ActivateReliableStream(
154 std::unique_ptr<QboneReadOnlyStream>(stream_));
155 }
156
~QboneReadOnlyStreamTest()157 ~QboneReadOnlyStreamTest() override {}
158
GetClock() const159 const QuicClock* GetClock() const override { return &clock_; }
160
GetRandomGenerator()161 QuicRandom* GetRandomGenerator() override {
162 return QuicRandom::GetInstance();
163 }
164
GetStreamSendBufferAllocator()165 QuicBufferAllocator* GetStreamSendBufferAllocator() override {
166 return &buffer_allocator_;
167 }
168
169 protected:
170 // The QuicSession will take the ownership.
171 QboneReadOnlyStream* stream_;
172 std::unique_ptr<StrictMock<MockQuicSession>> session_;
173 std::unique_ptr<QuicAlarmFactory> alarm_factory_;
174 std::unique_ptr<QuicConnection> connection_;
175 // Used to implement the QuicConnectionHelperInterface.
176 SimpleBufferAllocator buffer_allocator_;
177 MockClock clock_;
178 const QuicStreamId kStreamId = QuicUtils::GetFirstUnidirectionalStreamId(
179 CurrentSupportedVersions()[0].transport_version,
180 Perspective::IS_CLIENT);
181 };
182
183 // Read an entire string.
TEST_F(QboneReadOnlyStreamTest,ReadDataWhole)184 TEST_F(QboneReadOnlyStreamTest, ReadDataWhole) {
185 std::string packet = "Stuff";
186 CreateReliableQuicStream();
187 QuicStreamFrame frame(kStreamId, true, 0, packet);
188 EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff"));
189 stream_->OnStreamFrame(frame);
190 }
191
192 // Test buffering.
TEST_F(QboneReadOnlyStreamTest,ReadBuffered)193 TEST_F(QboneReadOnlyStreamTest, ReadBuffered) {
194 CreateReliableQuicStream();
195 std::string packet = "Stuf";
196 {
197 QuicStreamFrame frame(kStreamId, false, 0, packet);
198 stream_->OnStreamFrame(frame);
199 }
200 // We didn't write 5 bytes yet...
201
202 packet = "f";
203 EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff"));
204 {
205 QuicStreamFrame frame(kStreamId, true, 4, packet);
206 stream_->OnStreamFrame(frame);
207 }
208 }
209
TEST_F(QboneReadOnlyStreamTest,ReadOutOfOrder)210 TEST_F(QboneReadOnlyStreamTest, ReadOutOfOrder) {
211 CreateReliableQuicStream();
212 std::string packet = "f";
213 {
214 QuicStreamFrame frame(kStreamId, true, 4, packet);
215 stream_->OnStreamFrame(frame);
216 }
217
218 packet = "S";
219 {
220 QuicStreamFrame frame(kStreamId, false, 0, packet);
221 stream_->OnStreamFrame(frame);
222 }
223
224 packet = "tuf";
225 EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff"));
226 {
227 QuicStreamFrame frame(kStreamId, false, 1, packet);
228 stream_->OnStreamFrame(frame);
229 }
230 }
231
232 // Test buffering too many bytes.
TEST_F(QboneReadOnlyStreamTest,ReadBufferedTooLarge)233 TEST_F(QboneReadOnlyStreamTest, ReadBufferedTooLarge) {
234 CreateReliableQuicStream();
235 std::string packet = "0123456789";
236 int iterations = (QboneConstants::kMaxQbonePacketBytes / packet.size()) + 2;
237 EXPECT_CALL(*session_,
238 SendRstStream(kStreamId, QUIC_BAD_APPLICATION_PAYLOAD, _));
239 for (int i = 0; i < iterations; ++i) {
240 QuicStreamFrame frame(kStreamId, i == (iterations - 1), i * packet.size(),
241 packet);
242 if (!stream_->reading_stopped()) {
243 stream_->OnStreamFrame(frame);
244 }
245 }
246 // We should have nothing written to the network and the stream
247 // should have stopped reading.
248 EXPECT_TRUE(stream_->reading_stopped());
249 }
250
251 } // namespace
252
253 } // namespace quic
254