OLD | NEW |
---|---|
(Empty) | |
1 /* | |
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 <string> | |
12 #include <vector> | |
13 | |
14 #include "webrtc/p2p/quic/reliablequicstream.h" | |
15 | |
16 #include "webrtc/base/gunit.h" | |
17 #include "webrtc/p2p/quic/quicconnectionhelper.h" | |
18 | |
19 #include "net/base/ip_address_number.h" | |
20 #include "net/quic/quic_connection.h" | |
21 #include "net/quic/quic_protocol.h" | |
22 #include "net/quic/quic_session.h" | |
23 | |
24 #include "webrtc/base/sigslot.h" | |
25 #include "webrtc/base/stream.h" | |
26 | |
27 using cricket::QuicConnectionHelper; | |
28 using cricket::ReliableQuicStream; | |
29 | |
30 using net::FecProtection; | |
31 using net::IPAddressNumber; | |
32 using net::IPEndPoint; | |
33 using net::Perspective; | |
34 using net::QuicAckListenerInterface; | |
35 using net::QuicConfig; | |
36 using net::QuicConnection; | |
37 using net::QuicConsumedData; | |
38 using net::QuicCryptoStream; | |
39 using net::QuicErrorCode; | |
40 using net::QuicIOVector; | |
41 using net::QuicPacketWriter; | |
42 using net::QuicRstStreamErrorCode; | |
43 using net::QuicSession; | |
44 using net::QuicStreamId; | |
45 using net::QuicStreamOffset; | |
46 using net::SpdyPriority; | |
47 | |
48 using rtc::SR_SUCCESS; | |
49 using rtc::SR_BLOCK; | |
50 | |
51 // QuicSession that does not create streams and writes data from | |
52 // ReliableQuicStream to a string buffer. | |
53 class MockQuicSession : public QuicSession { | |
54 public: | |
55 MockQuicSession(QuicConnection* connection, | |
56 const QuicConfig& config, | |
57 std::vector<std::string>* write_buffer) | |
58 : QuicSession(connection, config), write_buffer_(write_buffer) {} | |
59 | |
60 ~MockQuicSession() override {} | |
61 | |
62 // Writes outgoing data from ReliableQuicStream to a string buffer. | |
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_->push_back(std::string(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::vector<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. | |
115 class DummyPacketWriter : public QuicPacketWriter { | |
116 public: | |
117 DummyPacketWriter() {} | |
118 ~DummyPacketWriter() override {} | |
119 | |
120 // QuicPacketWriter overrides. | |
121 virtual net::WriteResult WritePacket(const char* buffer, | |
122 size_t buf_len, | |
123 const IPAddressNumber& self_address, | |
124 const IPEndPoint& peer_address) { | |
125 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 | |
140 // QuicPacketWriter is not necessary, so this creates a packet writer that | |
141 // doesn't do anything. | |
142 class DummyPacketWriterFactory : public QuicConnection::PacketWriterFactory { | |
143 public: | |
144 DummyPacketWriterFactory() {} | |
145 ~DummyPacketWriterFactory() override {} | |
146 | |
147 QuicPacketWriter* Create(QuicConnection* connection) const override { | |
148 return new DummyPacketWriter(); | |
149 } | |
150 }; | |
151 | |
152 class ReliableQuicStreamTest : public ::testing::Test, | |
153 public sigslot::has_slots<> { | |
154 public: | |
155 ReliableQuicStreamTest() {} | |
156 | |
157 ~ReliableQuicStreamTest() override {} | |
158 | |
159 void CreateReliableQuicStream() { | |
160 const net::QuicStreamId kStreamId = 5; | |
161 | |
162 // Arbitrary values for QuicConnection | |
163 QuicConnectionHelper* quic_helper = | |
164 new QuicConnectionHelper(rtc::Thread::Current()); | |
165 Perspective perspective = Perspective::IS_SERVER; | |
166 net::IPAddressNumber ip(net::kIPv4AddressSize, 0); | |
167 | |
168 QuicConnection* connection = new QuicConnection( | |
169 0, IPEndPoint(ip, 0), quic_helper, DummyPacketWriterFactory(), | |
170 false /* owns_writer */, perspective, net::QuicSupportedVersions()); | |
pthatcher1
2016/02/03 23:27:24
I'd prefer to put above:
bool owns_writer = false
mikescarlett
2016/02/05 21:10:29
Done.
| |
171 | |
172 session_.reset( | |
173 new MockQuicSession(connection, QuicConfig(), &write_buffer_)); | |
174 stream_.reset(new ReliableQuicStream(kStreamId, session_.get())); | |
175 stream_->SignalDataReceived.connect( | |
176 this, &ReliableQuicStreamTest::OnDataReceived); | |
177 stream_->SignalClosed.connect(this, &ReliableQuicStreamTest::OnClosed); | |
178 | |
179 session_->register_write_blocked_stream(stream_->id(), stream_->Priority()); | |
180 } | |
181 | |
182 void OnDataReceived(QuicStreamId id, const char* data, size_t length) { | |
183 ASSERT_EQ(id, stream_->id()); | |
184 read_buffer_.push_back(std::string(data, length)); | |
185 } | |
186 | |
187 void OnClosed(QuicStreamId id, QuicErrorCode err) { closed_ = true; } | |
188 | |
189 protected: | |
190 scoped_ptr<ReliableQuicStream> stream_; | |
191 scoped_ptr<MockQuicSession> session_; | |
192 | |
193 // Data written by the ReliableQuicStream | |
194 std::vector<std::string> write_buffer_; | |
195 // Data read by the ReliableQuicStream | |
196 std::vector<std::string> read_buffer_; | |
pthatcher1
2016/02/03 23:27:24
An rtc::Buffer might be a better fit here.
mikescarlett
2016/02/05 21:10:29
Agreed that's a better fit (did not know about rtc
pthatcher1
2016/02/05 21:32:34
Actually, now that I see it, I think a std::string
mikescarlett
2016/02/05 22:12:28
I replaced rtc::Buffer with std::string and no lon
| |
197 // Whether the ReliableQuicStream is closed | |
198 bool closed_ = false; | |
199 }; | |
200 | |
201 // Write an entire string. | |
202 TEST_F(ReliableQuicStreamTest, WriteDataWhole) { | |
203 CreateReliableQuicStream(); | |
204 EXPECT_EQ(SR_SUCCESS, stream_->Write("Foo bar", 7)); | |
205 | |
206 ASSERT_EQ(1ul, write_buffer_.size()); | |
207 ASSERT_EQ("Foo bar", write_buffer_[0]); | |
208 } | |
209 | |
210 // Write part of a string | |
211 TEST_F(ReliableQuicStreamTest, WriteDataPartial) { | |
212 CreateReliableQuicStream(); | |
213 EXPECT_EQ(SR_SUCCESS, stream_->Write("Hello, World!", 8)); | |
214 | |
215 ASSERT_EQ(1ul, write_buffer_.size()); | |
216 ASSERT_EQ("Hello, W", write_buffer_[0]); | |
217 } | |
218 | |
219 // Test that strings are buffered correctly. | |
220 TEST_F(ReliableQuicStreamTest, BufferData) { | |
221 CreateReliableQuicStream(); | |
222 | |
223 session_->set_writable(false); | |
224 EXPECT_EQ(SR_BLOCK, stream_->Write("Foo bar", 7)); | |
225 | |
226 ASSERT_EQ(0ul, write_buffer_.size()); | |
227 ASSERT_TRUE(stream_->HasBufferedData()); | |
228 | |
229 session_->set_writable(true); | |
230 stream_->OnCanWrite(); | |
231 | |
232 ASSERT_FALSE(stream_->HasBufferedData()); | |
233 ASSERT_EQ(1ul, write_buffer_.size()); | |
234 ASSERT_EQ("Foo bar", write_buffer_[0]); | |
235 | |
236 EXPECT_EQ(SR_SUCCESS, stream_->Write("xyzzy", 5)); | |
237 ASSERT_EQ(2ul, write_buffer_.size()); | |
238 ASSERT_EQ("xyzzy", write_buffer_[1]); | |
239 } | |
240 | |
241 // Read an entire string. | |
242 TEST_F(ReliableQuicStreamTest, ReadDataWhole) { | |
243 CreateReliableQuicStream(); | |
244 net::QuicStreamFrame frame(-1, false, 0, "Hello, World!"); | |
245 stream_->OnStreamFrame(frame); | |
246 | |
247 ASSERT_EQ(1ul, read_buffer_.size()); | |
248 ASSERT_EQ("Hello, World!", read_buffer_[0]); | |
249 } | |
250 | |
251 // Read part of a string. | |
252 TEST_F(ReliableQuicStreamTest, ReadDataPartial) { | |
253 CreateReliableQuicStream(); | |
254 net::QuicStreamFrame frame(-1, false, 0, "Hello, World!"); | |
255 frame.frame_length = 5; | |
256 stream_->OnStreamFrame(frame); | |
257 | |
258 ASSERT_EQ(1ul, read_buffer_.size()); | |
259 ASSERT_EQ("Hello", read_buffer_[0]); | |
260 } | |
261 | |
262 // Test that closing the stream results in a callback. | |
263 TEST_F(ReliableQuicStreamTest, CloseStream) { | |
264 CreateReliableQuicStream(); | |
265 ASSERT_FALSE(closed_); | |
266 stream_->OnClose(); | |
267 ASSERT_TRUE(closed_); | |
268 } | |
OLD | NEW |