| Index: webrtc/p2p/quic/reliablequicstream_unittest.cc
|
| diff --git a/webrtc/p2p/quic/reliablequicstream_unittest.cc b/webrtc/p2p/quic/reliablequicstream_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..f9fb5cd7cd63b7cd7eea04c4c2b9e1c8d59ee5a2
|
| --- /dev/null
|
| +++ b/webrtc/p2p/quic/reliablequicstream_unittest.cc
|
| @@ -0,0 +1,255 @@
|
| +/*
|
| + * Copyright 2016 The WebRTC Project Authors. All rights reserved.
|
| + *
|
| + * Use of this source code is governed by a BSD-style license
|
| + * that can be found in the LICENSE file in the root of the source
|
| + * tree. An additional intellectual property rights grant can be found
|
| + * in the file PATENTS. All contributing project authors may
|
| + * be found in the AUTHORS file in the root of the source tree.
|
| + */
|
| +
|
| +#include "webrtc/p2p/quic/reliablequicstream.h"
|
| +
|
| +#include <string>
|
| +
|
| +#include "net/base/ip_address_number.h"
|
| +#include "net/quic/quic_connection.h"
|
| +#include "net/quic/quic_protocol.h"
|
| +#include "net/quic/quic_session.h"
|
| +#include "webrtc/base/buffer.h"
|
| +#include "webrtc/base/gunit.h"
|
| +#include "webrtc/base/sigslot.h"
|
| +#include "webrtc/base/stream.h"
|
| +#include "webrtc/p2p/quic/quicconnectionhelper.h"
|
| +
|
| +using cricket::QuicConnectionHelper;
|
| +using cricket::ReliableQuicStream;
|
| +
|
| +using net::FecProtection;
|
| +using net::IPAddressNumber;
|
| +using net::IPEndPoint;
|
| +using net::Perspective;
|
| +using net::QuicAckListenerInterface;
|
| +using net::QuicConfig;
|
| +using net::QuicConnection;
|
| +using net::QuicConsumedData;
|
| +using net::QuicCryptoStream;
|
| +using net::QuicErrorCode;
|
| +using net::QuicIOVector;
|
| +using net::QuicPacketWriter;
|
| +using net::QuicRstStreamErrorCode;
|
| +using net::QuicSession;
|
| +using net::QuicStreamId;
|
| +using net::QuicStreamOffset;
|
| +using net::SpdyPriority;
|
| +
|
| +using rtc::SR_SUCCESS;
|
| +using rtc::SR_BLOCK;
|
| +
|
| +// QuicSession that does not create streams and writes data from
|
| +// ReliableQuicStream to a string.
|
| +class MockQuicSession : public QuicSession {
|
| + public:
|
| + MockQuicSession(QuicConnection* connection,
|
| + const QuicConfig& config,
|
| + std::string* write_buffer)
|
| + : QuicSession(connection, config), write_buffer_(write_buffer) {}
|
| +
|
| + // Writes outgoing data from ReliableQuicStream to a string.
|
| + QuicConsumedData WritevData(
|
| + QuicStreamId id,
|
| + QuicIOVector iovector,
|
| + QuicStreamOffset offset,
|
| + bool fin,
|
| + FecProtection fec_protection,
|
| + QuicAckListenerInterface* ack_notifier_delegate) override {
|
| + if (!writable_) {
|
| + return QuicConsumedData(0, false);
|
| + }
|
| +
|
| + const char* data = reinterpret_cast<const char*>(iovector.iov->iov_base);
|
| + size_t len = iovector.total_length;
|
| + write_buffer_->append(data, len);
|
| + return QuicConsumedData(len, false);
|
| + }
|
| +
|
| + net::ReliableQuicStream* CreateIncomingDynamicStream(
|
| + QuicStreamId id) override {
|
| + return nullptr;
|
| + }
|
| +
|
| + net::ReliableQuicStream* CreateOutgoingDynamicStream(
|
| + SpdyPriority priority) override {
|
| + return nullptr;
|
| + }
|
| +
|
| + QuicCryptoStream* GetCryptoStream() override { return nullptr; }
|
| +
|
| + // Called by ReliableQuicStream when they want to close stream.
|
| + void SendRstStream(QuicStreamId id,
|
| + QuicRstStreamErrorCode error,
|
| + QuicStreamOffset bytes_written) 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 register_write_blocked_stream(QuicStreamId stream_id,
|
| + SpdyPriority priority) {
|
| + write_blocked_streams()->RegisterStream(stream_id, priority);
|
| + }
|
| +
|
| + private:
|
| + // Stores written data from ReliableQuicStream.
|
| + std::string* write_buffer_;
|
| + // 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.
|
| + virtual net::WriteResult WritePacket(const char* buffer,
|
| + size_t buf_len,
|
| + const IPAddressNumber& self_address,
|
| + const IPEndPoint& peer_address) {
|
| + return net::WriteResult(net::WRITE_STATUS_ERROR, 0);
|
| + }
|
| +
|
| + bool IsWriteBlockedDataBuffered() const override { return false; }
|
| +
|
| + bool IsWriteBlocked() const override { return false; };
|
| +
|
| + void SetWritable() override {}
|
| +
|
| + net::QuicByteCount GetMaxPacketSize(
|
| + const net::IPEndPoint& peer_address) const override {
|
| + return 0;
|
| + }
|
| +};
|
| +
|
| +// QuicPacketWriter is not necessary, so this creates a packet writer that
|
| +// doesn't do anything.
|
| +class DummyPacketWriterFactory : public QuicConnection::PacketWriterFactory {
|
| + public:
|
| + DummyPacketWriterFactory() {}
|
| +
|
| + QuicPacketWriter* Create(QuicConnection* connection) const override {
|
| + return new DummyPacketWriter();
|
| + }
|
| +};
|
| +
|
| +class ReliableQuicStreamTest : public ::testing::Test,
|
| + public sigslot::has_slots<> {
|
| + public:
|
| + ReliableQuicStreamTest() {}
|
| +
|
| + void CreateReliableQuicStream() {
|
| + const net::QuicStreamId kStreamId = 5;
|
| +
|
| + // Arbitrary values for QuicConnection.
|
| + QuicConnectionHelper* quic_helper =
|
| + new QuicConnectionHelper(rtc::Thread::Current());
|
| + Perspective perspective = Perspective::IS_SERVER;
|
| + net::IPAddressNumber ip(net::kIPv4AddressSize, 0);
|
| +
|
| + bool owns_writer = false;
|
| +
|
| + QuicConnection* connection = new QuicConnection(
|
| + 0, IPEndPoint(ip, 0), quic_helper, DummyPacketWriterFactory(),
|
| + owns_writer, perspective, net::QuicSupportedVersions());
|
| +
|
| + session_.reset(
|
| + new MockQuicSession(connection, QuicConfig(), &write_buffer_));
|
| + stream_.reset(new ReliableQuicStream(kStreamId, session_.get()));
|
| + stream_->SignalDataReceived.connect(
|
| + this, &ReliableQuicStreamTest::OnDataReceived);
|
| + stream_->SignalClosed.connect(this, &ReliableQuicStreamTest::OnClosed);
|
| +
|
| + session_->register_write_blocked_stream(stream_->id(), stream_->Priority());
|
| + }
|
| +
|
| + void OnDataReceived(QuicStreamId id, const char* data, size_t length) {
|
| + ASSERT_EQ(id, stream_->id());
|
| + read_buffer_.append(data, length);
|
| + }
|
| +
|
| + void OnClosed(QuicStreamId id, QuicErrorCode err) { closed_ = true; }
|
| +
|
| + protected:
|
| + scoped_ptr<ReliableQuicStream> stream_;
|
| + scoped_ptr<MockQuicSession> session_;
|
| +
|
| + // Data written by the ReliableQuicStream.
|
| + std::string write_buffer_;
|
| + // Data read by the ReliableQuicStream.
|
| + std::string read_buffer_;
|
| + // Whether the ReliableQuicStream is closed.
|
| + bool closed_ = false;
|
| +};
|
| +
|
| +// Write an entire string.
|
| +TEST_F(ReliableQuicStreamTest, WriteDataWhole) {
|
| + CreateReliableQuicStream();
|
| + EXPECT_EQ(SR_SUCCESS, stream_->Write("Foo bar", 7));
|
| +
|
| + EXPECT_EQ("Foo bar", write_buffer_);
|
| +}
|
| +
|
| +// Write part of a string.
|
| +TEST_F(ReliableQuicStreamTest, WriteDataPartial) {
|
| + CreateReliableQuicStream();
|
| + EXPECT_EQ(SR_SUCCESS, stream_->Write("Hello, World!", 8));
|
| + EXPECT_EQ("Hello, W", write_buffer_);
|
| +}
|
| +
|
| +// Test that strings are buffered correctly.
|
| +TEST_F(ReliableQuicStreamTest, BufferData) {
|
| + CreateReliableQuicStream();
|
| +
|
| + session_->set_writable(false);
|
| + EXPECT_EQ(SR_BLOCK, stream_->Write("Foo bar", 7));
|
| +
|
| + EXPECT_EQ(0ul, write_buffer_.size());
|
| + EXPECT_TRUE(stream_->HasBufferedData());
|
| +
|
| + session_->set_writable(true);
|
| + stream_->OnCanWrite();
|
| +
|
| + EXPECT_FALSE(stream_->HasBufferedData());
|
| + EXPECT_EQ("Foo bar", write_buffer_);
|
| +
|
| + EXPECT_EQ(SR_SUCCESS, stream_->Write("xyzzy", 5));
|
| + EXPECT_EQ("Foo barxyzzy", write_buffer_);
|
| +}
|
| +
|
| +// Read an entire string.
|
| +TEST_F(ReliableQuicStreamTest, ReadDataWhole) {
|
| + CreateReliableQuicStream();
|
| + net::QuicStreamFrame frame(-1, false, 0, "Hello, World!");
|
| + stream_->OnStreamFrame(frame);
|
| +
|
| + EXPECT_EQ("Hello, World!", read_buffer_);
|
| +}
|
| +
|
| +// Read part of a string.
|
| +TEST_F(ReliableQuicStreamTest, ReadDataPartial) {
|
| + CreateReliableQuicStream();
|
| + net::QuicStreamFrame frame(-1, false, 0, "Hello, World!");
|
| + frame.frame_length = 5;
|
| + stream_->OnStreamFrame(frame);
|
| +
|
| + EXPECT_EQ("Hello", read_buffer_);
|
| +}
|
| +
|
| +// Test that closing the stream results in a callback.
|
| +TEST_F(ReliableQuicStreamTest, CloseStream) {
|
| + CreateReliableQuicStream();
|
| + EXPECT_FALSE(closed_);
|
| + stream_->OnClose();
|
| + EXPECT_TRUE(closed_);
|
| +}
|
|
|