]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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); | |
224ce89b WB |
609 | |
610 | // see http://tracker.ceph.com/issues/19518 | |
611 | //ASSERT_EQ(-ECANCELED, r_vals); | |
7c673cae FG |
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 | } |