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. 4 5 #include "net/spdy/spdy_read_queue.h" 6 7 #include <algorithm> 8 #include <cstddef> 9 #include <string> 10 11 #include "base/memory/scoped_ptr.h" 12 #include "base/stl_util.h" 13 #include "net/spdy/spdy_buffer.h" 14 #include "testing/gtest/include/gtest/gtest.h" 15 16 namespace net { 17 18 namespace { 19 20 const char kData[] = "SPDY read queue test data.\0Some more data."; 21 const size_t kDataSize = arraysize(kData); 22 23 // Enqueues |data| onto |queue| in chunks of at most |max_buffer_size| 24 // bytes. 25 void EnqueueString(const std::string& data, 26 size_t max_buffer_size, 27 SpdyReadQueue* queue) { 28 ASSERT_GT(data.size(), 0u); 29 ASSERT_GT(max_buffer_size, 0u); 30 size_t old_total_size = queue->GetTotalSize(); 31 for (size_t i = 0; i < data.size();) { 32 size_t buffer_size = std::min(data.size() - i, max_buffer_size); 33 queue->Enqueue( 34 scoped_ptr<SpdyBuffer>(new SpdyBuffer(data.data() + i, buffer_size))); 35 i += buffer_size; 36 EXPECT_FALSE(queue->IsEmpty()); 37 EXPECT_EQ(old_total_size + i, queue->GetTotalSize()); 38 } 39 } 40 41 // Dequeues all bytes in |queue| in chunks of at most 42 // |max_buffer_size| bytes and returns the data as a string. 43 std::string DrainToString(size_t max_buffer_size, SpdyReadQueue* queue) { 44 std::string data; 45 46 // Pad the buffer so we can detect out-of-bound writes. 47 size_t padding = std::max(static_cast<size_t>(4096), queue->GetTotalSize()); 48 size_t buffer_size_with_padding = padding + max_buffer_size + padding; 49 scoped_ptr<char[]> buffer(new char[buffer_size_with_padding]); 50 std::memset(buffer.get(), 0, buffer_size_with_padding); 51 char* buffer_data = buffer.get() + padding; 52 53 while (!queue->IsEmpty()) { 54 size_t old_total_size = queue->GetTotalSize(); 55 EXPECT_GT(old_total_size, 0u); 56 size_t dequeued_bytes = queue->Dequeue(buffer_data, max_buffer_size); 57 58 // Make sure |queue| doesn't write past either end of its given 59 // boundaries. 60 for (int i = 1; i <= static_cast<int>(padding); ++i) { 61 EXPECT_EQ('\0', buffer_data[-i]) << -i; 62 } 63 for (size_t i = 0; i < padding; ++i) { 64 EXPECT_EQ('\0', buffer_data[max_buffer_size + i]) << i; 65 } 66 67 data.append(buffer_data, dequeued_bytes); 68 EXPECT_EQ(dequeued_bytes, std::min(max_buffer_size, dequeued_bytes)); 69 EXPECT_EQ(queue->GetTotalSize(), old_total_size - dequeued_bytes); 70 } 71 EXPECT_TRUE(queue->IsEmpty()); 72 return data; 73 } 74 75 // Enqueue a test string with the given enqueue/dequeue max buffer 76 // sizes. 77 void RunEnqueueDequeueTest(size_t enqueue_max_buffer_size, 78 size_t dequeue_max_buffer_size) { 79 std::string data(kData, kDataSize); 80 SpdyReadQueue read_queue; 81 EnqueueString(data, enqueue_max_buffer_size, &read_queue); 82 const std::string& drained_data = 83 DrainToString(dequeue_max_buffer_size, &read_queue); 84 EXPECT_EQ(data, drained_data); 85 } 86 87 class SpdyReadQueueTest : public ::testing::Test {}; 88 89 // Call RunEnqueueDequeueTest() with various buffer size combinatinos. 90 91 TEST_F(SpdyReadQueueTest, LargeEnqueueAndDequeueBuffers) { 92 RunEnqueueDequeueTest(2 * kDataSize, 2 * kDataSize); 93 } 94 95 TEST_F(SpdyReadQueueTest, OneByteEnqueueAndDequeueBuffers) { 96 RunEnqueueDequeueTest(1, 1); 97 } 98 99 TEST_F(SpdyReadQueueTest, CoprimeBufferSizes) { 100 RunEnqueueDequeueTest(2, 3); 101 RunEnqueueDequeueTest(3, 2); 102 } 103 104 } // namespace 105 106 } // namespace net 107