diff options
Diffstat (limited to 'chromium/net/third_party/quiche/src/quiche/quic/qbone/qbone_stream_test.cc')
-rw-r--r-- | chromium/net/third_party/quiche/src/quiche/quic/qbone/qbone_stream_test.cc | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/chromium/net/third_party/quiche/src/quiche/quic/qbone/qbone_stream_test.cc b/chromium/net/third_party/quiche/src/quiche/quic/qbone/qbone_stream_test.cc new file mode 100644 index 00000000000..83924969879 --- /dev/null +++ b/chromium/net/third_party/quiche/src/quiche/quic/qbone/qbone_stream_test.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2019 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 "quiche/quic/qbone/qbone_stream.h" + +#include <utility> + +#include "absl/strings/string_view.h" +#include "quiche/quic/core/crypto/quic_random.h" +#include "quiche/quic/core/quic_session.h" +#include "quiche/quic/core/quic_utils.h" +#include "quiche/quic/platform/api/quic_test.h" +#include "quiche/quic/platform/api/quic_test_loopback.h" +#include "quiche/quic/qbone/qbone_constants.h" +#include "quiche/quic/qbone/qbone_session_base.h" +#include "quiche/quic/test_tools/mock_clock.h" +#include "quiche/quic/test_tools/quic_test_utils.h" +#include "quiche/common/simple_buffer_allocator.h" +#include "quiche/spdy/core/spdy_protocol.h" + +namespace quic { + +namespace { + +using ::testing::_; +using ::testing::StrictMock; + +// MockQuicSession that does not create streams and writes data from +// QuicStream to a string. +class MockQuicSession : public QboneSessionBase { + public: + MockQuicSession(QuicConnection* connection, const QuicConfig& config) + : QboneSessionBase(connection, nullptr /*visitor*/, config, + CurrentSupportedVersions(), nullptr /*writer*/) {} + + ~MockQuicSession() override {} + + // Writes outgoing data from QuicStream to a string. + QuicConsumedData WritevData(QuicStreamId id, size_t write_length, + QuicStreamOffset offset, StreamSendingState state, + TransmissionType type, + EncryptionLevel level) override { + if (!writable_) { + return QuicConsumedData(0, false); + } + + return QuicConsumedData(write_length, state != StreamSendingState::NO_FIN); + } + + QboneReadOnlyStream* CreateIncomingStream(QuicStreamId id) override { + return nullptr; + } + + // Called by QuicStream when they want to close stream. + MOCK_METHOD(void, MaybeSendRstStreamFrame, + (QuicStreamId stream_id, QuicResetStreamError error, + QuicStreamOffset bytes_written), + (override)); + MOCK_METHOD(void, MaybeSendStopSendingFrame, + (QuicStreamId stream_id, QuicResetStreamError error), (override)); + + // Sets whether data is written to buffer, or else if this is write blocked. + void set_writable(bool writable) { writable_ = writable; } + + // Tracks whether the stream is write blocked and its priority. + void RegisterReliableStream(QuicStreamId stream_id) { + // The priority effectively does not matter. Put all streams on the same + // priority. + write_blocked_streams()->RegisterStream( + stream_id, + /*is_static_stream=*/false, + /* precedence= */ spdy::SpdyStreamPrecedence(3)); + } + + // The session take ownership of the stream. + void ActivateReliableStream(std::unique_ptr<QuicStream> stream) { + ActivateStream(std::move(stream)); + } + + std::unique_ptr<QuicCryptoStream> CreateCryptoStream() override { + return std::make_unique<test::MockQuicCryptoStream>(this); + } + + MOCK_METHOD(void, ProcessPacketFromPeer, (absl::string_view), (override)); + MOCK_METHOD(void, ProcessPacketFromNetwork, (absl::string_view), (override)); + + private: + // Whether data is written to write_buffer_. + bool writable_ = true; +}; + +// Packet writer that does nothing. This is required for QuicConnection but +// isn't used for writing data. +class DummyPacketWriter : public QuicPacketWriter { + public: + DummyPacketWriter() {} + + // QuicPacketWriter overrides. + WriteResult WritePacket(const char* buffer, size_t buf_len, + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address, + PerPacketOptions* options) override { + return WriteResult(WRITE_STATUS_ERROR, 0); + } + + bool IsWriteBlocked() const override { return false; }; + + void SetWritable() override {} + + absl::optional<int> MessageTooBigErrorCode() const override { + return absl::nullopt; + } + + QuicByteCount GetMaxPacketSize( + const QuicSocketAddress& peer_address) const override { + return 0; + } + + bool SupportsReleaseTime() const override { return false; } + + bool IsBatchMode() const override { return false; } + + QuicPacketBuffer GetNextWriteLocation( + const QuicIpAddress& self_address, + const QuicSocketAddress& peer_address) override { + return {nullptr, nullptr}; + } + + WriteResult Flush() override { return WriteResult(WRITE_STATUS_OK, 0); } +}; + +class QboneReadOnlyStreamTest : public ::testing::Test, + public QuicConnectionHelperInterface { + public: + void CreateReliableQuicStream() { + // Arbitrary values for QuicConnection. + Perspective perspective = Perspective::IS_SERVER; + bool owns_writer = true; + + alarm_factory_ = std::make_unique<test::MockAlarmFactory>(); + + connection_.reset(new QuicConnection( + test::TestConnectionId(0), QuicSocketAddress(TestLoopback(), 0), + QuicSocketAddress(TestLoopback(), 0), + this /*QuicConnectionHelperInterface*/, alarm_factory_.get(), + new DummyPacketWriter(), owns_writer, perspective, + ParsedVersionOfIndex(CurrentSupportedVersions(), 0))); + clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1)); + session_ = std::make_unique<StrictMock<MockQuicSession>>(connection_.get(), + QuicConfig()); + session_->Initialize(); + stream_ = new QboneReadOnlyStream(kStreamId, session_.get()); + session_->ActivateReliableStream( + std::unique_ptr<QboneReadOnlyStream>(stream_)); + } + + ~QboneReadOnlyStreamTest() override {} + + const QuicClock* GetClock() const override { return &clock_; } + + QuicRandom* GetRandomGenerator() override { + return QuicRandom::GetInstance(); + } + + quiche::QuicheBufferAllocator* GetStreamSendBufferAllocator() override { + return &buffer_allocator_; + } + + protected: + // The QuicSession will take the ownership. + QboneReadOnlyStream* stream_; + std::unique_ptr<StrictMock<MockQuicSession>> session_; + std::unique_ptr<QuicAlarmFactory> alarm_factory_; + std::unique_ptr<QuicConnection> connection_; + // Used to implement the QuicConnectionHelperInterface. + quiche::SimpleBufferAllocator buffer_allocator_; + MockClock clock_; + const QuicStreamId kStreamId = QuicUtils::GetFirstUnidirectionalStreamId( + CurrentSupportedVersions()[0].transport_version, Perspective::IS_CLIENT); +}; + +// Read an entire string. +TEST_F(QboneReadOnlyStreamTest, ReadDataWhole) { + std::string packet = "Stuff"; + CreateReliableQuicStream(); + QuicStreamFrame frame(kStreamId, true, 0, packet); + EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff")); + stream_->OnStreamFrame(frame); +} + +// Test buffering. +TEST_F(QboneReadOnlyStreamTest, ReadBuffered) { + CreateReliableQuicStream(); + std::string packet = "Stuf"; + { + QuicStreamFrame frame(kStreamId, false, 0, packet); + stream_->OnStreamFrame(frame); + } + // We didn't write 5 bytes yet... + + packet = "f"; + EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff")); + { + QuicStreamFrame frame(kStreamId, true, 4, packet); + stream_->OnStreamFrame(frame); + } +} + +TEST_F(QboneReadOnlyStreamTest, ReadOutOfOrder) { + CreateReliableQuicStream(); + std::string packet = "f"; + { + QuicStreamFrame frame(kStreamId, true, 4, packet); + stream_->OnStreamFrame(frame); + } + + packet = "S"; + { + QuicStreamFrame frame(kStreamId, false, 0, packet); + stream_->OnStreamFrame(frame); + } + + packet = "tuf"; + EXPECT_CALL(*session_, ProcessPacketFromPeer("Stuff")); + { + QuicStreamFrame frame(kStreamId, false, 1, packet); + stream_->OnStreamFrame(frame); + } +} + +// Test buffering too many bytes. +TEST_F(QboneReadOnlyStreamTest, ReadBufferedTooLarge) { + CreateReliableQuicStream(); + std::string packet = "0123456789"; + int iterations = (QboneConstants::kMaxQbonePacketBytes / packet.size()) + 2; + EXPECT_CALL(*session_, MaybeSendStopSendingFrame( + kStreamId, QuicResetStreamError::FromInternal( + QUIC_BAD_APPLICATION_PAYLOAD))); + EXPECT_CALL( + *session_, + MaybeSendRstStreamFrame( + kStreamId, + QuicResetStreamError::FromInternal(QUIC_BAD_APPLICATION_PAYLOAD), _)); + for (int i = 0; i < iterations; ++i) { + QuicStreamFrame frame(kStreamId, i == (iterations - 1), i * packet.size(), + packet); + if (!stream_->reading_stopped()) { + stream_->OnStreamFrame(frame); + } + } + // We should have nothing written to the network and the stream + // should have stopped reading. + EXPECT_TRUE(stream_->reading_stopped()); +} + +} // namespace + +} // namespace quic |