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