blob: b8875894576a0f1836cdc84ca8c6df57bacca6c9 [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
13#include <string>
14
15#include "net/base/ip_address_number.h"
16#include "net/quic/quic_connection.h"
17#include "net/quic/quic_protocol.h"
18#include "net/quic/quic_session.h"
19#include "webrtc/base/buffer.h"
20#include "webrtc/base/gunit.h"
21#include "webrtc/base/sigslot.h"
22#include "webrtc/base/stream.h"
23#include "webrtc/p2p/quic/quicconnectionhelper.h"
24
25using cricket::QuicConnectionHelper;
26using cricket::ReliableQuicStream;
27
28using net::FecProtection;
mikescarlettf5377682016-03-29 12:14:55 -070029using net::IPAddress;
mikescarlettcd0e4752016-02-08 17:35:47 -080030using net::IPEndPoint;
mikescarlettf5377682016-03-29 12:14:55 -070031using net::PerPacketOptions;
mikescarlettcd0e4752016-02-08 17:35:47 -080032using net::Perspective;
33using net::QuicAckListenerInterface;
34using net::QuicConfig;
35using net::QuicConnection;
36using net::QuicConsumedData;
37using net::QuicCryptoStream;
38using net::QuicErrorCode;
39using net::QuicIOVector;
40using net::QuicPacketWriter;
41using net::QuicRstStreamErrorCode;
42using net::QuicSession;
43using net::QuicStreamId;
44using net::QuicStreamOffset;
45using net::SpdyPriority;
46
47using rtc::SR_SUCCESS;
48using rtc::SR_BLOCK;
49
mikescarlettf5377682016-03-29 12:14:55 -070050// Arbitrary number for a stream's write blocked priority.
51static const SpdyPriority kDefaultPriority = 3;
52
mikescarlettcd0e4752016-02-08 17:35:47 -080053// QuicSession that does not create streams and writes data from
54// ReliableQuicStream to a string.
55class MockQuicSession : public QuicSession {
56 public:
57 MockQuicSession(QuicConnection* connection,
58 const QuicConfig& config,
59 std::string* write_buffer)
60 : QuicSession(connection, config), write_buffer_(write_buffer) {}
61
62 // Writes outgoing data from ReliableQuicStream to a string.
63 QuicConsumedData WritevData(
64 QuicStreamId id,
65 QuicIOVector iovector,
66 QuicStreamOffset offset,
67 bool fin,
68 FecProtection fec_protection,
69 QuicAckListenerInterface* ack_notifier_delegate) override {
70 if (!writable_) {
71 return QuicConsumedData(0, false);
72 }
73
74 const char* data = reinterpret_cast<const char*>(iovector.iov->iov_base);
75 size_t len = iovector.total_length;
76 write_buffer_->append(data, len);
77 return QuicConsumedData(len, false);
78 }
79
80 net::ReliableQuicStream* CreateIncomingDynamicStream(
81 QuicStreamId id) override {
82 return nullptr;
83 }
84
85 net::ReliableQuicStream* CreateOutgoingDynamicStream(
86 SpdyPriority priority) override {
87 return nullptr;
88 }
89
90 QuicCryptoStream* GetCryptoStream() override { return nullptr; }
91
92 // Called by ReliableQuicStream when they want to close stream.
93 void SendRstStream(QuicStreamId id,
94 QuicRstStreamErrorCode error,
95 QuicStreamOffset bytes_written) override {}
96
97 // Sets whether data is written to buffer, or else if this is write blocked.
98 void set_writable(bool writable) { writable_ = writable; }
99
100 // Tracks whether the stream is write blocked and its priority.
101 void register_write_blocked_stream(QuicStreamId stream_id,
102 SpdyPriority priority) {
103 write_blocked_streams()->RegisterStream(stream_id, priority);
104 }
105
106 private:
107 // Stores written data from ReliableQuicStream.
108 std::string* write_buffer_;
109 // Whether data is written to write_buffer_.
110 bool writable_ = true;
111};
112
113// Packet writer that does nothing. This is required for QuicConnection but
114// isn't used for writing data.
115class DummyPacketWriter : public QuicPacketWriter {
116 public:
117 DummyPacketWriter() {}
118
119 // QuicPacketWriter overrides.
120 virtual net::WriteResult WritePacket(const char* buffer,
121 size_t buf_len,
mikescarlettf5377682016-03-29 12:14:55 -0700122 const IPAddress& self_address,
123 const IPEndPoint& peer_address,
124 PerPacketOptions* options) {
mikescarlettcd0e4752016-02-08 17:35:47 -0800125 return net::WriteResult(net::WRITE_STATUS_ERROR, 0);
126 }
127
128 bool IsWriteBlockedDataBuffered() const override { return false; }
129
130 bool IsWriteBlocked() const override { return false; };
131
132 void SetWritable() override {}
133
134 net::QuicByteCount GetMaxPacketSize(
135 const net::IPEndPoint& peer_address) const override {
136 return 0;
137 }
138};
139
mikescarlettcd0e4752016-02-08 17:35:47 -0800140class ReliableQuicStreamTest : public ::testing::Test,
141 public sigslot::has_slots<> {
142 public:
143 ReliableQuicStreamTest() {}
144
145 void CreateReliableQuicStream() {
146 const net::QuicStreamId kStreamId = 5;
147
148 // Arbitrary values for QuicConnection.
149 QuicConnectionHelper* quic_helper =
150 new QuicConnectionHelper(rtc::Thread::Current());
151 Perspective perspective = Perspective::IS_SERVER;
mikescarlettf5377682016-03-29 12:14:55 -0700152 net::IPAddress ip(0, 0, 0, 0);
mikescarlettcd0e4752016-02-08 17:35:47 -0800153
mikescarlettf5377682016-03-29 12:14:55 -0700154 bool owns_writer = true;
mikescarlettcd0e4752016-02-08 17:35:47 -0800155
156 QuicConnection* connection = new QuicConnection(
mikescarlettf5377682016-03-29 12:14:55 -0700157 0, IPEndPoint(ip, 0), quic_helper, new DummyPacketWriter(), owns_writer,
158 perspective, net::QuicSupportedVersions());
mikescarlettcd0e4752016-02-08 17:35:47 -0800159
160 session_.reset(
161 new MockQuicSession(connection, QuicConfig(), &write_buffer_));
162 stream_.reset(new ReliableQuicStream(kStreamId, session_.get()));
163 stream_->SignalDataReceived.connect(
164 this, &ReliableQuicStreamTest::OnDataReceived);
165 stream_->SignalClosed.connect(this, &ReliableQuicStreamTest::OnClosed);
mikescarlett18b67a52016-04-11 16:56:23 -0700166 stream_->SignalQueuedBytesWritten.connect(
167 this, &ReliableQuicStreamTest::OnQueuedBytesWritten);
mikescarlettcd0e4752016-02-08 17:35:47 -0800168
mikescarlettf5377682016-03-29 12:14:55 -0700169 session_->register_write_blocked_stream(stream_->id(), kDefaultPriority);
mikescarlettcd0e4752016-02-08 17:35:47 -0800170 }
171
172 void OnDataReceived(QuicStreamId id, const char* data, size_t length) {
173 ASSERT_EQ(id, stream_->id());
174 read_buffer_.append(data, length);
175 }
176
mikescarlett18b67a52016-04-11 16:56:23 -0700177 void OnClosed(QuicStreamId id, int err) { closed_ = true; }
178
179 void OnQueuedBytesWritten(QuicStreamId id, uint64_t queued_bytes_written) {
180 queued_bytes_written_ = queued_bytes_written;
181 }
mikescarlettcd0e4752016-02-08 17:35:47 -0800182
183 protected:
mikescarlettf5377682016-03-29 12:14:55 -0700184 rtc::scoped_ptr<ReliableQuicStream> stream_;
185 rtc::scoped_ptr<MockQuicSession> session_;
mikescarlettcd0e4752016-02-08 17:35:47 -0800186
187 // Data written by the ReliableQuicStream.
188 std::string write_buffer_;
189 // Data read by the ReliableQuicStream.
190 std::string read_buffer_;
191 // Whether the ReliableQuicStream is closed.
192 bool closed_ = false;
mikescarlett18b67a52016-04-11 16:56:23 -0700193 // Bytes written by OnCanWrite().
194 uint64_t queued_bytes_written_;
mikescarlettcd0e4752016-02-08 17:35:47 -0800195};
196
197// Write an entire string.
198TEST_F(ReliableQuicStreamTest, WriteDataWhole) {
199 CreateReliableQuicStream();
200 EXPECT_EQ(SR_SUCCESS, stream_->Write("Foo bar", 7));
201
202 EXPECT_EQ("Foo bar", write_buffer_);
203}
204
205// Write part of a string.
206TEST_F(ReliableQuicStreamTest, WriteDataPartial) {
207 CreateReliableQuicStream();
208 EXPECT_EQ(SR_SUCCESS, stream_->Write("Hello, World!", 8));
209 EXPECT_EQ("Hello, W", write_buffer_);
210}
211
212// Test that strings are buffered correctly.
213TEST_F(ReliableQuicStreamTest, BufferData) {
214 CreateReliableQuicStream();
215
216 session_->set_writable(false);
217 EXPECT_EQ(SR_BLOCK, stream_->Write("Foo bar", 7));
218
219 EXPECT_EQ(0ul, write_buffer_.size());
220 EXPECT_TRUE(stream_->HasBufferedData());
221
222 session_->set_writable(true);
223 stream_->OnCanWrite();
mikescarlett18b67a52016-04-11 16:56:23 -0700224 EXPECT_EQ(7ul, queued_bytes_written_);
mikescarlettcd0e4752016-02-08 17:35:47 -0800225
226 EXPECT_FALSE(stream_->HasBufferedData());
227 EXPECT_EQ("Foo bar", write_buffer_);
228
229 EXPECT_EQ(SR_SUCCESS, stream_->Write("xyzzy", 5));
230 EXPECT_EQ("Foo barxyzzy", write_buffer_);
231}
232
233// Read an entire string.
234TEST_F(ReliableQuicStreamTest, ReadDataWhole) {
235 CreateReliableQuicStream();
236 net::QuicStreamFrame frame(-1, false, 0, "Hello, World!");
237 stream_->OnStreamFrame(frame);
238
239 EXPECT_EQ("Hello, World!", read_buffer_);
240}
241
242// Read part of a string.
243TEST_F(ReliableQuicStreamTest, ReadDataPartial) {
244 CreateReliableQuicStream();
245 net::QuicStreamFrame frame(-1, false, 0, "Hello, World!");
246 frame.frame_length = 5;
247 stream_->OnStreamFrame(frame);
248
249 EXPECT_EQ("Hello", read_buffer_);
250}
251
252// Test that closing the stream results in a callback.
253TEST_F(ReliableQuicStreamTest, CloseStream) {
254 CreateReliableQuicStream();
255 EXPECT_FALSE(closed_);
256 stream_->OnClose();
257 EXPECT_TRUE(closed_);
258}