blob: 9f55c911cc7161bf80b0537777a24077ac9beaa3 [file] [log] [blame]
mikescarlettcd0e4752016-02-08 17:35:47 -08001/*
2 * Copyright 2016 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/p2p/quic/reliablequicstream.h"
12
kwiberg3ec46792016-04-27 07:22:53 -070013#include <memory>
mikescarlettcd0e4752016-02-08 17:35:47 -080014#include <string>
15
16#include "net/base/ip_address_number.h"
17#include "net/quic/quic_connection.h"
18#include "net/quic/quic_protocol.h"
19#include "net/quic/quic_session.h"
20#include "webrtc/base/buffer.h"
21#include "webrtc/base/gunit.h"
22#include "webrtc/base/sigslot.h"
23#include "webrtc/base/stream.h"
24#include "webrtc/p2p/quic/quicconnectionhelper.h"
25
26using cricket::QuicConnectionHelper;
27using cricket::ReliableQuicStream;
28
29using net::FecProtection;
mikescarlettf5377682016-03-29 12:14:55 -070030using net::IPAddress;
mikescarlettcd0e4752016-02-08 17:35:47 -080031using net::IPEndPoint;
mikescarlettf5377682016-03-29 12:14:55 -070032using net::PerPacketOptions;
mikescarlettcd0e4752016-02-08 17:35:47 -080033using net::Perspective;
34using net::QuicAckListenerInterface;
35using net::QuicConfig;
36using net::QuicConnection;
37using net::QuicConsumedData;
38using net::QuicCryptoStream;
39using net::QuicErrorCode;
40using net::QuicIOVector;
41using net::QuicPacketWriter;
42using net::QuicRstStreamErrorCode;
43using net::QuicSession;
44using net::QuicStreamId;
45using net::QuicStreamOffset;
46using net::SpdyPriority;
47
48using rtc::SR_SUCCESS;
49using rtc::SR_BLOCK;
50
mikescarlettf5377682016-03-29 12:14:55 -070051// Arbitrary number for a stream's write blocked priority.
52static const SpdyPriority kDefaultPriority = 3;
53
mikescarlettcd0e4752016-02-08 17:35:47 -080054// QuicSession that does not create streams and writes data from
55// ReliableQuicStream to a string.
56class MockQuicSession : public QuicSession {
57 public:
58 MockQuicSession(QuicConnection* connection,
59 const QuicConfig& config,
60 std::string* write_buffer)
61 : QuicSession(connection, config), write_buffer_(write_buffer) {}
62
63 // Writes outgoing data from ReliableQuicStream to a string.
64 QuicConsumedData WritevData(
65 QuicStreamId id,
66 QuicIOVector iovector,
67 QuicStreamOffset offset,
68 bool fin,
69 FecProtection fec_protection,
70 QuicAckListenerInterface* ack_notifier_delegate) override {
71 if (!writable_) {
72 return QuicConsumedData(0, false);
73 }
74
75 const char* data = reinterpret_cast<const char*>(iovector.iov->iov_base);
76 size_t len = iovector.total_length;
77 write_buffer_->append(data, len);
78 return QuicConsumedData(len, false);
79 }
80
81 net::ReliableQuicStream* CreateIncomingDynamicStream(
82 QuicStreamId id) override {
83 return nullptr;
84 }
85
86 net::ReliableQuicStream* CreateOutgoingDynamicStream(
87 SpdyPriority priority) override {
88 return nullptr;
89 }
90
91 QuicCryptoStream* GetCryptoStream() override { return nullptr; }
92
93 // Called by ReliableQuicStream when they want to close stream.
94 void SendRstStream(QuicStreamId id,
95 QuicRstStreamErrorCode error,
96 QuicStreamOffset bytes_written) override {}
97
98 // Sets whether data is written to buffer, or else if this is write blocked.
99 void set_writable(bool writable) { writable_ = writable; }
100
101 // Tracks whether the stream is write blocked and its priority.
102 void register_write_blocked_stream(QuicStreamId stream_id,
103 SpdyPriority priority) {
104 write_blocked_streams()->RegisterStream(stream_id, priority);
105 }
106
107 private:
108 // Stores written data from ReliableQuicStream.
109 std::string* write_buffer_;
110 // Whether data is written to write_buffer_.
111 bool writable_ = true;
112};
113
114// Packet writer that does nothing. This is required for QuicConnection but
115// isn't used for writing data.
116class DummyPacketWriter : public QuicPacketWriter {
117 public:
118 DummyPacketWriter() {}
119
120 // QuicPacketWriter overrides.
121 virtual net::WriteResult WritePacket(const char* buffer,
122 size_t buf_len,
mikescarlettf5377682016-03-29 12:14:55 -0700123 const IPAddress& self_address,
124 const IPEndPoint& peer_address,
125 PerPacketOptions* options) {
mikescarlettcd0e4752016-02-08 17:35:47 -0800126 return net::WriteResult(net::WRITE_STATUS_ERROR, 0);
127 }
128
129 bool IsWriteBlockedDataBuffered() const override { return false; }
130
131 bool IsWriteBlocked() const override { return false; };
132
133 void SetWritable() override {}
134
135 net::QuicByteCount GetMaxPacketSize(
136 const net::IPEndPoint& peer_address) const override {
137 return 0;
138 }
139};
140
mikescarlettcd0e4752016-02-08 17:35:47 -0800141class ReliableQuicStreamTest : public ::testing::Test,
142 public sigslot::has_slots<> {
143 public:
144 ReliableQuicStreamTest() {}
145
146 void CreateReliableQuicStream() {
147 const net::QuicStreamId kStreamId = 5;
148
149 // Arbitrary values for QuicConnection.
150 QuicConnectionHelper* quic_helper =
151 new QuicConnectionHelper(rtc::Thread::Current());
152 Perspective perspective = Perspective::IS_SERVER;
mikescarlettf5377682016-03-29 12:14:55 -0700153 net::IPAddress ip(0, 0, 0, 0);
mikescarlettcd0e4752016-02-08 17:35:47 -0800154
mikescarlettf5377682016-03-29 12:14:55 -0700155 bool owns_writer = true;
mikescarlettcd0e4752016-02-08 17:35:47 -0800156
157 QuicConnection* connection = new QuicConnection(
mikescarlettf5377682016-03-29 12:14:55 -0700158 0, IPEndPoint(ip, 0), quic_helper, new DummyPacketWriter(), owns_writer,
159 perspective, net::QuicSupportedVersions());
mikescarlettcd0e4752016-02-08 17:35:47 -0800160
161 session_.reset(
162 new MockQuicSession(connection, QuicConfig(), &write_buffer_));
163 stream_.reset(new ReliableQuicStream(kStreamId, session_.get()));
164 stream_->SignalDataReceived.connect(
165 this, &ReliableQuicStreamTest::OnDataReceived);
166 stream_->SignalClosed.connect(this, &ReliableQuicStreamTest::OnClosed);
mikescarlett18b67a52016-04-11 16:56:23 -0700167 stream_->SignalQueuedBytesWritten.connect(
168 this, &ReliableQuicStreamTest::OnQueuedBytesWritten);
mikescarlettcd0e4752016-02-08 17:35:47 -0800169
mikescarlettf5377682016-03-29 12:14:55 -0700170 session_->register_write_blocked_stream(stream_->id(), kDefaultPriority);
mikescarlettcd0e4752016-02-08 17:35:47 -0800171 }
172
173 void OnDataReceived(QuicStreamId id, const char* data, size_t length) {
174 ASSERT_EQ(id, stream_->id());
175 read_buffer_.append(data, length);
176 }
177
mikescarlett18b67a52016-04-11 16:56:23 -0700178 void OnClosed(QuicStreamId id, int err) { closed_ = true; }
179
180 void OnQueuedBytesWritten(QuicStreamId id, uint64_t queued_bytes_written) {
181 queued_bytes_written_ = queued_bytes_written;
182 }
mikescarlettcd0e4752016-02-08 17:35:47 -0800183
184 protected:
kwiberg3ec46792016-04-27 07:22:53 -0700185 std::unique_ptr<ReliableQuicStream> stream_;
186 std::unique_ptr<MockQuicSession> session_;
mikescarlettcd0e4752016-02-08 17:35:47 -0800187
188 // Data written by the ReliableQuicStream.
189 std::string write_buffer_;
190 // Data read by the ReliableQuicStream.
191 std::string read_buffer_;
192 // Whether the ReliableQuicStream is closed.
193 bool closed_ = false;
mikescarlett18b67a52016-04-11 16:56:23 -0700194 // Bytes written by OnCanWrite().
195 uint64_t queued_bytes_written_;
mikescarlettcd0e4752016-02-08 17:35:47 -0800196};
197
198// Write an entire string.
199TEST_F(ReliableQuicStreamTest, WriteDataWhole) {
200 CreateReliableQuicStream();
201 EXPECT_EQ(SR_SUCCESS, stream_->Write("Foo bar", 7));
202
203 EXPECT_EQ("Foo bar", write_buffer_);
204}
205
206// Write part of a string.
207TEST_F(ReliableQuicStreamTest, WriteDataPartial) {
208 CreateReliableQuicStream();
209 EXPECT_EQ(SR_SUCCESS, stream_->Write("Hello, World!", 8));
210 EXPECT_EQ("Hello, W", write_buffer_);
211}
212
213// Test that strings are buffered correctly.
214TEST_F(ReliableQuicStreamTest, BufferData) {
215 CreateReliableQuicStream();
216
217 session_->set_writable(false);
218 EXPECT_EQ(SR_BLOCK, stream_->Write("Foo bar", 7));
219
220 EXPECT_EQ(0ul, write_buffer_.size());
221 EXPECT_TRUE(stream_->HasBufferedData());
222
223 session_->set_writable(true);
224 stream_->OnCanWrite();
mikescarlett18b67a52016-04-11 16:56:23 -0700225 EXPECT_EQ(7ul, queued_bytes_written_);
mikescarlettcd0e4752016-02-08 17:35:47 -0800226
227 EXPECT_FALSE(stream_->HasBufferedData());
228 EXPECT_EQ("Foo bar", write_buffer_);
229
230 EXPECT_EQ(SR_SUCCESS, stream_->Write("xyzzy", 5));
231 EXPECT_EQ("Foo barxyzzy", write_buffer_);
232}
233
234// Read an entire string.
235TEST_F(ReliableQuicStreamTest, ReadDataWhole) {
236 CreateReliableQuicStream();
237 net::QuicStreamFrame frame(-1, false, 0, "Hello, World!");
238 stream_->OnStreamFrame(frame);
239
240 EXPECT_EQ("Hello, World!", read_buffer_);
241}
242
243// Read part of a string.
244TEST_F(ReliableQuicStreamTest, ReadDataPartial) {
245 CreateReliableQuicStream();
246 net::QuicStreamFrame frame(-1, false, 0, "Hello, World!");
247 frame.frame_length = 5;
248 stream_->OnStreamFrame(frame);
249
250 EXPECT_EQ("Hello", read_buffer_);
251}
252
253// Test that closing the stream results in a callback.
254TEST_F(ReliableQuicStreamTest, CloseStream) {
255 CreateReliableQuicStream();
256 EXPECT_FALSE(closed_);
257 stream_->OnClose();
258 EXPECT_TRUE(closed_);
259}