diff options
Diffstat (limited to 'chromium/net/spdy/spdy_write_queue_unittest.cc')
-rw-r--r-- | chromium/net/spdy/spdy_write_queue_unittest.cc | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/chromium/net/spdy/spdy_write_queue_unittest.cc b/chromium/net/spdy/spdy_write_queue_unittest.cc new file mode 100644 index 00000000000..6d6cb3cd3b5 --- /dev/null +++ b/chromium/net/spdy/spdy_write_queue_unittest.cc @@ -0,0 +1,252 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "net/spdy/spdy_write_queue.h" + +#include <cstddef> +#include <cstring> +#include <string> + +#include "base/basictypes.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" +#include "net/base/net_log.h" +#include "net/base/request_priority.h" +#include "net/spdy/spdy_buffer_producer.h" +#include "net/spdy/spdy_stream.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace net { + +namespace { + +class SpdyWriteQueueTest : public ::testing::Test {}; + +// Makes a SpdyFrameProducer producing a frame with the data in the +// given string. +scoped_ptr<SpdyBufferProducer> StringToProducer(const std::string& s) { + scoped_ptr<char[]> data(new char[s.size()]); + std::memcpy(data.get(), s.data(), s.size()); + return scoped_ptr<SpdyBufferProducer>( + new SimpleBufferProducer( + scoped_ptr<SpdyBuffer>( + new SpdyBuffer( + scoped_ptr<SpdyFrame>( + new SpdyFrame(data.release(), s.size(), true)))))); +} + +// Makes a SpdyBufferProducer producing a frame with the data in the +// given int (converted to a string). +scoped_ptr<SpdyBufferProducer> IntToProducer(int i) { + return StringToProducer(base::IntToString(i)); +} + +// Produces a frame with the given producer and returns a copy of its +// data as a string. +std::string ProducerToString(scoped_ptr<SpdyBufferProducer> producer) { + scoped_ptr<SpdyBuffer> buffer = producer->ProduceBuffer(); + return std::string(buffer->GetRemainingData(), buffer->GetRemainingSize()); +} + +// Produces a frame with the given producer and returns a copy of its +// data as an int (converted from a string). +int ProducerToInt(scoped_ptr<SpdyBufferProducer> producer) { + int i = 0; + EXPECT_TRUE(base::StringToInt(ProducerToString(producer.Pass()), &i)); + return i; +} + +// Makes a SpdyStream with the given priority and a NULL SpdySession +// -- be careful to not call any functions that expect the session to +// be there. +SpdyStream* MakeTestStream(RequestPriority priority) { + return new SpdyStream( + SPDY_BIDIRECTIONAL_STREAM, base::WeakPtr<SpdySession>(), + GURL(), priority, 0, 0, BoundNetLog()); +} + +// Add some frame producers of different priority. The producers +// should be dequeued in priority order with their associated stream. +TEST_F(SpdyWriteQueueTest, DequeuesByPriority) { + SpdyWriteQueue write_queue; + + scoped_ptr<SpdyBufferProducer> producer_low = StringToProducer("LOW"); + scoped_ptr<SpdyBufferProducer> producer_medium = StringToProducer("MEDIUM"); + scoped_ptr<SpdyBufferProducer> producer_highest = StringToProducer("HIGHEST"); + + scoped_ptr<SpdyStream> stream_medium(MakeTestStream(MEDIUM)); + scoped_ptr<SpdyStream> stream_highest(MakeTestStream(HIGHEST)); + + // A NULL stream should still work. + write_queue.Enqueue( + LOW, SYN_STREAM, producer_low.Pass(), base::WeakPtr<SpdyStream>()); + write_queue.Enqueue( + MEDIUM, SYN_REPLY, producer_medium.Pass(), stream_medium->GetWeakPtr()); + write_queue.Enqueue( + HIGHEST, RST_STREAM, producer_highest.Pass(), + stream_highest->GetWeakPtr()); + + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(RST_STREAM, frame_type); + EXPECT_EQ("HIGHEST", ProducerToString(frame_producer.Pass())); + EXPECT_EQ(stream_highest, stream.get()); + + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(SYN_REPLY, frame_type); + EXPECT_EQ("MEDIUM", ProducerToString(frame_producer.Pass())); + EXPECT_EQ(stream_medium, stream.get()); + + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(SYN_STREAM, frame_type); + EXPECT_EQ("LOW", ProducerToString(frame_producer.Pass())); + EXPECT_EQ(NULL, stream.get()); + + EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); +} + +// Add some frame producers with the same priority. The producers +// should be dequeued in FIFO order with their associated stream. +TEST_F(SpdyWriteQueueTest, DequeuesFIFO) { + SpdyWriteQueue write_queue; + + scoped_ptr<SpdyBufferProducer> producer1 = IntToProducer(1); + scoped_ptr<SpdyBufferProducer> producer2 = IntToProducer(2); + scoped_ptr<SpdyBufferProducer> producer3 = IntToProducer(3); + + scoped_ptr<SpdyStream> stream1(MakeTestStream(DEFAULT_PRIORITY)); + scoped_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY)); + scoped_ptr<SpdyStream> stream3(MakeTestStream(DEFAULT_PRIORITY)); + + write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, producer1.Pass(), + stream1->GetWeakPtr()); + write_queue.Enqueue(DEFAULT_PRIORITY, SYN_REPLY, producer2.Pass(), + stream2->GetWeakPtr()); + write_queue.Enqueue(DEFAULT_PRIORITY, RST_STREAM, producer3.Pass(), + stream3->GetWeakPtr()); + + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(SYN_STREAM, frame_type); + EXPECT_EQ(1, ProducerToInt(frame_producer.Pass())); + EXPECT_EQ(stream1, stream.get()); + + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(SYN_REPLY, frame_type); + EXPECT_EQ(2, ProducerToInt(frame_producer.Pass())); + EXPECT_EQ(stream2, stream.get()); + + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(RST_STREAM, frame_type); + EXPECT_EQ(3, ProducerToInt(frame_producer.Pass())); + EXPECT_EQ(stream3, stream.get()); + + EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); +} + +// Enqueue a bunch of writes and then call +// RemovePendingWritesForStream() on one of the streams. No dequeued +// write should be for that stream. +TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStream) { + SpdyWriteQueue write_queue; + + scoped_ptr<SpdyStream> stream1(MakeTestStream(DEFAULT_PRIORITY)); + scoped_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY)); + + for (int i = 0; i < 100; ++i) { + base::WeakPtr<SpdyStream> stream = + (((i % 3) == 0) ? stream1 : stream2)->GetWeakPtr(); + write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i), stream); + } + + write_queue.RemovePendingWritesForStream(stream2->GetWeakPtr()); + + for (int i = 0; i < 100; i += 3) { + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); + EXPECT_EQ(SYN_STREAM, frame_type); + EXPECT_EQ(i, ProducerToInt(frame_producer.Pass())); + EXPECT_EQ(stream1, stream.get()); + } + + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); +} + +// Enqueue a bunch of writes and then call +// RemovePendingWritesForStreamsAfter(). No dequeued write should be for +// those streams without a stream id, or with a stream_id after that +// argument. +TEST_F(SpdyWriteQueueTest, RemovePendingWritesForStreamsAfter) { + SpdyWriteQueue write_queue; + + scoped_ptr<SpdyStream> stream1(MakeTestStream(DEFAULT_PRIORITY)); + stream1->set_stream_id(1); + scoped_ptr<SpdyStream> stream2(MakeTestStream(DEFAULT_PRIORITY)); + stream2->set_stream_id(3); + scoped_ptr<SpdyStream> stream3(MakeTestStream(DEFAULT_PRIORITY)); + stream3->set_stream_id(5); + // No stream id assigned. + scoped_ptr<SpdyStream> stream4(MakeTestStream(DEFAULT_PRIORITY)); + base::WeakPtr<SpdyStream> streams[] = { + stream1->GetWeakPtr(), stream2->GetWeakPtr(), + stream3->GetWeakPtr(), stream4->GetWeakPtr() + }; + + for (int i = 0; i < 100; ++i) { + write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i), + streams[i % arraysize(streams)]); + } + + write_queue.RemovePendingWritesForStreamsAfter(stream1->stream_id()); + + for (int i = 0; i < 100; i += arraysize(streams)) { + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + ASSERT_TRUE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)) + << "Unable to Dequeue i: " << i; + EXPECT_EQ(SYN_STREAM, frame_type); + EXPECT_EQ(i, ProducerToInt(frame_producer.Pass())); + EXPECT_EQ(stream1, stream.get()); + } + + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); +} + +// Enqueue a bunch of writes and then call Clear(). The write queue +// should clean up the memory properly, and Dequeue() should return +// false. +TEST_F(SpdyWriteQueueTest, Clear) { + SpdyWriteQueue write_queue; + + for (int i = 0; i < 100; ++i) { + write_queue.Enqueue(DEFAULT_PRIORITY, SYN_STREAM, IntToProducer(i), + base::WeakPtr<SpdyStream>()); + } + + write_queue.Clear(); + + SpdyFrameType frame_type = DATA; + scoped_ptr<SpdyBufferProducer> frame_producer; + base::WeakPtr<SpdyStream> stream; + EXPECT_FALSE(write_queue.Dequeue(&frame_type, &frame_producer, &stream)); +} + +} // namespace + +} // namespace net |