Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librados / io.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*
2 // vim: ts=8 sw=2 smarttab
3
4 #include <climits>
5
6 #include "include/rados/librados.h"
7 #include "include/rados/librados.hpp"
8 #include "include/encoding.h"
9 #include "include/err.h"
10 #include "include/scope_guard.h"
11 #include "test/librados/test.h"
12 #include "test/librados/TestCase.h"
13
14 #include <errno.h>
15 #include "gtest/gtest.h"
16
17 using namespace librados;
18 using std::string;
19
20 typedef RadosTest LibRadosIo;
21 typedef RadosTestEC LibRadosIoEC;
22 typedef RadosTestPP LibRadosIoPP;
23 typedef RadosTestECPP LibRadosIoECPP;
24
25 TEST_F(LibRadosIo, SimpleWrite) {
26   char buf[128];
27   memset(buf, 0xcc, sizeof(buf));
28   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
29   rados_ioctx_set_namespace(ioctx, "nspace");
30   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
31 }
32
33 TEST_F(LibRadosIo, TooBig) {
34   char buf[1];
35   ASSERT_EQ(-E2BIG, rados_write(ioctx, "A", buf, UINT_MAX, 0));
36   ASSERT_EQ(-E2BIG, rados_append(ioctx, "A", buf, UINT_MAX));
37   ASSERT_EQ(-E2BIG, rados_write_full(ioctx, "A", buf, UINT_MAX));
38   ASSERT_EQ(-E2BIG, rados_writesame(ioctx, "A", buf, sizeof(buf), UINT_MAX, 0));
39   IoCtx ioctx;
40   bufferlist bl;
41   ASSERT_EQ(-E2BIG, ioctx.write("foo", bl, UINT_MAX, 0));
42   ASSERT_EQ(-E2BIG, ioctx.append("foo", bl, UINT_MAX));
43   // ioctx.write_full no way to overflow bl.length()
44   ASSERT_EQ(-E2BIG, ioctx.writesame("foo", bl, UINT_MAX, 0));
45 }
46
47 TEST_F(LibRadosIo, ReadTimeout) {
48   char buf[128];
49   memset(buf, 'a', sizeof(buf));
50   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
51
52   {
53     // set up a second client
54     rados_t cluster;
55     rados_ioctx_t ioctx;
56     ASSERT_EQ(0, rados_create(&cluster, "admin"));
57     ASSERT_EQ(0, rados_conf_read_file(cluster, NULL));
58     ASSERT_EQ(0, rados_conf_parse_env(cluster, NULL));
59     ASSERT_EQ(0, rados_conf_set(cluster, "rados_osd_op_timeout", "0.00001")); // use any small value that will result in a timeout
60     ASSERT_EQ(0, rados_connect(cluster));
61     ASSERT_EQ(0, rados_ioctx_create(cluster, pool_name.c_str(), &ioctx));
62     rados_ioctx_set_namespace(ioctx, nspace.c_str());
63
64     // then we show that the buffer is changed after rados_read returned
65     // with a timeout
66     for (int i=0; i<5; i++) {
67       char buf2[sizeof(buf)];
68       memset(buf2, 0, sizeof(buf2));
69       int err = rados_read(ioctx, "foo", buf2, sizeof(buf2), 0);
70       if (err == -110) {
71         int startIndex = 0;
72         // find the index until which librados already read the object before the timeout occurred
73         for (unsigned b=0; b<sizeof(buf); b++) {
74           if (buf2[b] != buf[b]) {
75             startIndex = b;
76             break;
77           }
78         }
79
80         // wait some time to give librados a change to do something
81         sleep(1);
82
83         // then check if the buffer was changed after the call
84         if (buf2[startIndex] == 'a') {
85           printf("byte at index %d was changed after the timeout to %d\n",
86                  startIndex, (int)buf[startIndex]);
87           ASSERT_TRUE(0);
88           break;
89         }
90       } else {
91         printf("no timeout :/\n");
92       }
93     }
94     rados_ioctx_destroy(ioctx);
95     rados_shutdown(cluster);
96   }
97 }
98
99 TEST_F(LibRadosIoPP, SimpleWritePP) {
100   char buf[128];
101   memset(buf, 0xcc, sizeof(buf));
102   bufferlist bl;
103   bl.append(buf, sizeof(buf));
104   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
105   ioctx.set_namespace("nspace");
106   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
107 }
108
109 TEST_F(LibRadosIoPP, ReadOpPP) {
110   char buf[128];
111   memset(buf, 0xcc, sizeof(buf));
112   bufferlist bl;
113   bl.append(buf, sizeof(buf));
114   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
115
116   {
117       bufferlist op_bl;
118       ObjectReadOperation op;
119       op.read(0, sizeof(buf), NULL, NULL);
120       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
121       ASSERT_EQ(sizeof(buf), op_bl.length());
122       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
123   }
124
125   {
126       bufferlist op_bl;
127       ObjectReadOperation op;
128       op.read(0, 0, NULL, NULL); //len=0 mean read the whole object data.
129       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
130       ASSERT_EQ(sizeof(buf), op_bl.length());
131       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
132   }
133
134   {
135       bufferlist read_bl, op_bl;
136       ObjectReadOperation op;
137       op.read(0, sizeof(buf), &read_bl, NULL);
138       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
139       ASSERT_EQ(sizeof(buf), read_bl.length());
140       ASSERT_EQ(sizeof(buf), op_bl.length());
141       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
142       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
143   }
144
145   {
146       bufferlist op_bl;
147       int rval = 1000;
148       ObjectReadOperation op;
149       op.read(0, sizeof(buf), NULL, &rval);
150       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
151       ASSERT_EQ(sizeof(buf), op_bl.length());
152       ASSERT_EQ(0, rval);
153       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
154   }
155
156   {
157       bufferlist read_bl, op_bl;
158       int rval = 1000;
159       ObjectReadOperation op;
160       op.read(0, sizeof(buf), &read_bl, &rval);
161       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
162       ASSERT_EQ(sizeof(buf), read_bl.length());
163       ASSERT_EQ(sizeof(buf), op_bl.length());
164       ASSERT_EQ(0, rval);
165       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
166       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
167   }
168
169   {
170       bufferlist read_bl1, read_bl2, op_bl;
171       int rval1 = 1000, rval2 = 1002;
172       ObjectReadOperation op;
173       op.read(0, sizeof(buf), &read_bl1, &rval1);
174       op.read(0, sizeof(buf), &read_bl2, &rval2);
175       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
176       ASSERT_EQ(sizeof(buf), read_bl1.length());
177       ASSERT_EQ(sizeof(buf), read_bl2.length());
178       ASSERT_EQ(sizeof(buf) * 2, op_bl.length());
179       ASSERT_EQ(0, rval1);
180       ASSERT_EQ(0, rval2);
181       ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
182       ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
183       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
184       ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf)));
185   }
186
187   {
188       bufferlist op_bl;
189       ObjectReadOperation op;
190       op.read(0, sizeof(buf), NULL, NULL);
191       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
192       ASSERT_EQ(sizeof(buf), op_bl.length());
193       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
194   }
195
196   {
197       bufferlist read_bl;
198       ObjectReadOperation op;
199       op.read(0, sizeof(buf), &read_bl, NULL);
200       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
201       ASSERT_EQ(sizeof(buf), read_bl.length());
202       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
203   }
204
205   {
206       int rval = 1000;
207       ObjectReadOperation op;
208       op.read(0, sizeof(buf), NULL, &rval);
209       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
210       ASSERT_EQ(0, rval);
211   }
212
213   {
214       bufferlist read_bl;
215       int rval = 1000;
216       ObjectReadOperation op;
217       op.read(0, sizeof(buf), &read_bl, &rval);
218       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
219       ASSERT_EQ(sizeof(buf), read_bl.length());
220       ASSERT_EQ(0, rval);
221       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
222   }
223
224   {
225       bufferlist read_bl1, read_bl2;
226       int rval1 = 1000, rval2 = 1002;
227       ObjectReadOperation op;
228       op.read(0, sizeof(buf), &read_bl1, &rval1);
229       op.read(0, sizeof(buf), &read_bl2, &rval2);
230       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
231       ASSERT_EQ(sizeof(buf), read_bl1.length());
232       ASSERT_EQ(sizeof(buf), read_bl2.length());
233       ASSERT_EQ(0, rval1);
234       ASSERT_EQ(0, rval2);
235       ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
236       ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
237   }
238 }
239
240 TEST_F(LibRadosIoPP, SparseReadOpPP) {
241   char buf[128];
242   memset(buf, 0xcc, sizeof(buf));
243   bufferlist bl;
244   bl.append(buf, sizeof(buf));
245   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
246
247   {
248     std::map<uint64_t, uint64_t> extents;
249     bufferlist read_bl;
250     int rval = -1;
251     ObjectReadOperation op;
252     op.sparse_read(0, sizeof(buf), &extents, &read_bl, &rval);
253     ASSERT_EQ(0, ioctx.operate("foo", &op, nullptr));
254     ASSERT_EQ(0, rval);
255     assert_eq_sparse(bl, extents, read_bl);
256   }
257 }
258
259 TEST_F(LibRadosIo, RoundTrip) {
260   char buf[128];
261   char buf2[128];
262   memset(buf, 0xcc, sizeof(buf));
263   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
264   memset(buf2, 0, sizeof(buf2));
265   ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
266   ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
267
268   uint64_t off = 19;
269   memset(buf, 0xcc, sizeof(buf));
270   ASSERT_EQ(0, rados_write(ioctx, "bar", buf, sizeof(buf), off));
271   memset(buf2, 0, sizeof(buf2));
272   ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "bar", buf2, sizeof(buf2), off));
273   ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
274 }
275
276 TEST_F(LibRadosIoPP, RoundTripPP) {
277   char buf[128];
278   Rados cluster;
279   memset(buf, 0xcc, sizeof(buf));
280   bufferlist bl;
281   bl.append(buf, sizeof(buf));
282   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
283   bufferlist cl;
284   ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf), 0));
285   ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
286 }
287
288 TEST_F(LibRadosIoPP, RoundTripPP2)
289 {
290   bufferlist bl;
291   bl.append("ceph");
292   ObjectWriteOperation write;
293   write.write(0, bl);
294   write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
295   ASSERT_EQ(0, ioctx.operate("foo", &write));
296
297   ObjectReadOperation read;
298   read.read(0, bl.length(), NULL, NULL);
299   read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
300   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
301   ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
302 }
303
304 TEST_F(LibRadosIo, Checksum) {
305   char buf[128];
306   memset(buf, 0xcc, sizeof(buf));
307   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
308
309   uint32_t expected_crc = ceph_crc32c(-1, reinterpret_cast<const uint8_t*>(buf),
310                                       sizeof(buf));
311   uint32_t init_value = -1;
312   uint32_t crc[2];
313   ASSERT_EQ(0, rados_checksum(ioctx, "foo", LIBRADOS_CHECKSUM_TYPE_CRC32C,
314                               reinterpret_cast<char*>(&init_value),
315                               sizeof(init_value), sizeof(buf), 0, 0,
316                               reinterpret_cast<char*>(&crc), sizeof(crc)));
317   ASSERT_EQ(1U, crc[0]);
318   ASSERT_EQ(expected_crc, crc[1]);
319 }
320
321 TEST_F(LibRadosIoPP, Checksum) {
322   char buf[128];
323   Rados cluster;
324   memset(buf, 0xcc, sizeof(buf));
325   bufferlist bl;
326   bl.append(buf, sizeof(buf));
327   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
328   bufferlist init_value_bl;
329   ::encode(static_cast<uint32_t>(-1), init_value_bl);
330   bufferlist csum_bl;
331   ASSERT_EQ(0, ioctx.checksum("foo", LIBRADOS_CHECKSUM_TYPE_CRC32C,
332                               init_value_bl, sizeof(buf), 0, 0, &csum_bl));
333   auto csum_bl_it = csum_bl.begin();
334   uint32_t csum_count;
335   ::decode(csum_count, csum_bl_it);
336   ASSERT_EQ(1U, csum_count);
337   uint32_t csum;
338   ::decode(csum, csum_bl_it);
339   ASSERT_EQ(bl.crc32c(-1), csum);
340 }
341
342 TEST_F(LibRadosIo, OverlappingWriteRoundTrip) {
343   char buf[128];
344   char buf2[64];
345   char buf3[128];
346   memset(buf, 0xcc, sizeof(buf));
347   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
348   memset(buf2, 0xdd, sizeof(buf2));
349   ASSERT_EQ(0, rados_write(ioctx, "foo", buf2, sizeof(buf2), 0));
350   memset(buf3, 0xdd, sizeof(buf3));
351   ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
352   ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
353   ASSERT_EQ(0, memcmp(buf3 + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
354 }
355
356 TEST_F(LibRadosIoPP, OverlappingWriteRoundTripPP) {
357   char buf[128];
358   char buf2[64];
359   memset(buf, 0xcc, sizeof(buf));
360   bufferlist bl1;
361   bl1.append(buf, sizeof(buf));
362   ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
363   memset(buf2, 0xdd, sizeof(buf2));
364   bufferlist bl2;
365   bl2.append(buf2, sizeof(buf2));
366   ASSERT_EQ(0, ioctx.write("foo", bl2, sizeof(buf2), 0));
367   bufferlist bl3;
368   ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl3, sizeof(buf), 0));
369   ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
370   ASSERT_EQ(0, memcmp(bl3.c_str() + sizeof(buf2), buf, sizeof(buf) - sizeof(buf2)));
371 }
372
373 TEST_F(LibRadosIo, WriteFullRoundTrip) {
374   char buf[128];
375   char buf2[64];
376   char buf3[128];
377   memset(buf, 0xcc, sizeof(buf));
378   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
379   memset(buf2, 0xdd, sizeof(buf2));
380   ASSERT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2)));
381   memset(buf3, 0x00, sizeof(buf3));
382   ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
383   ASSERT_EQ(0, memcmp(buf2, buf3, sizeof(buf2)));
384 }
385
386 TEST_F(LibRadosIoPP, WriteFullRoundTripPP) {
387   char buf[128];
388   char buf2[64];
389   memset(buf, 0xcc, sizeof(buf));
390   bufferlist bl1;
391   bl1.append(buf, sizeof(buf));
392   ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
393   memset(buf2, 0xdd, sizeof(buf2));
394   bufferlist bl2;
395   bl2.append(buf2, sizeof(buf2));
396   ASSERT_EQ(0, ioctx.write_full("foo", bl2));
397   bufferlist bl3;
398   ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0));
399   ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
400 }
401
402 TEST_F(LibRadosIoPP, WriteFullRoundTripPP2)
403 {
404   bufferlist bl;
405   bl.append("ceph");
406   ObjectWriteOperation write;
407   write.write_full(bl);
408   write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_NOCACHE);
409   ASSERT_EQ(0, ioctx.operate("foo", &write));
410
411   ObjectReadOperation read;
412   read.read(0, bl.length(), NULL, NULL);
413   read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
414   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
415   ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
416 }
417
418 TEST_F(LibRadosIo, AppendRoundTrip) {
419   char buf[64];
420   char buf2[64];
421   char buf3[sizeof(buf) + sizeof(buf2)];
422   memset(buf, 0xde, sizeof(buf));
423   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
424   memset(buf2, 0xad, sizeof(buf2));
425   ASSERT_EQ(0, rados_append(ioctx, "foo", buf2, sizeof(buf2)));
426   memset(buf3, 0, sizeof(buf3));
427   ASSERT_EQ((int)sizeof(buf3), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
428   ASSERT_EQ(0, memcmp(buf3, buf, sizeof(buf)));
429   ASSERT_EQ(0, memcmp(buf3 + sizeof(buf), buf2, sizeof(buf2)));
430 }
431
432 TEST_F(LibRadosIoPP, AppendRoundTripPP) {
433   char buf[64];
434   char buf2[64];
435   memset(buf, 0xde, sizeof(buf));
436   bufferlist bl1;
437   bl1.append(buf, sizeof(buf));
438   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
439   memset(buf2, 0xad, sizeof(buf2));
440   bufferlist bl2;
441   bl2.append(buf2, sizeof(buf2));
442   ASSERT_EQ(0, ioctx.append("foo", bl2, sizeof(buf2)));
443   bufferlist bl3;
444   ASSERT_EQ((int)(sizeof(buf) + sizeof(buf2)),
445             ioctx.read("foo", bl3, (sizeof(buf) + sizeof(buf2)), 0));
446   const char *bl3_str = bl3.c_str();
447   ASSERT_EQ(0, memcmp(bl3_str, buf, sizeof(buf)));
448   ASSERT_EQ(0, memcmp(bl3_str + sizeof(buf), buf2, sizeof(buf2)));
449 }
450
451 TEST_F(LibRadosIo, TruncTest) {
452   char buf[128];
453   char buf2[sizeof(buf)];
454   memset(buf, 0xaa, sizeof(buf));
455   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
456   ASSERT_EQ(0, rados_trunc(ioctx, "foo", sizeof(buf) / 2));
457   memset(buf2, 0, sizeof(buf2));
458   ASSERT_EQ((int)(sizeof(buf)/2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
459   ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)/2));
460 }
461
462 TEST_F(LibRadosIoPP, TruncTestPP) {
463   char buf[128];
464   memset(buf, 0xaa, sizeof(buf));
465   bufferlist bl;
466   bl.append(buf, sizeof(buf));
467   ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf)));
468   ASSERT_EQ(0, ioctx.trunc("foo", sizeof(buf) / 2));
469   bufferlist bl2;
470   ASSERT_EQ((int)(sizeof(buf)/2), ioctx.read("foo", bl2, sizeof(buf), 0));
471   ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)/2));
472 }
473
474 TEST_F(LibRadosIo, RemoveTest) {
475   char buf[128];
476   char buf2[sizeof(buf)];
477   memset(buf, 0xaa, sizeof(buf));
478   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
479   ASSERT_EQ(0, rados_remove(ioctx, "foo"));
480   memset(buf2, 0, sizeof(buf2));
481   ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
482 }
483
484 TEST_F(LibRadosIoPP, RemoveTestPP) {
485   char buf[128];
486   memset(buf, 0xaa, sizeof(buf));
487   bufferlist bl1;
488   bl1.append(buf, sizeof(buf));
489   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
490   ASSERT_EQ(0, ioctx.remove("foo"));
491   bufferlist bl2;
492   ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0));
493 }
494
495 TEST_F(LibRadosIo, XattrsRoundTrip) {
496   char buf[128];
497   char attr1[] = "attr1";
498   char attr1_buf[] = "foo bar baz";
499   memset(buf, 0xaa, sizeof(buf));
500   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
501   ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
502   ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
503   ASSERT_EQ((int)sizeof(attr1_buf),
504             rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
505   ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
506 }
507
508 TEST_F(LibRadosIoPP, XattrsRoundTripPP) {
509   char buf[128];
510   char attr1[] = "attr1";
511   char attr1_buf[] = "foo bar baz";
512   memset(buf, 0xaa, sizeof(buf));
513   bufferlist bl1;
514   bl1.append(buf, sizeof(buf));
515   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
516   bufferlist bl2;
517   ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2));
518   bufferlist bl3;
519   bl3.append(attr1_buf, sizeof(attr1_buf));
520   ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3));
521   bufferlist bl4;
522   ASSERT_EQ((int)sizeof(attr1_buf),
523       ioctx.getxattr("foo", attr1, bl4));
524   ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
525 }
526
527 TEST_F(LibRadosIo, RmXattr) {
528   char buf[128];
529   char attr1[] = "attr1";
530   char attr1_buf[] = "foo bar baz";
531   memset(buf, 0xaa, sizeof(buf));
532   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
533   ASSERT_EQ(0,
534       rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
535   ASSERT_EQ(0, rados_rmxattr(ioctx, "foo", attr1));
536   ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
537
538   // Test rmxattr on a removed object
539   char buf2[128];
540   char attr2[] = "attr2";
541   char attr2_buf[] = "foo bar baz";
542   memset(buf2, 0xbb, sizeof(buf2));
543   ASSERT_EQ(0, rados_write(ioctx, "foo_rmxattr", buf2, sizeof(buf2), 0));
544   ASSERT_EQ(0,
545       rados_setxattr(ioctx, "foo_rmxattr", attr2, attr2_buf, sizeof(attr2_buf)));
546   ASSERT_EQ(0, rados_remove(ioctx, "foo_rmxattr"));
547   ASSERT_EQ(-ENOENT, rados_rmxattr(ioctx, "foo_rmxattr", attr2));
548 }
549
550 TEST_F(LibRadosIoPP, RmXattrPP) {
551   char buf[128];
552   char attr1[] = "attr1";
553   char attr1_buf[] = "foo bar baz";
554   memset(buf, 0xaa, sizeof(buf));
555   bufferlist bl1;
556   bl1.append(buf, sizeof(buf));
557   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
558   bufferlist bl2;
559   bl2.append(attr1_buf, sizeof(attr1_buf));
560   ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
561   ASSERT_EQ(0, ioctx.rmxattr("foo", attr1));
562   bufferlist bl3;
563   ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3));
564
565   // Test rmxattr on a removed object
566   char buf2[128];
567   char attr2[] = "attr2";
568   char attr2_buf[] = "foo bar baz";
569   memset(buf2, 0xbb, sizeof(buf2));
570   bufferlist bl21;
571   bl21.append(buf, sizeof(buf));
572   ASSERT_EQ(0, ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
573   bufferlist bl22;
574   bl22.append(attr2_buf, sizeof(attr2_buf));
575   ASSERT_EQ(0, ioctx.setxattr("foo_rmxattr", attr2, bl22));
576   ASSERT_EQ(0, ioctx.remove("foo_rmxattr"));
577   ASSERT_EQ(-ENOENT, ioctx.rmxattr("foo_rmxattr", attr2));
578 }
579
580 TEST_F(LibRadosIo, XattrIter) {
581   char buf[128];
582   char attr1[] = "attr1";
583   char attr1_buf[] = "foo bar baz";
584   char attr2[] = "attr2";
585   char attr2_buf[256];
586   for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
587     attr2_buf[j] = j % 0xff;
588   }
589   memset(buf, 0xaa, sizeof(buf));
590   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
591   ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
592   ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf)));
593   rados_xattrs_iter_t iter;
594   ASSERT_EQ(0, rados_getxattrs(ioctx, "foo", &iter));
595   int num_seen = 0;
596   while (true) {
597     const char *name;
598     const char *val;
599     size_t len;
600     ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len));
601     if (name == NULL) {
602       break;
603     }
604     ASSERT_LT(num_seen, 2);
605     if ((strcmp(name, attr1) == 0) && (val != NULL) && (memcmp(val, attr1_buf, len) == 0)) {
606       num_seen++;
607       continue;
608     }
609     else if ((strcmp(name, attr2) == 0) && (val != NULL) && (memcmp(val, attr2_buf, len) == 0)) {
610       num_seen++;
611       continue;
612     }
613     else {
614       ASSERT_EQ(0, 1);
615     }
616   }
617   rados_getxattrs_end(iter);
618 }
619
620 TEST_F(LibRadosIoPP, XattrListPP) {
621   char buf[128];
622   char attr1[] = "attr1";
623   char attr1_buf[] = "foo bar baz";
624   char attr2[] = "attr2";
625   char attr2_buf[256];
626   for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
627     attr2_buf[j] = j % 0xff;
628   }
629   memset(buf, 0xaa, sizeof(buf));
630   bufferlist bl1;
631   bl1.append(buf, sizeof(buf));
632   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
633   bufferlist bl2;
634   bl2.append(attr1_buf, sizeof(attr1_buf));
635   ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
636   bufferlist bl3;
637   bl3.append(attr2_buf, sizeof(attr2_buf));
638   ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3));
639   std::map<std::string, bufferlist> attrset;
640   ASSERT_EQ(0, ioctx.getxattrs("foo", attrset));
641   for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
642        i != attrset.end(); ++i) {
643     if (i->first == string(attr1)) {
644       ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
645     }
646     else if (i->first == string(attr2)) {
647       ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
648     }
649     else {
650       ASSERT_EQ(0, 1);
651     }
652   }
653 }
654
655 TEST_F(LibRadosIoEC, SimpleWrite) {
656   char buf[128];
657   memset(buf, 0xcc, sizeof(buf));
658   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
659   rados_ioctx_set_namespace(ioctx, "nspace");
660   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
661 }
662
663 TEST_F(LibRadosIoECPP, SimpleWritePP) {
664   char buf[128];
665   memset(buf, 0xcc, sizeof(buf));
666   bufferlist bl;
667   bl.append(buf, sizeof(buf));
668   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
669   ioctx.set_namespace("nspace");
670   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
671 }
672
673 TEST_F(LibRadosIoECPP, ReadOpPP) {
674   char buf[128];
675   memset(buf, 0xcc, sizeof(buf));
676   bufferlist bl;
677   bl.append(buf, sizeof(buf));
678   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
679
680   {
681       bufferlist op_bl;
682       ObjectReadOperation op;
683       op.read(0, sizeof(buf), NULL, NULL);
684       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
685       ASSERT_EQ(sizeof(buf), op_bl.length());
686       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
687   }
688
689   {
690     bufferlist op_bl;
691     ObjectReadOperation op;
692     op.read(0, 0, NULL, NULL); //len=0 mean read the whole object data
693     ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
694     ASSERT_EQ(sizeof(buf), op_bl.length());
695     ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
696   }
697
698   {
699       bufferlist read_bl, op_bl;
700       ObjectReadOperation op;
701       op.read(0, sizeof(buf), &read_bl, NULL);
702       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
703       ASSERT_EQ(sizeof(buf), read_bl.length());
704       ASSERT_EQ(sizeof(buf), op_bl.length());
705       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
706       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
707   }
708
709   {
710       bufferlist op_bl;
711       int rval = 1000;
712       ObjectReadOperation op;
713       op.read(0, sizeof(buf), NULL, &rval);
714       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
715       ASSERT_EQ(sizeof(buf), op_bl.length());
716       ASSERT_EQ(0, rval);
717       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
718   }
719
720   {
721       bufferlist read_bl, op_bl;
722       int rval = 1000;
723       ObjectReadOperation op;
724       op.read(0, sizeof(buf), &read_bl, &rval);
725       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
726       ASSERT_EQ(sizeof(buf), read_bl.length());
727       ASSERT_EQ(sizeof(buf), op_bl.length());
728       ASSERT_EQ(0, rval);
729       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
730       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
731   }
732
733   {
734       bufferlist read_bl1, read_bl2, op_bl;
735       int rval1 = 1000, rval2 = 1002;
736       ObjectReadOperation op;
737       op.read(0, sizeof(buf), &read_bl1, &rval1);
738       op.read(0, sizeof(buf), &read_bl2, &rval2);
739       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
740       ASSERT_EQ(sizeof(buf), read_bl1.length());
741       ASSERT_EQ(sizeof(buf), read_bl2.length());
742       ASSERT_EQ(sizeof(buf) * 2, op_bl.length());
743       ASSERT_EQ(0, rval1);
744       ASSERT_EQ(0, rval2);
745       ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
746       ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
747       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
748       ASSERT_EQ(0, memcmp(op_bl.c_str() + sizeof(buf), buf, sizeof(buf)));
749   }
750
751   {
752       bufferlist op_bl;
753       ObjectReadOperation op;
754       op.read(0, sizeof(buf), NULL, NULL);
755       ASSERT_EQ(0, ioctx.operate("foo", &op, &op_bl));
756       ASSERT_EQ(sizeof(buf), op_bl.length());
757       ASSERT_EQ(0, memcmp(op_bl.c_str(), buf, sizeof(buf)));
758   }
759
760   {
761       bufferlist read_bl;
762       ObjectReadOperation op;
763       op.read(0, sizeof(buf), &read_bl, NULL);
764       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
765       ASSERT_EQ(sizeof(buf), read_bl.length());
766       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
767   }
768
769   {
770       int rval = 1000;
771       ObjectReadOperation op;
772       op.read(0, sizeof(buf), NULL, &rval);
773       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
774       ASSERT_EQ(0, rval);
775   }
776
777   {
778       bufferlist read_bl;
779       int rval = 1000;
780       ObjectReadOperation op;
781       op.read(0, sizeof(buf), &read_bl, &rval);
782       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
783       ASSERT_EQ(sizeof(buf), read_bl.length());
784       ASSERT_EQ(0, rval);
785       ASSERT_EQ(0, memcmp(read_bl.c_str(), buf, sizeof(buf)));
786   }
787
788   {
789       bufferlist read_bl1, read_bl2;
790       int rval1 = 1000, rval2 = 1002;
791       ObjectReadOperation op;
792       op.read(0, sizeof(buf), &read_bl1, &rval1);
793       op.read(0, sizeof(buf), &read_bl2, &rval2);
794       ASSERT_EQ(0, ioctx.operate("foo", &op, NULL));
795       ASSERT_EQ(sizeof(buf), read_bl1.length());
796       ASSERT_EQ(sizeof(buf), read_bl2.length());
797       ASSERT_EQ(0, rval1);
798       ASSERT_EQ(0, rval2);
799       ASSERT_EQ(0, memcmp(read_bl1.c_str(), buf, sizeof(buf)));
800       ASSERT_EQ(0, memcmp(read_bl2.c_str(), buf, sizeof(buf)));
801   }
802 }
803
804 TEST_F(LibRadosIoECPP, SparseReadOpPP) {
805   char buf[128];
806   memset(buf, 0xcc, sizeof(buf));
807   bufferlist bl;
808   bl.append(buf, sizeof(buf));
809   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
810
811   {
812     std::map<uint64_t, uint64_t> extents;
813     bufferlist read_bl;
814     int rval = -1;
815     ObjectReadOperation op;
816     op.sparse_read(0, sizeof(buf), &extents, &read_bl, &rval);
817     ASSERT_EQ(0, ioctx.operate("foo", &op, nullptr));
818     ASSERT_EQ(0, rval);
819     assert_eq_sparse(bl, extents, read_bl);
820   }
821 }
822
823 TEST_F(LibRadosIoEC, RoundTrip) {
824   char buf[128];
825   char buf2[128];
826   memset(buf, 0xcc, sizeof(buf));
827   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
828   memset(buf2, 0, sizeof(buf2));
829   ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
830   ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
831
832   uint64_t off = 19;
833   ASSERT_EQ(-EOPNOTSUPP, rados_write(ioctx, "bar", buf, sizeof(buf), off));
834 }
835
836 TEST_F(LibRadosIoECPP, RoundTripPP) {
837   char buf[128];
838   Rados cluster;
839   memset(buf, 0xcc, sizeof(buf));
840   bufferlist bl;
841   bl.append(buf, sizeof(buf));
842   ASSERT_EQ(0, ioctx.write("foo", bl, sizeof(buf), 0));
843   bufferlist cl;
844   ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", cl, sizeof(buf) * 3, 0));
845   ASSERT_EQ(0, memcmp(buf, cl.c_str(), sizeof(buf)));
846 }
847
848 TEST_F(LibRadosIoECPP, RoundTripPP2)
849 {
850   bufferlist bl;
851   bl.append("ceph");
852   ObjectWriteOperation write;
853   write.write(0, bl);
854   write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
855   ASSERT_EQ(0, ioctx.operate("foo", &write));
856
857   ObjectReadOperation read;
858   read.read(0, bl.length(), NULL, NULL);
859   read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
860   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
861   ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
862 }
863
864 TEST_F(LibRadosIoEC, OverlappingWriteRoundTrip) {
865   int bsize = alignment;
866   int dbsize = bsize * 2;
867   char *buf = (char *)new char[dbsize];
868   char *buf2 = (char *)new char[bsize];
869   char *buf3 = (char *)new char[dbsize];
870   auto cleanup = [&] {
871     delete[] buf;
872     delete[] buf2;
873     delete[] buf3;
874   };
875   scope_guard<decltype(cleanup)> sg(std::move(cleanup));
876   memset(buf, 0xcc, dbsize);
877   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, dbsize, 0));
878   memset(buf2, 0xdd, bsize);
879   ASSERT_EQ(-EOPNOTSUPP, rados_write(ioctx, "foo", buf2, bsize, 0));
880   memset(buf3, 0xdd, dbsize);
881   ASSERT_EQ(dbsize, rados_read(ioctx, "foo", buf3, dbsize, 0));
882   // Read the same as first write
883   ASSERT_EQ(0, memcmp(buf3, buf, dbsize));
884 }
885
886 TEST_F(LibRadosIoECPP, OverlappingWriteRoundTripPP) {
887   int bsize = alignment;
888   int dbsize = bsize * 2;
889   char *buf = (char *)new char[dbsize];
890   char *buf2 = (char *)new char[bsize];
891   auto cleanup = [&] {
892     delete[] buf;
893     delete[] buf2;
894   };
895   scope_guard<decltype(cleanup)> sg(std::move(cleanup));
896   memset(buf, 0xcc, dbsize);
897   bufferlist bl1;
898   bl1.append(buf, dbsize);
899   ASSERT_EQ(0, ioctx.write("foo", bl1, dbsize, 0));
900   memset(buf2, 0xdd, bsize);
901   bufferlist bl2;
902   bl2.append(buf2, bsize);
903   ASSERT_EQ(-EOPNOTSUPP, ioctx.write("foo", bl2, bsize, 0));
904   bufferlist bl3;
905   ASSERT_EQ(dbsize, ioctx.read("foo", bl3, dbsize, 0));
906   // Read the same as first write
907   ASSERT_EQ(0, memcmp(bl3.c_str(), buf, dbsize));
908 }
909
910 TEST_F(LibRadosIoEC, WriteFullRoundTrip) {
911   char buf[128];
912   char buf2[64];
913   char buf3[128];
914   memset(buf, 0xcc, sizeof(buf));
915   ASSERT_EQ(0, rados_write(ioctx, "foo", buf, sizeof(buf), 0));
916   memset(buf2, 0xdd, sizeof(buf2));
917   ASSERT_EQ(0, rados_write_full(ioctx, "foo", buf2, sizeof(buf2)));
918   memset(buf3, 0xee, sizeof(buf3));
919   ASSERT_EQ((int)sizeof(buf2), rados_read(ioctx, "foo", buf3, sizeof(buf3), 0));
920   ASSERT_EQ(0, memcmp(buf3, buf2, sizeof(buf2)));
921 }
922
923 TEST_F(LibRadosIoECPP, WriteFullRoundTripPP) {
924   char buf[128];
925   char buf2[64];
926   memset(buf, 0xcc, sizeof(buf));
927   bufferlist bl1;
928   bl1.append(buf, sizeof(buf));
929   ASSERT_EQ(0, ioctx.write("foo", bl1, sizeof(buf), 0));
930   memset(buf2, 0xdd, sizeof(buf2));
931   bufferlist bl2;
932   bl2.append(buf2, sizeof(buf2));
933   ASSERT_EQ(0, ioctx.write_full("foo", bl2));
934   bufferlist bl3;
935   ASSERT_EQ((int)sizeof(buf2), ioctx.read("foo", bl3, sizeof(buf), 0));
936   ASSERT_EQ(0, memcmp(bl3.c_str(), buf2, sizeof(buf2)));
937 }
938
939 TEST_F(LibRadosIoECPP, WriteFullRoundTripPP2)
940 {
941   bufferlist bl;
942   bl.append("ceph");
943   ObjectWriteOperation write;
944   write.write_full(bl);
945   write.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED);
946   ASSERT_EQ(0, ioctx.operate("foo", &write));
947
948   ObjectReadOperation read;
949   read.read(0, bl.length(), NULL, NULL);
950   read.set_op_flags2(LIBRADOS_OP_FLAG_FADVISE_DONTNEED|LIBRADOS_OP_FLAG_FADVISE_RANDOM);
951   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
952   ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
953 }
954
955 TEST_F(LibRadosIoEC, AppendRoundTrip) {
956   char *buf = (char *)new char[alignment];
957   char *buf2 = (char *)new char[alignment];
958   char *buf3 = (char *)new char[alignment *2];
959   int uasize = alignment/2;
960   char *unalignedbuf = (char *)new char[uasize];
961   auto cleanup = [&] {
962     delete[] buf;
963     delete[] buf2;
964     delete[] buf3;
965     delete[] unalignedbuf;
966   };
967   scope_guard<decltype(cleanup)> sg(std::move(cleanup));
968   memset(buf, 0xde, alignment);
969   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, alignment));
970   memset(buf2, 0xad, alignment);
971   ASSERT_EQ(0, rados_append(ioctx, "foo", buf2, alignment));
972   memset(buf3, 0, alignment*2);
973   ASSERT_EQ((int)alignment*2, rados_read(ioctx, "foo", buf3, alignment*2, 0));
974   ASSERT_EQ(0, memcmp(buf3, buf, alignment));
975   ASSERT_EQ(0, memcmp(buf3 + alignment, buf2, alignment));
976   memset(unalignedbuf, 0, uasize);
977   ASSERT_EQ(0, rados_append(ioctx, "foo", unalignedbuf, uasize));
978   ASSERT_EQ(-EOPNOTSUPP, rados_append(ioctx, "foo", unalignedbuf, uasize));
979 }
980
981 TEST_F(LibRadosIoECPP, AppendRoundTripPP) {
982   char *buf = (char *)new char[alignment];
983   char *buf2 = (char *)new char[alignment];
984   auto cleanup = [&] {
985     delete[] buf;
986     delete[] buf2;
987   };
988   scope_guard<decltype(cleanup)> sg(std::move(cleanup));
989   memset(buf, 0xde, alignment);
990   bufferlist bl1;
991   bl1.append(buf, alignment);
992   ASSERT_EQ(0, ioctx.append("foo", bl1, alignment));
993   memset(buf2, 0xad, alignment);
994   bufferlist bl2;
995   bl2.append(buf2, alignment);
996   ASSERT_EQ(0, ioctx.append("foo", bl2, alignment));
997   bufferlist bl3;
998   ASSERT_EQ((int)(alignment * 2),
999             ioctx.read("foo", bl3, (alignment * 4), 0));
1000   const char *bl3_str = bl3.c_str();
1001   ASSERT_EQ(0, memcmp(bl3_str, buf, alignment));
1002   ASSERT_EQ(0, memcmp(bl3_str + alignment, buf2, alignment));
1003 }
1004
1005 TEST_F(LibRadosIoEC, TruncTest) {
1006   char buf[128];
1007   char buf2[sizeof(buf)];
1008   memset(buf, 0xaa, sizeof(buf));
1009   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
1010   ASSERT_EQ(-EOPNOTSUPP, rados_trunc(ioctx, "foo", sizeof(buf) / 2));
1011   memset(buf2, 0, sizeof(buf2));
1012   // Same size
1013   ASSERT_EQ((int)sizeof(buf), rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
1014   // No change
1015   ASSERT_EQ(0, memcmp(buf, buf2, sizeof(buf)));
1016 }
1017
1018 TEST_F(LibRadosIoECPP, TruncTestPP) {
1019   char buf[128];
1020   memset(buf, 0xaa, sizeof(buf));
1021   bufferlist bl;
1022   bl.append(buf, sizeof(buf));
1023   ASSERT_EQ(0, ioctx.append("foo", bl, sizeof(buf)));
1024   ASSERT_EQ(-EOPNOTSUPP, ioctx.trunc("foo", sizeof(buf) / 2));
1025   bufferlist bl2;
1026   // Same size
1027   ASSERT_EQ((int)sizeof(buf), ioctx.read("foo", bl2, sizeof(buf), 0));
1028   // No change
1029   ASSERT_EQ(0, memcmp(bl2.c_str(), buf, sizeof(buf)));
1030 }
1031
1032 TEST_F(LibRadosIoEC, RemoveTest) {
1033   char buf[128];
1034   char buf2[sizeof(buf)];
1035   memset(buf, 0xaa, sizeof(buf));
1036   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
1037   ASSERT_EQ(0, rados_remove(ioctx, "foo"));
1038   memset(buf2, 0, sizeof(buf2));
1039   ASSERT_EQ(-ENOENT, rados_read(ioctx, "foo", buf2, sizeof(buf2), 0));
1040 }
1041
1042 TEST_F(LibRadosIoECPP, RemoveTestPP) {
1043   char buf[128];
1044   memset(buf, 0xaa, sizeof(buf));
1045   bufferlist bl1;
1046   bl1.append(buf, sizeof(buf));
1047   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
1048   ASSERT_EQ(0, ioctx.remove("foo"));
1049   bufferlist bl2;
1050   ASSERT_EQ(-ENOENT, ioctx.read("foo", bl2, sizeof(buf), 0));
1051 }
1052
1053 TEST_F(LibRadosIoEC, XattrsRoundTrip) {
1054   char buf[128];
1055   char attr1[] = "attr1";
1056   char attr1_buf[] = "foo bar baz";
1057   memset(buf, 0xaa, sizeof(buf));
1058   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
1059   ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
1060   ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
1061   ASSERT_EQ((int)sizeof(attr1_buf),
1062             rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
1063   ASSERT_EQ(0, memcmp(attr1_buf, buf, sizeof(attr1_buf)));
1064 }
1065
1066 TEST_F(LibRadosIoECPP, XattrsRoundTripPP) {
1067   char buf[128];
1068   char attr1[] = "attr1";
1069   char attr1_buf[] = "foo bar baz";
1070   memset(buf, 0xaa, sizeof(buf));
1071   bufferlist bl1;
1072   bl1.append(buf, sizeof(buf));
1073   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
1074   bufferlist bl2;
1075   ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl2));
1076   bufferlist bl3;
1077   bl3.append(attr1_buf, sizeof(attr1_buf));
1078   ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl3));
1079   bufferlist bl4;
1080   ASSERT_EQ((int)sizeof(attr1_buf),
1081       ioctx.getxattr("foo", attr1, bl4));
1082   ASSERT_EQ(0, memcmp(bl4.c_str(), attr1_buf, sizeof(attr1_buf)));
1083 }
1084
1085 TEST_F(LibRadosIoEC, RmXattr) {
1086   char buf[128];
1087   char attr1[] = "attr1";
1088   char attr1_buf[] = "foo bar baz";
1089   memset(buf, 0xaa, sizeof(buf));
1090   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
1091   ASSERT_EQ(0,
1092       rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
1093   ASSERT_EQ(0, rados_rmxattr(ioctx, "foo", attr1));
1094   ASSERT_EQ(-ENODATA, rados_getxattr(ioctx, "foo", attr1, buf, sizeof(buf)));
1095
1096   // Test rmxattr on a removed object
1097   char buf2[128];
1098   char attr2[] = "attr2";
1099   char attr2_buf[] = "foo bar baz";
1100   memset(buf2, 0xbb, sizeof(buf2));
1101   ASSERT_EQ(0, rados_write(ioctx, "foo_rmxattr", buf2, sizeof(buf2), 0));
1102   ASSERT_EQ(0,
1103       rados_setxattr(ioctx, "foo_rmxattr", attr2, attr2_buf, sizeof(attr2_buf)));
1104   ASSERT_EQ(0, rados_remove(ioctx, "foo_rmxattr"));
1105   ASSERT_EQ(-ENOENT, rados_rmxattr(ioctx, "foo_rmxattr", attr2));
1106 }
1107
1108 TEST_F(LibRadosIoECPP, RmXattrPP) {
1109   char buf[128];
1110   char attr1[] = "attr1";
1111   char attr1_buf[] = "foo bar baz";
1112   memset(buf, 0xaa, sizeof(buf));
1113   bufferlist bl1;
1114   bl1.append(buf, sizeof(buf));
1115   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
1116   bufferlist bl2;
1117   bl2.append(attr1_buf, sizeof(attr1_buf));
1118   ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
1119   ASSERT_EQ(0, ioctx.rmxattr("foo", attr1));
1120   bufferlist bl3;
1121   ASSERT_EQ(-ENODATA, ioctx.getxattr("foo", attr1, bl3));
1122
1123   // Test rmxattr on a removed object
1124   char buf2[128];
1125   char attr2[] = "attr2";
1126   char attr2_buf[] = "foo bar baz";
1127   memset(buf2, 0xbb, sizeof(buf2));
1128   bufferlist bl21;
1129   bl21.append(buf, sizeof(buf));
1130   ASSERT_EQ(0, ioctx.write("foo_rmxattr", bl21, sizeof(buf2), 0));
1131   bufferlist bl22;
1132   bl22.append(attr2_buf, sizeof(attr2_buf));
1133   ASSERT_EQ(0, ioctx.setxattr("foo_rmxattr", attr2, bl22));
1134   ASSERT_EQ(0, ioctx.remove("foo_rmxattr"));
1135   ASSERT_EQ(-ENOENT, ioctx.rmxattr("foo_rmxattr", attr2));
1136 }
1137
1138 TEST_F(LibRadosIoEC, XattrIter) {
1139   char buf[128];
1140   char attr1[] = "attr1";
1141   char attr1_buf[] = "foo bar baz";
1142   char attr2[] = "attr2";
1143   char attr2_buf[256];
1144   for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
1145     attr2_buf[j] = j % 0xff;
1146   }
1147   memset(buf, 0xaa, sizeof(buf));
1148   ASSERT_EQ(0, rados_append(ioctx, "foo", buf, sizeof(buf)));
1149   ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr1, attr1_buf, sizeof(attr1_buf)));
1150   ASSERT_EQ(0, rados_setxattr(ioctx, "foo", attr2, attr2_buf, sizeof(attr2_buf)));
1151   rados_xattrs_iter_t iter;
1152   ASSERT_EQ(0, rados_getxattrs(ioctx, "foo", &iter));
1153   int num_seen = 0;
1154   while (true) {
1155     const char *name;
1156     const char *val;
1157     size_t len;
1158     ASSERT_EQ(0, rados_getxattrs_next(iter, &name, &val, &len));
1159     if (name == NULL) {
1160       break;
1161     }
1162     ASSERT_LT(num_seen, 2);
1163     if ((strcmp(name, attr1) == 0) && (val != NULL) && (memcmp(val, attr1_buf, len) == 0)) {
1164       num_seen++;
1165       continue;
1166     }
1167     else if ((strcmp(name, attr2) == 0) && (val != NULL) && (memcmp(val, attr2_buf, len) == 0)) {
1168       num_seen++;
1169       continue;
1170     }
1171     else {
1172       ASSERT_EQ(0, 1);
1173     }
1174   }
1175   rados_getxattrs_end(iter);
1176 }
1177
1178 TEST_F(LibRadosIoECPP, XattrListPP) {
1179   char buf[128];
1180   char attr1[] = "attr1";
1181   char attr1_buf[] = "foo bar baz";
1182   char attr2[] = "attr2";
1183   char attr2_buf[256];
1184   for (size_t j = 0; j < sizeof(attr2_buf); ++j) {
1185     attr2_buf[j] = j % 0xff;
1186   }
1187   memset(buf, 0xaa, sizeof(buf));
1188   bufferlist bl1;
1189   bl1.append(buf, sizeof(buf));
1190   ASSERT_EQ(0, ioctx.append("foo", bl1, sizeof(buf)));
1191   bufferlist bl2;
1192   bl2.append(attr1_buf, sizeof(attr1_buf));
1193   ASSERT_EQ(0, ioctx.setxattr("foo", attr1, bl2));
1194   bufferlist bl3;
1195   bl3.append(attr2_buf, sizeof(attr2_buf));
1196   ASSERT_EQ(0, ioctx.setxattr("foo", attr2, bl3));
1197   std::map<std::string, bufferlist> attrset;
1198   ASSERT_EQ(0, ioctx.getxattrs("foo", attrset));
1199   for (std::map<std::string, bufferlist>::iterator i = attrset.begin();
1200        i != attrset.end(); ++i) {
1201     if (i->first == string(attr1)) {
1202       ASSERT_EQ(0, memcmp(i->second.c_str(), attr1_buf, sizeof(attr1_buf)));
1203     }
1204     else if (i->first == string(attr2)) {
1205       ASSERT_EQ(0, memcmp(i->second.c_str(), attr2_buf, sizeof(attr2_buf)));
1206     }
1207     else {
1208       ASSERT_EQ(0, 1);
1209     }
1210   }
1211 }
1212
1213 TEST_F(LibRadosIoPP, CmpExtPP) {
1214   bufferlist bl;
1215   bl.append("ceph");
1216   ObjectWriteOperation write1;
1217   write1.write(0, bl);
1218   ASSERT_EQ(0, ioctx.operate("foo", &write1));
1219
1220   bufferlist new_bl;
1221   new_bl.append("CEPH");
1222   ObjectWriteOperation write2;
1223   write2.cmpext(0, bl, nullptr);
1224   write2.write(0, new_bl);
1225   ASSERT_EQ(0, ioctx.operate("foo", &write2));
1226
1227   ObjectReadOperation read;
1228   read.read(0, bl.length(), NULL, NULL);
1229   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
1230   ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
1231 }
1232
1233 TEST_F(LibRadosIoPP, CmpExtDNEPP) {
1234   bufferlist bl;
1235   bl.append(std::string(4, '\0'));
1236
1237   bufferlist new_bl;
1238   new_bl.append("CEPH");
1239   ObjectWriteOperation write;
1240   write.cmpext(0, bl, nullptr);
1241   write.write(0, new_bl);
1242   ASSERT_EQ(0, ioctx.operate("foo", &write));
1243
1244   ObjectReadOperation read;
1245   read.read(0, bl.length(), NULL, NULL);
1246   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
1247   ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
1248 }
1249
1250 TEST_F(LibRadosIoPP, CmpExtMismatchPP) {
1251   bufferlist bl;
1252   bl.append("ceph");
1253   ObjectWriteOperation write1;
1254   write1.write(0, bl);
1255   ASSERT_EQ(0, ioctx.operate("foo", &write1));
1256
1257   bufferlist new_bl;
1258   new_bl.append("CEPH");
1259   ObjectWriteOperation write2;
1260   write2.cmpext(0, new_bl, nullptr);
1261   write2.write(0, new_bl);
1262   ASSERT_EQ(-MAX_ERRNO, ioctx.operate("foo", &write2));
1263
1264   ObjectReadOperation read;
1265   read.read(0, bl.length(), NULL, NULL);
1266   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
1267   ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
1268 }
1269
1270 TEST_F(LibRadosIoECPP, CmpExtPP) {
1271   bufferlist bl;
1272   bl.append("ceph");
1273   ObjectWriteOperation write1;
1274   write1.write(0, bl);
1275   ASSERT_EQ(0, ioctx.operate("foo", &write1));
1276
1277   bufferlist new_bl;
1278   new_bl.append("CEPH");
1279   ObjectWriteOperation write2;
1280   write2.cmpext(0, bl, nullptr);
1281   write2.write_full(new_bl);
1282   ASSERT_EQ(0, ioctx.operate("foo", &write2));
1283
1284   ObjectReadOperation read;
1285   read.read(0, bl.length(), NULL, NULL);
1286   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
1287   ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
1288 }
1289
1290 TEST_F(LibRadosIoECPP, CmpExtDNEPP) {
1291   bufferlist bl;
1292   bl.append(std::string(4, '\0'));
1293
1294   bufferlist new_bl;
1295   new_bl.append("CEPH");
1296   ObjectWriteOperation write;
1297   write.cmpext(0, bl, nullptr);
1298   write.write_full(new_bl);
1299   ASSERT_EQ(0, ioctx.operate("foo", &write));
1300
1301   ObjectReadOperation read;
1302   read.read(0, bl.length(), NULL, NULL);
1303   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
1304   ASSERT_EQ(0, memcmp(bl.c_str(), "CEPH", 4));
1305 }
1306
1307 TEST_F(LibRadosIoECPP, CmpExtMismatchPP) {
1308   bufferlist bl;
1309   bl.append("ceph");
1310   ObjectWriteOperation write1;
1311   write1.write(0, bl);
1312   ASSERT_EQ(0, ioctx.operate("foo", &write1));
1313
1314   bufferlist new_bl;
1315   new_bl.append("CEPH");
1316   ObjectWriteOperation write2;
1317   write2.cmpext(0, new_bl, nullptr);
1318   write2.write_full(new_bl);
1319   ASSERT_EQ(-MAX_ERRNO, ioctx.operate("foo", &write2));
1320
1321   ObjectReadOperation read;
1322   read.read(0, bl.length(), NULL, NULL);
1323   ASSERT_EQ(0, ioctx.operate("foo", &read, &bl));
1324   ASSERT_EQ(0, memcmp(bl.c_str(), "ceph", 4));
1325 }