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"
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/net_log.h"
16 #include "net/base/request_priority.h"
17 #include "net/spdy/spdy_buffer_producer.h"
18 #include "net/spdy/spdy_stream.h"
19 #include "testing/gtest/include/gtest/gtest.h"
26 class SpdyWriteQueueTest
: public ::testing::Test
{};
28 // Makes a SpdyFrameProducer producing a frame with the data in the
30 scoped_ptr
<SpdyBufferProducer
> StringToProducer(const std::string
& s
) {
31 scoped_ptr
<char[]> data(new char[s
.size()]);
32 std::memcpy(data
.get(), s
.data(), s
.size());
33 return scoped_ptr
<SpdyBufferProducer
>(
34 new SimpleBufferProducer(
35 scoped_ptr
<SpdyBuffer
>(
37 scoped_ptr
<SpdyFrame
>(
38 new SpdyFrame(data
.release(), s
.size(), true))))));
41 // Makes a SpdyBufferProducer producing a frame with the data in the
42 // given int (converted to a string).
43 scoped_ptr
<SpdyBufferProducer
> IntToProducer(int i
) {
44 return StringToProducer(base::IntToString(i
));
47 // Produces a frame with the given producer and returns a copy of its
49 std::string
ProducerToString(scoped_ptr
<SpdyBufferProducer
> producer
) {
50 scoped_ptr
<SpdyBuffer
> buffer
= producer
->ProduceBuffer();
51 return std::string(buffer
->GetRemainingData(), buffer
->GetRemainingSize());
54 // Produces a frame with the given producer and returns a copy of its
55 // data as an int (converted from a string).
56 int ProducerToInt(scoped_ptr
<SpdyBufferProducer
> producer
) {
58 EXPECT_TRUE(base::StringToInt(ProducerToString(producer
.Pass()), &i
));
62 // Makes a SpdyStream with the given priority and a NULL SpdySession
63 // -- be careful to not call any functions that expect the session to
65 SpdyStream
* MakeTestStream(RequestPriority priority
) {
66 return new SpdyStream(
67 SPDY_BIDIRECTIONAL_STREAM
, base::WeakPtr
<SpdySession
>(),
68 GURL(), priority
, 0, 0, BoundNetLog());
71 // Add some frame producers of different priority. The producers
72 // should be dequeued in priority order with their associated stream.
73 TEST_F(SpdyWriteQueueTest
, DequeuesByPriority
) {
74 SpdyWriteQueue write_queue
;
76 scoped_ptr
<SpdyBufferProducer
> producer_low
= StringToProducer("LOW");
77 scoped_ptr
<SpdyBufferProducer
> producer_medium
= StringToProducer("MEDIUM");
78 scoped_ptr
<SpdyBufferProducer
> producer_highest
= StringToProducer("HIGHEST");
80 scoped_ptr
<SpdyStream
> stream_medium(MakeTestStream(MEDIUM
));
81 scoped_ptr
<SpdyStream
> stream_highest(MakeTestStream(HIGHEST
));
83 // A NULL stream should still work.
85 LOW
, SYN_STREAM
, producer_low
.Pass(), base::WeakPtr
<SpdyStream
>());
87 MEDIUM
, SYN_REPLY
, producer_medium
.Pass(), stream_medium
->GetWeakPtr());
89 HIGHEST
, RST_STREAM
, producer_highest
.Pass(),
90 stream_highest
->GetWeakPtr());
92 SpdyFrameType frame_type
= DATA
;
93 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
94 base::WeakPtr
<SpdyStream
> stream
;
95 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
96 EXPECT_EQ(RST_STREAM
, frame_type
);
97 EXPECT_EQ("HIGHEST", ProducerToString(frame_producer
.Pass()));
98 EXPECT_EQ(stream_highest
, stream
.get());
100 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
101 EXPECT_EQ(SYN_REPLY
, frame_type
);
102 EXPECT_EQ("MEDIUM", ProducerToString(frame_producer
.Pass()));
103 EXPECT_EQ(stream_medium
, stream
.get());
105 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
106 EXPECT_EQ(SYN_STREAM
, frame_type
);
107 EXPECT_EQ("LOW", ProducerToString(frame_producer
.Pass()));
108 EXPECT_EQ(NULL
, stream
.get());
110 EXPECT_FALSE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
113 // Add some frame producers with the same priority. The producers
114 // should be dequeued in FIFO order with their associated stream.
115 TEST_F(SpdyWriteQueueTest
, DequeuesFIFO
) {
116 SpdyWriteQueue write_queue
;
118 scoped_ptr
<SpdyBufferProducer
> producer1
= IntToProducer(1);
119 scoped_ptr
<SpdyBufferProducer
> producer2
= IntToProducer(2);
120 scoped_ptr
<SpdyBufferProducer
> producer3
= IntToProducer(3);
122 scoped_ptr
<SpdyStream
> stream1(MakeTestStream(DEFAULT_PRIORITY
));
123 scoped_ptr
<SpdyStream
> stream2(MakeTestStream(DEFAULT_PRIORITY
));
124 scoped_ptr
<SpdyStream
> stream3(MakeTestStream(DEFAULT_PRIORITY
));
126 write_queue
.Enqueue(DEFAULT_PRIORITY
, SYN_STREAM
, producer1
.Pass(),
127 stream1
->GetWeakPtr());
128 write_queue
.Enqueue(DEFAULT_PRIORITY
, SYN_REPLY
, producer2
.Pass(),
129 stream2
->GetWeakPtr());
130 write_queue
.Enqueue(DEFAULT_PRIORITY
, RST_STREAM
, producer3
.Pass(),
131 stream3
->GetWeakPtr());
133 SpdyFrameType frame_type
= DATA
;
134 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
135 base::WeakPtr
<SpdyStream
> stream
;
136 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
137 EXPECT_EQ(SYN_STREAM
, frame_type
);
138 EXPECT_EQ(1, ProducerToInt(frame_producer
.Pass()));
139 EXPECT_EQ(stream1
, stream
.get());
141 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
142 EXPECT_EQ(SYN_REPLY
, frame_type
);
143 EXPECT_EQ(2, ProducerToInt(frame_producer
.Pass()));
144 EXPECT_EQ(stream2
, stream
.get());
146 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
147 EXPECT_EQ(RST_STREAM
, frame_type
);
148 EXPECT_EQ(3, ProducerToInt(frame_producer
.Pass()));
149 EXPECT_EQ(stream3
, stream
.get());
151 EXPECT_FALSE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
154 // Enqueue a bunch of writes and then call
155 // RemovePendingWritesForStream() on one of the streams. No dequeued
156 // write should be for that stream.
157 TEST_F(SpdyWriteQueueTest
, RemovePendingWritesForStream
) {
158 SpdyWriteQueue write_queue
;
160 scoped_ptr
<SpdyStream
> stream1(MakeTestStream(DEFAULT_PRIORITY
));
161 scoped_ptr
<SpdyStream
> stream2(MakeTestStream(DEFAULT_PRIORITY
));
163 for (int i
= 0; i
< 100; ++i
) {
164 base::WeakPtr
<SpdyStream
> stream
=
165 (((i
% 3) == 0) ? stream1
: stream2
)->GetWeakPtr();
166 write_queue
.Enqueue(DEFAULT_PRIORITY
, SYN_STREAM
, IntToProducer(i
), stream
);
169 write_queue
.RemovePendingWritesForStream(stream2
->GetWeakPtr());
171 for (int i
= 0; i
< 100; i
+= 3) {
172 SpdyFrameType frame_type
= DATA
;
173 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
174 base::WeakPtr
<SpdyStream
> stream
;
175 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
176 EXPECT_EQ(SYN_STREAM
, frame_type
);
177 EXPECT_EQ(i
, ProducerToInt(frame_producer
.Pass()));
178 EXPECT_EQ(stream1
, stream
.get());
181 SpdyFrameType frame_type
= DATA
;
182 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
183 base::WeakPtr
<SpdyStream
> stream
;
184 EXPECT_FALSE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
187 // Enqueue a bunch of writes and then call
188 // RemovePendingWritesForStreamsAfter(). No dequeued write should be for
189 // those streams without a stream id, or with a stream_id after that
191 TEST_F(SpdyWriteQueueTest
, RemovePendingWritesForStreamsAfter
) {
192 SpdyWriteQueue write_queue
;
194 scoped_ptr
<SpdyStream
> stream1(MakeTestStream(DEFAULT_PRIORITY
));
195 stream1
->set_stream_id(1);
196 scoped_ptr
<SpdyStream
> stream2(MakeTestStream(DEFAULT_PRIORITY
));
197 stream2
->set_stream_id(3);
198 scoped_ptr
<SpdyStream
> stream3(MakeTestStream(DEFAULT_PRIORITY
));
199 stream3
->set_stream_id(5);
200 // No stream id assigned.
201 scoped_ptr
<SpdyStream
> stream4(MakeTestStream(DEFAULT_PRIORITY
));
202 base::WeakPtr
<SpdyStream
> streams
[] = {
203 stream1
->GetWeakPtr(), stream2
->GetWeakPtr(),
204 stream3
->GetWeakPtr(), stream4
->GetWeakPtr()
207 for (int i
= 0; i
< 100; ++i
) {
208 write_queue
.Enqueue(DEFAULT_PRIORITY
, SYN_STREAM
, IntToProducer(i
),
209 streams
[i
% arraysize(streams
)]);
212 write_queue
.RemovePendingWritesForStreamsAfter(stream1
->stream_id());
214 for (int i
= 0; i
< 100; i
+= arraysize(streams
)) {
215 SpdyFrameType frame_type
= DATA
;
216 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
217 base::WeakPtr
<SpdyStream
> stream
;
218 ASSERT_TRUE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
))
219 << "Unable to Dequeue i: " << i
;
220 EXPECT_EQ(SYN_STREAM
, frame_type
);
221 EXPECT_EQ(i
, ProducerToInt(frame_producer
.Pass()));
222 EXPECT_EQ(stream1
, stream
.get());
225 SpdyFrameType frame_type
= DATA
;
226 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
227 base::WeakPtr
<SpdyStream
> stream
;
228 EXPECT_FALSE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));
231 // Enqueue a bunch of writes and then call Clear(). The write queue
232 // should clean up the memory properly, and Dequeue() should return
234 TEST_F(SpdyWriteQueueTest
, Clear
) {
235 SpdyWriteQueue write_queue
;
237 for (int i
= 0; i
< 100; ++i
) {
238 write_queue
.Enqueue(DEFAULT_PRIORITY
, SYN_STREAM
, IntToProducer(i
),
239 base::WeakPtr
<SpdyStream
>());
244 SpdyFrameType frame_type
= DATA
;
245 scoped_ptr
<SpdyBufferProducer
> frame_producer
;
246 base::WeakPtr
<SpdyStream
> stream
;
247 EXPECT_FALSE(write_queue
.Dequeue(&frame_type
, &frame_producer
, &stream
));