]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librados/c_read_operations.cc
update sources to v12.1.1
[ceph.git] / ceph / src / test / librados / c_read_operations.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // Tests for the C API coverage of atomic read operations
3
4 #include <errno.h>
5 #include <string>
6
7 #include "include/err.h"
8 #include "include/rados/librados.h"
9 #include "test/librados/test.h"
10 #include "test/librados/TestCase.h"
11
12 const char *data = "testdata";
13 const char *obj = "testobj";
14 const size_t len = strlen(data);
15
16 class CReadOpsTest : public RadosTest {
17 protected:
18 void write_object() {
19 // Create an object and write to it
20 ASSERT_EQ(0, rados_write(ioctx, obj, data, len, 0));
21 }
22 void remove_object() {
23 ASSERT_EQ(0, rados_remove(ioctx, obj));
24 }
25 int cmp_xattr(const char *xattr, const char *value, size_t value_len,
26 uint8_t cmp_op)
27 {
28 rados_read_op_t op = rados_create_read_op();
29 rados_read_op_cmpxattr(op, xattr, cmp_op, value, value_len);
30 int r = rados_read_op_operate(op, ioctx, obj, 0);
31 rados_release_read_op(op);
32 return r;
33 }
34
35 void fetch_and_verify_omap_vals(char const* const* keys,
36 char const* const* vals,
37 const size_t *lens,
38 size_t len)
39 {
40 rados_omap_iter_t iter_vals, iter_keys, iter_vals_by_key;
41 int r_vals, r_keys, r_vals_by_key;
42 rados_read_op_t op = rados_create_read_op();
43 rados_read_op_omap_get_vals2(op, NULL, NULL, 100, &iter_vals, NULL, &r_vals);
44 rados_read_op_omap_get_keys2(op, NULL, 100, &iter_keys, NULL, &r_keys);
45 rados_read_op_omap_get_vals_by_keys(op, keys, len,
46 &iter_vals_by_key, &r_vals_by_key);
47 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
48 rados_release_read_op(op);
49 ASSERT_EQ(0, r_vals);
50 ASSERT_EQ(0, r_keys);
51 ASSERT_EQ(0, r_vals_by_key);
52
53 const char *zeros[len];
54 size_t zero_lens[len];
55 memset(zeros, 0, sizeof(zeros));
56 memset(zero_lens, 0, sizeof(zero_lens));
57 compare_omap_vals(keys, vals, lens, len, iter_vals);
58 compare_omap_vals(keys, zeros, zero_lens, len, iter_keys);
59 compare_omap_vals(keys, vals, lens, len, iter_vals_by_key);
60 }
61
62 void compare_omap_vals(char const* const* keys,
63 char const* const* vals,
64 const size_t *lens,
65 size_t len,
66 rados_omap_iter_t iter)
67 {
68 size_t i = 0;
69 char *key = NULL;
70 char *val = NULL;
71 size_t val_len = 0;
72 while (i < len) {
73 ASSERT_EQ(0, rados_omap_get_next(iter, &key, &val, &val_len));
74 if (val_len == 0 && key == NULL && val == NULL)
75 break;
76 if (key)
77 EXPECT_EQ(std::string(keys[i]), std::string(key));
78 else
79 EXPECT_EQ(keys[i], key);
80 ASSERT_EQ(0, memcmp(vals[i], val, val_len));
81 ASSERT_EQ(lens[i], val_len);
82 ++i;
83 }
84 ASSERT_EQ(i, len);
85 ASSERT_EQ(0, rados_omap_get_next(iter, &key, &val, &val_len));
86 ASSERT_EQ((char*)NULL, key);
87 ASSERT_EQ((char*)NULL, val);
88 ASSERT_EQ(0u, val_len);
89 rados_omap_get_end(iter);
90 }
91
92 void compare_xattrs(char const* const* keys,
93 char const* const* vals,
94 const size_t *lens,
95 size_t len,
96 rados_xattrs_iter_t iter)
97 {
98 size_t i = 0;
99 char *key = NULL;
100 char *val = NULL;
101 size_t val_len = 0;
102 while (i < len) {
103 ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**) &key,
104 (const char**) &val, &val_len));
105 if (key == NULL)
106 break;
107 EXPECT_EQ(std::string(keys[i]), std::string(key));
108 if (val != NULL) {
109 EXPECT_EQ(0, memcmp(vals[i], val, val_len));
110 }
111 EXPECT_EQ(lens[i], val_len);
112 ++i;
113 }
114 ASSERT_EQ(i, len);
115 ASSERT_EQ(0, rados_getxattrs_next(iter, (const char**)&key,
116 (const char**)&val, &val_len));
117 ASSERT_EQ((char*)NULL, key);
118 ASSERT_EQ((char*)NULL, val);
119 ASSERT_EQ(0u, val_len);
120 rados_getxattrs_end(iter);
121 }
122 };
123
124 TEST_F(CReadOpsTest, NewDelete) {
125 rados_read_op_t op = rados_create_read_op();
126 ASSERT_TRUE(op);
127 rados_release_read_op(op);
128 }
129
130 TEST_F(CReadOpsTest, SetOpFlags) {
131 write_object();
132
133 rados_read_op_t op = rados_create_read_op();
134 size_t bytes_read = 0;
135 char *out = NULL;
136 int rval = 0;
137 rados_read_op_exec(op, "rbd", "get_id", NULL, 0, &out,
138 &bytes_read, &rval);
139 rados_read_op_set_flags(op, LIBRADOS_OP_FLAG_FAILOK);
140 EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
141 EXPECT_EQ(-EIO, rval);
142 EXPECT_EQ(0u, bytes_read);
143 EXPECT_EQ((char*)NULL, out);
144 rados_release_read_op(op);
145
146 remove_object();
147 }
148
149 TEST_F(CReadOpsTest, AssertExists) {
150 rados_read_op_t op = rados_create_read_op();
151 rados_read_op_assert_exists(op);
152
153 ASSERT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0));
154 rados_release_read_op(op);
155
156 op = rados_create_read_op();
157 rados_read_op_assert_exists(op);
158
159 rados_completion_t completion;
160 ASSERT_EQ(0, rados_aio_create_completion(NULL, NULL, NULL, &completion));
161 ASSERT_EQ(0, rados_aio_read_op_operate(op, ioctx, completion, obj, 0));
162 rados_aio_wait_for_complete(completion);
163 ASSERT_EQ(-ENOENT, rados_aio_get_return_value(completion));
164 rados_aio_release(completion);
165 rados_release_read_op(op);
166
167 write_object();
168
169 op = rados_create_read_op();
170 rados_read_op_assert_exists(op);
171 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
172 rados_release_read_op(op);
173
174 remove_object();
175 }
176
177 TEST_F(CReadOpsTest, AssertVersion) {
178 write_object();
179 // Write to the object a second time to guarantee that its
180 // version number is greater than 0
181 write_object();
182 uint64_t v = rados_get_last_version(ioctx);
183
184 rados_read_op_t op = rados_create_read_op();
185 rados_read_op_assert_version(op, v+1);
186 ASSERT_EQ(-EOVERFLOW, rados_read_op_operate(op, ioctx, obj, 0));
187 rados_release_read_op(op);
188
189 op = rados_create_read_op();
190 rados_read_op_assert_version(op, v-1);
191 ASSERT_EQ(-ERANGE, rados_read_op_operate(op, ioctx, obj, 0));
192 rados_release_read_op(op);
193
194 op = rados_create_read_op();
195 rados_read_op_assert_version(op, v);
196 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
197 rados_release_read_op(op);
198
199 remove_object();
200 }
201
202 TEST_F(CReadOpsTest, CmpXattr) {
203 write_object();
204
205 char buf[len];
206 memset(buf, 0xcc, sizeof(buf));
207
208 const char *xattr = "test";
209 rados_setxattr(ioctx, obj, xattr, buf, sizeof(buf));
210
211 // equal value
212 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_EQ));
213 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_NE));
214 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GT));
215 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GTE));
216 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LT));
217 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LTE));
218
219 // < value
220 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_EQ));
221 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_NE));
222 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_GT));
223 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_GTE));
224 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_LT));
225 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf) - 1, LIBRADOS_CMPXATTR_OP_LTE));
226
227 // > value
228 memset(buf, 0xcd, sizeof(buf));
229 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_EQ));
230 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_NE));
231 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GT));
232 EXPECT_EQ(1, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_GTE));
233 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LT));
234 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, sizeof(buf), LIBRADOS_CMPXATTR_OP_LTE));
235
236 // check that null bytes are compared correctly
237 rados_setxattr(ioctx, obj, xattr, "\0\0", 2);
238 buf[0] = '\0';
239 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_EQ));
240 EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_NE));
241 EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GT));
242 EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GTE));
243 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LT));
244 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LTE));
245
246 buf[1] = '\0';
247 EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_EQ));
248 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_NE));
249 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GT));
250 EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_GTE));
251 EXPECT_EQ(-ECANCELED, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LT));
252 EXPECT_EQ(1, cmp_xattr(xattr, buf, 2, LIBRADOS_CMPXATTR_OP_LTE));
253
254 remove_object();
255 }
256
257 TEST_F(CReadOpsTest, Read) {
258 write_object();
259
260 char buf[len];
261 // check that using read_ops returns the same data with
262 // or without bytes_read and rval out params
263 {
264 rados_read_op_t op = rados_create_read_op();
265 rados_read_op_read(op, 0, len, buf, NULL, NULL);
266 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
267 ASSERT_EQ(0, memcmp(data, buf, len));
268 rados_release_read_op(op);
269 }
270
271 {
272 rados_read_op_t op = rados_create_read_op();
273 int rval;
274 rados_read_op_read(op, 0, len, buf, NULL, &rval);
275 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
276 ASSERT_EQ(0, rval);
277 ASSERT_EQ(0, memcmp(data, buf, len));
278 rados_release_read_op(op);
279 }
280
281 {
282 rados_read_op_t op = rados_create_read_op();
283 size_t bytes_read = 0;
284 rados_read_op_read(op, 0, len, buf, &bytes_read, NULL);
285 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
286 ASSERT_EQ(len, bytes_read);
287 ASSERT_EQ(0, memcmp(data, buf, len));
288 rados_release_read_op(op);
289 }
290
291 {
292 rados_read_op_t op = rados_create_read_op();
293 size_t bytes_read = 0;
294 int rval;
295 rados_read_op_read(op, 0, len, buf, &bytes_read, &rval);
296 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
297 ASSERT_EQ(len, bytes_read);
298 ASSERT_EQ(0, rval);
299 ASSERT_EQ(0, memcmp(data, buf, len));
300 rados_release_read_op(op);
301 }
302
303 {
304 rados_read_op_t op = rados_create_read_op();
305 size_t bytes_read = 0;
306 int rval;
307 rados_read_op_read(op, 0, len, buf, &bytes_read, &rval);
308 rados_read_op_set_flags(op, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
309 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
310 ASSERT_EQ(len, bytes_read);
311 ASSERT_EQ(0, rval);
312 ASSERT_EQ(0, memcmp(data, buf, len));
313 rados_release_read_op(op);
314 }
315
316 remove_object();
317 }
318
319 TEST_F(CReadOpsTest, Checksum) {
320 write_object();
321
322 {
323 rados_read_op_t op = rados_create_read_op();
324 uint64_t init_value = -1;
325 rados_read_op_checksum(op, LIBRADOS_CHECKSUM_TYPE_XXHASH64,
326 reinterpret_cast<char *>(&init_value),
327 sizeof(init_value), 0, len, 0, NULL, 0, NULL);
328 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
329 rados_release_read_op(op);
330 }
331
332 {
333 uint32_t init_value = -1;
334 uint32_t crc[2];
335 rados_read_op_t op = rados_create_read_op();
336 rados_read_op_checksum(op, LIBRADOS_CHECKSUM_TYPE_CRC32C,
337 reinterpret_cast<char *>(&init_value),
338 sizeof(init_value), 0, len, 0,
339 reinterpret_cast<char *>(&crc), sizeof(crc),
340 nullptr);
341 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
342 ASSERT_EQ(1U, crc[0]);
343 uint32_t expected_crc = ceph_crc32c(
344 -1, reinterpret_cast<const uint8_t*>(data), static_cast<uint32_t>(len));
345 ASSERT_EQ(expected_crc, crc[1]);
346 rados_release_read_op(op);
347 }
348
349 {
350 uint32_t init_value = -1;
351 int rval;
352 rados_read_op_t op = rados_create_read_op();
353 rados_read_op_checksum(op, LIBRADOS_CHECKSUM_TYPE_XXHASH32,
354 reinterpret_cast<char *>(&init_value),
355 sizeof(init_value), 0, len, 0, nullptr, 0, &rval);
356 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
357 ASSERT_EQ(0, rval);
358 rados_release_read_op(op);
359 }
360
361 {
362 uint32_t init_value = -1;
363 uint32_t crc[3];
364 int rval;
365 rados_read_op_t op = rados_create_read_op();
366 rados_read_op_checksum(op, LIBRADOS_CHECKSUM_TYPE_CRC32C,
367 reinterpret_cast<char *>(&init_value),
368 sizeof(init_value), 0, len, 4,
369 reinterpret_cast<char *>(&crc), sizeof(crc), &rval);
370 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
371 ASSERT_EQ(2U, crc[0]);
372 uint32_t expected_crc[2];
373 expected_crc[0] = ceph_crc32c(
374 -1, reinterpret_cast<const uint8_t*>(data), 4U);
375 expected_crc[1] = ceph_crc32c(
376 -1, reinterpret_cast<const uint8_t*>(data + 4), 4U);
377 ASSERT_EQ(expected_crc[0], crc[1]);
378 ASSERT_EQ(expected_crc[1], crc[2]);
379 ASSERT_EQ(0, rval);
380 rados_release_read_op(op);
381 }
382
383 remove_object();
384 }
385
386 TEST_F(CReadOpsTest, RWOrderedRead) {
387 write_object();
388
389 char buf[len];
390 rados_read_op_t op = rados_create_read_op();
391 size_t bytes_read = 0;
392 int rval;
393 rados_read_op_read(op, 0, len, buf, &bytes_read, &rval);
394 rados_read_op_set_flags(op, LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
395 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj,
396 LIBRADOS_OPERATION_ORDER_READS_WRITES));
397 ASSERT_EQ(len, bytes_read);
398 ASSERT_EQ(0, rval);
399 ASSERT_EQ(0, memcmp(data, buf, len));
400 rados_release_read_op(op);
401
402 remove_object();
403 }
404
405 TEST_F(CReadOpsTest, ShortRead) {
406 write_object();
407
408 char buf[len * 2];
409 // check that using read_ops returns the same data with
410 // or without bytes_read and rval out params
411 {
412 rados_read_op_t op = rados_create_read_op();
413 rados_read_op_read(op, 0, len * 2, buf, NULL, NULL);
414 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
415 ASSERT_EQ(0, memcmp(data, buf, len));
416 rados_release_read_op(op);
417 }
418
419 {
420 rados_read_op_t op = rados_create_read_op();
421 int rval;
422 rados_read_op_read(op, 0, len * 2, buf, NULL, &rval);
423 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
424 ASSERT_EQ(0, rval);
425 ASSERT_EQ(0, memcmp(data, buf, len));
426 rados_release_read_op(op);
427 }
428
429 {
430 rados_read_op_t op = rados_create_read_op();
431 size_t bytes_read = 0;
432 rados_read_op_read(op, 0, len * 2, buf, &bytes_read, NULL);
433 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
434 ASSERT_EQ(len, bytes_read);
435 ASSERT_EQ(0, memcmp(data, buf, len));
436 rados_release_read_op(op);
437 }
438
439 {
440 rados_read_op_t op = rados_create_read_op();
441 size_t bytes_read = 0;
442 int rval;
443 rados_read_op_read(op, 0, len * 2, buf, &bytes_read, &rval);
444 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
445 ASSERT_EQ(len, bytes_read);
446 ASSERT_EQ(0, rval);
447 ASSERT_EQ(0, memcmp(data, buf, len));
448 rados_release_read_op(op);
449 }
450
451 remove_object();
452 }
453
454 TEST_F(CReadOpsTest, Exec) {
455 // create object so we don't get -ENOENT
456 write_object();
457
458 rados_read_op_t op = rados_create_read_op();
459 ASSERT_TRUE(op);
460 size_t bytes_read = 0;
461 char *out = NULL;
462 int rval = 0;
463 rados_read_op_exec(op, "rbd", "get_all_features", NULL, 0, &out,
464 &bytes_read, &rval);
465 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
466 rados_release_read_op(op);
467 EXPECT_EQ(0, rval);
468 EXPECT_TRUE(out);
469 uint64_t features;
470 EXPECT_EQ(sizeof(features), bytes_read);
471 // make sure buffer is at least as long as it claims
472 ASSERT_TRUE(out[bytes_read-1] == out[bytes_read-1]);
473 rados_buffer_free(out);
474
475 remove_object();
476 }
477
478 TEST_F(CReadOpsTest, ExecUserBuf) {
479 // create object so we don't get -ENOENT
480 write_object();
481
482 rados_read_op_t op = rados_create_read_op();
483 size_t bytes_read = 0;
484 uint64_t features;
485 char out[sizeof(features)];
486 int rval = 0;
487 rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out,
488 sizeof(out), &bytes_read, &rval);
489 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
490 rados_release_read_op(op);
491 EXPECT_EQ(0, rval);
492 EXPECT_EQ(sizeof(features), bytes_read);
493
494 // buffer too short
495 bytes_read = 1024;
496 op = rados_create_read_op();
497 rados_read_op_exec_user_buf(op, "rbd", "get_all_features", NULL, 0, out,
498 sizeof(features) - 1, &bytes_read, &rval);
499 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
500 rados_release_read_op(op);
501 EXPECT_EQ(0u, bytes_read);
502 EXPECT_EQ(-ERANGE, rval);
503
504 // input buffer and no rval or bytes_read
505 op = rados_create_read_op();
506 rados_read_op_exec_user_buf(op, "rbd", "get_all_features", out, sizeof(out),
507 out, sizeof(out), NULL, NULL);
508 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
509 rados_release_read_op(op);
510
511 remove_object();
512 }
513
514 TEST_F(CReadOpsTest, Stat) {
515 rados_read_op_t op = rados_create_read_op();
516 uint64_t size = 1;
517 int rval;
518 rados_read_op_stat(op, &size, NULL, &rval);
519 EXPECT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0));
520 EXPECT_EQ(-EIO, rval);
521 EXPECT_EQ(1u, size);
522 rados_release_read_op(op);
523
524 write_object();
525
526 op = rados_create_read_op();
527 rados_read_op_stat(op, &size, NULL, &rval);
528 EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
529 EXPECT_EQ(0, rval);
530 EXPECT_EQ(len, size);
531 rados_release_read_op(op);
532
533 op = rados_create_read_op();
534 rados_read_op_stat(op, NULL, NULL, NULL);
535 EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
536 rados_release_read_op(op);
537
538 remove_object();
539
540 op = rados_create_read_op();
541 rados_read_op_stat(op, NULL, NULL, NULL);
542 EXPECT_EQ(-ENOENT, rados_read_op_operate(op, ioctx, obj, 0));
543 rados_release_read_op(op);
544 }
545
546 TEST_F(CReadOpsTest, Omap) {
547 char *keys[] = {(char*)"bar",
548 (char*)"foo",
549 (char*)"test1",
550 (char*)"test2"};
551 char *vals[] = {(char*)"",
552 (char*)"\0",
553 (char*)"abc",
554 (char*)"va\0lue"};
555 size_t lens[] = {0, 1, 3, 6};
556
557 // check for -ENOENT before the object exists and when it exists
558 // with no omap entries
559 rados_omap_iter_t iter_vals;
560 rados_read_op_t rop = rados_create_read_op();
561 rados_read_op_omap_get_vals2(rop, "", "", 10, &iter_vals, NULL, NULL);
562 ASSERT_EQ(-ENOENT, rados_read_op_operate(rop, ioctx, obj, 0));
563 rados_release_read_op(rop);
564 compare_omap_vals(NULL, NULL, NULL, 0, iter_vals);
565
566 write_object();
567
568 fetch_and_verify_omap_vals(NULL, NULL, NULL, 0);
569
570 // write and check for the k/v pairs
571 rados_write_op_t op = rados_create_write_op();
572 rados_write_op_omap_set(op, keys, vals, lens, 4);
573 ASSERT_EQ(0, rados_write_op_operate(op, ioctx, obj, NULL, 0));
574 rados_release_write_op(op);
575
576 fetch_and_verify_omap_vals(keys, vals, lens, 4);
577
578 rados_omap_iter_t iter_keys;
579 int r_vals = -1, r_keys = -1;
580 rop = rados_create_read_op();
581 rados_read_op_omap_get_vals2(rop, "", "test", 1, &iter_vals, NULL, &r_vals);
582 rados_read_op_omap_get_keys2(rop, "test", 1, &iter_keys, NULL, &r_keys);
583 ASSERT_EQ(0, rados_read_op_operate(rop, ioctx, obj, 0));
584 rados_release_read_op(rop);
585 EXPECT_EQ(0, r_vals);
586 EXPECT_EQ(0, r_keys);
587
588 compare_omap_vals(&keys[2], &vals[2], &lens[2], 1, iter_vals);
589 compare_omap_vals(&keys[2], &vals[0], &lens[0], 1, iter_keys);
590
591 // check omap_cmp finds all expected values
592 rop = rados_create_read_op();
593 int rvals[4];
594 for (int i = 0; i < 4; ++i)
595 rados_read_op_omap_cmp(rop, keys[i], LIBRADOS_CMPXATTR_OP_EQ,
596 vals[i], lens[i], &rvals[i]);
597 EXPECT_EQ(0, rados_read_op_operate(rop, ioctx, obj, 0));
598 rados_release_read_op(rop);
599 for (int i = 0; i < 4; ++i)
600 EXPECT_EQ(0, rvals[i]);
601
602 // try to remove keys with a guard that should fail
603 op = rados_create_write_op();
604 rados_write_op_omap_cmp(op, keys[2], LIBRADOS_CMPXATTR_OP_LT,
605 vals[2], lens[2], &r_vals);
606 rados_write_op_omap_rm_keys(op, keys, 2);
607 EXPECT_EQ(-ECANCELED, rados_write_op_operate(op, ioctx, obj, NULL, 0));
608 rados_release_write_op(op);
609
610 // see http://tracker.ceph.com/issues/19518
611 //ASSERT_EQ(-ECANCELED, r_vals);
612
613 // verifying the keys are still there, and then remove them
614 op = rados_create_write_op();
615 rados_write_op_omap_cmp(op, keys[0], LIBRADOS_CMPXATTR_OP_EQ,
616 vals[0], lens[0], NULL);
617 rados_write_op_omap_cmp(op, keys[1], LIBRADOS_CMPXATTR_OP_EQ,
618 vals[1], lens[1], NULL);
619 rados_write_op_omap_rm_keys(op, keys, 2);
620 EXPECT_EQ(0, rados_write_op_operate(op, ioctx, obj, NULL, 0));
621 rados_release_write_op(op);
622
623 fetch_and_verify_omap_vals(&keys[2], &vals[2], &lens[2], 2);
624
625 // clear the rest and check there are none left
626 op = rados_create_write_op();
627 rados_write_op_omap_clear(op);
628 EXPECT_EQ(0, rados_write_op_operate(op, ioctx, obj, NULL, 0));
629 rados_release_write_op(op);
630
631 fetch_and_verify_omap_vals(NULL, NULL, NULL, 0);
632
633 remove_object();
634 }
635
636 TEST_F(CReadOpsTest, GetXattrs) {
637 write_object();
638
639 char *keys[] = {(char*)"bar",
640 (char*)"foo",
641 (char*)"test1",
642 (char*)"test2"};
643 char *vals[] = {(char*)"",
644 (char*)"\0",
645 (char*)"abc",
646 (char*)"va\0lue"};
647 size_t lens[] = {0, 1, 3, 6};
648
649 int rval = 1;
650 rados_read_op_t op = rados_create_read_op();
651 rados_xattrs_iter_t it;
652 rados_read_op_getxattrs(op, &it, &rval);
653 EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
654 EXPECT_EQ(0, rval);
655 rados_release_read_op(op);
656 compare_xattrs(keys, vals, lens, 0, it);
657
658 for (int i = 0; i < 4; ++i)
659 rados_setxattr(ioctx, obj, keys[i], vals[i], lens[i]);
660
661 rval = 1;
662 op = rados_create_read_op();
663 rados_read_op_getxattrs(op, &it, &rval);
664 EXPECT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
665 EXPECT_EQ(0, rval);
666 rados_release_read_op(op);
667 compare_xattrs(keys, vals, lens, 4, it);
668
669 remove_object();
670 }
671
672 TEST_F(CReadOpsTest, CmpExt) {
673 char buf[len];
674 size_t bytes_read = 0;
675 int cmpext_val = 0;
676 int read_val = 0;
677
678 write_object();
679
680 // cmpext with match should ensure that the following read is successful
681 rados_read_op_t op = rados_create_read_op();
682 ASSERT_TRUE(op);
683 // @obj, @data and @len correspond to object initialised by write_object()
684 rados_read_op_cmpext(op, data, len, 0, &cmpext_val);
685 rados_read_op_read(op, 0, len, buf, &bytes_read, &read_val);
686 ASSERT_EQ(0, rados_read_op_operate(op, ioctx, obj, 0));
687 ASSERT_EQ(len, bytes_read);
688 ASSERT_EQ(0, memcmp(data, buf, len));
689 ASSERT_EQ(cmpext_val, 0);
690 rados_release_read_op(op);
691
692 // cmpext with mismatch should fail and fill mismatch_buf accordingly
693 memset(buf, 0, sizeof(buf));
694 bytes_read = 0;
695 cmpext_val = 0;
696 read_val = 0;
697 op = rados_create_read_op();
698 ASSERT_TRUE(op);
699 // @obj, @data and @len correspond to object initialised by write_object()
700 rados_read_op_cmpext(op, "mismatch", strlen("mismatch"), 0, &cmpext_val);
701 rados_read_op_read(op, 0, len, buf, &bytes_read, &read_val);
702 ASSERT_EQ(-MAX_ERRNO, rados_read_op_operate(op, ioctx, obj, 0));
703 rados_release_read_op(op);
704
705 ASSERT_EQ(-MAX_ERRNO, cmpext_val);
706
707 remove_object();
708 }