Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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   bufferlist::iterator i(bl.begin());
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   bufferlist::iterator i(bl.begin());
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::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 // make sure that the legacy encode/decode methods are selected
238 // over the ones defined using templates. the later is likely to
239 // be slower, see also the definition of "WRITE_INT_DENC" in
240 // include/denc.h
241 template<>
242 void encode<uint64_t, denc_traits<uint64_t>>(const uint64_t&,
243                                              bufferlist&,
244                                              uint64_t f) {
245   static_assert(denc_traits<uint64_t>::supported,
246                 "should support new encoder");
247   static_assert(!denc_traits<uint64_t>::featured,
248                 "should not be featured");
249   ASSERT_EQ(0UL, f);
250   // make sure the test fails if i get called
251   ASSERT_TRUE(false);
252 }
253
254 template<>
255 void encode<ceph_le64, denc_traits<ceph_le64>>(const ceph_le64&,
256                                                bufferlist&,
257                                                uint64_t f) {
258   static_assert(denc_traits<ceph_le64>::supported,
259                 "should support new encoder");
260   static_assert(!denc_traits<ceph_le64>::featured,
261                 "should not be featured");
262   ASSERT_EQ(0UL, f);
263   // make sure the test fails if i get called
264   ASSERT_TRUE(false);
265 }
266
267 TEST(EncodingRoundTrip, Integers) {
268   // int types
269   {
270     uint64_t i = 42;
271     test_encode_and_decode(i);
272   }
273   {
274     int16_t i = 42;
275     test_encode_and_decode(i);
276   }
277   {
278     bool b = true;
279     test_encode_and_decode(b);
280   }
281   {
282     bool b = false;
283     test_encode_and_decode(b);
284   }
285   // raw encoder
286   {
287     ceph_le64 i;
288     i = 42;
289     test_encode_and_decode(i);
290   }
291 }
292
293 const char* expected_what[] = {
294   "buffer::malformed_input: void lame_decoder(int) no longer understand old encoding version 100 < 200",
295   "buffer::malformed_input: void lame_decoder(int) decode past end of struct encoding",
296 };
297
298 void lame_decoder(int which) {
299   switch (which) {
300   case 0:
301     throw buffer::malformed_input(DECODE_ERR_OLDVERSION(__PRETTY_FUNCTION__, 100, 200));
302   case 1:
303     throw buffer::malformed_input(DECODE_ERR_PAST(__PRETTY_FUNCTION__));
304   }
305 }
306
307 TEST(EncodingException, Macros) {
308   for (unsigned i = 0; i < sizeof(expected_what)/sizeof(expected_what[0]); i++) {
309     try {
310       lame_decoder(i);
311     } catch (const exception& e) {
312       ASSERT_EQ(string(expected_what[i]), string(e.what()));
313     }
314   }
315 }
316
317
318 TEST(small_encoding, varint) {
319   uint32_t v[][4] = {
320     /* value, varint bytes, signed varint bytes, signed varint bytes (neg) */
321     {0, 1, 1, 1},
322     {1, 1, 1, 1},
323     {2, 1, 1, 1},
324     {31, 1, 1, 1},
325     {32, 1, 1, 1},
326     {0xff, 2, 2, 2},
327     {0x100, 2, 2, 2},
328     {0xfff, 2, 2, 2},
329     {0x1000, 2, 2, 2},
330     {0x2000, 2, 3, 3},
331     {0x3fff, 2, 3, 3},
332     {0x4000, 3, 3, 3},
333     {0x4001, 3, 3, 3},
334     {0x10001, 3, 3, 3},
335     {0x20001, 3, 3, 3},
336     {0x40001, 3, 3, 3},
337     {0x80001, 3, 3, 3},
338     {0x7f0001, 4, 4, 4},
339     {0xff00001, 4, 5, 5},
340     {0x1ff00001, 5, 5, 5},
341     {0xffff0001, 5, 5, 5},
342     {0xffffffff, 5, 5, 5},
343     {1074790401, 5, 5, 5},
344     {0, 0, 0, 0}
345   };
346   for (unsigned i=0; v[i][1]; ++i) {
347     {
348       bufferlist bl;
349       {
350          auto app = bl.get_contiguous_appender(16, true);
351          denc_varint(v[i][0], app);
352       }
353       cout << std::hex << v[i][0] << "\t" << v[i][1] << "\t";
354       bl.hexdump(cout, false);
355       cout << std::endl;
356       ASSERT_EQ(bl.length(), v[i][1]);
357       uint32_t u;
358       auto p = bl.begin().get_current_ptr().begin();
359       denc_varint(u, p);
360       ASSERT_EQ(v[i][0], u);
361     }
362     {
363       bufferlist bl;
364       {
365          auto app = bl.get_contiguous_appender(16, true);
366          denc_signed_varint(v[i][0], app);
367       }
368       cout << std::hex << v[i][0] << "\t" << v[i][2] << "\t";
369       bl.hexdump(cout, false);
370       cout << std::endl;
371       ASSERT_EQ(bl.length(), v[i][2]);
372       int32_t u;
373       auto p = bl.begin().get_current_ptr().begin();
374       denc_signed_varint(u, p);
375       ASSERT_EQ((int32_t)v[i][0], u);
376     }
377     {
378       bufferlist bl;
379       int64_t x = -(int64_t)v[i][0];
380       {
381          auto app = bl.get_contiguous_appender(16, true);
382          denc_signed_varint(x, app);
383       }
384       cout << std::dec << x << std::hex << "\t" << v[i][3] << "\t";
385       bl.hexdump(cout, false);
386       cout << std::endl;
387       ASSERT_EQ(bl.length(), v[i][3]);
388       int64_t u;
389       auto p = bl.begin().get_current_ptr().begin();
390       denc_signed_varint(u, p);
391       ASSERT_EQ(x, u);
392     }
393   }
394 }
395
396 TEST(small_encoding, varint_lowz) {
397   uint32_t v[][4] = {
398     /* value, bytes encoded */
399     {0, 1, 1, 1},
400     {1, 1, 1, 1},
401     {2, 1, 1, 1},
402     {15, 1, 1, 1},
403     {16, 1, 1, 1},
404     {31, 1, 2, 2},
405     {63, 2, 2, 2},
406     {64, 1, 1, 1},
407     {0xff, 2, 2, 2},
408     {0x100, 1, 1, 1},
409     {0x7ff, 2, 2, 2},
410     {0xfff, 2, 3, 3},
411     {0x1000, 1, 1, 1},
412     {0x4000, 1, 1, 1},
413     {0x8000, 1, 1, 1},
414     {0x10000, 1, 2, 2},
415     {0x20000, 2, 2, 2},
416     {0x40000, 2, 2, 2},
417     {0x80000, 2, 2, 2},
418     {0x7f0000, 2, 2, 2},
419     {0xffff0000, 4, 4, 4},
420     {0xffffffff, 5, 5, 5},
421     {0x41000000, 3, 4, 4},
422     {0, 0, 0, 0}
423   };
424   for (unsigned i=0; v[i][1]; ++i) {
425     {
426       bufferlist bl;
427       {
428          auto app = bl.get_contiguous_appender(16, true);
429          denc_varint_lowz(v[i][0], app);
430       }
431       cout << std::hex << v[i][0] << "\t" << v[i][1] << "\t";
432       bl.hexdump(cout, false);
433       cout << std::endl;
434       ASSERT_EQ(bl.length(), v[i][1]);
435       uint32_t u;
436       auto p = bl.begin().get_current_ptr().begin();
437       denc_varint_lowz(u, p);
438       ASSERT_EQ(v[i][0], u);
439     }
440     {
441       bufferlist bl;
442       int64_t x = v[i][0];
443       {
444          auto app = bl.get_contiguous_appender(16, true);
445          denc_signed_varint_lowz(x, app);
446       }
447       cout << std::hex << x << "\t" << v[i][1] << "\t";
448       bl.hexdump(cout, false);
449       cout << std::endl;
450       ASSERT_EQ(bl.length(), v[i][2]);
451       int64_t u;
452       auto p = bl.begin().get_current_ptr().begin();
453       denc_signed_varint_lowz(u, p);
454       ASSERT_EQ(x, u);
455     }
456     {
457       bufferlist bl;
458       int64_t x = -(int64_t)v[i][0];
459       {
460          auto app = bl.get_contiguous_appender(16, true);
461          denc_signed_varint_lowz(x, app);
462       }
463       cout << std::dec << x << "\t" << v[i][1] << "\t";
464       bl.hexdump(cout, false);
465       cout << std::endl;
466       ASSERT_EQ(bl.length(), v[i][3]);
467       int64_t u;
468       auto p = bl.begin().get_current_ptr().begin();
469       denc_signed_varint_lowz(u, p);
470       ASSERT_EQ(x, u);
471     }    
472   }
473 }
474
475 TEST(small_encoding, lba) {
476   uint64_t v[][2] = {
477     /* value, bytes encoded */
478     {0, 4},
479     {1, 4},
480     {0xff, 4},
481     {0x10000, 4},
482     {0x7f0000, 4},
483     {0xffff0000, 4},
484     {0x0fffffff, 4},
485     {0x1fffffff, 5},
486     {0xffffffff, 5},
487     {0x3fffffff000, 4},
488     {0x7fffffff000, 5},
489     {0x1fffffff0000, 4},
490     {0x3fffffff0000, 5},
491     {0xfffffff00000, 4},
492     {0x1fffffff00000, 5},
493     {0x41000000, 4},
494     {0, 0}
495   };
496   for (unsigned i=0; v[i][1]; ++i) {
497     bufferlist bl;
498     {
499        auto app = bl.get_contiguous_appender(16, true);
500        denc_lba(v[i][0], app);
501     }
502     cout << std::hex << v[i][0] << "\t" << v[i][1] << "\t";
503     bl.hexdump(cout, false);
504     cout << std::endl;
505     ASSERT_EQ(bl.length(), v[i][1]);
506     uint64_t u;
507     auto p = bl.begin().get_current_ptr().begin();
508     denc_lba(u, p);
509     ASSERT_EQ(v[i][0], u);
510   }
511
512 }