1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "net/spdy/spdy_write_queue.h"
6
7 #include <cstddef>
8 #include <cstring>
9 #include <string>
10 #include <utility>
11
12 #include "base/functional/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/notreached.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "net/base/request_priority.h"
17 #include "net/log/net_log_with_source.h"
18 #include "net/spdy/spdy_buffer_producer.h"
19 #include "net/spdy/spdy_stream.h"
20 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22 #include "url/gurl.h"
23
24 namespace net {
25
26 namespace {
27
28 const char kOriginal[] = "original";
29 const char kRequeued[] = "requeued";
30
31 class SpdyWriteQueueTest : public ::testing::Test {};
32
33 // Makes a SpdyFrameProducer producing a frame with the data in the
34 // given string.
StringToProducer(const std::string & s)35 std::unique_ptr<SpdyBufferProducer> StringToProducer(const std::string& s) {
36 auto data = std::make_unique<char[]>(s.size());
37 std::memcpy(data.get(), s.data(), s.size());
38 auto frame =
39 std::make_unique<spdy::SpdySerializedFrame>(std::move(data), s.size());
40 auto buffer = std::make_unique<SpdyBuffer>(std::move(frame));
41 return std::make_unique<SimpleBufferProducer>(std::move(buffer));
42 }
43
44 // Makes a SpdyBufferProducer producing a frame with the data in the
45 // given int (converted to a string).
IntToProducer(int i)46 std::unique_ptr<SpdyBufferProducer> IntToProducer(int i) {
47 return StringToProducer(base::NumberToString(i));
48 }
49
50 // Producer whose produced buffer will enqueue yet another buffer into the
51 // SpdyWriteQueue upon destruction.
52 class RequeingBufferProducer : public SpdyBufferProducer {
53 public:
RequeingBufferProducer(SpdyWriteQueue * queue)54 explicit RequeingBufferProducer(SpdyWriteQueue* queue) {
55 buffer_ = std::make_unique<SpdyBuffer>(kOriginal, std::size(kOriginal));
56 buffer_->AddConsumeCallback(
57 base::BindRepeating(RequeingBufferProducer::ConsumeCallback, queue));
58 }
59
ProduceBuffer()60 std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
61 return std::move(buffer_);
62 }
63
ConsumeCallback(SpdyWriteQueue * queue,size_t size,SpdyBuffer::ConsumeSource source)64 static void ConsumeCallback(SpdyWriteQueue* queue,
65 size_t size,
66 SpdyBuffer::ConsumeSource source) {
67 auto buffer = std::make_unique<SpdyBuffer>(kRequeued, std::size(kRequeued));
68 auto buffer_producer =
69 std::make_unique<SimpleBufferProducer>(std::move(buffer));
70
71 queue->Enqueue(MEDIUM, spdy::SpdyFrameType::RST_STREAM,
72 std::move(buffer_producer), base::WeakPtr<SpdyStream>(),
73 TRAFFIC_ANNOTATION_FOR_TESTS);
74 }
75
76 private:
77 std::unique_ptr<SpdyBuffer> buffer_;
78 };
79
80 // Produces a frame with the given producer and returns a copy of its
81 // data as a string.
ProducerToString(std::unique_ptr<SpdyBufferProducer> producer)82 std::string ProducerToString(std::unique_ptr<SpdyBufferProducer> producer) {
83 std::unique_ptr<SpdyBuffer> buffer = producer->ProduceBuffer();
84 return std::string(buffer->GetRemainingData(), buffer->GetRemainingSize());
85 }
86
87 // Produces a frame with the given producer and returns a copy of its
88 // data as an int (converted from a string).
ProducerToInt(std::unique_ptr<SpdyBufferProducer> producer)89 int ProducerToInt(std::unique_ptr<SpdyBufferProducer> producer) {
90 int i = 0;
91 EXPECT_TRUE(base::StringToInt(ProducerToString(std::move(producer)), &i));
92 return i;
93 }
94
95 // Makes a SpdyStream with the given priority and a NULL SpdySession
96 // -- be careful to not call any functions that expect the session to
97 // be there.
MakeTestStream(RequestPriority priority)98 std::unique_ptr<SpdyStream> MakeTestStream(RequestPriority priority) {
99 return std::make_unique<SpdyStream>(
100 SPDY_BIDIRECTIONAL_STREAM, base::WeakPtr<SpdySession>(), GURL(), priority,
101 0, 0, NetLogWithSource(), TRAFFIC_ANNOTATION_FOR_TESTS,
102 false /* detect_broken_connection */);
103 }
104
105 // Add some frame producers of different priority. The producers
106 // should be dequeued in priority order with their associated stream.
TEST_F(SpdyWriteQueueTest,DequeuesByPriority)107 TEST_F(SpdyWriteQueueTest, DequeuesByPriority) {
108 SpdyWriteQueue write_queue;
109
110 std::unique_ptr<SpdyBufferProducer> producer_low = StringToProducer("LOW");
111 std::unique_ptr<SpdyBufferProducer> producer_medium =
112 StringToProducer("MEDIUM");
113 std::unique_ptr<SpdyBufferProducer> producer_highest =
114 StringToProducer("HIGHEST");
115
116 std::unique_ptr<SpdyStream> stream_medium = MakeTestStream(MEDIUM);
117 std::unique_ptr<SpdyStream> stream_highest = MakeTestStream(HIGHEST);
118
119 // A NULL stream should still work.
120 write_queue.Enqueue(LOW, spdy::SpdyFrameType::HEADERS,
121 std::move(producer_low), base::WeakPtr<SpdyStream>(),
122 TRAFFIC_ANNOTATION_FOR_TESTS);
123 write_queue.Enqueue(MEDIUM, spdy::SpdyFrameType::HEADERS,
124 std::move(producer_medium), stream_medium->GetWeakPtr(),
125 TRAFFIC_ANNOTATION_FOR_TESTS);
126 write_queue.Enqueue(HIGHEST, spdy::SpdyFrameType::RST_STREAM,
127 std::move(producer_highest), stream_highest->GetWeakPtr(),
128 TRAFFIC_ANNOTATION_FOR_TESTS);
129
130 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
131 std::unique_ptr<SpdyBufferProducer> frame_producer;
132 base::WeakPtr<SpdyStream> stream;
133 MutableNetworkTrafficAnnotationTag traffic_annotation;
134 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
135 &traffic_annotation));
136 EXPECT_EQ(spdy::SpdyFrameType::RST_STREAM, frame_type);
137 EXPECT_EQ("HIGHEST", ProducerToString(std::move(frame_producer)));
138 EXPECT_EQ(stream_highest.get(), stream.get());
139
140 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
141 &traffic_annotation));
142 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
143 EXPECT_EQ("MEDIUM", ProducerToString(std::move(frame_producer)));
144 EXPECT_EQ(stream_medium.get(), stream.get());
145
146 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
147 &traffic_annotation));
148 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
149 EXPECT_EQ("LOW", ProducerToString(std::move(frame_producer)));
150 EXPECT_EQ(nullptr, stream.get());
151
152 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
153 &traffic_annotation));
154 }
155
156 // Add some frame producers with the same priority. The producers
157 // should be dequeued in FIFO order with their associated stream.
TEST_F(SpdyWriteQueueTest,DequeuesFIFO)158 TEST_F(SpdyWriteQueueTest, DequeuesFIFO) {
159 SpdyWriteQueue write_queue;
160
161 std::unique_ptr<SpdyBufferProducer> producer1 = IntToProducer(1);
162 std::unique_ptr<SpdyBufferProducer> producer2 = IntToProducer(2);
163 std::unique_ptr<SpdyBufferProducer> producer3 = IntToProducer(3);
164
165 std::unique_ptr<SpdyStream> stream1 = MakeTestStream(DEFAULT_PRIORITY);
166 std::unique_ptr<SpdyStream> stream2 = MakeTestStream(DEFAULT_PRIORITY);
167 std::unique_ptr<SpdyStream> stream3 = MakeTestStream(DEFAULT_PRIORITY);
168
169 write_queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
170 std::move(producer1), stream1->GetWeakPtr(),
171 TRAFFIC_ANNOTATION_FOR_TESTS);
172 write_queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
173 std::move(producer2), stream2->GetWeakPtr(),
174 TRAFFIC_ANNOTATION_FOR_TESTS);
175 write_queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::RST_STREAM,
176 std::move(producer3), stream3->GetWeakPtr(),
177 TRAFFIC_ANNOTATION_FOR_TESTS);
178
179 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
180 std::unique_ptr<SpdyBufferProducer> frame_producer;
181 base::WeakPtr<SpdyStream> stream;
182 MutableNetworkTrafficAnnotationTag traffic_annotation;
183 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
184 &traffic_annotation));
185 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
186 EXPECT_EQ(1, ProducerToInt(std::move(frame_producer)));
187 EXPECT_EQ(stream1.get(), stream.get());
188
189 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
190 &traffic_annotation));
191 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
192 EXPECT_EQ(2, ProducerToInt(std::move(frame_producer)));
193 EXPECT_EQ(stream2.get(), stream.get());
194
195 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
196 &traffic_annotation));
197 EXPECT_EQ(spdy::SpdyFrameType::RST_STREAM, frame_type);
198 EXPECT_EQ(3, ProducerToInt(std::move(frame_producer)));
199 EXPECT_EQ(stream3.get(), stream.get());
200
201 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
202 &traffic_annotation));
203 }
204
205 // Enqueue a bunch of writes and then call
206 // RemovePendingWritesForStream() on one of the streams. No dequeued
207 // write should be for that stream.
TEST_F(SpdyWriteQueueTest,RemovePendingWritesForStream)208 TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStream) {
209 SpdyWriteQueue write_queue;
210
211 std::unique_ptr<SpdyStream> stream1 = MakeTestStream(DEFAULT_PRIORITY);
212 std::unique_ptr<SpdyStream> stream2 = MakeTestStream(DEFAULT_PRIORITY);
213
214 for (int i = 0; i < 100; ++i) {
215 base::WeakPtr<SpdyStream> stream =
216 (((i % 3) == 0) ? stream1 : stream2)->GetWeakPtr();
217 write_queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
218 IntToProducer(i), stream, TRAFFIC_ANNOTATION_FOR_TESTS);
219 }
220
221 write_queue.RemovePendingWritesForStream(stream2.get());
222
223 for (int i = 0; i < 100; i += 3) {
224 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
225 std::unique_ptr<SpdyBufferProducer> frame_producer;
226 base::WeakPtr<SpdyStream> stream;
227 MutableNetworkTrafficAnnotationTag traffic_annotation;
228 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
229 &traffic_annotation));
230 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
231 EXPECT_EQ(i, ProducerToInt(std::move(frame_producer)));
232 EXPECT_EQ(stream1.get(), stream.get());
233 EXPECT_EQ(MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
234 traffic_annotation);
235 }
236
237 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
238 std::unique_ptr<SpdyBufferProducer> frame_producer;
239 base::WeakPtr<SpdyStream> stream;
240 MutableNetworkTrafficAnnotationTag traffic_annotation;
241 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
242 &traffic_annotation));
243 }
244
245 // Enqueue a bunch of writes and then call
246 // RemovePendingWritesForStreamsAfter(). No dequeued write should be for
247 // those streams without a stream id, or with a stream_id after that
248 // argument.
TEST_F(SpdyWriteQueueTest,RemovePendingWritesForStreamsAfter)249 TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStreamsAfter) {
250 SpdyWriteQueue write_queue;
251
252 std::unique_ptr<SpdyStream> stream1 = MakeTestStream(DEFAULT_PRIORITY);
253 stream1->set_stream_id(1);
254 std::unique_ptr<SpdyStream> stream2 = MakeTestStream(DEFAULT_PRIORITY);
255 stream2->set_stream_id(3);
256 std::unique_ptr<SpdyStream> stream3 = MakeTestStream(DEFAULT_PRIORITY);
257 stream3->set_stream_id(5);
258 // No stream id assigned.
259 std::unique_ptr<SpdyStream> stream4 = MakeTestStream(DEFAULT_PRIORITY);
260 base::WeakPtr<SpdyStream> streams[] = {
261 stream1->GetWeakPtr(), stream2->GetWeakPtr(),
262 stream3->GetWeakPtr(), stream4->GetWeakPtr()
263 };
264
265 for (int i = 0; i < 100; ++i) {
266 write_queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
267 IntToProducer(i), streams[i % std::size(streams)],
268 TRAFFIC_ANNOTATION_FOR_TESTS);
269 }
270
271 write_queue.RemovePendingWritesForStreamsAfter(stream1->stream_id());
272
273 for (int i = 0; i < 100; i += std::size(streams)) {
274 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
275 std::unique_ptr<SpdyBufferProducer> frame_producer;
276 base::WeakPtr<SpdyStream> stream;
277 MutableNetworkTrafficAnnotationTag traffic_annotation;
278 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
279 &traffic_annotation))
280 << "Unable to Dequeue i: " << i;
281 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
282 EXPECT_EQ(i, ProducerToInt(std::move(frame_producer)));
283 EXPECT_EQ(stream1.get(), stream.get());
284 EXPECT_EQ(MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS),
285 traffic_annotation);
286 }
287
288 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
289 std::unique_ptr<SpdyBufferProducer> frame_producer;
290 base::WeakPtr<SpdyStream> stream;
291 MutableNetworkTrafficAnnotationTag traffic_annotation;
292 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
293 &traffic_annotation));
294 }
295
296 // Enqueue a bunch of writes and then call Clear(). The write queue
297 // should clean up the memory properly, and Dequeue() should return
298 // false.
TEST_F(SpdyWriteQueueTest,Clear)299 TEST_F(SpdyWriteQueueTest, Clear) {
300 SpdyWriteQueue write_queue;
301
302 for (int i = 0; i < 100; ++i) {
303 write_queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
304 IntToProducer(i), base::WeakPtr<SpdyStream>(),
305 TRAFFIC_ANNOTATION_FOR_TESTS);
306 }
307
308 write_queue.Clear();
309
310 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
311 std::unique_ptr<SpdyBufferProducer> frame_producer;
312 base::WeakPtr<SpdyStream> stream;
313 MutableNetworkTrafficAnnotationTag traffic_annotation;
314 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
315 &traffic_annotation));
316 }
317
TEST_F(SpdyWriteQueueTest,RequeingProducerWithoutReentrance)318 TEST_F(SpdyWriteQueueTest, RequeingProducerWithoutReentrance) {
319 SpdyWriteQueue queue;
320 queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
321 std::make_unique<RequeingBufferProducer>(&queue),
322 base::WeakPtr<SpdyStream>(), TRAFFIC_ANNOTATION_FOR_TESTS);
323 {
324 spdy::SpdyFrameType frame_type;
325 std::unique_ptr<SpdyBufferProducer> producer;
326 base::WeakPtr<SpdyStream> stream;
327 MutableNetworkTrafficAnnotationTag traffic_annotation;
328
329 EXPECT_TRUE(
330 queue.Dequeue(&frame_type, &producer, &stream, &traffic_annotation));
331 EXPECT_TRUE(queue.IsEmpty());
332 EXPECT_EQ(std::string(kOriginal),
333 producer->ProduceBuffer()->GetRemainingData());
334 }
335 // |producer| was destroyed, and a buffer is re-queued.
336 EXPECT_FALSE(queue.IsEmpty());
337
338 spdy::SpdyFrameType frame_type;
339 std::unique_ptr<SpdyBufferProducer> producer;
340 base::WeakPtr<SpdyStream> stream;
341 MutableNetworkTrafficAnnotationTag traffic_annotation;
342
343 EXPECT_TRUE(
344 queue.Dequeue(&frame_type, &producer, &stream, &traffic_annotation));
345 EXPECT_EQ(std::string(kRequeued),
346 producer->ProduceBuffer()->GetRemainingData());
347 }
348
TEST_F(SpdyWriteQueueTest,ReentranceOnClear)349 TEST_F(SpdyWriteQueueTest, ReentranceOnClear) {
350 SpdyWriteQueue queue;
351 queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
352 std::make_unique<RequeingBufferProducer>(&queue),
353 base::WeakPtr<SpdyStream>(), TRAFFIC_ANNOTATION_FOR_TESTS);
354
355 queue.Clear();
356 EXPECT_FALSE(queue.IsEmpty());
357
358 spdy::SpdyFrameType frame_type;
359 std::unique_ptr<SpdyBufferProducer> producer;
360 base::WeakPtr<SpdyStream> stream;
361 MutableNetworkTrafficAnnotationTag traffic_annotation;
362
363 EXPECT_TRUE(
364 queue.Dequeue(&frame_type, &producer, &stream, &traffic_annotation));
365 EXPECT_EQ(std::string(kRequeued),
366 producer->ProduceBuffer()->GetRemainingData());
367 }
368
TEST_F(SpdyWriteQueueTest,ReentranceOnRemovePendingWritesAfter)369 TEST_F(SpdyWriteQueueTest, ReentranceOnRemovePendingWritesAfter) {
370 std::unique_ptr<SpdyStream> stream = MakeTestStream(DEFAULT_PRIORITY);
371 stream->set_stream_id(2);
372
373 SpdyWriteQueue queue;
374 queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
375 std::make_unique<RequeingBufferProducer>(&queue),
376 stream->GetWeakPtr(), TRAFFIC_ANNOTATION_FOR_TESTS);
377
378 queue.RemovePendingWritesForStreamsAfter(1);
379 EXPECT_FALSE(queue.IsEmpty());
380
381 spdy::SpdyFrameType frame_type;
382 std::unique_ptr<SpdyBufferProducer> producer;
383 base::WeakPtr<SpdyStream> weak_stream;
384 MutableNetworkTrafficAnnotationTag traffic_annotation;
385
386 EXPECT_TRUE(
387 queue.Dequeue(&frame_type, &producer, &weak_stream, &traffic_annotation));
388 EXPECT_EQ(std::string(kRequeued),
389 producer->ProduceBuffer()->GetRemainingData());
390 }
391
TEST_F(SpdyWriteQueueTest,ReentranceOnRemovePendingWritesForStream)392 TEST_F(SpdyWriteQueueTest, ReentranceOnRemovePendingWritesForStream) {
393 std::unique_ptr<SpdyStream> stream = MakeTestStream(DEFAULT_PRIORITY);
394 stream->set_stream_id(2);
395
396 SpdyWriteQueue queue;
397 queue.Enqueue(DEFAULT_PRIORITY, spdy::SpdyFrameType::HEADERS,
398 std::make_unique<RequeingBufferProducer>(&queue),
399 stream->GetWeakPtr(), TRAFFIC_ANNOTATION_FOR_TESTS);
400
401 queue.RemovePendingWritesForStream(stream.get());
402 EXPECT_FALSE(queue.IsEmpty());
403
404 spdy::SpdyFrameType frame_type;
405 std::unique_ptr<SpdyBufferProducer> producer;
406 base::WeakPtr<SpdyStream> weak_stream;
407 MutableNetworkTrafficAnnotationTag traffic_annotation;
408
409 EXPECT_TRUE(
410 queue.Dequeue(&frame_type, &producer, &weak_stream, &traffic_annotation));
411 EXPECT_EQ(std::string(kRequeued),
412 producer->ProduceBuffer()->GetRemainingData());
413 }
414
TEST_F(SpdyWriteQueueTest,ChangePriority)415 TEST_F(SpdyWriteQueueTest, ChangePriority) {
416 SpdyWriteQueue write_queue;
417
418 std::unique_ptr<SpdyBufferProducer> producer1 = IntToProducer(1);
419 std::unique_ptr<SpdyBufferProducer> producer2 = IntToProducer(2);
420 std::unique_ptr<SpdyBufferProducer> producer3 = IntToProducer(3);
421
422 std::unique_ptr<SpdyStream> stream1 = MakeTestStream(HIGHEST);
423 std::unique_ptr<SpdyStream> stream2 = MakeTestStream(MEDIUM);
424 std::unique_ptr<SpdyStream> stream3 = MakeTestStream(LOW);
425
426 write_queue.Enqueue(HIGHEST, spdy::SpdyFrameType::HEADERS,
427 std::move(producer1), stream1->GetWeakPtr(),
428 TRAFFIC_ANNOTATION_FOR_TESTS);
429 write_queue.Enqueue(MEDIUM, spdy::SpdyFrameType::DATA, std::move(producer2),
430 stream2->GetWeakPtr(), TRAFFIC_ANNOTATION_FOR_TESTS);
431 write_queue.Enqueue(LOW, spdy::SpdyFrameType::RST_STREAM,
432 std::move(producer3), stream3->GetWeakPtr(),
433 TRAFFIC_ANNOTATION_FOR_TESTS);
434
435 write_queue.ChangePriorityOfWritesForStream(stream3.get(), LOW, HIGHEST);
436
437 spdy::SpdyFrameType frame_type = spdy::SpdyFrameType::DATA;
438 std::unique_ptr<SpdyBufferProducer> frame_producer;
439 base::WeakPtr<SpdyStream> stream;
440 MutableNetworkTrafficAnnotationTag traffic_annotation;
441 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
442 &traffic_annotation));
443 EXPECT_EQ(spdy::SpdyFrameType::HEADERS, frame_type);
444 EXPECT_EQ(1, ProducerToInt(std::move(frame_producer)));
445 EXPECT_EQ(stream1.get(), stream.get());
446
447 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
448 &traffic_annotation));
449 EXPECT_EQ(spdy::SpdyFrameType::RST_STREAM, frame_type);
450 EXPECT_EQ(3, ProducerToInt(std::move(frame_producer)));
451 EXPECT_EQ(stream3.get(), stream.get());
452
453 ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
454 &traffic_annotation));
455 EXPECT_EQ(spdy::SpdyFrameType::DATA, frame_type);
456 EXPECT_EQ(2, ProducerToInt(std::move(frame_producer)));
457 EXPECT_EQ(stream2.get(), stream.get());
458
459 EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream,
460 &traffic_annotation));
461 }
462
463 } // namespace
464
465 } // namespace net
466