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