xref: /5.5.2/platform/tests/pipe_test/pipe_test.cc (revision 1ebd7828)
1/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2017 Couchbase, Inc.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17
18#include <platform/pipe.h>
19
20#include <gtest/gtest.h>
21
22class PipeTest : public ::testing::Test {
23protected:
24    cb::Pipe buffer;
25};
26
27TEST_F(PipeTest, DefaultSize) {
28    EXPECT_EQ(2048, buffer.produce([](void*, size_t size) -> ssize_t {
29        return size;
30    }));
31    EXPECT_EQ(2048, buffer.consume([](const void*, size_t size) -> ssize_t {
32        return size;
33    }));
34    EXPECT_TRUE(buffer.empty());
35}
36
37TEST_F(PipeTest, EnsureCapacity) {
38    buffer.ensureCapacity(100);
39    EXPECT_EQ(buffer.capacity(), buffer.wsize());
40
41    size_t capacity = buffer.capacity();
42    buffer.produce([capacity](void*, size_t size) -> ssize_t {
43        EXPECT_EQ(capacity, size);
44        return 0;
45    });
46
47    buffer.consume([](const void*, size_t size) -> ssize_t {
48        // It should be empty..
49        EXPECT_EQ(0u, size);
50        return 0;
51    });
52    EXPECT_EQ(0u, buffer.rsize());
53
54    // Make sure that it keep the data between the iterations, even if it isn't
55    // at the beginning of the buffer
56    const std::string message{"hello world"};
57    buffer.produce([&message](cb::byte_buffer buffer) -> ssize_t {
58        std::copy(message.begin(), message.end(), buffer.data());
59        return message.size();
60    });
61
62    EXPECT_EQ(message.size(), buffer.rsize());
63    EXPECT_EQ(buffer.capacity() - message.size(), buffer.wsize());
64
65    // Read out some of the data
66    buffer.consume([](const void*, size_t size) -> ssize_t {
67        return 6; // "hello "
68    });
69
70    EXPECT_EQ(5u, buffer.rsize()); // The buffer should still contain world
71    EXPECT_EQ(buffer.capacity() - message.size(), buffer.wsize());
72
73    buffer.ensureCapacity(3000);
74    // the buffer should have been doubled in size
75    EXPECT_EQ(capacity * 2, buffer.capacity());
76    capacity = buffer.capacity();
77    buffer.produce([capacity](void*, size_t size) -> ssize_t {
78        // the reallocation should be doubled, and the memory in the old
79        // buffer was moved to the beginning of the buffer so that we've
80        // freed up the data we've already consumed.
81        EXPECT_EQ(capacity - 5, size);
82        return 0;
83    });
84
85    // Make sure that the data was persisted across the move
86    buffer.consume([](cb::const_byte_buffer buffer) -> ssize_t {
87        const std::string data{reinterpret_cast<const char*>(buffer.data()),
88                               buffer.size()};
89        EXPECT_EQ("world", data);
90        return data.length();
91    });
92}
93
94TEST_F(PipeTest, ProduceOverfow) {
95    buffer.ensureCapacity(100);
96    EXPECT_THROW(buffer.produce([](void*, size_t size) -> ssize_t {
97        return size + 1;
98    }),
99                 std::logic_error);
100}
101
102TEST_F(PipeTest, ConsumeOverfow) {
103    buffer.ensureCapacity(100);
104    EXPECT_THROW(buffer.consume([](const void*, size_t size) -> ssize_t {
105        return size + 1;
106    }),
107                 std::logic_error);
108}
109
110TEST_F(PipeTest, ProduceConsume) {
111    buffer.ensureCapacity(100);
112    const auto capacity = buffer.capacity();
113    EXPECT_EQ(3u, buffer.produce([capacity](void* ptr, size_t size) -> ssize_t {
114        EXPECT_EQ(capacity, size);
115        ::memcpy(ptr, "abc", 3);
116        return 3;
117    }));
118
119    // We should have occupied 3 elements
120    buffer.produce([capacity](void* ptr, size_t size) -> ssize_t {
121        EXPECT_EQ(capacity - 3, size);
122        return 0;
123    });
124
125    // And 3 available..
126    buffer.consume([](const void* ptr, size_t size) -> ssize_t {
127        EXPECT_EQ(3u, size);
128
129        // Let's read out the first (which should be an a)
130        EXPECT_EQ('a', *static_cast<const char*>(ptr));
131        return 1;
132    });
133
134    // We've consumed only 1 byte so the produce space is unchanged,
135    // but the consumer space is less
136    buffer.produce([capacity](void* ptr, size_t size) -> ssize_t {
137        EXPECT_EQ(capacity - 3, size);
138        return 0;
139    });
140
141    buffer.consume([](const void* ptr, size_t size) -> ssize_t {
142        EXPECT_EQ(2u, size);
143        // Let's read out the first (which should be an b)
144        EXPECT_EQ('b', *static_cast<const char*>(ptr));
145        return 1;
146    });
147
148    // We've consumed only 1 byte so the produce space is unchanged,
149    // but the consumer space is less
150    buffer.produce([capacity](void* ptr, size_t size) -> ssize_t {
151        EXPECT_EQ(capacity - 3, size);
152        return 0;
153    });
154
155    buffer.consume([](const void* ptr, size_t size) -> ssize_t {
156        EXPECT_EQ(1u, size);
157        // Let's read out the first (which should be an c)
158        EXPECT_EQ('c', *static_cast<const char*>(ptr));
159        // But let's not consume it at this time
160        return 0;
161    });
162
163    // Let's pack the buffer.. that should move the bytes and leave
164    // the entire capacity minus one element available in the buffer.
165    // pack() returns true if the pipe is empty.
166    EXPECT_FALSE(buffer.pack());
167    buffer.produce([capacity](void* ptr, size_t size) -> ssize_t {
168        // Everything should have been moved to the front..
169        EXPECT_EQ(capacity - 1, size);
170        return 0;
171    });
172
173    buffer.consume([](const void* ptr, size_t size) -> ssize_t {
174        EXPECT_EQ(1u, size);
175        // Let's read out the first (which should be an c)
176        EXPECT_EQ('c', *static_cast<const char*>(ptr));
177        return 1;
178    });
179
180    // The pipe should be empty now..
181    EXPECT_TRUE(buffer.empty());
182
183    // And trying to pack it should return true
184    EXPECT_TRUE(buffer.pack());
185
186    // And we should be able to insert the initial capacity number of items
187    EXPECT_EQ(capacity, buffer.wsize());
188    buffer.produce([capacity](void* ptr, size_t size) -> ssize_t {
189        EXPECT_EQ(capacity, size);
190        return 0;
191    });
192}
193
194TEST_F(PipeTest, RellocationSizes) {
195    cb::Pipe pipe;
196
197    // Verify that we always double the size of the buffer
198    for (int ii = 1; ii < 8; ii++) {
199        EXPECT_EQ(2048u << ii, pipe.ensureCapacity(pipe.capacity() + 1));
200    }
201}
202