1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
2 // vim: ts=8 sw=2 smarttab
6 #include "include/rados/librados.h"
7 #include "include/encoding.h"
8 #include "include/err.h"
9 #include "include/scope_guard.h"
10 #include "test/librados/test.h"
11 #include "test/librados/TestCase.h"
14 #include "gtest/gtest.h"
18 typedef RadosTest LibRadosIo
;
19 typedef RadosTestEC LibRadosIoEC
;
21 TEST_F(LibRadosIo
, SimpleWrite
) {
23 memset(buf
, 0xcc, sizeof(buf
));
24 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
25 rados_ioctx_set_namespace(ioctx
, "nspace");
26 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
29 TEST_F(LibRadosIo
, TooBig
) {
31 ASSERT_EQ(-E2BIG
, rados_write(ioctx
, "A", buf
, UINT_MAX
, 0));
32 ASSERT_EQ(-E2BIG
, rados_append(ioctx
, "A", buf
, UINT_MAX
));
33 ASSERT_EQ(-E2BIG
, rados_write_full(ioctx
, "A", buf
, UINT_MAX
));
34 ASSERT_EQ(-E2BIG
, rados_writesame(ioctx
, "A", buf
, sizeof(buf
), UINT_MAX
, 0));
37 TEST_F(LibRadosIo
, ReadTimeout
) {
39 memset(buf
, 'a', sizeof(buf
));
40 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
43 // set up a second client
46 ASSERT_EQ(0, rados_create(&cluster
, "admin"));
47 ASSERT_EQ(0, rados_conf_read_file(cluster
, NULL
));
48 ASSERT_EQ(0, rados_conf_parse_env(cluster
, NULL
));
49 ASSERT_EQ(0, rados_conf_set(cluster
, "rados_osd_op_timeout", "0.00001")); // use any small value that will result in a timeout
50 ASSERT_EQ(0, rados_connect(cluster
));
51 ASSERT_EQ(0, rados_ioctx_create(cluster
, pool_name
.c_str(), &ioctx
));
52 rados_ioctx_set_namespace(ioctx
, nspace
.c_str());
54 // then we show that the buffer is changed after rados_read returned
56 for (int i
=0; i
<5; i
++) {
57 char buf2
[sizeof(buf
)];
58 memset(buf2
, 0, sizeof(buf2
));
59 int err
= rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0);
62 // find the index until which librados already read the object before the timeout occurred
63 for (unsigned b
=0; b
<sizeof(buf
); b
++) {
64 if (buf2
[b
] != buf
[b
]) {
70 // wait some time to give librados a change to do something
73 // then check if the buffer was changed after the call
74 if (buf2
[startIndex
] == 'a') {
75 printf("byte at index %d was changed after the timeout to %d\n",
76 startIndex
, (int)buf
[startIndex
]);
81 printf("no timeout :/\n");
84 rados_ioctx_destroy(ioctx
);
85 rados_shutdown(cluster
);
90 TEST_F(LibRadosIo
, RoundTrip
) {
93 memset(buf
, 0xcc, sizeof(buf
));
94 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
95 memset(buf2
, 0, sizeof(buf2
));
96 ASSERT_EQ((int)sizeof(buf2
), rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
97 ASSERT_EQ(0, memcmp(buf
, buf2
, sizeof(buf
)));
100 memset(buf
, 0xcc, sizeof(buf
));
101 ASSERT_EQ(0, rados_write(ioctx
, "bar", buf
, sizeof(buf
), off
));
102 memset(buf2
, 0, sizeof(buf2
));
103 ASSERT_EQ((int)sizeof(buf2
), rados_read(ioctx
, "bar", buf2
, sizeof(buf2
), off
));
104 ASSERT_EQ(0, memcmp(buf
, buf2
, sizeof(buf
)));
107 TEST_F(LibRadosIo
, Checksum
) {
109 memset(buf
, 0xcc, sizeof(buf
));
110 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
112 uint32_t expected_crc
= ceph_crc32c(-1, reinterpret_cast<const uint8_t*>(buf
),
114 uint32_t init_value
= -1;
116 ASSERT_EQ(0, rados_checksum(ioctx
, "foo", LIBRADOS_CHECKSUM_TYPE_CRC32C
,
117 reinterpret_cast<char*>(&init_value
),
118 sizeof(init_value
), sizeof(buf
), 0, 0,
119 reinterpret_cast<char*>(&crc
), sizeof(crc
)));
120 ASSERT_EQ(1U, crc
[0]);
121 ASSERT_EQ(expected_crc
, crc
[1]);
124 TEST_F(LibRadosIo
, OverlappingWriteRoundTrip
) {
128 memset(buf
, 0xcc, sizeof(buf
));
129 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
130 memset(buf2
, 0xdd, sizeof(buf2
));
131 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
132 memset(buf3
, 0xdd, sizeof(buf3
));
133 ASSERT_EQ((int)sizeof(buf3
), rados_read(ioctx
, "foo", buf3
, sizeof(buf3
), 0));
134 ASSERT_EQ(0, memcmp(buf3
, buf2
, sizeof(buf2
)));
135 ASSERT_EQ(0, memcmp(buf3
+ sizeof(buf2
), buf
, sizeof(buf
) - sizeof(buf2
)));
138 TEST_F(LibRadosIo
, WriteFullRoundTrip
) {
142 memset(buf
, 0xcc, sizeof(buf
));
143 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
144 memset(buf2
, 0xdd, sizeof(buf2
));
145 ASSERT_EQ(0, rados_write_full(ioctx
, "foo", buf2
, sizeof(buf2
)));
146 memset(buf3
, 0x00, sizeof(buf3
));
147 ASSERT_EQ((int)sizeof(buf2
), rados_read(ioctx
, "foo", buf3
, sizeof(buf3
), 0));
148 ASSERT_EQ(0, memcmp(buf2
, buf3
, sizeof(buf2
)));
151 TEST_F(LibRadosIo
, AppendRoundTrip
) {
154 char buf3
[sizeof(buf
) + sizeof(buf2
)];
155 memset(buf
, 0xde, sizeof(buf
));
156 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
157 memset(buf2
, 0xad, sizeof(buf2
));
158 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf2
, sizeof(buf2
)));
159 memset(buf3
, 0, sizeof(buf3
));
160 ASSERT_EQ((int)sizeof(buf3
), rados_read(ioctx
, "foo", buf3
, sizeof(buf3
), 0));
161 ASSERT_EQ(0, memcmp(buf3
, buf
, sizeof(buf
)));
162 ASSERT_EQ(0, memcmp(buf3
+ sizeof(buf
), buf2
, sizeof(buf2
)));
165 TEST_F(LibRadosIo
, TruncTest
) {
167 char buf2
[sizeof(buf
)];
168 memset(buf
, 0xaa, sizeof(buf
));
169 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
170 ASSERT_EQ(0, rados_trunc(ioctx
, "foo", sizeof(buf
) / 2));
171 memset(buf2
, 0, sizeof(buf2
));
172 ASSERT_EQ((int)(sizeof(buf
)/2), rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
173 ASSERT_EQ(0, memcmp(buf
, buf2
, sizeof(buf
)/2));
176 TEST_F(LibRadosIo
, RemoveTest
) {
178 char buf2
[sizeof(buf
)];
179 memset(buf
, 0xaa, sizeof(buf
));
180 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
181 ASSERT_EQ(0, rados_remove(ioctx
, "foo"));
182 memset(buf2
, 0, sizeof(buf2
));
183 ASSERT_EQ(-ENOENT
, rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
186 TEST_F(LibRadosIo
, XattrsRoundTrip
) {
188 char attr1
[] = "attr1";
189 char attr1_buf
[] = "foo bar baz";
190 memset(buf
, 0xaa, sizeof(buf
));
191 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
192 ASSERT_EQ(-ENODATA
, rados_getxattr(ioctx
, "foo", attr1
, buf
, sizeof(buf
)));
193 ASSERT_EQ(0, rados_setxattr(ioctx
, "foo", attr1
, attr1_buf
, sizeof(attr1_buf
)));
194 ASSERT_EQ((int)sizeof(attr1_buf
),
195 rados_getxattr(ioctx
, "foo", attr1
, buf
, sizeof(buf
)));
196 ASSERT_EQ(0, memcmp(attr1_buf
, buf
, sizeof(attr1_buf
)));
199 TEST_F(LibRadosIo
, RmXattr
) {
201 char attr1
[] = "attr1";
202 char attr1_buf
[] = "foo bar baz";
203 memset(buf
, 0xaa, sizeof(buf
));
204 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
206 rados_setxattr(ioctx
, "foo", attr1
, attr1_buf
, sizeof(attr1_buf
)));
207 ASSERT_EQ(0, rados_rmxattr(ioctx
, "foo", attr1
));
208 ASSERT_EQ(-ENODATA
, rados_getxattr(ioctx
, "foo", attr1
, buf
, sizeof(buf
)));
210 // Test rmxattr on a removed object
212 char attr2
[] = "attr2";
213 char attr2_buf
[] = "foo bar baz";
214 memset(buf2
, 0xbb, sizeof(buf2
));
215 ASSERT_EQ(0, rados_write(ioctx
, "foo_rmxattr", buf2
, sizeof(buf2
), 0));
217 rados_setxattr(ioctx
, "foo_rmxattr", attr2
, attr2_buf
, sizeof(attr2_buf
)));
218 ASSERT_EQ(0, rados_remove(ioctx
, "foo_rmxattr"));
219 ASSERT_EQ(-ENOENT
, rados_rmxattr(ioctx
, "foo_rmxattr", attr2
));
222 TEST_F(LibRadosIo
, XattrIter
) {
224 char attr1
[] = "attr1";
225 char attr1_buf
[] = "foo bar baz";
226 char attr2
[] = "attr2";
228 for (size_t j
= 0; j
< sizeof(attr2_buf
); ++j
) {
229 attr2_buf
[j
] = j
% 0xff;
231 memset(buf
, 0xaa, sizeof(buf
));
232 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
233 ASSERT_EQ(0, rados_setxattr(ioctx
, "foo", attr1
, attr1_buf
, sizeof(attr1_buf
)));
234 ASSERT_EQ(0, rados_setxattr(ioctx
, "foo", attr2
, attr2_buf
, sizeof(attr2_buf
)));
235 rados_xattrs_iter_t iter
;
236 ASSERT_EQ(0, rados_getxattrs(ioctx
, "foo", &iter
));
242 ASSERT_EQ(0, rados_getxattrs_next(iter
, &name
, &val
, &len
));
246 ASSERT_LT(num_seen
, 2);
247 if ((strcmp(name
, attr1
) == 0) && (val
!= NULL
) && (memcmp(val
, attr1_buf
, len
) == 0)) {
251 else if ((strcmp(name
, attr2
) == 0) && (val
!= NULL
) && (memcmp(val
, attr2_buf
, len
) == 0)) {
259 rados_getxattrs_end(iter
);
262 TEST_F(LibRadosIoEC
, SimpleWrite
) {
264 memset(buf
, 0xcc, sizeof(buf
));
265 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
266 rados_ioctx_set_namespace(ioctx
, "nspace");
267 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
270 TEST_F(LibRadosIoEC
, RoundTrip
) {
273 memset(buf
, 0xcc, sizeof(buf
));
274 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
275 memset(buf2
, 0, sizeof(buf2
));
276 ASSERT_EQ((int)sizeof(buf2
), rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
277 ASSERT_EQ(0, memcmp(buf
, buf2
, sizeof(buf
)));
280 ASSERT_EQ(-EOPNOTSUPP
, rados_write(ioctx
, "bar", buf
, sizeof(buf
), off
));
283 TEST_F(LibRadosIoEC
, OverlappingWriteRoundTrip
) {
284 int bsize
= alignment
;
285 int dbsize
= bsize
* 2;
286 char *buf
= (char *)new char[dbsize
];
287 char *buf2
= (char *)new char[bsize
];
288 char *buf3
= (char *)new char[dbsize
];
294 scope_guard
<decltype(cleanup
)> sg(std::move(cleanup
));
295 memset(buf
, 0xcc, dbsize
);
296 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, dbsize
, 0));
297 memset(buf2
, 0xdd, bsize
);
298 ASSERT_EQ(-EOPNOTSUPP
, rados_write(ioctx
, "foo", buf2
, bsize
, 0));
299 memset(buf3
, 0xdd, dbsize
);
300 ASSERT_EQ(dbsize
, rados_read(ioctx
, "foo", buf3
, dbsize
, 0));
301 // Read the same as first write
302 ASSERT_EQ(0, memcmp(buf3
, buf
, dbsize
));
305 TEST_F(LibRadosIoEC
, WriteFullRoundTrip
) {
309 memset(buf
, 0xcc, sizeof(buf
));
310 ASSERT_EQ(0, rados_write(ioctx
, "foo", buf
, sizeof(buf
), 0));
311 memset(buf2
, 0xdd, sizeof(buf2
));
312 ASSERT_EQ(0, rados_write_full(ioctx
, "foo", buf2
, sizeof(buf2
)));
313 memset(buf3
, 0xee, sizeof(buf3
));
314 ASSERT_EQ((int)sizeof(buf2
), rados_read(ioctx
, "foo", buf3
, sizeof(buf3
), 0));
315 ASSERT_EQ(0, memcmp(buf3
, buf2
, sizeof(buf2
)));
318 TEST_F(LibRadosIoEC
, AppendRoundTrip
) {
319 char *buf
= (char *)new char[alignment
];
320 char *buf2
= (char *)new char[alignment
];
321 char *buf3
= (char *)new char[alignment
*2];
322 int uasize
= alignment
/2;
323 char *unalignedbuf
= (char *)new char[uasize
];
328 delete[] unalignedbuf
;
330 scope_guard
<decltype(cleanup
)> sg(std::move(cleanup
));
331 memset(buf
, 0xde, alignment
);
332 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, alignment
));
333 memset(buf2
, 0xad, alignment
);
334 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf2
, alignment
));
335 memset(buf3
, 0, alignment
*2);
336 ASSERT_EQ((int)alignment
*2, rados_read(ioctx
, "foo", buf3
, alignment
*2, 0));
337 ASSERT_EQ(0, memcmp(buf3
, buf
, alignment
));
338 ASSERT_EQ(0, memcmp(buf3
+ alignment
, buf2
, alignment
));
339 memset(unalignedbuf
, 0, uasize
);
340 ASSERT_EQ(0, rados_append(ioctx
, "foo", unalignedbuf
, uasize
));
341 ASSERT_EQ(-EOPNOTSUPP
, rados_append(ioctx
, "foo", unalignedbuf
, uasize
));
344 TEST_F(LibRadosIoEC
, TruncTest
) {
346 char buf2
[sizeof(buf
)];
347 memset(buf
, 0xaa, sizeof(buf
));
348 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
349 ASSERT_EQ(-EOPNOTSUPP
, rados_trunc(ioctx
, "foo", sizeof(buf
) / 2));
350 memset(buf2
, 0, sizeof(buf2
));
352 ASSERT_EQ((int)sizeof(buf
), rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
354 ASSERT_EQ(0, memcmp(buf
, buf2
, sizeof(buf
)));
357 TEST_F(LibRadosIoEC
, RemoveTest
) {
359 char buf2
[sizeof(buf
)];
360 memset(buf
, 0xaa, sizeof(buf
));
361 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
362 ASSERT_EQ(0, rados_remove(ioctx
, "foo"));
363 memset(buf2
, 0, sizeof(buf2
));
364 ASSERT_EQ(-ENOENT
, rados_read(ioctx
, "foo", buf2
, sizeof(buf2
), 0));
367 TEST_F(LibRadosIoEC
, XattrsRoundTrip
) {
369 char attr1
[] = "attr1";
370 char attr1_buf
[] = "foo bar baz";
371 memset(buf
, 0xaa, sizeof(buf
));
372 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
373 ASSERT_EQ(-ENODATA
, rados_getxattr(ioctx
, "foo", attr1
, buf
, sizeof(buf
)));
374 ASSERT_EQ(0, rados_setxattr(ioctx
, "foo", attr1
, attr1_buf
, sizeof(attr1_buf
)));
375 ASSERT_EQ((int)sizeof(attr1_buf
),
376 rados_getxattr(ioctx
, "foo", attr1
, buf
, sizeof(buf
)));
377 ASSERT_EQ(0, memcmp(attr1_buf
, buf
, sizeof(attr1_buf
)));
380 TEST_F(LibRadosIoEC
, RmXattr
) {
382 char attr1
[] = "attr1";
383 char attr1_buf
[] = "foo bar baz";
384 memset(buf
, 0xaa, sizeof(buf
));
385 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
387 rados_setxattr(ioctx
, "foo", attr1
, attr1_buf
, sizeof(attr1_buf
)));
388 ASSERT_EQ(0, rados_rmxattr(ioctx
, "foo", attr1
));
389 ASSERT_EQ(-ENODATA
, rados_getxattr(ioctx
, "foo", attr1
, buf
, sizeof(buf
)));
391 // Test rmxattr on a removed object
393 char attr2
[] = "attr2";
394 char attr2_buf
[] = "foo bar baz";
395 memset(buf2
, 0xbb, sizeof(buf2
));
396 ASSERT_EQ(0, rados_write(ioctx
, "foo_rmxattr", buf2
, sizeof(buf2
), 0));
398 rados_setxattr(ioctx
, "foo_rmxattr", attr2
, attr2_buf
, sizeof(attr2_buf
)));
399 ASSERT_EQ(0, rados_remove(ioctx
, "foo_rmxattr"));
400 ASSERT_EQ(-ENOENT
, rados_rmxattr(ioctx
, "foo_rmxattr", attr2
));
403 TEST_F(LibRadosIoEC
, XattrIter
) {
405 char attr1
[] = "attr1";
406 char attr1_buf
[] = "foo bar baz";
407 char attr2
[] = "attr2";
409 for (size_t j
= 0; j
< sizeof(attr2_buf
); ++j
) {
410 attr2_buf
[j
] = j
% 0xff;
412 memset(buf
, 0xaa, sizeof(buf
));
413 ASSERT_EQ(0, rados_append(ioctx
, "foo", buf
, sizeof(buf
)));
414 ASSERT_EQ(0, rados_setxattr(ioctx
, "foo", attr1
, attr1_buf
, sizeof(attr1_buf
)));
415 ASSERT_EQ(0, rados_setxattr(ioctx
, "foo", attr2
, attr2_buf
, sizeof(attr2_buf
)));
416 rados_xattrs_iter_t iter
;
417 ASSERT_EQ(0, rados_getxattrs(ioctx
, "foo", &iter
));
423 ASSERT_EQ(0, rados_getxattrs_next(iter
, &name
, &val
, &len
));
427 ASSERT_LT(num_seen
, 2);
428 if ((strcmp(name
, attr1
) == 0) && (val
!= NULL
) && (memcmp(val
, attr1_buf
, len
) == 0)) {
432 else if ((strcmp(name
, attr2
) == 0) && (val
!= NULL
) && (memcmp(val
, attr2_buf
, len
) == 0)) {
440 rados_getxattrs_end(iter
);