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