1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 #include "gtest/gtest.h"
5 #include "mds/mdstypes.h"
6 #include "include/err.h"
7 #include "include/buffer.h"
8 #include "include/rbd_types.h"
9 #include "include/rados/librados.h"
10 #include "include/rados/librados.hpp"
11 #include "include/stringify.h"
12 #include "common/Checksummer.h"
13 #include "global/global_context.h"
14 #include "test/librados/test.h"
15 #include "test/librados/TestCase.h"
16 #include "gtest/gtest.h"
22 #include <boost/regex.hpp>
24 using namespace librados
;
26 using std::ostringstream
;
29 typedef RadosTest LibRadosMisc
;
30 typedef RadosTestPP LibRadosMiscPP
;
31 typedef RadosTestECPP LibRadosMiscECPP
;
33 TEST(LibRadosMiscVersion
, Version
) {
34 int major
, minor
, extra
;
35 rados_version(&major
, &minor
, &extra
);
38 TEST(LibRadosMiscVersion
, VersionPP
) {
39 int major
, minor
, extra
;
40 Rados::version(&major
, &minor
, &extra
);
43 static void test_rados_log_cb(void *arg
,
46 uint64_t sec
, uint64_t nsec
,
47 uint64_t seq
, const char *level
,
50 std::cerr
<< "monitor log callback invoked" << std::endl
;
53 TEST(LibRadosMiscConnectFailure
, ConnectFailure
) {
56 char *id
= getenv("CEPH_CLIENT_ID");
58 std::cerr
<< "Client id is: " << id
<< std::endl
;
60 ASSERT_EQ(0, rados_create(&cluster
, NULL
));
61 ASSERT_EQ(0, rados_conf_read_file(cluster
, NULL
));
62 ASSERT_EQ(0, rados_conf_parse_env(cluster
, NULL
));
64 ASSERT_EQ(0, rados_conf_set(cluster
, "client_mount_timeout", "0.000000001"));
65 ASSERT_EQ(0, rados_conf_set(cluster
, "debug_monc", "20"));
66 ASSERT_EQ(0, rados_conf_set(cluster
, "debug_ms", "1"));
67 ASSERT_EQ(0, rados_conf_set(cluster
, "log_to_stderr", "true"));
69 ASSERT_EQ(-ENOTCONN
, rados_monitor_log(cluster
, "error",
70 test_rados_log_cb
, NULL
));
72 // try this a few times; sometimes we don't schedule fast enough for the
75 for (unsigned i
=0; i
<16; ++i
) {
76 cout
<< i
<< std::endl
;
77 r
= rados_connect(cluster
);
79 break; // yay, we timed out
81 rados_shutdown(cluster
);
82 ASSERT_EQ(0, rados_create(&cluster
, NULL
));
86 rados_shutdown(cluster
);
89 TEST(LibRadosMiscPool
, PoolCreationRace
) {
90 rados_t cluster_a
, cluster_b
;
92 char *id
= getenv("CEPH_CLIENT_ID");
94 std::cerr
<< "Client id is: " << id
<< std::endl
;
96 ASSERT_EQ(0, rados_create(&cluster_a
, NULL
));
97 ASSERT_EQ(0, rados_conf_read_file(cluster_a
, NULL
));
98 // kludge: i want to --log-file foo and only get cluster b
99 //ASSERT_EQ(0, rados_conf_parse_env(cluster_a, NULL));
100 ASSERT_EQ(0, rados_connect(cluster_a
));
102 ASSERT_EQ(0, rados_create(&cluster_b
, NULL
));
103 ASSERT_EQ(0, rados_conf_read_file(cluster_b
, NULL
));
104 ASSERT_EQ(0, rados_conf_parse_env(cluster_b
, NULL
));
105 ASSERT_EQ(0, rados_conf_set(cluster_b
,
106 "objecter_debug_inject_relock_delay", "true"));
107 ASSERT_EQ(0, rados_connect(cluster_b
));
110 snprintf(poolname
, sizeof(poolname
), "poolrace.%d", rand());
111 rados_pool_create(cluster_a
, poolname
);
113 rados_ioctx_create(cluster_a
, poolname
, &a
);
114 int64_t poolid
= rados_ioctx_get_id(a
);
116 rados_ioctx_create2(cluster_b
, poolid
+1, &b
);
119 snprintf(pool2name
, sizeof(pool2name
), "poolrace2.%d", rand());
120 rados_pool_create(cluster_a
, pool2name
);
122 list
<rados_completion_t
> cls
;
123 // this should normally trigger pretty easily, but we need to bound
124 // the requests because if we get too many we'll get stuck by always
125 // sending enough messages that we hit the socket failure injection.
129 rados_completion_t c
;
130 rados_aio_create_completion(0, 0, 0, &c
);
132 rados_aio_read(b
, "PoolCreationRaceObj", c
, buf
, 100, 0);
133 cout
<< "started " << (void*)c
<< std::endl
;
134 if (rados_aio_is_complete(cls
.front())) {
138 while (!rados_aio_is_complete(cls
.front())) {
139 cout
<< "waiting 1 sec" << std::endl
;
143 cout
<< " started " << cls
.size() << " aios" << std::endl
;
145 cout
<< "waiting " << (void*)c
<< std::endl
;
146 rados_aio_wait_for_complete_and_cb(c
);
147 rados_aio_release(c
);
149 cout
<< "done." << std::endl
;
151 rados_ioctx_destroy(a
);
152 rados_ioctx_destroy(b
);
153 rados_pool_delete(cluster_a
, poolname
);
154 rados_pool_delete(cluster_a
, pool2name
);
155 rados_shutdown(cluster_b
);
156 rados_shutdown(cluster_a
);
159 TEST_F(LibRadosMisc
, ClusterFSID
) {
161 ASSERT_EQ(-ERANGE
, rados_cluster_fsid(cluster
, fsid
, sizeof(fsid
) - 1));
162 ASSERT_EQ(sizeof(fsid
) - 1,
163 (size_t)rados_cluster_fsid(cluster
, fsid
, sizeof(fsid
)));
166 TEST_F(LibRadosMiscPP
, WaitOSDMapPP
) {
167 ASSERT_EQ(0, cluster
.wait_for_latest_osdmap());
170 TEST_F(LibRadosMiscPP
, LongNamePP
) {
172 bl
.append("content");
173 int maxlen
= g_conf
->osd_max_object_name_len
;
174 ASSERT_EQ(0, ioctx
.write(string(maxlen
/2, 'a').c_str(), bl
, bl
.length(), 0));
175 ASSERT_EQ(0, ioctx
.write(string(maxlen
-1, 'a').c_str(), bl
, bl
.length(), 0));
176 ASSERT_EQ(0, ioctx
.write(string(maxlen
, 'a').c_str(), bl
, bl
.length(), 0));
177 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.write(string(maxlen
+1, 'a').c_str(), bl
, bl
.length(), 0));
178 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.write(string(maxlen
*2, 'a').c_str(), bl
, bl
.length(), 0));
181 TEST_F(LibRadosMiscPP
, LongLocatorPP
) {
183 bl
.append("content");
184 int maxlen
= g_conf
->osd_max_object_name_len
;
185 ioctx
.locator_set_key(
186 string((maxlen
/2), 'a'));
191 bl
, bl
.length(), 0));
192 ioctx
.locator_set_key(
193 string(maxlen
- 1, 'a'));
198 bl
, bl
.length(), 0));
199 ioctx
.locator_set_key(
200 string(maxlen
, 'a'));
205 bl
, bl
.length(), 0));
206 ioctx
.locator_set_key(
207 string(maxlen
+1, 'a'));
212 bl
, bl
.length(), 0));
213 ioctx
.locator_set_key(
214 string((maxlen
*2), 'a'));
219 bl
, bl
.length(), 0));
222 TEST_F(LibRadosMiscPP
, LongNSpacePP
) {
224 bl
.append("content");
225 int maxlen
= g_conf
->osd_max_object_namespace_len
;
227 string((maxlen
/2), 'a'));
232 bl
, bl
.length(), 0));
234 string(maxlen
- 1, 'a'));
239 bl
, bl
.length(), 0));
241 string(maxlen
, 'a'));
246 bl
, bl
.length(), 0));
248 string(maxlen
+1, 'a'));
253 bl
, bl
.length(), 0));
255 string((maxlen
*2), 'a'));
260 bl
, bl
.length(), 0));
263 TEST_F(LibRadosMiscPP
, LongAttrNamePP
) {
265 bl
.append("content");
266 int maxlen
= g_conf
->osd_max_attr_name_len
;
267 ASSERT_EQ(0, ioctx
.setxattr("bigattrobj", string(maxlen
/2, 'a').c_str(), bl
));
268 ASSERT_EQ(0, ioctx
.setxattr("bigattrobj", string(maxlen
-1, 'a').c_str(), bl
));
269 ASSERT_EQ(0, ioctx
.setxattr("bigattrobj", string(maxlen
, 'a').c_str(), bl
));
270 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.setxattr("bigattrobj", string(maxlen
+1, 'a').c_str(), bl
));
271 ASSERT_EQ(-ENAMETOOLONG
, ioctx
.setxattr("bigattrobj", string(maxlen
*2, 'a').c_str(), bl
));
274 static std::string
read_key_from_tmap(IoCtx
& ioctx
, const std::string
&obj
,
275 const std::string
&key
)
278 int r
= ioctx
.read(obj
, bl
, 0, 0);
281 oss
<< "ioctx.read(" << obj
<< ", bl, 0, 0) returned " << r
;
284 bufferlist::iterator p
= bl
.begin();
286 map
<string
, bufferlist
> m
;
289 map
<string
, bufferlist
>::iterator i
= m
.find(key
);
292 std::string retstring
;
293 ::decode(retstring
, i
->second
);
297 static std::string
add_key_to_tmap(IoCtx
&ioctx
, const std::string
&obj
,
298 const std::string
&key
, const std::string
&val
)
300 __u8 c
= CEPH_OSD_TMAP_SET
;
307 ::encode(blbl
, tmbl
);
308 int ret
= ioctx
.tmap_update(obj
, tmbl
);
311 oss
<< "ioctx.tmap_update(obj=" << obj
<< ", key="
312 << key
<< ", val=" << val
<< ") failed with error " << ret
;
318 static int remove_key_from_tmap(IoCtx
&ioctx
, const std::string
&obj
,
319 const std::string
&key
)
321 __u8 c
= CEPH_OSD_TMAP_RM
;
326 int ret
= ioctx
.tmap_update(obj
, tmbl
);
329 oss
<< "ioctx.tmap_update(obj=" << obj
<< ", key="
330 << key
<< ") failed with error " << ret
;
335 TEST_F(LibRadosMiscPP
, TmapUpdatePP
) {
338 __u8 c
= CEPH_OSD_TMAP_CREATE
;
339 std::string
my_tmap("my_tmap");
344 ::encode(my_tmap
, tmbl
);
345 ::encode(emptybl
, tmbl
);
346 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
349 ASSERT_EQ(string(""), add_key_to_tmap(ioctx
, "foo", "key1", "val1"));
351 ASSERT_EQ(string(""), add_key_to_tmap(ioctx
, "foo", "key2", "val2"));
353 // read key1 from the tmap
354 ASSERT_EQ(string("val1"), read_key_from_tmap(ioctx
, "foo", "key1"));
356 // remove key1 from tmap
357 ASSERT_EQ(0, remove_key_from_tmap(ioctx
, "foo", "key1"));
358 ASSERT_EQ(-ENOENT
, remove_key_from_tmap(ioctx
, "foo", "key1"));
360 // key should be removed
361 ASSERT_EQ(string(""), read_key_from_tmap(ioctx
, "foo", "key1"));
364 TEST_F(LibRadosMiscPP
, TmapUpdateMisorderedPP
) {
367 __u8 c
= CEPH_OSD_TMAP_CREATE
;
368 std::string
my_tmap("my_tmap");
373 ::encode(my_tmap
, tmbl
);
374 ::encode(emptybl
, tmbl
);
375 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
380 __u8 c
= CEPH_OSD_TMAP_SET
;
385 ::encode("old", blbl
);
386 ::encode(blbl
, tmbl
);
390 ::encode(blbl
, tmbl
);
394 ::encode(blbl
, tmbl
);
396 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
401 __u8 c
= CEPH_OSD_TMAP_SET
;
406 ::encode("new", blbl
);
407 ::encode(blbl
, tmbl
);
411 ::encode(blbl
, tmbl
);
415 ::encode(blbl
, tmbl
);
417 ASSERT_EQ(0, ioctx
.tmap_update("foo", tmbl
));
421 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx
, "foo", "a"));
422 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx
, "foo", "b"));
423 ASSERT_EQ(string("new"), read_key_from_tmap(ioctx
, "foo", "c"));
425 ASSERT_EQ(0, remove_key_from_tmap(ioctx
, "foo", "a"));
426 ASSERT_EQ(string(""), read_key_from_tmap(ioctx
, "foo", "a"));
428 ASSERT_EQ(0, remove_key_from_tmap(ioctx
, "foo", "b"));
429 ASSERT_EQ(string(""), read_key_from_tmap(ioctx
, "foo", "a"));
432 TEST_F(LibRadosMiscPP
, TmapUpdateMisorderedPutPP
) {
433 // create unsorted tmap
439 ::encode(string("b"), bl
);
440 ::encode(string("bval"), bl
);
441 ::encode(string("a"), bl
);
442 ::encode(string("aval"), bl
);
443 ::encode(string("c"), bl
);
444 ::encode(string("cval"), bl
);
445 bufferlist orig
= bl
; // tmap_put steals bl content
446 ASSERT_EQ(0, ioctx
.tmap_put("foo", bl
));
450 ioctx
.read("foo", newbl
, orig
.length(), 0);
451 ASSERT_EQ(orig
.contents_equal(newbl
), false);
454 TEST_F(LibRadosMiscPP
, Tmap2OmapPP
) {
457 hdr
.append("header");
458 map
<string
, bufferlist
> omap
;
459 omap
["1"].append("a");
460 omap
["2"].append("b");
461 omap
["3"].append("c");
466 ASSERT_EQ(0, ioctx
.tmap_put("foo", bl
));
469 // convert tmap to omap
470 ASSERT_EQ(0, ioctx
.tmap_to_omap("foo", false));
472 // if tmap was truncated ?
476 ASSERT_EQ(0, ioctx
.stat("foo", &size
, &mtime
));
481 ASSERT_EQ(0, ioctx
.tmap_to_omap("foo", true));
482 ASSERT_LE(ioctx
.tmap_to_omap("foo", false), 0);
487 map
<string
, bufferlist
> m
;
488 ObjectReadOperation o
;
489 o
.omap_get_header(&got
, NULL
);
490 o
.omap_get_vals2("", 1024, &m
, nullptr, nullptr);
491 ASSERT_EQ(0, ioctx
.operate("foo", &o
, NULL
));
494 ASSERT_TRUE(hdr
.contents_equal(got
));
497 ASSERT_EQ(omap
.size(), m
.size());
499 for (map
<string
, bufferlist
>::iterator p
= omap
.begin(); p
!= omap
.end(); ++p
) {
500 map
<string
, bufferlist
>::iterator q
= m
.find(p
->first
);
501 if (q
== m
.end() || !p
->second
.contents_equal(q
->second
)) {
510 TEST_F(LibRadosMisc
, Exec
) {
512 memset(buf
, 0xcc, sizeof(buf
));
513 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
515 int res
= rados_exec(ioctx
, "foo", "rbd", "get_all_features",
516 NULL
, 0, buf2
, sizeof(buf2
));
519 bl
.append(buf2
, res
);
520 bufferlist::iterator iter
= bl
.begin();
521 uint64_t all_features
;
522 ::decode(all_features
, iter
);
523 // make sure *some* features are specified; don't care which ones
524 ASSERT_NE(all_features
, (unsigned)0);
527 TEST_F(LibRadosMiscPP
, ExecPP
) {
529 ASSERT_EQ(0, ioctx
.write("foo", bl
, 0, 0));
531 int r
= ioctx
.exec("foo", "rbd", "get_all_features", bl2
, out
);
533 bufferlist::iterator iter
= out
.begin();
534 uint64_t all_features
;
535 ::decode(all_features
, iter
);
536 // make sure *some* features are specified; don't care which ones
537 ASSERT_NE(all_features
, (unsigned)0);
540 void set_completion_complete(rados_completion_t cb
, void *arg
)
542 bool *my_aio_complete
= (bool*)arg
;
543 *my_aio_complete
= true;
546 TEST_F(LibRadosMiscPP
, BadFlagsPP
) {
547 unsigned badflags
= CEPH_OSD_FLAG_PARALLELEXEC
;
551 ASSERT_EQ(0, ioctx
.write("badfoo", bl
, bl
.length(), 0));
554 ASSERT_EQ(-EINVAL
, ioctx
.remove("badfoo", badflags
));
558 TEST_F(LibRadosMiscPP
, Operate1PP
) {
559 ObjectWriteOperation o
;
564 std::string
val1("val1");
567 bl
.append(val1
.c_str(), val1
.size() + 1);
568 o
.setxattr("key1", bl
);
569 o
.omap_clear(); // shouldn't affect attrs!
571 ASSERT_EQ(0, ioctx
.operate("foo", &o
));
573 ObjectWriteOperation empty
;
574 ASSERT_EQ(0, ioctx
.operate("foo", &empty
));
578 ASSERT_GT(ioctx
.getxattr("foo", "key1", bl
), 0);
579 ASSERT_EQ(0, strcmp(bl
.c_str(), val1
.c_str()));
581 ObjectWriteOperation o2
;
585 o2
.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ
, bl
);
588 ASSERT_EQ(-ECANCELED
, ioctx
.operate("foo", &o2
));
589 ObjectWriteOperation o3
;
593 o3
.cmpxattr("key1", CEPH_OSD_CMPXATTR_OP_EQ
, bl
);
595 ASSERT_EQ(-ECANCELED
, ioctx
.operate("foo", &o3
));
598 TEST_F(LibRadosMiscPP
, Operate2PP
) {
599 ObjectWriteOperation o
;
602 bl
.append("abcdefg");
605 std::string
val1("val1");
608 bl
.append(val1
.c_str(), val1
.size() + 1);
609 o
.setxattr("key1", bl
);
612 ASSERT_EQ(0, ioctx
.operate("foo", &o
));
615 ASSERT_EQ(0, ioctx
.stat("foo", &size
, &mtime
));
619 TEST_F(LibRadosMiscPP
, BigObjectPP
) {
621 bl
.append("abcdefg");
622 ASSERT_EQ(0, ioctx
.write("foo", bl
, bl
.length(), 0));
625 ObjectWriteOperation o
;
626 o
.truncate(500000000000ull);
627 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
630 ObjectWriteOperation o
;
631 o
.zero(500000000000ull, 1);
632 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
635 ObjectWriteOperation o
;
636 o
.zero(1, 500000000000ull);
637 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
640 ObjectWriteOperation o
;
641 o
.zero(500000000000ull, 500000000000ull);
642 ASSERT_EQ(-EFBIG
, ioctx
.operate("foo", &o
));
646 // this test only works on 64-bit platforms
647 ASSERT_EQ(-EFBIG
, ioctx
.write("foo", bl
, bl
.length(), 500000000000ull));
651 TEST_F(LibRadosMiscPP
, AioOperatePP
) {
652 bool my_aio_complete
= false;
653 AioCompletion
*my_completion
= cluster
.aio_create_completion(
654 (void*)&my_aio_complete
, set_completion_complete
, NULL
);
655 AioCompletion
*my_completion_null
= NULL
;
656 ASSERT_NE(my_completion
, my_completion_null
);
658 ObjectWriteOperation o
;
663 std::string
val1("val1");
666 bl
.append(val1
.c_str(), val1
.size() + 1);
667 o
.setxattr("key1", bl
);
670 memset(buf2
, 0xdd, sizeof(buf2
));
671 bl2
.append(buf2
, sizeof(buf2
));
674 ASSERT_EQ(0, ioctx
.aio_operate("foo", my_completion
, &o
));
675 ASSERT_EQ(0, my_completion
->wait_for_complete_and_cb());
676 ASSERT_EQ(my_aio_complete
, true);
677 my_completion
->release();
681 ASSERT_EQ(0, ioctx
.stat("foo", &size
, &mtime
));
682 ASSERT_EQ(1024U, size
);
685 TEST_F(LibRadosMiscPP
, AssertExistsPP
) {
687 memset(buf
, 0xcc, sizeof(buf
));
689 bl
.append(buf
, sizeof(buf
));
691 ObjectWriteOperation op
;
694 ASSERT_EQ(-ENOENT
, ioctx
.operate("asdffoo", &op
));
695 ASSERT_EQ(0, ioctx
.create("asdffoo", true));
696 ASSERT_EQ(0, ioctx
.operate("asdffoo", &op
));
697 ASSERT_EQ(-EEXIST
, ioctx
.create("asdffoo", true));
700 TEST_F(LibRadosMiscPP
, AssertVersionPP
) {
702 memset(buf
, 0xcc, sizeof(buf
));
704 bl
.append(buf
, sizeof(buf
));
706 // Create test object...
707 ASSERT_EQ(0, ioctx
.create("asdfbar", true));
708 // ...then write it again to guarantee that the
709 // (unsigned) version must be at least 1 (not 0)
710 // since we want to decrement it by 1 later.
711 ASSERT_EQ(0, ioctx
.write_full("asdfbar", bl
));
713 uint64_t v
= ioctx
.get_last_version();
714 ObjectWriteOperation op1
;
715 op1
.assert_version(v
+1);
717 ASSERT_EQ(-EOVERFLOW
, ioctx
.operate("asdfbar", &op1
));
718 ObjectWriteOperation op2
;
719 op2
.assert_version(v
-1);
721 ASSERT_EQ(-ERANGE
, ioctx
.operate("asdfbar", &op2
));
722 ObjectWriteOperation op3
;
723 op3
.assert_version(v
);
725 ASSERT_EQ(0, ioctx
.operate("asdfbar", &op3
));
728 TEST_F(LibRadosMiscPP
, BigAttrPP
) {
730 memset(buf
, 0xcc, sizeof(buf
));
732 bl
.append(buf
, sizeof(buf
));
734 ASSERT_EQ(0, ioctx
.create("foo", true));
738 cout
<< "osd_max_attr_size = " << g_conf
->osd_max_attr_size
<< std::endl
;
739 if (g_conf
->osd_max_attr_size
) {
742 bl
.append(buffer::create(g_conf
->osd_max_attr_size
));
743 ASSERT_EQ(0, ioctx
.setxattr("foo", "one", bl
));
744 ASSERT_EQ((int)bl
.length(), ioctx
.getxattr("foo", "one", got
));
745 ASSERT_TRUE(bl
.contents_equal(got
));
748 bl
.append(buffer::create(g_conf
->osd_max_attr_size
+1));
749 ASSERT_EQ(-EFBIG
, ioctx
.setxattr("foo", "one", bl
));
751 cout
<< "osd_max_attr_size == 0; skipping test" << std::endl
;
754 for (int i
=0; i
<1000; i
++) {
757 bl
.append(buffer::create(MIN(g_conf
->osd_max_attr_size
, 1024)));
759 snprintf(n
, sizeof(n
), "a%d", i
);
760 ASSERT_EQ(0, ioctx
.setxattr("foo", n
, bl
));
761 ASSERT_EQ((int)bl
.length(), ioctx
.getxattr("foo", n
, got
));
762 ASSERT_TRUE(bl
.contents_equal(got
));
766 TEST_F(LibRadosMiscPP
, CopyPP
) {
768 bl
.append("hi there");
774 ASSERT_EQ(0, ioctx
.write_full("foo", blc
));
775 ASSERT_EQ(0, ioctx
.setxattr("foo", "myattr", xc
));
777 version_t uv
= ioctx
.get_last_version();
779 // pass future version
780 ObjectWriteOperation op
;
781 op
.copy_from2("foo", ioctx
, uv
+ 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
782 ASSERT_EQ(-EOVERFLOW
, ioctx
.operate("foo.copy", &op
));
786 ObjectWriteOperation op
;
787 op
.copy_from2("foo", ioctx
, uv
- 1, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
788 ASSERT_EQ(-ERANGE
, ioctx
.operate("foo.copy", &op
));
791 ObjectWriteOperation op
;
792 op
.copy_from2("foo", ioctx
, uv
, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
793 ASSERT_EQ(0, ioctx
.operate("foo.copy", &op
));
796 ASSERT_EQ((int)bl
.length(), ioctx
.read("foo.copy", bl2
, 10000, 0));
797 ASSERT_TRUE(bl
.contents_equal(bl2
));
798 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy", "myattr", x2
));
799 ASSERT_TRUE(x
.contents_equal(x2
));
802 // small object without a version
804 ObjectWriteOperation op
;
805 op
.copy_from2("foo", ioctx
, 0, LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
806 ASSERT_EQ(0, ioctx
.operate("foo.copy2", &op
));
809 ASSERT_EQ((int)bl
.length(), ioctx
.read("foo.copy2", bl2
, 10000, 0));
810 ASSERT_TRUE(bl
.contents_equal(bl2
));
811 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy2", "myattr", x2
));
812 ASSERT_TRUE(x
.contents_equal(x2
));
816 bl
.append(buffer::create(g_conf
->osd_copyfrom_max_chunk
* 3));
821 ASSERT_EQ(0, ioctx
.write_full("big", blc
));
822 ASSERT_EQ(0, ioctx
.setxattr("big", "myattr", xc
));
825 ObjectWriteOperation op
;
826 op
.copy_from2("big", ioctx
, ioctx
.get_last_version(), LIBRADOS_OP_FLAG_FADVISE_DONTNEED
);
827 ASSERT_EQ(0, ioctx
.operate("big.copy", &op
));
830 ASSERT_EQ((int)bl
.length(), ioctx
.read("big.copy", bl2
, bl
.length(), 0));
831 ASSERT_TRUE(bl
.contents_equal(bl2
));
832 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy", "myattr", x2
));
833 ASSERT_TRUE(x
.contents_equal(x2
));
837 ObjectWriteOperation op
;
838 op
.copy_from2("big", ioctx
, 0, LIBRADOS_OP_FLAG_FADVISE_SEQUENTIAL
);
839 ASSERT_EQ(0, ioctx
.operate("big.copy2", &op
));
842 ASSERT_EQ((int)bl
.length(), ioctx
.read("big.copy2", bl2
, bl
.length(), 0));
843 ASSERT_TRUE(bl
.contents_equal(bl2
));
844 ASSERT_EQ((int)x
.length(), ioctx
.getxattr("foo.copy2", "myattr", x2
));
845 ASSERT_TRUE(x
.contents_equal(x2
));
849 class LibRadosTwoPoolsECPP
: public RadosTestECPP
852 LibRadosTwoPoolsECPP() {};
853 ~LibRadosTwoPoolsECPP() override
{};
855 static void SetUpTestCase() {
856 pool_name
= get_temp_pool_name();
857 ASSERT_EQ("", create_one_ec_pool_pp(pool_name
, s_cluster
));
858 src_pool_name
= get_temp_pool_name();
859 ASSERT_EQ(0, s_cluster
.pool_create(src_pool_name
.c_str()));
861 librados::IoCtx ioctx
;
862 ASSERT_EQ(0, s_cluster
.ioctx_create(pool_name
.c_str(), ioctx
));
863 ioctx
.application_enable("rados", true);
865 librados::IoCtx src_ioctx
;
866 ASSERT_EQ(0, s_cluster
.ioctx_create(src_pool_name
.c_str(), src_ioctx
));
867 src_ioctx
.application_enable("rados", true);
869 static void TearDownTestCase() {
870 ASSERT_EQ(0, s_cluster
.pool_delete(src_pool_name
.c_str()));
871 ASSERT_EQ(0, destroy_one_ec_pool_pp(pool_name
, s_cluster
));
873 static std::string src_pool_name
;
875 void SetUp() override
{
876 RadosTestECPP::SetUp();
877 ASSERT_EQ(0, cluster
.ioctx_create(src_pool_name
.c_str(), src_ioctx
));
878 src_ioctx
.set_namespace(nspace
);
880 void TearDown() override
{
881 // wait for maps to settle before next test
882 cluster
.wait_for_latest_osdmap();
884 RadosTestECPP::TearDown();
886 cleanup_default_namespace(src_ioctx
);
887 cleanup_namespace(src_ioctx
, nspace
);
892 librados::IoCtx src_ioctx
;
894 std::string
LibRadosTwoPoolsECPP::src_pool_name
;
896 //copy_from between ecpool and no-ecpool.
897 TEST_F(LibRadosTwoPoolsECPP
, CopyFrom
) {
899 z
.append_zero(4194304*2);
901 b
.append("copyfrom");
903 // create big object w/ omapheader
905 ASSERT_EQ(0, src_ioctx
.write_full("foo", z
));
906 ASSERT_EQ(0, src_ioctx
.omap_set_header("foo", b
));
907 version_t uv
= src_ioctx
.get_last_version();
908 ObjectWriteOperation op
;
909 op
.copy_from("foo", src_ioctx
, uv
);
910 ASSERT_EQ(-EOPNOTSUPP
, ioctx
.operate("foo.copy", &op
));
913 // same with small object
915 ASSERT_EQ(0, src_ioctx
.omap_set_header("bar", b
));
916 version_t uv
= src_ioctx
.get_last_version();
917 ObjectWriteOperation op
;
918 op
.copy_from("bar", src_ioctx
, uv
);
919 ASSERT_EQ(-EOPNOTSUPP
, ioctx
.operate("bar.copy", &op
));
923 TEST_F(LibRadosMiscPP
, CopyScrubPP
) {
924 bufferlist inbl
, bl
, x
;
925 for (int i
=0; i
<100; ++i
)
926 x
.append("barrrrrrrrrrrrrrrrrrrrrrrrrr");
927 bl
.append(buffer::create(g_conf
->osd_copyfrom_max_chunk
* 3));
932 map
<string
, bufferlist
> to_set
;
933 for (int i
=0; i
<1000; ++i
)
934 to_set
[string("foo") + stringify(i
)] = x
;
938 ASSERT_EQ(0, ioctx
.write_full("small", cbl
));
939 ASSERT_EQ(0, ioctx
.setxattr("small", "myattr", x
));
943 ASSERT_EQ(0, ioctx
.write_full("big", cbl
));
947 ASSERT_EQ(0, ioctx
.write_full("big2", cbl
));
948 ASSERT_EQ(0, ioctx
.setxattr("big2", "myattr", x
));
949 ASSERT_EQ(0, ioctx
.setxattr("big2", "myattr2", x
));
950 ASSERT_EQ(0, ioctx
.omap_set("big2", to_set
));
954 ASSERT_EQ(0, ioctx
.write_full("big3", cbl
));
955 ASSERT_EQ(0, ioctx
.omap_set_header("big3", x
));
956 ASSERT_EQ(0, ioctx
.omap_set("big3", to_set
));
958 // deep scrub to ensure digests are in place
960 for (int i
=0; i
<10; ++i
) {
962 ss
<< "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
963 << ioctx
.get_id() << "." << i
965 cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
968 // give it a few seconds to go. this is sloppy but is usually enough time
969 cout
<< "waiting for initial deep scrubs..." << std::endl
;
971 cout
<< "done waiting, doing copies" << std::endl
;
975 ObjectWriteOperation op
;
976 op
.copy_from("small", ioctx
, 0);
977 ASSERT_EQ(0, ioctx
.operate("small.copy", &op
));
981 ObjectWriteOperation op
;
982 op
.copy_from("big", ioctx
, 0);
983 ASSERT_EQ(0, ioctx
.operate("big.copy", &op
));
987 ObjectWriteOperation op
;
988 op
.copy_from("big2", ioctx
, 0);
989 ASSERT_EQ(0, ioctx
.operate("big2.copy", &op
));
993 ObjectWriteOperation op
;
994 op
.copy_from("big3", ioctx
, 0);
995 ASSERT_EQ(0, ioctx
.operate("big3.copy", &op
));
998 // deep scrub to ensure digests are correct
1000 for (int i
=0; i
<10; ++i
) {
1002 ss
<< "{\"prefix\": \"pg deep-scrub\", \"pgid\": \""
1003 << ioctx
.get_id() << "." << i
1005 cluster
.mon_command(ss
.str(), inbl
, NULL
, NULL
);
1008 // give it a few seconds to go. this is sloppy but is usually enough time
1009 cout
<< "waiting for final deep scrubs..." << std::endl
;
1011 cout
<< "done waiting" << std::endl
;
1015 TEST_F(LibRadosMiscPP
, WriteSamePP
) {
1022 /* zero the full range before using writesame */
1023 memset(full
, 0, sizeof(full
));
1024 fl
.append(full
, sizeof(full
));
1025 ASSERT_EQ(0, ioctx
.write("ws", fl
, fl
.length(), 0));
1027 memset(buf
, 0xcc, sizeof(buf
));
1029 bl
.append(buf
, sizeof(buf
));
1030 /* write the same buf four times */
1031 ASSERT_EQ(0, ioctx
.writesame("ws", bl
, sizeof(full
), 0));
1033 /* read back the full buffer and confirm that it matches */
1035 fl
.append(full
, sizeof(full
));
1036 ASSERT_EQ((int)fl
.length(), ioctx
.read("ws", fl
, fl
.length(), 0));
1038 for (cmp
= fl
.c_str(); cmp
< fl
.c_str() + fl
.length(); cmp
+= sizeof(buf
)) {
1039 ASSERT_EQ(0, memcmp(cmp
, buf
, sizeof(buf
)));
1042 /* write_len not a multiple of data_len should throw error */
1044 bl
.append(buf
, sizeof(buf
));
1045 ASSERT_EQ(-EINVAL
, ioctx
.writesame("ws", bl
, (sizeof(buf
) * 4) - 1, 0));
1047 ioctx
.writesame("ws", bl
, bl
.length() / 2, 0));
1048 /* write_len = data_len, i.e. same as write() */
1049 ASSERT_EQ(0, ioctx
.writesame("ws", bl
, sizeof(buf
), 0));
1052 ioctx
.writesame("ws", bl
, sizeof(buf
), 0));
1055 TEST_F(LibRadosMisc
, WriteSame
) {
1060 /* zero the full range before using writesame */
1061 memset(full
, 0, sizeof(full
));
1062 ASSERT_EQ(0, rados_write(ioctx
, "ws", full
, sizeof(full
), 0));
1064 memset(buf
, 0xcc, sizeof(buf
));
1065 /* write the same buf four times */
1066 ASSERT_EQ(0, rados_writesame(ioctx
, "ws", buf
, sizeof(buf
), sizeof(full
), 0));
1068 /* read back the full buffer and confirm that it matches */
1069 ASSERT_EQ((int)sizeof(full
), rados_read(ioctx
, "ws", full
, sizeof(full
), 0));
1071 for (cmp
= full
; cmp
< full
+ sizeof(full
); cmp
+= sizeof(buf
)) {
1072 ASSERT_EQ(0, memcmp(cmp
, buf
, sizeof(buf
)));
1075 /* write_len not a multiple of data_len should throw error */
1076 ASSERT_EQ(-EINVAL
, rados_writesame(ioctx
, "ws", buf
, sizeof(buf
),
1077 (sizeof(buf
) * 4) - 1, 0));
1079 rados_writesame(ioctx
, "ws", buf
, sizeof(buf
), sizeof(buf
) / 2, 0));
1081 rados_writesame(ioctx
, "ws", buf
, 0, sizeof(buf
), 0));
1082 /* write_len = data_len, i.e. same as rados_write() */
1083 ASSERT_EQ(0, rados_writesame(ioctx
, "ws", buf
, sizeof(buf
), sizeof(buf
), 0));
1086 template <typename T
>
1087 class LibRadosChecksum
: public LibRadosMiscPP
{
1089 typedef typename
T::alg_t alg_t
;
1090 typedef typename
T::value_t value_t
;
1091 typedef typename
alg_t::init_value_t init_value_t
;
1093 static const rados_checksum_type_t type
= T::type
;
1095 bufferlist content_bl
;
1097 using LibRadosMiscPP::SetUpTestCase
;
1098 using LibRadosMiscPP::TearDownTestCase
;
1100 void SetUp() override
{
1101 LibRadosMiscPP::SetUp();
1103 std::string
content(4096, '\0');
1104 for (size_t i
= 0; i
< content
.length(); ++i
) {
1105 content
[i
] = static_cast<char>(rand() % (126 - 33) + 33);
1107 content_bl
.append(content
);
1108 ASSERT_EQ(0, ioctx
.write("foo", content_bl
, content_bl
.length(), 0));
1112 template <rados_checksum_type_t _type
, typename AlgT
, typename ValueT
>
1113 class LibRadosChecksumParams
{
1116 typedef ValueT value_t
;
1117 static const rados_checksum_type_t type
= _type
;
1120 typedef ::testing::Types
<
1121 LibRadosChecksumParams
<LIBRADOS_CHECKSUM_TYPE_XXHASH32
,
1122 Checksummer::xxhash32
, uint32_t>,
1123 LibRadosChecksumParams
<LIBRADOS_CHECKSUM_TYPE_XXHASH64
,
1124 Checksummer::xxhash64
, uint64_t>,
1125 LibRadosChecksumParams
<LIBRADOS_CHECKSUM_TYPE_CRC32C
,
1126 Checksummer::crc32c
, uint32_t>
1127 > LibRadosChecksumTypes
;
1129 TYPED_TEST_CASE(LibRadosChecksum
, LibRadosChecksumTypes
);
1131 TYPED_TEST(LibRadosChecksum
, Subset
) {
1132 uint32_t chunk_size
= 1024;
1133 uint32_t csum_count
= this->content_bl
.length() / chunk_size
;
1135 typename
TestFixture::init_value_t init_value
= -1;
1136 bufferlist init_value_bl
;
1137 ::encode(init_value
, init_value_bl
);
1139 std::vector
<bufferlist
> checksum_bls(csum_count
);
1140 std::vector
<int> checksum_rvals(csum_count
);
1142 // individual checksum ops for each chunk
1143 ObjectReadOperation op
;
1144 for (uint32_t i
= 0; i
< csum_count
; ++i
) {
1145 op
.checksum(TestFixture::type
, init_value_bl
, i
* chunk_size
, chunk_size
,
1146 0, &checksum_bls
[i
], &checksum_rvals
[i
]);
1148 ASSERT_EQ(0, this->ioctx
.operate("foo", &op
, NULL
));
1150 for (uint32_t i
= 0; i
< csum_count
; ++i
) {
1151 ASSERT_EQ(0, checksum_rvals
[i
]);
1153 auto bl_it
= checksum_bls
[i
].begin();
1155 ::decode(count
, bl_it
);
1156 ASSERT_EQ(1U, count
);
1158 typename
TestFixture::value_t value
;
1159 ::decode(value
, bl_it
);
1161 bufferlist content_sub_bl
;
1162 content_sub_bl
.substr_of(this->content_bl
, i
* chunk_size
, chunk_size
);
1164 typename
TestFixture::value_t expected_value
;
1165 bufferptr expected_value_bp
= buffer::create_static(
1166 sizeof(expected_value
), reinterpret_cast<char*>(&expected_value
));
1167 Checksummer::template calculate
<typename
TestFixture::alg_t
>(
1168 init_value
, chunk_size
, 0, chunk_size
, content_sub_bl
,
1169 &expected_value_bp
);
1170 ASSERT_EQ(expected_value
, value
);
1174 TYPED_TEST(LibRadosChecksum
, Chunked
) {
1175 uint32_t chunk_size
= 1024;
1176 uint32_t csum_count
= this->content_bl
.length() / chunk_size
;
1178 typename
TestFixture::init_value_t init_value
= -1;
1179 bufferlist init_value_bl
;
1180 ::encode(init_value
, init_value_bl
);
1182 bufferlist checksum_bl
;
1185 // single op with chunked checksum results
1186 ObjectReadOperation op
;
1187 op
.checksum(TestFixture::type
, init_value_bl
, 0, this->content_bl
.length(),
1188 chunk_size
, &checksum_bl
, &checksum_rval
);
1189 ASSERT_EQ(0, this->ioctx
.operate("foo", &op
, NULL
));
1190 ASSERT_EQ(0, checksum_rval
);
1192 auto bl_it
= checksum_bl
.begin();
1194 ::decode(count
, bl_it
);
1195 ASSERT_EQ(csum_count
, count
);
1197 std::vector
<typename
TestFixture::value_t
> expected_values(csum_count
);
1198 bufferptr expected_values_bp
= buffer::create_static(
1199 csum_count
* sizeof(typename
TestFixture::value_t
),
1200 reinterpret_cast<char*>(&expected_values
[0]));
1202 Checksummer::template calculate
<typename
TestFixture::alg_t
>(
1203 init_value
, chunk_size
, 0, this->content_bl
.length(), this->content_bl
,
1204 &expected_values_bp
);
1206 for (uint32_t i
= 0; i
< csum_count
; ++i
) {
1207 typename
TestFixture::value_t value
;
1208 ::decode(value
, bl_it
);
1209 ASSERT_EQ(expected_values
[i
], value
);
1213 TEST_F(LibRadosMiscPP
, CmpExtPP
) {
1214 bufferlist cmp_bl
, bad_cmp_bl
, write_bl
;
1215 char stored_str
[] = "1234567891";
1216 char mismatch_str
[] = "1234577777";
1218 write_bl
.append(stored_str
);
1219 ioctx
.write("cmpextpp", write_bl
, write_bl
.length(), 0);
1220 cmp_bl
.append(stored_str
);
1221 ASSERT_EQ(0, ioctx
.cmpext("cmpextpp", 0, cmp_bl
));
1223 bad_cmp_bl
.append(mismatch_str
);
1224 ASSERT_EQ(-MAX_ERRNO
- 5, ioctx
.cmpext("cmpextpp", 0, bad_cmp_bl
));
1227 TEST_F(LibRadosMisc
, CmpExt
) {
1228 bufferlist cmp_bl
, bad_cmp_bl
, write_bl
;
1229 char stored_str
[] = "1234567891";
1230 char mismatch_str
[] = "1234577777";
1233 rados_write(ioctx
, "cmpextpp", stored_str
, sizeof(stored_str
), 0));
1236 rados_cmpext(ioctx
, "cmpextpp", stored_str
, sizeof(stored_str
), 0));
1238 ASSERT_EQ(-MAX_ERRNO
- 5,
1239 rados_cmpext(ioctx
, "cmpextpp", mismatch_str
, sizeof(mismatch_str
), 0));
1242 TEST_F(LibRadosMisc
, Applications
) {
1243 const char *cmd
[] = {"{\"prefix\":\"osd dump\"}", nullptr};
1245 size_t buflen
, stlen
;
1246 ASSERT_EQ(0, rados_mon_command(cluster
, (const char **)cmd
, 1, "", 0, &buf
,
1247 &buflen
, &st
, &stlen
));
1248 ASSERT_LT(0u, buflen
);
1250 rados_buffer_free(buf
);
1251 rados_buffer_free(st
);
1252 if (!boost::regex_search(result
, boost::regex("require_osd_release [l-z]"))) {
1253 std::cout
<< "SKIPPING";
1260 app_len
= sizeof(apps
);
1261 ASSERT_EQ(0, rados_application_list(ioctx
, apps
, &app_len
));
1262 ASSERT_EQ(6U, app_len
);
1263 ASSERT_EQ(0, memcmp("rados\0", apps
, app_len
));
1265 ASSERT_EQ(0, rados_application_enable(ioctx
, "app1", 1));
1266 ASSERT_EQ(-EPERM
, rados_application_enable(ioctx
, "app2", 0));
1267 ASSERT_EQ(0, rados_application_enable(ioctx
, "app2", 1));
1269 ASSERT_EQ(-ERANGE
, rados_application_list(ioctx
, apps
, &app_len
));
1270 ASSERT_EQ(16U, app_len
);
1271 ASSERT_EQ(0, rados_application_list(ioctx
, apps
, &app_len
));
1272 ASSERT_EQ(16U, app_len
);
1273 ASSERT_EQ(0, memcmp("app1\0app2\0rados\0", apps
, app_len
));
1280 key_len
= sizeof(keys
);
1281 val_len
= sizeof(vals
);
1282 ASSERT_EQ(-ENOENT
, rados_application_metadata_list(ioctx
, "dne", keys
,
1283 &key_len
, vals
, &val_len
));
1284 ASSERT_EQ(0, rados_application_metadata_list(ioctx
, "app1", keys
, &key_len
,
1286 ASSERT_EQ(0U, key_len
);
1287 ASSERT_EQ(0U, val_len
);
1289 ASSERT_EQ(-ENOENT
, rados_application_metadata_set(ioctx
, "dne", "key",
1291 ASSERT_EQ(0, rados_application_metadata_set(ioctx
, "app1", "key1", "value1"));
1292 ASSERT_EQ(0, rados_application_metadata_set(ioctx
, "app1", "key2", "value2"));
1294 ASSERT_EQ(-ERANGE
, rados_application_metadata_list(ioctx
, "app1", keys
,
1295 &key_len
, vals
, &val_len
));
1296 ASSERT_EQ(10U, key_len
);
1297 ASSERT_EQ(14U, val_len
);
1298 ASSERT_EQ(0, rados_application_metadata_list(ioctx
, "app1", keys
, &key_len
,
1300 ASSERT_EQ(10U, key_len
);
1301 ASSERT_EQ(14U, val_len
);
1302 ASSERT_EQ(0, memcmp("key1\0key2\0", keys
, key_len
));
1303 ASSERT_EQ(0, memcmp("value1\0value2\0", vals
, val_len
));
1305 ASSERT_EQ(0, rados_application_metadata_remove(ioctx
, "app1", "key1"));
1306 ASSERT_EQ(0, rados_application_metadata_list(ioctx
, "app1", keys
, &key_len
,
1308 ASSERT_EQ(5U, key_len
);
1309 ASSERT_EQ(7U, val_len
);
1310 ASSERT_EQ(0, memcmp("key2\0", keys
, key_len
));
1311 ASSERT_EQ(0, memcmp("value2\0", vals
, val_len
));
1314 TEST_F(LibRadosMiscPP
, Applications
) {
1315 bufferlist inbl
, outbl
;
1317 ASSERT_EQ(0, cluster
.mon_command("{\"prefix\": \"osd dump\"}",
1318 inbl
, &outbl
, &outs
));
1319 ASSERT_LT(0u, outbl
.length());
1320 ASSERT_LE(0u, outs
.length());
1321 if (!boost::regex_search(outbl
.to_str(),
1322 boost::regex("require_osd_release [l-z]"))) {
1323 std::cout
<< "SKIPPING";
1327 std::set
<std::string
> expected_apps
= {"rados"};
1328 std::set
<std::string
> apps
;
1329 ASSERT_EQ(0, ioctx
.application_list(&apps
));
1330 ASSERT_EQ(expected_apps
, apps
);
1332 ASSERT_EQ(0, ioctx
.application_enable("app1", true));
1333 ASSERT_EQ(-EPERM
, ioctx
.application_enable("app2", false));
1334 ASSERT_EQ(0, ioctx
.application_enable("app2", true));
1336 expected_apps
= {"app1", "app2", "rados"};
1337 ASSERT_EQ(0, ioctx
.application_list(&apps
));
1338 ASSERT_EQ(expected_apps
, apps
);
1340 std::map
<std::string
, std::string
> expected_meta
;
1341 std::map
<std::string
, std::string
> meta
;
1342 ASSERT_EQ(-ENOENT
, ioctx
.application_metadata_list("dne", &meta
));
1343 ASSERT_EQ(0, ioctx
.application_metadata_list("app1", &meta
));
1344 ASSERT_EQ(expected_meta
, meta
);
1346 ASSERT_EQ(-ENOENT
, ioctx
.application_metadata_set("dne", "key1", "value1"));
1347 ASSERT_EQ(0, ioctx
.application_metadata_set("app1", "key1", "value1"));
1348 ASSERT_EQ(0, ioctx
.application_metadata_set("app1", "key2", "value2"));
1350 expected_meta
= {{"key1", "value1"}, {"key2", "value2"}};
1351 ASSERT_EQ(0, ioctx
.application_metadata_list("app1", &meta
));
1352 ASSERT_EQ(expected_meta
, meta
);
1354 ASSERT_EQ(0, ioctx
.application_metadata_remove("app1", "key1"));
1356 expected_meta
= {{"key2", "value2"}};
1357 ASSERT_EQ(0, ioctx
.application_metadata_list("app1", &meta
));
1358 ASSERT_EQ(expected_meta
, meta
);
1361 TEST_F(LibRadosMiscECPP
, CompareExtentRange
) {
1364 ObjectWriteOperation write
;
1365 write
.write(0, bl1
);
1366 ASSERT_EQ(0, ioctx
.operate("foo", &write
));
1370 bl2
.append(std::string(2, '\0'));
1371 ObjectReadOperation read1
;
1372 read1
.cmpext(2, bl2
, nullptr);
1373 ASSERT_EQ(0, ioctx
.operate("foo", &read1
, nullptr));
1376 bl3
.append(std::string(4, '\0'));
1377 ObjectReadOperation read2
;
1378 read2
.cmpext(2097152, bl3
, nullptr);
1379 ASSERT_EQ(0, ioctx
.operate("foo", &read2
, nullptr));