blob: 53e5d15e010227ac64eb7a94db3406f11833c04d [file] [log] [blame]
David Reissea2cba82009-03-30 21:35:00 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
Christopher Friedtedcad982020-06-18 21:50:54 -040020#include <array>
zeshuai0076b1cb302020-05-27 12:08:01 +080021#include <boost/test/unit_test.hpp>
David Reiss2dc72c32007-08-21 23:59:34 +000022#include <climits>
Christopher Friedtedcad982020-06-18 21:50:54 -040023#include <cstdlib>
24#include <iostream>
cyy316723a2019-01-05 16:35:14 +080025#include <memory>
Christopher Friedtedcad982020-06-18 21:50:54 -040026#include <numeric>
27#include <thrift/protocol/TBinaryProtocol.h>
James E. King, III82ae9572017-08-05 12:23:54 -040028#include <thrift/transport/TBufferTransports.h>
Christopher Friedtedcad982020-06-18 21:50:54 -040029#include <vector>
30
David Reiss2dc72c32007-08-21 23:59:34 +000031#include "gen-cpp/ThriftTest_types.h"
32
Konrad Grochowski16a23a62014-11-13 15:33:38 +010033BOOST_AUTO_TEST_SUITE(TMemoryBufferTest)
David Reiss2dc72c32007-08-21 23:59:34 +000034
Jim King60774812015-05-10 08:08:18 -040035using apache::thrift::protocol::TBinaryProtocol;
36using apache::thrift::transport::TMemoryBuffer;
37using apache::thrift::transport::TTransportException;
cyy316723a2019-01-05 16:35:14 +080038using std::shared_ptr;
Jim King60774812015-05-10 08:08:18 -040039using std::string;
David Reiss2dc72c32007-08-21 23:59:34 +000040
Konrad Grochowski1f6e3802015-05-18 18:10:06 +020041BOOST_AUTO_TEST_CASE(test_read_write_grow) {
Roger Meiera6b66332015-05-15 15:21:50 +020042 // Added to test the fix for THRIFT-1248
43 TMemoryBuffer uut;
44 const int maxSize = 65536;
45 uint8_t verify[maxSize];
46 std::vector<uint8_t> buf;
47 buf.resize(maxSize);
Jim King60774812015-05-10 08:08:18 -040048
Konrad Grochowski1f6e3802015-05-18 18:10:06 +020049 for (uint32_t i = 0; i < maxSize; ++i) {
Roger Meiera6b66332015-05-15 15:21:50 +020050 buf[i] = static_cast<uint8_t>(i);
51 }
Jim King60774812015-05-10 08:08:18 -040052
Konrad Grochowski1f6e3802015-05-18 18:10:06 +020053 for (uint32_t i = 1; i < maxSize; i *= 2) {
Roger Meiera6b66332015-05-15 15:21:50 +020054 uut.write(&buf[0], i);
55 }
56
Konrad Grochowski1f6e3802015-05-18 18:10:06 +020057 for (uint32_t i = 1; i < maxSize; i *= 2) {
Roger Meiera6b66332015-05-15 15:21:50 +020058 uut.read(verify, i);
59 BOOST_CHECK_EQUAL(0, ::memcmp(verify, &buf[0], i));
60 }
Jim King60774812015-05-10 08:08:18 -040061}
62
Konrad Grochowski1f6e3802015-05-18 18:10:06 +020063BOOST_AUTO_TEST_CASE(test_roundtrip) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +010064 shared_ptr<TMemoryBuffer> strBuffer(new TMemoryBuffer());
65 shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(strBuffer));
David Reiss2dc72c32007-08-21 23:59:34 +000066
Konrad Grochowski16a23a62014-11-13 15:33:38 +010067 thrift::test::Xtruct a;
68 a.i32_thing = 10;
69 a.i64_thing = 30;
70 a.string_thing = "holla back a";
David Reiss2dc72c32007-08-21 23:59:34 +000071
Konrad Grochowski16a23a62014-11-13 15:33:38 +010072 a.write(binaryProtcol.get());
73 std::string serialized = strBuffer->getBufferAsString();
David Reiss2dc72c32007-08-21 23:59:34 +000074
Konrad Grochowski16a23a62014-11-13 15:33:38 +010075 shared_ptr<TMemoryBuffer> strBuffer2(new TMemoryBuffer());
76 shared_ptr<TBinaryProtocol> binaryProtcol2(new TBinaryProtocol(strBuffer2));
David Reiss2dc72c32007-08-21 23:59:34 +000077
Konrad Grochowski16a23a62014-11-13 15:33:38 +010078 strBuffer2->resetBuffer((uint8_t*)serialized.data(), static_cast<uint32_t>(serialized.length()));
79 thrift::test::Xtruct a2;
80 a2.read(binaryProtcol2.get());
David Reiss2dc72c32007-08-21 23:59:34 +000081
Claudius Heine5ef662b2015-06-24 10:03:50 +020082 BOOST_CHECK(a == a2);
Konrad Grochowski16a23a62014-11-13 15:33:38 +010083}
84
James E. King, III533405e2017-10-28 18:25:45 -040085BOOST_AUTO_TEST_CASE(test_readAppendToString) {
cyy64750162019-02-08 13:40:59 +080086 string str1 = "abcd1234";
87 TMemoryBuffer buf((uint8_t*)str1.data(),
88 static_cast<uint32_t>(str1.length()),
Konrad Grochowski16a23a62014-11-13 15:33:38 +010089 TMemoryBuffer::COPY);
Konrad Grochowski16a23a62014-11-13 15:33:38 +010090
91 string str3 = "wxyz", str4 = "6789";
92 buf.readAppendToString(str3, 4);
93 buf.readAppendToString(str4, INT_MAX);
94
Claudius Heine5ef662b2015-06-24 10:03:50 +020095 BOOST_CHECK(str3 == "wxyzabcd");
96 BOOST_CHECK(str4 == "67891234");
Konrad Grochowski16a23a62014-11-13 15:33:38 +010097}
98
Konrad Grochowski1f6e3802015-05-18 18:10:06 +020099BOOST_AUTO_TEST_CASE(test_exceptions) {
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100100 char data[] = "foo\0bar";
101
102 TMemoryBuffer buf1((uint8_t*)data, 7, TMemoryBuffer::OBSERVE);
103 string str = buf1.getBufferAsString();
Claudius Heine5ef662b2015-06-24 10:03:50 +0200104 BOOST_CHECK(str.length() == 7);
105
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100106 buf1.resetBuffer();
Claudius Heine5ef662b2015-06-24 10:03:50 +0200107
108 BOOST_CHECK_THROW(buf1.write((const uint8_t*)"foo", 3), TTransportException);
David Reiss2dc72c32007-08-21 23:59:34 +0000109
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100110 TMemoryBuffer buf2((uint8_t*)data, 7, TMemoryBuffer::COPY);
Claudius Heine5ef662b2015-06-24 10:03:50 +0200111 BOOST_CHECK_NO_THROW(buf2.write((const uint8_t*)"bar", 3));
Konrad Grochowski16a23a62014-11-13 15:33:38 +0100112}
David Reissf7baf542008-02-04 21:56:27 +0000113
James E. King, IIIaded00b2017-09-22 11:20:15 -0700114BOOST_AUTO_TEST_CASE(test_default_maximum_buffer_size)
115{
James E. King III9b75e4f2018-12-17 16:21:14 -0500116 BOOST_CHECK_EQUAL((std::numeric_limits<uint32_t>::max)(), TMemoryBuffer().getMaxBufferSize());
Alex Şuhan20116c62017-08-03 12:28:17 -0700117}
James E. King, IIIaded00b2017-09-22 11:20:15 -0700118
119BOOST_AUTO_TEST_CASE(test_default_buffer_size)
120{
121 BOOST_CHECK_EQUAL(1024, TMemoryBuffer().getBufferSize());
122}
123
124BOOST_AUTO_TEST_CASE(test_error_set_max_buffer_size_too_small)
125{
126 TMemoryBuffer buf;
127 BOOST_CHECK_THROW(buf.setMaxBufferSize(buf.getBufferSize() - 1), TTransportException);
128}
129
Christopher Friedtedcad982020-06-18 21:50:54 -0400130BOOST_AUTO_TEST_CASE(test_observe) {
131#ifdef _MSC_VER
132 #define N 73
133#else
134 constexpr size_t N = 73;
135#endif
136 constexpr size_t M = 42;
137 uint8_t one_byte = 42;
138 std::vector<uint8_t> scratch;
139 auto filler = [=]() {
140 std::array<uint8_t, N> x;
141 // Fill buf_mem with a sequence from 0 to N - 1
142 std::iota(x.begin(), x.end(), 0);
143 return x;
144 };
145 static const std::array<uint8_t, N> buf_mem = filler();
146
147 BOOST_STATIC_ASSERT(M < N);
148
149 TMemoryBuffer buf((uint8_t*)&buf_mem.front(), N, TMemoryBuffer::MemoryPolicy::OBSERVE);
150
151 // Readable
152 BOOST_CHECK_EQUAL(N, buf.available_read());
153 // No available write space
154 BOOST_CHECK_EQUAL(0, buf.available_write());
155 // Not writeable
156 BOOST_CHECK_THROW(buf.write(&one_byte, 1), TTransportException);
157
158 // Read some but not all
159 scratch.resize(M);
160 BOOST_CHECK_EQUAL(M, buf.read(&scratch[0], M));
161 // Check remaining
162 BOOST_CHECK_EQUAL(N - M, buf.available_read());
163 // No available write space
164 BOOST_CHECK_EQUAL(0, buf.available_write());
165 // Not writeable
166 BOOST_CHECK_THROW(buf.write(&one_byte, 1), TTransportException);
167 // Contents
168 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), buf_mem.begin(),
169 buf_mem.begin() + M);
170
171 // Readable (drain remaining)
172 scratch.resize(N);
173 BOOST_CHECK_EQUAL(N - M, buf.read(&scratch[M], N - M));
174 // No available write space
175 BOOST_CHECK_EQUAL(0, buf.available_write());
176 // Not writeable
177 BOOST_CHECK_THROW(buf.write(&one_byte, 1), TTransportException);
178 // Contents
179 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), buf_mem.begin(), buf_mem.end());
180
181 // Not readable
182 BOOST_CHECK_EQUAL(0, buf.read(&one_byte, 1));
183 BOOST_CHECK_EQUAL(0, buf.available_read());
184 // No available write space
185 BOOST_CHECK_EQUAL(0, buf.available_write());
186 // Not writeable
187 BOOST_CHECK_THROW(buf.write(&one_byte, 1), TTransportException);
188
189 /* OBSERVE buffer cannot be reread with the default reset */
190
191 buf.resetBuffer();
192 // Not Readable
193 BOOST_CHECK_EQUAL(0, buf.available_read());
194 // No available write space
195 BOOST_CHECK_EQUAL(0, buf.available_write());
196 // Not writeable
197 BOOST_CHECK_THROW(buf.write(&one_byte, 1), TTransportException);
198
199 /* OBSERVE buffers do not auto-resize when written to (implicit) */
200 /* OBSERVE buffers can be appended-to (implicit) */
201}
202
203BOOST_AUTO_TEST_CASE(test_copy) {
204#ifdef _MSC_VER
205 #define N 73
206#else
207 constexpr size_t N = 73;
208#endif
209 constexpr size_t M = 42;
210 uint8_t one_byte = 42;
211 std::vector<uint8_t> scratch;
212 auto filler = [&]() {
213 std::array<uint8_t, N> x;
214 // Fill buf_mem with a sequence from 0 to N - 1
215 std::iota(x.begin(), x.end(), 0);
216 return x;
217 };
218 static const std::array<uint8_t, N> buf_mem = filler();
219
220 BOOST_STATIC_ASSERT(M < N);
221
222 TMemoryBuffer buf((uint8_t*)&buf_mem.front(), N, TMemoryBuffer::MemoryPolicy::COPY);
223
224 // Readable
225 BOOST_CHECK_EQUAL(N, buf.available_read());
226 // No available write space
227 BOOST_CHECK_EQUAL(0, buf.available_write());
228
229 // Read some but not all
230 scratch.resize(M);
231 BOOST_CHECK_EQUAL(M, buf.read(&scratch[0], M));
232 // Check remaining
233 BOOST_CHECK_EQUAL(N - M, buf.available_read());
234 // No available write space
235 BOOST_CHECK_EQUAL(0, buf.available_write());
236 // Contents
237 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), buf_mem.begin(),
238 buf_mem.begin() + M);
239
240 // Readable (drain remaining)
241 scratch.resize(N);
242 BOOST_CHECK_EQUAL(N - M, buf.read(&scratch[M], N - M));
243 // No available write space
244 BOOST_CHECK_EQUAL(0, buf.available_write());
245 // Contents
246 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), buf_mem.begin(), buf_mem.end());
247
248 // Not readable
249 BOOST_CHECK_EQUAL(0, buf.read(&one_byte, 1));
250 BOOST_CHECK_EQUAL(0, buf.available_read());
251 // No available write space
252 BOOST_CHECK_EQUAL(0, buf.available_write());
253
254 /* COPY buffer cannot be reread with the default reset */
255
256 buf.resetBuffer();
257 // Not readable
258 BOOST_CHECK_EQUAL(0, buf.available_read());
259 // Has available write space
260 BOOST_CHECK_EQUAL(N, buf.available_write());
261
262 /* COPY buffers auto-resize when written to */
263
264 // Not readable
265 BOOST_CHECK_EQUAL(0, buf.read(&one_byte, 1));
266 BOOST_CHECK_EQUAL(0, buf.available_read());
267 // No available write space
268 BOOST_CHECK_GT(buf.available_write(), 0);
269 // Writeable
270 one_byte = M;
271 BOOST_CHECK_NO_THROW(buf.write(&one_byte, 1));
272 // Readable
273 one_byte = 0xff;
274 BOOST_CHECK_EQUAL(1, buf.read(&one_byte, 1));
275 BOOST_CHECK_EQUAL(one_byte, M);
276
277 /* COPY buffers can be appended-to (and auto-resize) */
278
279 buf.resetBuffer((uint8_t*)&buf_mem.front(), N, TMemoryBuffer::MemoryPolicy::COPY);
280 // Appendable
281 one_byte = N + 1;
282 BOOST_CHECK_NO_THROW(buf.write(&one_byte, 1));
283 BOOST_CHECK_EQUAL(N, buf.read(&scratch[0], N));
284 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), buf_mem.begin(),
285 buf_mem.begin() + N);
286 one_byte = 0xff;
287 BOOST_CHECK_EQUAL(1, buf.read(&one_byte, 1));
288 BOOST_CHECK_EQUAL(one_byte, N + 1);
289}
290
291BOOST_AUTO_TEST_CASE(test_take_ownership)
292{
293#ifdef _MSC_VER
294 #define N 73
295#else
296 constexpr size_t N = 73;
297#endif
298 constexpr size_t M = 42;
299 uint8_t one_byte = 42;
300 std::vector<uint8_t> scratch;
301 auto filler = [&]() {
302 /* TAKE_OWNERSHIP buffers MUST be malloc'ed */
303 uint8_t* x = static_cast<uint8_t*>(malloc(N));
304 // Fill buf_mem with a sequence from 0 to N - 1
305 std::iota(&x[0], &x[N], 0);
306 return x;
307 };
308 uint8_t* buf_mem = filler();
309
310 BOOST_STATIC_ASSERT(M < N);
311
312 TMemoryBuffer buf(buf_mem, N, TMemoryBuffer::MemoryPolicy::TAKE_OWNERSHIP);
313
314 // Readable
315 BOOST_CHECK_EQUAL(N, buf.available_read());
316 // No available write space
317 BOOST_CHECK_EQUAL(0, buf.available_write());
318
319 // Read some but not all
320 scratch.resize(M);
321 BOOST_CHECK_EQUAL(M, buf.read(&scratch[0], M));
322 // Check remaining
323 BOOST_CHECK_EQUAL(N - M, buf.available_read());
324 // No available write space
325 BOOST_CHECK_EQUAL(0, buf.available_write());
326 // Contents
327 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), &buf_mem[0], &buf_mem[M]);
328
329 // Readable (drain remaining)
330 scratch.resize(N);
331 BOOST_CHECK_EQUAL(N - M, buf.read(&scratch[M], N - M));
332 // No available write space
333 BOOST_CHECK_EQUAL(0, buf.available_write());
334 // Contents
335 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), &buf_mem[0], &buf_mem[N]);
336
337 // Not readable
338 BOOST_CHECK_EQUAL(0, buf.read(&one_byte, 1));
339 BOOST_CHECK_EQUAL(0, buf.available_read());
340 // No available write space
341 BOOST_CHECK_EQUAL(0, buf.available_write());
342
343 /* TAKE_OWNERSHIP buffers auto-resize when written to */
344
345 // Not readable
346 BOOST_CHECK_EQUAL(0, buf.read(&one_byte, 1));
347 BOOST_CHECK_EQUAL(0, buf.available_read());
348 // No available write space
349 BOOST_CHECK_EQUAL(buf.available_write(), 0);
350 // Writeable
351 one_byte = M;
352 BOOST_CHECK_NO_THROW(buf.write(&one_byte, 1));
353 // Readable
354 one_byte = 0xff;
355 BOOST_CHECK_EQUAL(1, buf.read(&one_byte, 1));
356 BOOST_CHECK_EQUAL(one_byte, M);
357
358 /* TAKE_OWNERSHIP buffers can be appended-to (and auto-resize) */
359
360 buf_mem = filler();
361 buf.resetBuffer(buf_mem, N, TMemoryBuffer::MemoryPolicy::COPY);
362 // Appendable
363 one_byte = N + 1;
364 BOOST_CHECK_NO_THROW(buf.write(&one_byte, 1));
365 BOOST_CHECK_EQUAL(N, buf.read(&scratch[0], N));
366 BOOST_CHECK_EQUAL_COLLECTIONS(scratch.begin(), scratch.end(), &buf_mem[0], &buf_mem[N]);
367 one_byte = 0xff;
368 BOOST_CHECK_EQUAL(1, buf.read(&one_byte, 1));
369 BOOST_CHECK_EQUAL(one_byte, N + 1);
370}
371
James E. King, IIIaded00b2017-09-22 11:20:15 -0700372BOOST_AUTO_TEST_CASE(test_maximum_buffer_size)
373{
374 TMemoryBuffer buf;
375 buf.setMaxBufferSize(8192);
376 std::vector<uint8_t> small_buff(1);
377
378 for (size_t i = 0; i < 8192; ++i)
379 {
380 buf.write(&small_buff[0], 1);
381 }
382
383 BOOST_CHECK_THROW(buf.write(&small_buff[0], 1), TTransportException);
384}
385
stiga-huangd665e282023-06-16 22:53:43 +0800386BOOST_AUTO_TEST_CASE(test_buffer_overflow)
387{
388 TMemoryBuffer buf;
389 std::vector<uint8_t> small_buff(1);
390 buf.write(&small_buff[0], 1);
391 BOOST_CHECK_THROW(buf.getWritePtr(std::numeric_limits<uint32_t>::max()), TTransportException);
392}
393
James E. King, IIIaded00b2017-09-22 11:20:15 -0700394BOOST_AUTO_TEST_CASE(test_memory_buffer_to_get_sizeof_objects)
395{
396 // This is a demonstration of how to use TMemoryBuffer to determine
397 // the serialized size of a thrift object in the Binary protocol.
398 // See THRIFT-3480
399
400 shared_ptr<TMemoryBuffer> memBuffer(new TMemoryBuffer());
401 shared_ptr<TBinaryProtocol> binaryProtcol(new TBinaryProtocol(memBuffer));
402
403 thrift::test::Xtruct object;
404 object.i32_thing = 10;
405 object.i64_thing = 30;
406 object.string_thing = "who's your daddy?";
407
408 uint32_t size = object.write(binaryProtcol.get());
409 BOOST_CHECK_EQUAL(47, size);
410}
Alex Şuhan20116c62017-08-03 12:28:17 -0700411
Roger Meier0069cc42010-10-13 18:10:18 +0000412BOOST_AUTO_TEST_SUITE_END()