]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/test_denc.cc
bump version to 12.0.3-pve3
[ceph.git] / ceph / src / test / test_denc.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph distributed storage system
5 *
6 * Copyright (C) 2016 Red Hat
7 *
8 * Author: Sage Weil <sage@redhat.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 */
16
17#include <stdio.h>
18
19#include "global/global_init.h"
20#include "common/ceph_argparse.h"
21#include "global/global_context.h"
22#include "gtest/gtest.h"
23
24#include "include/denc.h"
25
26// test helpers
27
28template<typename T>
29void test_encode_decode(T v) {
30 bufferlist bl;
31 ::encode(v, bl);
32 bufferlist::iterator p = bl.begin();
33 T out;
34 ::decode(out, p);
35 ASSERT_EQ(v, out);
36}
37
38template<typename T>
39void test_denc(T v) {
40 // estimate
41 size_t s = 0;
42 denc(v, s);
43 ASSERT_NE(s, 0u);
44
45 // encode
46 bufferlist bl;
47 {
48 auto a = bl.get_contiguous_appender(s);
49 denc(v, a);
50 }
51 ASSERT_LE(bl.length(), s);
52
53 // decode
54 bl.rebuild();
55 T out;
56 auto bpi = bl.front().begin();
57 denc(out, bpi);
58 ASSERT_EQ(v, out);
59 ASSERT_EQ(bpi.get_pos(), bl.c_str() + bl.length());
60
61 // test glue
62 test_encode_decode(v);
63}
64
65template<typename T>
66void test_encode_decode_featured(T v) {
67 bufferlist bl;
68 ::encode(v, bl, 123);
69 bufferlist::iterator p = bl.begin();
70 T out;
71 ::decode(out, p);
72 ASSERT_EQ(v, out);
73}
74
75template<typename T>
76void test_denc_featured(T v) {
77 // estimate
78 size_t s = 0;
79 denc(v, s, 0);
80 ASSERT_GT(s, 0u);
81
82 // encode
83 bufferlist bl;
84 {
85 auto a = bl.get_contiguous_appender(s);
86 denc(v, a, 1);
87 }
88 ASSERT_LE(bl.length(), s);
89
90 // decode
91 bl.rebuild();
92 T out;
93 auto bpi = bl.front().begin();
94 denc(out, bpi, 1);
95 ASSERT_EQ(v, out);
96 ASSERT_EQ(bpi.get_pos(), bl.c_str() + bl.length());
97
98 // test glue
99 test_encode_decode_featured(v);
100}
101
102
103// hooks to count bound calls
104
105struct counts_t {
106 int num_bound_encode = 0;
107 int num_encode = 0;
108 int num_decode = 0;
109 void reset() {
110 num_bound_encode = 0;
111 num_encode = 0;
112 num_decode = 0;
113 }
114} counts;
115
116struct denc_counter_t {
117 void bound_encode(size_t& p) const {
118 ++counts.num_bound_encode;
119 ++p; // denc.h does not like 0-length objects
120 }
121 void encode(buffer::list::contiguous_appender& p) const {
122 p.append("a", 1);
123 ++counts.num_encode;
124 }
125 void decode(buffer::ptr::iterator &p) {
126 p.advance(1);
127 ++counts.num_decode;
128 }
129};
130WRITE_CLASS_DENC(denc_counter_t)
131
132struct denc_counter_bounded_t {
133 void bound_encode(size_t& p) const {
134 ++counts.num_bound_encode;
135 ++p; // denc.h does not like 0-length objects
136 }
137 void encode(buffer::list::contiguous_appender& p) const {
138 p.append("a", 1);
139 ++counts.num_encode;
140 }
141 void decode(buffer::ptr::iterator &p) {
142 p.advance(1);
143 ++counts.num_decode;
144 }
145};
146WRITE_CLASS_DENC_BOUNDED(denc_counter_bounded_t)
147
148TEST(denc, denc_counter)
149{
150 denc_counter_t single, single2;
151 {
152 bufferlist bl;
153 ::encode(single, bl);
154 ::decode(single2, bl);
155 }
156 ASSERT_EQ(counts.num_bound_encode, 1);
157 ASSERT_EQ(counts.num_encode, 1);
158 ASSERT_EQ(counts.num_decode, 1);
159 counts.reset();
160}
161
162TEST(denc, simple)
163{
164 test_denc((uint8_t)4);
165 test_denc((int8_t)-5);
166 test_denc((uint16_t)6);
167 test_denc((int16_t)-7);
168 test_denc((uint32_t)8);
169 test_denc((int32_t)-9);
170 test_denc((uint64_t)10);
171 test_denc((int64_t)-11);
172}
173
174TEST(denc, string)
175{
176 string a, b("hi"), c("multi\nline\n");
177 test_denc(a);
178 test_denc(b);
179 test_denc(c);
180}
181
182struct legacy_t {
183 int32_t a = 1;
184 void encode(bufferlist& bl) const {
185 ::encode(a, bl);
186 }
187 void decode(bufferlist::iterator& p) {
188 ::decode(a, p);
189 }
190 legacy_t() {}
191 legacy_t(int32_t i) : a(i) {}
192 friend bool operator<(const legacy_t& l, const legacy_t& r) {
193 return l.a < r.a;
194 }
195 friend bool operator==(const legacy_t& l, const legacy_t& r) {
196 return l.a == r.a;
197 }
198};
199WRITE_CLASS_ENCODER(legacy_t)
200
201template<template<class> class C>
202void test_common_veclist(const char* c) {
203 {
204 cout << c << "<std::string>" << std::endl;
205 C<std::string> s;
206 s.push_back("foo");
207 s.push_back("bar");
208 s.push_back("baz");
209 counts.reset();
210 test_denc(s);
211 }
212 {
213 cout << c << "<int32_t>" << std::endl;
214 C<int32_t> s;
215 s.push_back(1);
216 s.push_back(2);
217 s.push_back(3);
218 test_denc(s);
219 }
220 {
221 cout << c << "<legacy_t>" << std::endl;
222 C<legacy_t> s;
223 s.push_back(legacy_t(1));
224 s.push_back(legacy_t(2));
225 test_encode_decode(s);
226 }
227}
228
229// We only care about specializing the type, all other template
230// parameters should have the default values. (Like first-class
231// functions, first-class templates do not bring their defaults.)
232
233template<typename T>
234using default_vector = std::vector<T>;
235
236TEST(denc, vector)
237{
238 test_common_veclist<default_vector>("std::vector");
239 {
240 counts.reset();
241 vector<denc_counter_t> v, v2;
242 v.resize(100);
243 {
244 bufferlist bl;
245 ::encode(v, bl);
246 ::decode(v2, bl);
247 }
248 ASSERT_EQ(counts.num_bound_encode, 100);
249 ASSERT_EQ(counts.num_encode, 100);
250 ASSERT_EQ(counts.num_decode, 100);
251 }
252 {
253 counts.reset();
254 vector<denc_counter_bounded_t> v, v2;
255 v.resize(100);
256 {
257 bufferlist bl;
258 ::encode(v, bl);
259 ::decode(v2, bl);
260 }
261 ASSERT_EQ(counts.num_bound_encode, 1);
262 ASSERT_EQ(counts.num_encode, 100);
263 ASSERT_EQ(counts.num_decode, 100);
264 }
265}
266
267template<typename T>
268using default_list = std::list<T>;
269
270TEST(denc, list)
271{
272 test_common_veclist<default_list>("std::list");
273 {
274 counts.reset();
275 list<denc_counter_bounded_t> l, l2;
276 for (unsigned i=0; i<100; ++i) {
277 l.emplace_back(denc_counter_bounded_t());
278 }
279 {
280 bufferlist bl;
281 ::encode(l, bl);
282 ::decode(l2, bl);
283 }
284 ASSERT_EQ(counts.num_bound_encode, 1);
285 ASSERT_EQ(counts.num_encode, 100);
286 ASSERT_EQ(counts.num_decode, 100);
287 }
288}
289
290template<template<class> class C>
291void test_setlike(const char* c) {
292 {
293 cout << c << "<std::string>" << std::endl;
294 C<std::string> s;
295 s.insert("foo");
296 s.insert("bar");
297 s.insert("baz");
298 test_denc(s);
299 }
300 {
301 cout << c << "<int32_t>" << std::endl;
302 C<int32_t> s;
303 s.insert(1);
304 s.insert(2);
305 s.insert(3);
306 test_denc(s);
307 }
308 {
309 cout << c << "<legacy_t>" << std::endl;
310 C<legacy_t> s;
311 s.insert(legacy_t(1));
312 s.insert(legacy_t(2));
313 test_encode_decode(s);
314 }
315}
316
317template<typename T>
318using default_set = std::set<T>;
319
320TEST(denc, set)
321{
322 test_setlike<default_set>("std::set");
323}
324
325template<typename T>
326using default_flat_set= boost::container::flat_set<T>;
327
328TEST(denc, flat_set)
329{
330 test_setlike<default_flat_set>("std::set");
331}
332
333struct foo_t {
334 int32_t a = 0;
335 uint64_t b = 123;
336
337 DENC(foo_t, v, p) {
338 DENC_START(1, 1, p);
339 ::denc(v.a, p);
340 ::denc(v.b, p);
341 DENC_FINISH(p);
342 }
343
344 friend bool operator==(const foo_t& l, const foo_t& r) {
345 return l.a == r.a && l.b == r.b;
346 }
347};
348WRITE_CLASS_DENC_BOUNDED(foo_t)
349
350struct foo2_t {
351 int32_t c = 0;
352 uint64_t d = 123;
353
354 DENC(foo2_t, v, p) {
355 DENC_START(1, 1, p);
356 ::denc(v.c, p);
357 ::denc(v.d, p);
358 DENC_FINISH(p);
359 }
360
361 friend bool operator==(const foo2_t& l, const foo2_t& r) {
362 return l.c == r.c && l.d == r.d;
363 }
364};
365WRITE_CLASS_DENC_BOUNDED(foo2_t)
366
367
368struct bar_t {
369 int32_t a = 0;
370 uint64_t b = 123;
371
372 DENC_FEATURED(bar_t, v, p, f) {
373 ::denc(v.a, p, f);
374 ::denc(v.b, p, f);
375 }
376
377 friend bool operator==(const bar_t& l, const bar_t& r) {
378 return l.a == r.a && l.b == r.b;
379 }
380};
381WRITE_CLASS_DENC_FEATURED_BOUNDED(bar_t)
382
383TEST(denc, foo)
384{
385 foo_t a;
386 test_denc(a);
387 bufferlist bl;
388 ::encode(a, bl);
389 bl.hexdump(cout);
390}
391
392TEST(denc, bar)
393{
394 bar_t a;
395 test_denc_featured(a);
396}
397
398
399
400TEST(denc, pair)
401{
402 pair<int32_t,std::string> p;
403 bufferlist bl;
404 {
405 auto a = bl.get_contiguous_appender(1000);
406 denc(p, a);
407 ::encode(p, bl);
408 }
409
410 pair<int32_t,legacy_t> lp;
411 ::encode(lp, bl);
412}
413
414template<template<class, class> class C>
415void test_common_maplike(const char* c) {
416 {
417 cout << c << "<std::string, foo_t>" << std::endl;
418 C<string, foo_t> s;
419 s["foo"] = foo_t();
420 s["bar"] = foo_t();
421 s["baz"] = foo_t();
422 test_denc(s);
423 }
424 {
425 cout << c << "<std::string, bar_t>" << std::endl;
426 C<string, bar_t> s;
427 s["foo"] = bar_t();
428 s["bar"] = bar_t();
429 s["baz"] = bar_t();
430 test_denc_featured(s);
431 }
432 {
433 cout << c << "<std::string, legacy_t>" << std::endl;
434 C<std::string, legacy_t> s;
435 s["foo"] = legacy_t(1);
436 s["bar"] = legacy_t(2);
437 test_encode_decode(s);
438 }
439}
440
441template<typename U, typename V>
442using default_map = std::map<U, V>;
443
444TEST(denc, map)
445{
446 test_common_maplike<default_map>("std::map");
447}
448
449template<typename U, typename V>
450using default_flat_map = boost::container::flat_map<U, V>;
451
452TEST(denc, flat_map)
453{
454 test_common_maplike<default_flat_map>("boost::container::flat_map");
455}
456
457TEST(denc, bufferptr_shallow_and_deep) {
458 // shallow encode
459 int32_t i = 1;
460 bufferptr p1("foo", 3);
461 bufferlist bl;
462 {
463 auto a = bl.get_contiguous_appender(100);
464 denc(i, a);
465 denc(p1, a);
466 denc(i, a);
467 }
468 cout << "bl is " << bl << std::endl;
469 bl.hexdump(cout);
470 ASSERT_EQ(3u, bl.get_num_buffers());
471
472 bufferlist bl2 = bl;
473 bl.rebuild();
474 bl2.rebuild();
475
476 // shallow decode
477 {
478 cout << "bl is " << bl << std::endl;
479 bl.hexdump(cout);
480 auto p = bl.front().begin();
481 bufferptr op;
482 int32_t i;
483 denc(i, p);
484 denc(op, p);
485 denc(i, p);
486 ASSERT_EQ(3u, op.length());
487 ASSERT_EQ('f', op[0]);
488 memset(bl.c_str(), 0, bl.length());
489 ASSERT_EQ(0, op[0]);
490 }
491
492 // deep decode
493 {
494 cout << "bl is " << bl2 << std::endl;
495 bl2.hexdump(cout);
496 auto p = bl2.front().begin_deep();
497 bufferptr op;
498 int32_t i;
499 denc(i, p);
500 denc(op, p);
501 denc(i, p);
502 ASSERT_EQ('f', op[0]);
503 memset(bl2.c_str(), 1, bl2.length());
504 ASSERT_EQ('f', op[0]);
505 }
506}
507
508TEST(denc, array)
509{
510 {
511 cout << "std::array<std::string, 3>" << std::endl;
512 std::array<std::string, 3> s = { "foo", "bar", "baz" };
513 counts.reset();
514 test_denc(s);
515 }
516 {
517 cout << "std::array<uint32_t, 3>" << std::endl;
518 std::array<uint32_t, 3> s = { 1UL, 2UL, 3UL };
519 test_denc(s);
520 }
521}
522
523TEST(denc, tuple)
524{
525 {
526 cout << "std::tuple<uint64_t, uint32_t>" << std::endl;
527 std::tuple<uint64_t, uint32_t> s(100ULL, 97UL);
528 counts.reset();
529 test_denc(s);
530 }
531 {
532 cout << "std::tuple<std::string, uint3_t>" << std::endl;
533 std::tuple<std::string, uint32_t> s("foo", 97);
534 test_denc(s);
535 }
536 {
537 cout << "std::tuple<std::string, std::set<uint32_t>>" << std::endl;
538 std::tuple<std::string, std::set<uint32_t>> s(
539 "bar", std::set<uint32_t>{uint32_t(1), uint32_t(2), uint32_t(3)});
540 test_denc(s);
541 }
542}
543
544TEST(denc, optional)
545{
546 {
547 cout << "boost::optional<uint64_t>" << std::endl;
548 boost::optional<uint64_t> s = 97, t = boost::none;
549 counts.reset();
550 test_denc(s);
551 test_denc(t);
552 }
553 {
554 cout << "boost::optional<std::string>" << std::endl;
555 boost::optional<std::string> s = std::string("Meow"), t = boost::none;
556 counts.reset();
557 test_denc(s);
558 test_denc(t);
559 }
560 {
561 size_t s = 0;
562 denc(boost::none, s);
563 ASSERT_NE(s, 0u);
564
565 // encode
566 bufferlist bl;
567 {
568 auto a = bl.get_contiguous_appender(s);
569 denc(boost::none, a);
570 }
571 ASSERT_LE(bl.length(), s);
572
573 bl.rebuild();
574 boost::optional<uint32_t> out = 5;
575 auto bpi = bl.front().begin();
576 denc(out, bpi);
577 ASSERT_FALSE(!!out);
578 ASSERT_EQ(bpi.get_pos(), bl.c_str() + bl.length());
579 }
580}