Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / net / spdy / spdy_write_queue_unittest.cc
blob2fdcf5ea31a52c880f5378a12883b489de57c646
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/spdy/spdy_write_queue.h"
7 #include <cstddef>
8 #include <cstring>
9 #include <string>
11 #include "base/basictypes.h"
12 #include "base/memory/ref_counted.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "net/base/request_priority.h"
16 #include "net/log/net_log.h"
17 #include "net/spdy/spdy_buffer_producer.h"
18 #include "net/spdy/spdy_stream.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "url/gurl.h"
22 namespace net {
24 namespace {
26 using std::string;
28 const char kOriginal[] = "original";
29 const char kRequeued[] = "requeued";
31 class SpdyWriteQueueTest : public ::testing::Test {};
33 // Makes a SpdyFrameProducer producing a frame with the data in the
34 // given string.
35 scoped_ptr<SpdyBufferProducer> StringToProducer(const std::string& s) {
36 scoped_ptr<char[]> data(new char[s.size()]);
37 std::memcpy(data.get(), s.data(), s.size());
38 return scoped_ptr<SpdyBufferProducer>(
39 new SimpleBufferProducer(
40 scoped_ptr<SpdyBuffer>(
41 new SpdyBuffer(
42 scoped_ptr<SpdyFrame>(
43 new SpdyFrame(data.release(), s.size(), true))))));
46 // Makes a SpdyBufferProducer producing a frame with the data in the
47 // given int (converted to a string).
48 scoped_ptr<SpdyBufferProducer> IntToProducer(int i) {
49 return StringToProducer(base::IntToString(i));
52 // Producer whose produced buffer will enqueue yet another buffer into the
53 // SpdyWriteQueue upon destruction.
54 class RequeingBufferProducer : public SpdyBufferProducer {
55 public:
56 RequeingBufferProducer(SpdyWriteQueue* queue) {
57 buffer_.reset(new SpdyBuffer(kOriginal, arraysize(kOriginal)));
58 buffer_->AddConsumeCallback(
59 base::Bind(RequeingBufferProducer::ConsumeCallback, queue));
62 scoped_ptr<SpdyBuffer> ProduceBuffer() override { return buffer_.Pass(); }
64 static void ConsumeCallback(SpdyWriteQueue* queue,
65 size_t size,
66 SpdyBuffer::ConsumeSource source) {
67 scoped_ptr<SpdyBufferProducer> producer(
68 new SimpleBufferProducer(scoped_ptr<SpdyBuffer>(
69 new SpdyBuffer(kRequeued, arraysize(kRequeued)))));
71 queue->Enqueue(
72 MEDIUM, RST_STREAM, producer.Pass(), base::WeakPtr<SpdyStream>());
75 private:
76 scoped_ptr<SpdyBuffer> buffer_;
79 // Produces a frame with the given producer and returns a copy of its
80 // data as a string.
81 std::string ProducerToString(scoped_ptr<SpdyBufferProducer> producer) {
82 scoped_ptr<SpdyBuffer> buffer = producer->ProduceBuffer();
83 return std::string(buffer->GetRemainingData(), buffer->GetRemainingSize());
86 // Produces a frame with the given producer and returns a copy of its
87 // data as an int (converted from a string).
88 int ProducerToInt(scoped_ptr<SpdyBufferProducer> producer) {
89 int i = 0;
90 EXPECT_TRUE(base::StringToInt(ProducerToString(producer.Pass()), &i));
91 return i;
94 // Makes a SpdyStream with the given priority and a NULL SpdySession
95 // -- be careful to not call any functions that expect the session to
96 // be there.
97 SpdyStream* MakeTestStream(RequestPriority priority) {
98 return new SpdyStream(
99 SPDY_BIDIRECTIONAL_STREAM, base::WeakPtr<SpdySession>(),
100 GURL(), priority, 0, 0, BoundNetLog());
103 // Add some frame producers of different priority. The producers
104 // should be dequeued in priority order with their associated stream.
105 TEST_F(SpdyWriteQueueTest, DequeuesByPriority) {
106 SpdyWriteQueue write_queue;
108 scoped_ptr<SpdyBufferProducer> producer_low = StringToProducer("LOW");
109 scoped_ptr<SpdyBufferProducer> producer_medium = StringToProducer("MEDIUM");
110 scoped_ptr<SpdyBufferProducer> producer_highest = StringToProducer("HIGHEST");
112 scoped_ptr<SpdyStream> stream_medium(MakeTestStream(MEDIUM));
113 scoped_ptr<SpdyStream> stream_highest(MakeTestStream(HIGHEST));
115 // A NULL stream should still work.
116 write_queue.Enqueue(
117 LOW, SYN_STREAM, producer_low.Pass(), base::WeakPtr<SpdyStream>());
118 write_queue.Enqueue(
119 MEDIUM, SYN_REPLY, producer_medium.Pass(), stream_medium->GetWeakPtr());
120 write_queue.Enqueue(
121 HIGHEST, RST_STREAM, producer_highest.Pass(),
122 stream_highest->GetWeakPtr());
124 SpdyFrameType frame_type = DATA;
125 scoped_ptr<SpdyBufferProducer> frame_producer;
126 base::WeakPtr<SpdyStream> stream;
127 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
128 EXPECT_EQ(RST_STREAM, frame_type);
129 EXPECT_EQ("HIGHEST", ProducerToString(frame_producer.Pass()));
130 EXPECT_EQ(stream_highest, stream.get());
132 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
133 EXPECT_EQ(SYN_REPLY, frame_type);
134 EXPECT_EQ("MEDIUM", ProducerToString(frame_producer.Pass()));
135 EXPECT_EQ(stream_medium, stream.get());
137 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
138 EXPECT_EQ(SYN_STREAM, frame_type);
139 EXPECT_EQ("LOW", ProducerToString(frame_producer.Pass()));
140 EXPECT_EQ(NULL, stream.get());
142 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
145 // Add some frame producers with the same priority. The producers
146 // should be dequeued in FIFO order with their associated stream.
147 TEST_F(SpdyWriteQueueTest, DequeuesFIFO) {
148 SpdyWriteQueue write_queue;
150 scoped_ptr<SpdyBufferProducer> producer1 = IntToProducer(1);
151 scoped_ptr<SpdyBufferProducer> producer2 = IntToProducer(2);
152 scoped_ptr<SpdyBufferProducer> producer3 = IntToProducer(3);
154 scoped_ptr<SpdyStream> stream1(MakeTestStream(DEFAULT_PRIORITY));
155 scoped_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY));
156 scoped_ptr<SpdyStream> stream3(MakeTestStream(DEFAULT_PRIORITY));
158 write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, producer1.Pass(),
159 stream1->GetWeakPtr());
160 write_queue.Enqueue(DEFAULT_PRIORITY, SYN_REPLY, producer2.Pass(),
161 stream2->GetWeakPtr());
162 write_queue.Enqueue(DEFAULT_PRIORITY, RST_STREAM, producer3.Pass(),
163 stream3->GetWeakPtr());
165 SpdyFrameType frame_type = DATA;
166 scoped_ptr<SpdyBufferProducer> frame_producer;
167 base::WeakPtr<SpdyStream> stream;
168 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
169 EXPECT_EQ(SYN_STREAM, frame_type);
170 EXPECT_EQ(1, ProducerToInt(frame_producer.Pass()));
171 EXPECT_EQ(stream1, stream.get());
173 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
174 EXPECT_EQ(SYN_REPLY, frame_type);
175 EXPECT_EQ(2, ProducerToInt(frame_producer.Pass()));
176 EXPECT_EQ(stream2, stream.get());
178 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
179 EXPECT_EQ(RST_STREAM, frame_type);
180 EXPECT_EQ(3, ProducerToInt(frame_producer.Pass()));
181 EXPECT_EQ(stream3, stream.get());
183 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
186 // Enqueue a bunch of writes and then call
187 // RemovePendingWritesForStream() on one of the streams. No dequeued
188 // write should be for that stream.
189 TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStream) {
190 SpdyWriteQueue write_queue;
192 scoped_ptr<SpdyStream> stream1(MakeTestStream(DEFAULT_PRIORITY));
193 scoped_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY));
195 for (int i = 0; i < 100; ++i) {
196 base::WeakPtr<SpdyStream> stream =
197 (((i % 3) == 0) ? stream1 : stream2)->GetWeakPtr();
198 write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i), stream);
201 write_queue.RemovePendingWritesForStream(stream2->GetWeakPtr());
203 for (int i = 0; i < 100; i += 3) {
204 SpdyFrameType frame_type = DATA;
205 scoped_ptr<SpdyBufferProducer> frame_producer;
206 base::WeakPtr<SpdyStream> stream;
207 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
208 EXPECT_EQ(SYN_STREAM, frame_type);
209 EXPECT_EQ(i, ProducerToInt(frame_producer.Pass()));
210 EXPECT_EQ(stream1, stream.get());
213 SpdyFrameType frame_type = DATA;
214 scoped_ptr<SpdyBufferProducer> frame_producer;
215 base::WeakPtr<SpdyStream> stream;
216 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
219 // Enqueue a bunch of writes and then call
220 // RemovePendingWritesForStreamsAfter(). No dequeued write should be for
221 // those streams without a stream id, or with a stream_id after that
222 // argument.
223 TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStreamsAfter) {
224 SpdyWriteQueue write_queue;
226 scoped_ptr<SpdyStream> stream1(MakeTestStream(DEFAULT_PRIORITY));
227 stream1->set_stream_id(1);
228 scoped_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY));
229 stream2->set_stream_id(3);
230 scoped_ptr<SpdyStream> stream3(MakeTestStream(DEFAULT_PRIORITY));
231 stream3->set_stream_id(5);
232 // No stream id assigned.
233 scoped_ptr<SpdyStream> stream4(MakeTestStream(DEFAULT_PRIORITY));
234 base::WeakPtr<SpdyStream> streams[] = {
235 stream1->GetWeakPtr(), stream2->GetWeakPtr(),
236 stream3->GetWeakPtr(), stream4->GetWeakPtr()
239 for (int i = 0; i < 100; ++i) {
240 write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i),
241 streams[i % arraysize(streams)]);
244 write_queue.RemovePendingWritesForStreamsAfter(stream1->stream_id());
246 for (int i = 0; i < 100; i += arraysize(streams)) {
247 SpdyFrameType frame_type = DATA;
248 scoped_ptr<SpdyBufferProducer> frame_producer;
249 base::WeakPtr<SpdyStream> stream;
250 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream))
251 << "Unable to Dequeue i: " << i;
252 EXPECT_EQ(SYN_STREAM, frame_type);
253 EXPECT_EQ(i, ProducerToInt(frame_producer.Pass()));
254 EXPECT_EQ(stream1, stream.get());
257 SpdyFrameType frame_type = DATA;
258 scoped_ptr<SpdyBufferProducer> frame_producer;
259 base::WeakPtr<SpdyStream> stream;
260 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
263 // Enqueue a bunch of writes and then call Clear(). The write queue
264 // should clean up the memory properly, and Dequeue() should return
265 // false.
266 TEST_F(SpdyWriteQueueTest, Clear) {
267 SpdyWriteQueue write_queue;
269 for (int i = 0; i < 100; ++i) {
270 write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i),
271 base::WeakPtr<SpdyStream>());
274 write_queue.Clear();
276 SpdyFrameType frame_type = DATA;
277 scoped_ptr<SpdyBufferProducer> frame_producer;
278 base::WeakPtr<SpdyStream> stream;
279 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream));
282 TEST_F(SpdyWriteQueueTest, RequeingProducerWithoutReentrance) {
283 SpdyWriteQueue queue;
284 queue.Enqueue(
285 DEFAULT_PRIORITY,
286 SYN_STREAM,
287 scoped_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
288 base::WeakPtr<SpdyStream>());
290 SpdyFrameType frame_type;
291 scoped_ptr<SpdyBufferProducer> producer;
292 base::WeakPtr<SpdyStream> stream;
294 EXPECT_TRUE(queue.Dequeue(&frame_type, &producer, &stream));
295 EXPECT_TRUE(queue.IsEmpty());
296 EXPECT_EQ(string(kOriginal), producer->ProduceBuffer()->GetRemainingData());
298 // |producer| was destroyed, and a buffer is re-queued.
299 EXPECT_FALSE(queue.IsEmpty());
301 SpdyFrameType frame_type;
302 scoped_ptr<SpdyBufferProducer> producer;
303 base::WeakPtr<SpdyStream> stream;
305 EXPECT_TRUE(queue.Dequeue(&frame_type, &producer, &stream));
306 EXPECT_EQ(string(kRequeued), producer->ProduceBuffer()->GetRemainingData());
309 TEST_F(SpdyWriteQueueTest, ReentranceOnClear) {
310 SpdyWriteQueue queue;
311 queue.Enqueue(
312 DEFAULT_PRIORITY,
313 SYN_STREAM,
314 scoped_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
315 base::WeakPtr<SpdyStream>());
317 queue.Clear();
318 EXPECT_FALSE(queue.IsEmpty());
320 SpdyFrameType frame_type;
321 scoped_ptr<SpdyBufferProducer> producer;
322 base::WeakPtr<SpdyStream> stream;
324 EXPECT_TRUE(queue.Dequeue(&frame_type, &producer, &stream));
325 EXPECT_EQ(string(kRequeued), producer->ProduceBuffer()->GetRemainingData());
328 TEST_F(SpdyWriteQueueTest, ReentranceOnRemovePendingWritesAfter) {
329 scoped_ptr<SpdyStream> stream(MakeTestStream(DEFAULT_PRIORITY));
330 stream->set_stream_id(2);
332 SpdyWriteQueue queue;
333 queue.Enqueue(
334 DEFAULT_PRIORITY,
335 SYN_STREAM,
336 scoped_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
337 stream->GetWeakPtr());
339 queue.RemovePendingWritesForStreamsAfter(1);
340 EXPECT_FALSE(queue.IsEmpty());
342 SpdyFrameType frame_type;
343 scoped_ptr<SpdyBufferProducer> producer;
344 base::WeakPtr<SpdyStream> weak_stream;
346 EXPECT_TRUE(queue.Dequeue(&frame_type, &producer, &weak_stream));
347 EXPECT_EQ(string(kRequeued), producer->ProduceBuffer()->GetRemainingData());
350 TEST_F(SpdyWriteQueueTest, ReentranceOnRemovePendingWritesForStream) {
351 scoped_ptr<SpdyStream> stream(MakeTestStream(DEFAULT_PRIORITY));
352 stream->set_stream_id(2);
354 SpdyWriteQueue queue;
355 queue.Enqueue(
356 DEFAULT_PRIORITY,
357 SYN_STREAM,
358 scoped_ptr<SpdyBufferProducer>(new RequeingBufferProducer(&queue)),
359 stream->GetWeakPtr());
361 queue.RemovePendingWritesForStream(stream->GetWeakPtr());
362 EXPECT_FALSE(queue.IsEmpty());
364 SpdyFrameType frame_type;
365 scoped_ptr<SpdyBufferProducer> producer;
366 base::WeakPtr<SpdyStream> weak_stream;
368 EXPECT_TRUE(queue.Dequeue(&frame_type, &producer, &weak_stream));
369 EXPECT_EQ(string(kRequeued), producer->ProduceBuffer()->GetRemainingData());
372 } // namespace
374 } // namespace net