]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/encoding.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / test / encoding.cc
1 #include "include/buffer.h"
2 #include "include/encoding.h"
3
4 #include "gtest/gtest.h"
5
6 using namespace std;
7
8 template < typename T >
9 static void test_encode_and_decode(const T& src)
10 {
11 bufferlist bl(1000000);
12 encode(src, bl);
13 T dst;
14 auto i = bl.cbegin();
15 decode(dst, i);
16 ASSERT_EQ(src, dst) << "Encoding roundtrip changed the string: orig=" << src << ", but new=" << dst;
17 }
18
19 TEST(EncodingRoundTrip, StringSimple) {
20 string my_str("I am the very model of a modern major general");
21 test_encode_and_decode < std::string >(my_str);
22 }
23
24 TEST(EncodingRoundTrip, StringEmpty) {
25 string my_str("");
26 test_encode_and_decode < std::string >(my_str);
27 }
28
29 TEST(EncodingRoundTrip, StringNewline) {
30 string my_str("foo bar baz\n");
31 test_encode_and_decode < std::string >(my_str);
32 }
33
34 template <typename Size, typename T>
35 static void test_encode_and_nohead_nohead(Size len, const T& src)
36 {
37 bufferlist bl(1000000);
38 encode(len, bl);
39 encode_nohead(src, bl);
40 T dst;
41 auto i = bl.cbegin();
42 decode(len, i);
43 decode_nohead(len, dst, i);
44 ASSERT_EQ(src, dst) << "Encoding roundtrip changed the string: orig=" << src << ", but new=" << dst;
45 }
46
47 TEST(EncodingRoundTrip, StringNoHead) {
48 const string str("The quick brown fox jumps over the lazy dog");
49 auto size = str.size();
50 test_encode_and_nohead_nohead(static_cast<int>(size), str);
51 test_encode_and_nohead_nohead(static_cast<unsigned>(size), str);
52 test_encode_and_nohead_nohead(static_cast<uint32_t>(size), str);
53 test_encode_and_nohead_nohead(static_cast<__u32>(size), str);
54 test_encode_and_nohead_nohead(static_cast<size_t>(size), str);
55 }
56
57 TEST(EncodingRoundTrip, BufferListNoHead) {
58 bufferlist bl;
59 bl.append("is this a dagger which i see before me?");
60 auto size = bl.length();
61 test_encode_and_nohead_nohead(static_cast<int>(size), bl);
62 test_encode_and_nohead_nohead(static_cast<unsigned>(size), bl);
63 test_encode_and_nohead_nohead(static_cast<uint32_t>(size), bl);
64 test_encode_and_nohead_nohead(static_cast<__u32>(size), bl);
65 test_encode_and_nohead_nohead(static_cast<size_t>(size), bl);
66 }
67
68 typedef std::multimap < int, std::string > multimap_t;
69 typedef multimap_t::value_type my_val_ty;
70
71 namespace std {
72 static std::ostream& operator<<(std::ostream& oss, const multimap_t &multimap)
73 {
74 for (multimap_t::const_iterator m = multimap.begin();
75 m != multimap.end();
76 ++m)
77 {
78 oss << m->first << "->" << m->second << " ";
79 }
80 return oss;
81 }
82 }
83
84 TEST(EncodingRoundTrip, Multimap) {
85 multimap_t multimap;
86 multimap.insert( my_val_ty(1, "foo") );
87 multimap.insert( my_val_ty(2, "bar") );
88 multimap.insert( my_val_ty(2, "baz") );
89 multimap.insert( my_val_ty(3, "lucky number 3") );
90 multimap.insert( my_val_ty(10000, "large number") );
91
92 test_encode_and_decode < multimap_t >(multimap);
93 }
94
95
96
97 ///////////////////////////////////////////////////////
98 // ConstructorCounter
99 ///////////////////////////////////////////////////////
100 template <typename T>
101 class ConstructorCounter
102 {
103 public:
104 ConstructorCounter() : data(0)
105 {
106 default_ctor++;
107 }
108
109 explicit ConstructorCounter(const T& data_)
110 : data(data_)
111 {
112 one_arg_ctor++;
113 }
114
115 ConstructorCounter(const ConstructorCounter &rhs)
116 : data(rhs.data)
117 {
118 copy_ctor++;
119 }
120
121 ConstructorCounter &operator=(const ConstructorCounter &rhs)
122 {
123 data = rhs.data;
124 assigns++;
125 return *this;
126 }
127
128 static void init(void)
129 {
130 default_ctor = 0;
131 one_arg_ctor = 0;
132 copy_ctor = 0;
133 assigns = 0;
134 }
135
136 static int get_default_ctor(void)
137 {
138 return default_ctor;
139 }
140
141 static int get_one_arg_ctor(void)
142 {
143 return one_arg_ctor;
144 }
145
146 static int get_copy_ctor(void)
147 {
148 return copy_ctor;
149 }
150
151 static int get_assigns(void)
152 {
153 return assigns;
154 }
155
156 bool operator<(const ConstructorCounter &rhs) const
157 {
158 return data < rhs.data;
159 }
160
161 bool operator==(const ConstructorCounter &rhs) const
162 {
163 return data == rhs.data;
164 }
165
166 friend void decode(ConstructorCounter &s, bufferlist::const_iterator& p)
167 {
168 decode(s.data, p);
169 }
170
171 friend void encode(const ConstructorCounter &s, bufferlist& p)
172 {
173 encode(s.data, p);
174 }
175
176 friend ostream& operator<<(ostream &oss, const ConstructorCounter &cc)
177 {
178 oss << cc.data;
179 return oss;
180 }
181
182 T data;
183 private:
184 static int default_ctor;
185 static int one_arg_ctor;
186 static int copy_ctor;
187 static int assigns;
188 };
189
190 template class ConstructorCounter <int32_t>;
191 template class ConstructorCounter <int16_t>;
192
193 typedef ConstructorCounter <int32_t> my_key_t;
194 typedef ConstructorCounter <int16_t> my_val_t;
195 typedef std::multimap < my_key_t, my_val_t > multimap2_t;
196 typedef multimap2_t::value_type val2_ty;
197
198 template <class T> int ConstructorCounter<T>::default_ctor = 0;
199 template <class T> int ConstructorCounter<T>::one_arg_ctor = 0;
200 template <class T> int ConstructorCounter<T>::copy_ctor = 0;
201 template <class T> int ConstructorCounter<T>::assigns = 0;
202
203 static std::ostream& operator<<(std::ostream& oss, const multimap2_t &multimap)
204 {
205 for (multimap2_t::const_iterator m = multimap.begin();
206 m != multimap.end();
207 ++m)
208 {
209 oss << m->first << "->" << m->second << " ";
210 }
211 return oss;
212 }
213
214 TEST(EncodingRoundTrip, MultimapConstructorCounter) {
215 multimap2_t multimap2;
216 multimap2.insert( val2_ty(my_key_t(1), my_val_t(10)) );
217 multimap2.insert( val2_ty(my_key_t(2), my_val_t(20)) );
218 multimap2.insert( val2_ty(my_key_t(2), my_val_t(30)) );
219 multimap2.insert( val2_ty(my_key_t(3), my_val_t(40)) );
220 multimap2.insert( val2_ty(my_key_t(10000), my_val_t(1)) );
221
222 my_key_t::init();
223 my_val_t::init();
224 test_encode_and_decode < multimap2_t >(multimap2);
225
226 EXPECT_EQ(my_key_t::get_default_ctor(), 5);
227 EXPECT_EQ(my_key_t::get_one_arg_ctor(), 0);
228 EXPECT_EQ(my_key_t::get_copy_ctor(), 5);
229 EXPECT_EQ(my_key_t::get_assigns(), 0);
230
231 EXPECT_EQ(my_val_t::get_default_ctor(), 5);
232 EXPECT_EQ(my_val_t::get_one_arg_ctor(), 0);
233 EXPECT_EQ(my_val_t::get_copy_ctor(), 5);
234 EXPECT_EQ(my_val_t::get_assigns(), 0);
235 }
236
237 namespace ceph {
238 // make sure that the legacy encode/decode methods are selected
239 // over the ones defined using templates. the later is likely to
240 // be slower, see also the definition of "WRITE_INT_DENC" in
241 // include/denc.h
242 template<>
243 void encode<uint64_t, denc_traits<uint64_t>>(const uint64_t&,
244 bufferlist&,
245 uint64_t f) {
246 static_assert(denc_traits<uint64_t>::supported,
247 "should support new encoder");
248 static_assert(!denc_traits<uint64_t>::featured,
249 "should not be featured");
250 ASSERT_EQ(0UL, f);
251 // make sure the test fails if i get called
252 ASSERT_TRUE(false);
253 }
254
255 template<>
256 void encode<ceph_le64, denc_traits<ceph_le64>>(const ceph_le64&,
257 bufferlist&,
258 uint64_t f) {
259 static_assert(denc_traits<ceph_le64>::supported,
260 "should support new encoder");
261 static_assert(!denc_traits<ceph_le64>::featured,
262 "should not be featured");
263 ASSERT_EQ(0UL, f);
264 // make sure the test fails if i get called
265 ASSERT_TRUE(false);
266 }
267 }
268
269 namespace {
270 // search `underlying_type` in denc.h for supported underlying types
271 enum class Colour : int8_t { R,G,B };
272 ostream& operator<<(ostream& os, Colour c) {
273 switch (c) {
274 case Colour::R:
275 return os << "Colour::R";
276 case Colour::G:
277 return os << "Colour::G";
278 case Colour::B:
279 return os << "Colour::B";
280 default:
281 return os << "Colour::???";
282 }
283 }
284 }
285
286 TEST(EncodingRoundTrip, Integers) {
287 // int types
288 {
289 uint64_t i = 42;
290 test_encode_and_decode(i);
291 }
292 {
293 int16_t i = 42;
294 test_encode_and_decode(i);
295 }
296 {
297 bool b = true;
298 test_encode_and_decode(b);
299 }
300 {
301 bool b = false;
302 test_encode_and_decode(b);
303 }
304 // raw encoder
305 {
306 ceph_le64 i;
307 i = 42;
308 test_encode_and_decode(i);
309 }
310 // enum
311 {
312 test_encode_and_decode(Colour::R);
313 // this should not build, as the size of unsigned is not the same on
314 // different archs, that's why denc_traits<> intentionally leaves
315 // `int` and `unsigned int` out of supported types.
316 //
317 // enum E { R, G, B };
318 // test_encode_and_decode(R);
319 }
320 }
321
322 const char* expected_what[] = {
323 "buffer::malformed_input: void lame_decoder(int) no longer understand old encoding version 100 < 200",
324 "buffer::malformed_input: void lame_decoder(int) decode past end of struct encoding",
325 };
326
327 void lame_decoder(int which) {
328 switch (which) {
329 case 0:
330 throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, 100, 200));
331 case 1:
332 throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__));
333 }
334 }
335
336 TEST(EncodingException, Macros) {
337 for (unsigned i = 0; i < sizeof(expected_what)/sizeof(expected_what[0]); i++) {
338 try {
339 lame_decoder(i);
340 } catch (const exception& e) {
341 ASSERT_EQ(string(expected_what[i]), string(e.what()));
342 }
343 }
344 }
345
346
347 TEST(small_encoding, varint) {
348 uint32_t v[][4] = {
349 /* value, varint bytes, signed varint bytes, signed varint bytes (neg) */
350 {0, 1, 1, 1},
351 {1, 1, 1, 1},
352 {2, 1, 1, 1},
353 {31, 1, 1, 1},
354 {32, 1, 1, 1},
355 {0xff, 2, 2, 2},
356 {0x100, 2, 2, 2},
357 {0xfff, 2, 2, 2},
358 {0x1000, 2, 2, 2},
359 {0x2000, 2, 3, 3},
360 {0x3fff, 2, 3, 3},
361 {0x4000, 3, 3, 3},
362 {0x4001, 3, 3, 3},
363 {0x10001, 3, 3, 3},
364 {0x20001, 3, 3, 3},
365 {0x40001, 3, 3, 3},
366 {0x80001, 3, 3, 3},
367 {0x7f0001, 4, 4, 4},
368 {0xff00001, 4, 5, 5},
369 {0x1ff00001, 5, 5, 5},
370 {0xffff0001, 5, 5, 5},
371 {0xffffffff, 5, 5, 5},
372 {1074790401, 5, 5, 5},
373 {0, 0, 0, 0}
374 };
375 for (unsigned i=0; v[i][1]; ++i) {
376 {
377 bufferlist bl;
378 {
379 auto app = bl.get_contiguous_appender(16, true);
380 denc_varint(v[i][0], app);
381 }
382 cout << std::hex << v[i][0] << "\t" << v[i][1] << "\t";
383 bl.hexdump(cout, false);
384 cout << std::endl;
385 ASSERT_EQ(bl.length(), v[i][1]);
386 uint32_t u;
387 auto p = bl.begin().get_current_ptr().cbegin();
388 denc_varint(u, p);
389 ASSERT_EQ(v[i][0], u);
390 }
391 {
392 bufferlist bl;
393 {
394 auto app = bl.get_contiguous_appender(16, true);
395 denc_signed_varint(v[i][0], app);
396 }
397 cout << std::hex << v[i][0] << "\t" << v[i][2] << "\t";
398 bl.hexdump(cout, false);
399 cout << std::endl;
400 ASSERT_EQ(bl.length(), v[i][2]);
401 int32_t u;
402 auto p = bl.begin().get_current_ptr().cbegin();
403 denc_signed_varint(u, p);
404 ASSERT_EQ((int32_t)v[i][0], u);
405 }
406 {
407 bufferlist bl;
408 int64_t x = -(int64_t)v[i][0];
409 {
410 auto app = bl.get_contiguous_appender(16, true);
411 denc_signed_varint(x, app);
412 }
413 cout << std::dec << x << std::hex << "\t" << v[i][3] << "\t";
414 bl.hexdump(cout, false);
415 cout << std::endl;
416 ASSERT_EQ(bl.length(), v[i][3]);
417 int64_t u;
418 auto p = bl.begin().get_current_ptr().cbegin();
419 denc_signed_varint(u, p);
420 ASSERT_EQ(x, u);
421 }
422 }
423 }
424
425 TEST(small_encoding, varint_lowz) {
426 uint32_t v[][4] = {
427 /* value, bytes encoded */
428 {0, 1, 1, 1},
429 {1, 1, 1, 1},
430 {2, 1, 1, 1},
431 {15, 1, 1, 1},
432 {16, 1, 1, 1},
433 {31, 1, 2, 2},
434 {63, 2, 2, 2},
435 {64, 1, 1, 1},
436 {0xff, 2, 2, 2},
437 {0x100, 1, 1, 1},
438 {0x7ff, 2, 2, 2},
439 {0xfff, 2, 3, 3},
440 {0x1000, 1, 1, 1},
441 {0x4000, 1, 1, 1},
442 {0x8000, 1, 1, 1},
443 {0x10000, 1, 2, 2},
444 {0x20000, 2, 2, 2},
445 {0x40000, 2, 2, 2},
446 {0x80000, 2, 2, 2},
447 {0x7f0000, 2, 2, 2},
448 {0xffff0000, 4, 4, 4},
449 {0xffffffff, 5, 5, 5},
450 {0x41000000, 3, 4, 4},
451 {0, 0, 0, 0}
452 };
453 for (unsigned i=0; v[i][1]; ++i) {
454 {
455 bufferlist bl;
456 {
457 auto app = bl.get_contiguous_appender(16, true);
458 denc_varint_lowz(v[i][0], app);
459 }
460 cout << std::hex << v[i][0] << "\t" << v[i][1] << "\t";
461 bl.hexdump(cout, false);
462 cout << std::endl;
463 ASSERT_EQ(bl.length(), v[i][1]);
464 uint32_t u;
465 auto p = bl.begin().get_current_ptr().cbegin();
466 denc_varint_lowz(u, p);
467 ASSERT_EQ(v[i][0], u);
468 }
469 {
470 bufferlist bl;
471 int64_t x = v[i][0];
472 {
473 auto app = bl.get_contiguous_appender(16, true);
474 denc_signed_varint_lowz(x, app);
475 }
476 cout << std::hex << x << "\t" << v[i][1] << "\t";
477 bl.hexdump(cout, false);
478 cout << std::endl;
479 ASSERT_EQ(bl.length(), v[i][2]);
480 int64_t u;
481 auto p = bl.begin().get_current_ptr().cbegin();
482 denc_signed_varint_lowz(u, p);
483 ASSERT_EQ(x, u);
484 }
485 {
486 bufferlist bl;
487 int64_t x = -(int64_t)v[i][0];
488 {
489 auto app = bl.get_contiguous_appender(16, true);
490 denc_signed_varint_lowz(x, app);
491 }
492 cout << std::dec << x << "\t" << v[i][1] << "\t";
493 bl.hexdump(cout, false);
494 cout << std::endl;
495 ASSERT_EQ(bl.length(), v[i][3]);
496 int64_t u;
497 auto p = bl.begin().get_current_ptr().cbegin();
498 denc_signed_varint_lowz(u, p);
499 ASSERT_EQ(x, u);
500 }
501 }
502 }
503
504 TEST(small_encoding, lba) {
505 uint64_t v[][2] = {
506 /* value, bytes encoded */
507 {0, 4},
508 {1, 4},
509 {0xff, 4},
510 {0x10000, 4},
511 {0x7f0000, 4},
512 {0xffff0000, 4},
513 {0x0fffffff, 4},
514 {0x1fffffff, 5},
515 {0xffffffff, 5},
516 {0x3fffffff000, 4},
517 {0x7fffffff000, 5},
518 {0x1fffffff0000, 4},
519 {0x3fffffff0000, 5},
520 {0xfffffff00000, 4},
521 {0x1fffffff00000, 5},
522 {0x41000000, 4},
523 {0, 0}
524 };
525 for (unsigned i=0; v[i][1]; ++i) {
526 bufferlist bl;
527 {
528 auto app = bl.get_contiguous_appender(16, true);
529 denc_lba(v[i][0], app);
530 }
531 cout << std::hex << v[i][0] << "\t" << v[i][1] << "\t";
532 bl.hexdump(cout, false);
533 cout << std::endl;
534 ASSERT_EQ(bl.length(), v[i][1]);
535 uint64_t u;
536 auto p = bl.begin().get_current_ptr().cbegin();
537 denc_lba(u, p);
538 ASSERT_EQ(v[i][0], u);
539 }
540
541 }