]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/cls_rgw/test_cls_rgw.cc
import ceph 15.2.14
[ceph.git] / ceph / src / test / cls_rgw / test_cls_rgw.cc
CommitLineData
7c673cae
FG
1// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3
4#include "include/types.h"
5#include "cls/rgw/cls_rgw_client.h"
6#include "cls/rgw/cls_rgw_ops.h"
7
8#include "gtest/gtest.h"
11fdf7f2 9#include "test/librados/test_cxx.h"
1adf2230 10#include "global/global_context.h"
9f95a23c 11#include "common/ceph_context.h"
7c673cae
FG
12
13#include <errno.h>
14#include <string>
15#include <vector>
16#include <map>
31f18b77 17#include <set>
7c673cae
FG
18
19using namespace librados;
20
9f95a23c
TL
21// creates a temporary pool and initializes an IoCtx shared by all tests
22class cls_rgw : public ::testing::Test {
23 static librados::Rados rados;
24 static std::string pool_name;
25 protected:
26 static librados::IoCtx ioctx;
27
28 static void SetUpTestCase() {
29 pool_name = get_temp_pool_name();
30 /* create pool */
31 ASSERT_EQ("", create_one_pool_pp(pool_name, rados));
32 ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx));
33 }
34 static void TearDownTestCase() {
35 /* remove pool */
36 ioctx.close();
37 ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados));
38 }
39};
40librados::Rados cls_rgw::rados;
41std::string cls_rgw::pool_name;
42librados::IoCtx cls_rgw::ioctx;
7c673cae
FG
43
44
45string str_int(string s, int i)
46{
47 char buf[32];
48 snprintf(buf, sizeof(buf), "-%d", i);
49 s.append(buf);
50
51 return s;
52}
53
11fdf7f2 54void test_stats(librados::IoCtx& ioctx, string& oid, RGWObjCategory category, uint64_t num_entries, uint64_t total_size)
7c673cae
FG
55{
56 map<int, struct rgw_cls_list_ret> results;
57 map<int, string> oids;
58 oids[0] = oid;
59 ASSERT_EQ(0, CLSRGWIssueGetDirHeader(ioctx, oids, results, 8)());
60
61 uint64_t entries = 0;
62 uint64_t size = 0;
63 map<int, struct rgw_cls_list_ret>::iterator iter = results.begin();
64 for (; iter != results.end(); ++iter) {
65 entries += (iter->second).dir.header.stats[category].num_entries;
66 size += (iter->second).dir.header.stats[category].total_size;
67 }
68 ASSERT_EQ(total_size, size);
69 ASSERT_EQ(num_entries, entries);
70}
71
9f95a23c
TL
72void index_prepare(librados::IoCtx& ioctx, string& oid, RGWModifyOp index_op,
73 string& tag, const cls_rgw_obj_key& key, string& loc,
74 uint16_t bi_flags = 0, bool log_op = true)
7c673cae 75{
9f95a23c 76 ObjectWriteOperation op;
31f18b77 77 rgw_zone_set zones_trace;
9f95a23c
TL
78 cls_rgw_bucket_prepare_op(op, index_op, tag, key, loc, log_op, bi_flags, zones_trace);
79 ASSERT_EQ(0, ioctx.operate(oid, &op));
7c673cae
FG
80}
81
9f95a23c
TL
82void index_complete(librados::IoCtx& ioctx, string& oid, RGWModifyOp index_op,
83 string& tag, int epoch, const cls_rgw_obj_key& key,
84 rgw_bucket_dir_entry_meta& meta, uint16_t bi_flags = 0,
85 bool log_op = true)
7c673cae 86{
9f95a23c 87 ObjectWriteOperation op;
7c673cae
FG
88 rgw_bucket_entry_ver ver;
89 ver.pool = ioctx.get_id();
90 ver.epoch = epoch;
91 meta.accounted_size = meta.size;
9f95a23c
TL
92 cls_rgw_bucket_complete_op(op, index_op, tag, ver, key, meta, nullptr, log_op, bi_flags, nullptr);
93 ASSERT_EQ(0, ioctx.operate(oid, &op));
94 if (!key.instance.empty()) {
95 bufferlist olh_tag;
96 olh_tag.append(tag);
97 rgw_zone_set zone_set;
98 ASSERT_EQ(0, cls_rgw_bucket_link_olh(ioctx, oid, key, olh_tag,
99 false, tag, &meta, epoch,
100 ceph::real_time{}, true, true, zone_set));
101 }
7c673cae
FG
102}
103
9f95a23c 104TEST_F(cls_rgw, index_basic)
7c673cae
FG
105{
106 string bucket_oid = str_int("bucket", 0);
107
9f95a23c
TL
108 ObjectWriteOperation op;
109 cls_rgw_bucket_init_index(op);
110 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
7c673cae
FG
111
112 uint64_t epoch = 1;
113
114 uint64_t obj_size = 1024;
115
116#define NUM_OBJS 10
117 for (int i = 0; i < NUM_OBJS; i++) {
9f95a23c 118 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
119 string tag = str_int("tag", i);
120 string loc = str_int("loc", i);
121
9f95a23c 122 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
7c673cae 123
11fdf7f2 124 test_stats(ioctx, bucket_oid, RGWObjCategory::None, i, obj_size * i);
7c673cae 125
7c673cae 126 rgw_bucket_dir_entry_meta meta;
11fdf7f2 127 meta.category = RGWObjCategory::None;
7c673cae 128 meta.size = obj_size;
9f95a23c 129 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, epoch, obj, meta);
7c673cae
FG
130 }
131
11fdf7f2
TL
132 test_stats(ioctx, bucket_oid, RGWObjCategory::None, NUM_OBJS,
133 obj_size * NUM_OBJS);
7c673cae
FG
134}
135
9f95a23c 136TEST_F(cls_rgw, index_multiple_obj_writers)
7c673cae
FG
137{
138 string bucket_oid = str_int("bucket", 1);
139
9f95a23c
TL
140 ObjectWriteOperation op;
141 cls_rgw_bucket_init_index(op);
142 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
7c673cae
FG
143
144 uint64_t obj_size = 1024;
145
9f95a23c 146 cls_rgw_obj_key obj = str_int("obj", 0);
7c673cae
FG
147 string loc = str_int("loc", 0);
148 /* multi prepare on a single object */
149 for (int i = 0; i < NUM_OBJS; i++) {
150 string tag = str_int("tag", i);
151
9f95a23c 152 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
7c673cae 153
11fdf7f2 154 test_stats(ioctx, bucket_oid, RGWObjCategory::None, 0, 0);
7c673cae
FG
155 }
156
157 for (int i = NUM_OBJS; i > 0; i--) {
158 string tag = str_int("tag", i - 1);
159
160 rgw_bucket_dir_entry_meta meta;
11fdf7f2 161 meta.category = RGWObjCategory::None;
7c673cae
FG
162 meta.size = obj_size * i;
163
9f95a23c 164 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, i, obj, meta);
7c673cae
FG
165
166 /* verify that object size doesn't change, as we went back with epoch */
11fdf7f2
TL
167 test_stats(ioctx, bucket_oid, RGWObjCategory::None, 1,
168 obj_size * NUM_OBJS);
7c673cae
FG
169 }
170}
171
9f95a23c 172TEST_F(cls_rgw, index_remove_object)
7c673cae
FG
173{
174 string bucket_oid = str_int("bucket", 2);
175
9f95a23c
TL
176 ObjectWriteOperation op;
177 cls_rgw_bucket_init_index(op);
178 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
7c673cae
FG
179
180 uint64_t obj_size = 1024;
181 uint64_t total_size = 0;
182
183 int epoch = 0;
184
185 /* prepare multiple objects */
186 for (int i = 0; i < NUM_OBJS; i++) {
9f95a23c 187 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
188 string tag = str_int("tag", i);
189 string loc = str_int("loc", i);
190
9f95a23c 191 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
7c673cae 192
11fdf7f2 193 test_stats(ioctx, bucket_oid, RGWObjCategory::None, i, total_size);
7c673cae
FG
194
195 rgw_bucket_dir_entry_meta meta;
11fdf7f2 196 meta.category = RGWObjCategory::None;
7c673cae
FG
197 meta.size = i * obj_size;
198 total_size += i * obj_size;
199
9f95a23c 200 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, ++epoch, obj, meta);
7c673cae 201
11fdf7f2 202 test_stats(ioctx, bucket_oid, RGWObjCategory::None, i + 1, total_size);
7c673cae
FG
203 }
204
205 int i = NUM_OBJS / 2;
206 string tag_remove = "tag-rm";
207 string tag_modify = "tag-mod";
9f95a23c 208 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
209 string loc = str_int("loc", i);
210
211 /* prepare both removal and modification on the same object */
9f95a23c
TL
212 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_DEL, tag_remove, obj, loc);
213 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag_modify, obj, loc);
7c673cae 214
11fdf7f2 215 test_stats(ioctx, bucket_oid, RGWObjCategory::None, NUM_OBJS, total_size);
7c673cae
FG
216
217 rgw_bucket_dir_entry_meta meta;
218
219 /* complete object removal */
9f95a23c 220 index_complete(ioctx, bucket_oid, CLS_RGW_OP_DEL, tag_remove, ++epoch, obj, meta);
7c673cae
FG
221
222 /* verify stats correct */
223 total_size -= i * obj_size;
11fdf7f2 224 test_stats(ioctx, bucket_oid, RGWObjCategory::None, NUM_OBJS - 1, total_size);
7c673cae
FG
225
226 meta.size = 512;
11fdf7f2 227 meta.category = RGWObjCategory::None;
7c673cae
FG
228
229 /* complete object modification */
9f95a23c 230 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag_modify, ++epoch, obj, meta);
7c673cae
FG
231
232 /* verify stats correct */
233 total_size += meta.size;
11fdf7f2 234 test_stats(ioctx, bucket_oid, RGWObjCategory::None, NUM_OBJS, total_size);
7c673cae
FG
235
236
237 /* prepare both removal and modification on the same object, this time we'll
238 * first complete modification then remove*/
9f95a23c
TL
239 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_DEL, tag_remove, obj, loc);
240 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_DEL, tag_modify, obj, loc);
7c673cae
FG
241
242 /* complete modification */
243 total_size -= meta.size;
244 meta.size = i * obj_size * 2;
11fdf7f2 245 meta.category = RGWObjCategory::None;
7c673cae
FG
246
247 /* complete object modification */
9f95a23c 248 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag_modify, ++epoch, obj, meta);
7c673cae
FG
249
250 /* verify stats correct */
251 total_size += meta.size;
11fdf7f2 252 test_stats(ioctx, bucket_oid, RGWObjCategory::None, NUM_OBJS, total_size);
7c673cae
FG
253
254 /* complete object removal */
9f95a23c 255 index_complete(ioctx, bucket_oid, CLS_RGW_OP_DEL, tag_remove, ++epoch, obj, meta);
7c673cae
FG
256
257 /* verify stats correct */
258 total_size -= meta.size;
11fdf7f2
TL
259 test_stats(ioctx, bucket_oid, RGWObjCategory::None, NUM_OBJS - 1,
260 total_size);
7c673cae
FG
261}
262
9f95a23c 263TEST_F(cls_rgw, index_suggest)
7c673cae
FG
264{
265 string bucket_oid = str_int("bucket", 3);
9f95a23c
TL
266 {
267 ObjectWriteOperation op;
268 cls_rgw_bucket_init_index(op);
269 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
270 }
7c673cae
FG
271 uint64_t total_size = 0;
272
273 int epoch = 0;
274
275 int num_objs = 100;
276
277 uint64_t obj_size = 1024;
278
279 /* create multiple objects */
280 for (int i = 0; i < num_objs; i++) {
9f95a23c 281 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
282 string tag = str_int("tag", i);
283 string loc = str_int("loc", i);
284
9f95a23c 285 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
7c673cae 286
11fdf7f2 287 test_stats(ioctx, bucket_oid, RGWObjCategory::None, i, total_size);
7c673cae
FG
288
289 rgw_bucket_dir_entry_meta meta;
11fdf7f2 290 meta.category = RGWObjCategory::None;
7c673cae
FG
291 meta.size = obj_size;
292 total_size += meta.size;
293
9f95a23c 294 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, ++epoch, obj, meta);
7c673cae 295
11fdf7f2 296 test_stats(ioctx, bucket_oid, RGWObjCategory::None, i + 1, total_size);
7c673cae
FG
297 }
298
299 /* prepare (without completion) some of the objects */
300 for (int i = 0; i < num_objs; i += 2) {
9f95a23c 301 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
302 string tag = str_int("tag-prepare", i);
303 string loc = str_int("loc", i);
304
9f95a23c 305 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
7c673cae 306
11fdf7f2 307 test_stats(ioctx, bucket_oid, RGWObjCategory::None, num_objs, total_size);
7c673cae
FG
308 }
309
310 int actual_num_objs = num_objs;
311 /* remove half of the objects */
312 for (int i = num_objs / 2; i < num_objs; i++) {
9f95a23c 313 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
314 string tag = str_int("tag-rm", i);
315 string loc = str_int("loc", i);
316
9f95a23c 317 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
7c673cae 318
11fdf7f2 319 test_stats(ioctx, bucket_oid, RGWObjCategory::None, actual_num_objs, total_size);
7c673cae
FG
320
321 rgw_bucket_dir_entry_meta meta;
9f95a23c 322 index_complete(ioctx, bucket_oid, CLS_RGW_OP_DEL, tag, ++epoch, obj, meta);
7c673cae
FG
323
324 total_size -= obj_size;
325 actual_num_objs--;
11fdf7f2 326 test_stats(ioctx, bucket_oid, RGWObjCategory::None, actual_num_objs, total_size);
7c673cae
FG
327 }
328
329 bufferlist updates;
330
331 for (int i = 0; i < num_objs; i += 2) {
9f95a23c 332 cls_rgw_obj_key obj = str_int("obj", i);
7c673cae
FG
333 string tag = str_int("tag-rm", i);
334 string loc = str_int("loc", i);
335
336 rgw_bucket_dir_entry dirent;
9f95a23c 337 dirent.key.name = obj.name;
7c673cae
FG
338 dirent.locator = loc;
339 dirent.exists = (i < num_objs / 2); // we removed half the objects
340 dirent.meta.size = 1024;
341 dirent.meta.accounted_size = 1024;
342
343 char suggest_op = (i < num_objs / 2 ? CEPH_RGW_UPDATE : CEPH_RGW_REMOVE);
344 cls_rgw_encode_suggestion(suggest_op, dirent, updates);
345 }
346
347 map<int, string> bucket_objs;
348 bucket_objs[0] = bucket_oid;
349 int r = CLSRGWIssueSetTagTimeout(ioctx, bucket_objs, 8 /* max aio */, 1)();
350 ASSERT_EQ(0, r);
351
352 sleep(1);
353
354 /* suggest changes! */
9f95a23c
TL
355 {
356 ObjectWriteOperation op;
357 cls_rgw_suggest_changes(op, updates);
358 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
359 }
7c673cae 360 /* suggest changes twice! */
9f95a23c
TL
361 {
362 ObjectWriteOperation op;
363 cls_rgw_suggest_changes(op, updates);
364 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
365 }
11fdf7f2 366 test_stats(ioctx, bucket_oid, RGWObjCategory::None, num_objs / 2, total_size);
7c673cae
FG
367}
368
9f95a23c 369
1adf2230
AA
370/*
371 * This case is used to test whether get_obj_vals will
372 * return all validate utf8 objnames and filter out those
373 * in BI_PREFIX_CHAR private namespace.
374 */
9f95a23c 375TEST_F(cls_rgw, index_list)
1adf2230
AA
376{
377 string bucket_oid = str_int("bucket", 4);
378
9f95a23c
TL
379 ObjectWriteOperation op;
380 cls_rgw_bucket_init_index(op);
381 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
1adf2230
AA
382
383 uint64_t epoch = 1;
384 uint64_t obj_size = 1024;
81eedcae 385 const int num_objs = 4;
1adf2230
AA
386 const string keys[num_objs] = {
387 /* single byte utf8 character */
388 { static_cast<char>(0x41) },
389 /* double byte utf8 character */
390 { static_cast<char>(0xCF), static_cast<char>(0x8F) },
391 /* treble byte utf8 character */
392 { static_cast<char>(0xDF), static_cast<char>(0x8F), static_cast<char>(0x8F) },
393 /* quadruble byte utf8 character */
394 { static_cast<char>(0xF7), static_cast<char>(0x8F), static_cast<char>(0x8F), static_cast<char>(0x8F) },
1adf2230
AA
395 };
396
397 for (int i = 0; i < num_objs; i++) {
398 string obj = keys[i];
399 string tag = str_int("tag", i);
400 string loc = str_int("loc", i);
401
9f95a23c
TL
402 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc,
403 0 /* bi_flags */, false /* log_op */);
1adf2230 404
1adf2230 405 rgw_bucket_dir_entry_meta meta;
11fdf7f2 406 meta.category = RGWObjCategory::None;
1adf2230 407 meta.size = obj_size;
9f95a23c
TL
408 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, epoch, obj, meta,
409 0 /* bi_flags */, false /* log_op */);
81eedcae
TL
410 }
411
412 map<string, bufferlist> entries;
413 /* insert 998 omap key starts with BI_PREFIX_CHAR,
414 * so bucket list first time will get one key before 0x80 and one key after */
415 for (int i = 0; i < 998; ++i) {
416 char buf[10];
417 snprintf(buf, sizeof(buf), "%c%s%d", 0x80, "1000_", i);
418 entries.emplace(string{buf}, bufferlist{});
1adf2230 419 }
81eedcae 420 ioctx.omap_set(bucket_oid, entries);
1adf2230 421
9f95a23c
TL
422 test_stats(ioctx, bucket_oid, RGWObjCategory::None,
423 num_objs, obj_size * num_objs);
1adf2230
AA
424
425 map<int, string> oids = { {0, bucket_oid} };
426 map<int, struct rgw_cls_list_ret> list_results;
427 cls_rgw_obj_key start_key("", "");
9f95a23c
TL
428 string empty_prefix;
429 string empty_delimiter;
430 int r = CLSRGWIssueBucketList(ioctx, start_key,
431 empty_prefix, empty_delimiter,
432 1000, true, oids, list_results, 1)();
1adf2230 433 ASSERT_EQ(r, 0);
11fdf7f2 434 ASSERT_EQ(1u, list_results.size());
1adf2230
AA
435
436 auto it = list_results.begin();
437 auto m = (it->second).dir.m;
438
11fdf7f2 439 ASSERT_EQ(4u, m.size());
1adf2230 440 int i = 0;
9f95a23c 441 for(auto it2 = m.cbegin(); it2 != m.cend(); it2++, i++) {
1adf2230 442 ASSERT_EQ(it2->first.compare(keys[i]), 0);
9f95a23c 443 }
1adf2230
AA
444}
445
446
9f95a23c
TL
447/*
448 * This case is used to test when bucket index list that includes a
449 * delimiter can handle the first chunk ending in a delimiter.
450 */
451TEST_F(cls_rgw, index_list_delimited)
452{
453 string bucket_oid = str_int("bucket", 7);
454
455 ObjectWriteOperation op;
456 cls_rgw_bucket_init_index(op);
457 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
458
459 uint64_t epoch = 1;
460 uint64_t obj_size = 1024;
461 const int file_num_objs = 5;
462 const int dir_num_objs = 1005;
463
464 std::vector<std::string> file_prefixes =
465 { "a", "c", "e", "g", "i", "k", "m", "o", "q", "s", "u" };
466 std::vector<std::string> dir_prefixes =
467 { "b/", "d/", "f/", "h/", "j/", "l/", "n/", "p/", "r/", "t/" };
468
469 rgw_bucket_dir_entry_meta meta;
470 meta.category = RGWObjCategory::None;
471 meta.size = obj_size;
472
473 // create top-level files
474 for (const auto& p : file_prefixes) {
475 for (int i = 0; i < file_num_objs; i++) {
476 string tag = str_int("tag", i);
477 string loc = str_int("loc", i);
478 const string obj = str_int(p, i);
479
480 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc,
481 0 /* bi_flags */, false /* log_op */);
482
483 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, epoch, obj, meta,
484 0 /* bi_flags */, false /* log_op */);
485 }
486 }
487
488 // create large directories
489 for (const auto& p : dir_prefixes) {
490 for (int i = 0; i < dir_num_objs; i++) {
491 string tag = str_int("tag", i);
492 string loc = str_int("loc", i);
493 const string obj = p + str_int("f", i);
494
495 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc,
496 0 /* bi_flags */, false /* log_op */);
497
498 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, epoch, obj, meta,
499 0 /* bi_flags */, false /* log_op */);
500 }
501 }
502
503 map<int, string> oids = { {0, bucket_oid} };
504 map<int, struct rgw_cls_list_ret> list_results;
505 cls_rgw_obj_key start_key("", "");
506 const string empty_prefix;
507 const string delimiter = "/";
508 int r = CLSRGWIssueBucketList(ioctx, start_key,
509 empty_prefix, delimiter,
510 1000, true, oids, list_results, 1)();
511 ASSERT_EQ(r, 0);
512 ASSERT_EQ(1u, list_results.size()) <<
513 "Because we only have one bucket index shard, we should "
514 "only get one list_result.";
515
516 auto it = list_results.begin();
517 auto id_entry_map = it->second.dir.m;
518 bool truncated = it->second.is_truncated;
519
520 // the cls code will make 4 tries to get 1000 entries; however
521 // because each of the subdirectories is so large, each attempt will
522 // only retrieve the first part of the subdirectory
523
524 ASSERT_EQ(48u, id_entry_map.size()) <<
525 "We should get 40 top-level entries and the tops of 8 \"subdirectories\".";
526 ASSERT_EQ(true, truncated) << "We did not get all entries.";
527
528 ASSERT_EQ("a-0", id_entry_map.cbegin()->first);
529 ASSERT_EQ("p/", id_entry_map.crbegin()->first);
530
531 // now let's get the rest of the entries
532
533 list_results.clear();
534
535 cls_rgw_obj_key start_key2("p/", "");
536 r = CLSRGWIssueBucketList(ioctx, start_key2,
537 empty_prefix, delimiter,
538 1000, true, oids, list_results, 1)();
539 ASSERT_EQ(r, 0);
540
541 it = list_results.begin();
542 id_entry_map = it->second.dir.m;
543 truncated = it->second.is_truncated;
544
545 ASSERT_EQ(17u, id_entry_map.size()) <<
546 "We should get 15 top-level entries and the tops of 2 \"subdirectories\".";
547 ASSERT_EQ(false, truncated) << "We now have all entries.";
548
549 ASSERT_EQ("q-0", id_entry_map.cbegin()->first);
550 ASSERT_EQ("u-4", id_entry_map.crbegin()->first);
551}
552
553
554TEST_F(cls_rgw, bi_list)
1adf2230
AA
555{
556 string bucket_oid = str_int("bucket", 5);
557
558 CephContext *cct = reinterpret_cast<CephContext *>(ioctx.cct());
559
9f95a23c
TL
560 ObjectWriteOperation op;
561 cls_rgw_bucket_init_index(op);
562 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
1adf2230
AA
563
564 string name;
565 string marker;
566 uint64_t max = 10;
567 list<rgw_cls_bi_entry> entries;
568 bool is_truncated;
569
570 int ret = cls_rgw_bi_list(ioctx, bucket_oid, name, marker, max, &entries,
571 &is_truncated);
572 ASSERT_EQ(ret, 0);
9f95a23c
TL
573 ASSERT_EQ(entries.size(), 0u) <<
574 "The listing of an empty bucket as 0 entries.";
575 ASSERT_EQ(is_truncated, false) <<
576 "The listing of an empty bucket is not truncated.";
1adf2230
AA
577
578 uint64_t epoch = 1;
579 uint64_t obj_size = 1024;
580 uint64_t num_objs = 35;
581
582 for (uint64_t i = 0; i < num_objs; i++) {
ec96510d 583 string obj = str_int(i % 4 ? "obj" : "об'єкт", i);
1adf2230
AA
584 string tag = str_int("tag", i);
585 string loc = str_int("loc", i);
9f95a23c
TL
586 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc,
587 RGW_BILOG_FLAG_VERSIONED_OP);
588
1adf2230 589 rgw_bucket_dir_entry_meta meta;
11fdf7f2 590 meta.category = RGWObjCategory::None;
1adf2230 591 meta.size = obj_size;
9f95a23c
TL
592 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, epoch, obj, meta,
593 RGW_BILOG_FLAG_VERSIONED_OP);
1adf2230
AA
594 }
595
596 ret = cls_rgw_bi_list(ioctx, bucket_oid, name, marker, num_objs + 10, &entries,
597 &is_truncated);
598 ASSERT_EQ(ret, 0);
ec96510d
FG
599 if (is_truncated) {
600 ASSERT_LT(entries.size(), num_objs);
1adf2230
AA
601 } else {
602 ASSERT_EQ(entries.size(), num_objs);
603 }
604
605 uint64_t num_entries = 0;
606
607 is_truncated = true;
608 while(is_truncated) {
609 ret = cls_rgw_bi_list(ioctx, bucket_oid, name, marker, max, &entries,
610 &is_truncated);
611 ASSERT_EQ(ret, 0);
612 if (is_truncated) {
ec96510d 613 ASSERT_LT(entries.size(), num_objs - num_entries);
1adf2230
AA
614 } else {
615 ASSERT_EQ(entries.size(), num_objs - num_entries);
616 }
617 num_entries += entries.size();
618 marker = entries.back().idx;
619 }
620
621 ret = cls_rgw_bi_list(ioctx, bucket_oid, name, marker, max, &entries,
622 &is_truncated);
623 ASSERT_EQ(ret, 0);
11fdf7f2 624 ASSERT_EQ(entries.size(), 0u);
1adf2230
AA
625 ASSERT_EQ(is_truncated, false);
626
627 if (cct->_conf->osd_max_omap_entries_per_request < 15) {
628 num_entries = 0;
629 max = 15;
630 is_truncated = true;
631 marker.clear();
632 while(is_truncated) {
633 ret = cls_rgw_bi_list(ioctx, bucket_oid, name, marker, max, &entries,
634 &is_truncated);
635 ASSERT_EQ(ret, 0);
636 if (is_truncated) {
ec96510d 637 ASSERT_LT(entries.size(), num_objs - num_entries);
1adf2230
AA
638 } else {
639 ASSERT_EQ(entries.size(), num_objs - num_entries);
640 }
641 num_entries += entries.size();
642 marker = entries.back().idx;
643 }
644 }
645
646 ret = cls_rgw_bi_list(ioctx, bucket_oid, name, marker, max, &entries,
647 &is_truncated);
648 ASSERT_EQ(ret, 0);
11fdf7f2 649 ASSERT_EQ(entries.size(), 0u);
1adf2230
AA
650 ASSERT_EQ(is_truncated, false);
651}
652
7c673cae
FG
653/* test garbage collection */
654static void create_obj(cls_rgw_obj& obj, int i, int j)
655{
656 char buf[32];
657 snprintf(buf, sizeof(buf), "-%d.%d", i, j);
658 obj.pool = "pool";
659 obj.pool.append(buf);
660 obj.key.name = "oid";
661 obj.key.name.append(buf);
662 obj.loc = "loc";
663 obj.loc.append(buf);
664}
665
666static bool cmp_objs(cls_rgw_obj& obj1, cls_rgw_obj& obj2)
667{
668 return (obj1.pool == obj2.pool) &&
669 (obj1.key == obj2.key) &&
670 (obj1.loc == obj2.loc);
671}
672
673
9f95a23c 674TEST_F(cls_rgw, gc_set)
7c673cae
FG
675{
676 /* add chains */
677 string oid = "obj";
678 for (int i = 0; i < 10; i++) {
679 char buf[32];
680 snprintf(buf, sizeof(buf), "chain-%d", i);
681 string tag = buf;
682 librados::ObjectWriteOperation op;
683 cls_rgw_gc_obj_info info;
684
685 cls_rgw_obj obj1, obj2;
686 create_obj(obj1, i, 1);
687 create_obj(obj2, i, 2);
688 info.chain.objs.push_back(obj1);
689 info.chain.objs.push_back(obj2);
690
691 op.create(false); // create object
692
693 info.tag = tag;
694 cls_rgw_gc_set_entry(op, 0, info);
695
696 ASSERT_EQ(0, ioctx.operate(oid, &op));
697 }
698
699 bool truncated;
700 list<cls_rgw_gc_obj_info> entries;
701 string marker;
31f18b77 702 string next_marker;
7c673cae
FG
703
704 /* list chains, verify truncated */
31f18b77 705 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 8, true, entries, &truncated, next_marker));
7c673cae
FG
706 ASSERT_EQ(8, (int)entries.size());
707 ASSERT_EQ(1, truncated);
708
709 entries.clear();
31f18b77 710 next_marker.clear();
7c673cae
FG
711
712 /* list all chains, verify not truncated */
31f18b77 713 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 10, true, entries, &truncated, next_marker));
7c673cae
FG
714 ASSERT_EQ(10, (int)entries.size());
715 ASSERT_EQ(0, truncated);
716
717 /* verify all chains are valid */
718 list<cls_rgw_gc_obj_info>::iterator iter = entries.begin();
719 for (int i = 0; i < 10; i++, ++iter) {
720 cls_rgw_gc_obj_info& entry = *iter;
721
722 /* create expected chain name */
723 char buf[32];
724 snprintf(buf, sizeof(buf), "chain-%d", i);
725 string tag = buf;
726
727 /* verify chain name as expected */
728 ASSERT_EQ(entry.tag, tag);
729
730 /* verify expected num of objects in chain */
731 ASSERT_EQ(2, (int)entry.chain.objs.size());
732
733 list<cls_rgw_obj>::iterator oiter = entry.chain.objs.begin();
734 cls_rgw_obj obj1, obj2;
735
736 /* create expected objects */
737 create_obj(obj1, i, 1);
738 create_obj(obj2, i, 2);
739
740 /* assign returned object names */
741 cls_rgw_obj& ret_obj1 = *oiter++;
742 cls_rgw_obj& ret_obj2 = *oiter;
743
744 /* verify objects are as expected */
745 ASSERT_EQ(1, (int)cmp_objs(obj1, ret_obj1));
746 ASSERT_EQ(1, (int)cmp_objs(obj2, ret_obj2));
747 }
748}
749
9f95a23c 750TEST_F(cls_rgw, gc_list)
31f18b77
FG
751{
752 /* add chains */
753 string oid = "obj";
754 for (int i = 0; i < 10; i++) {
755 char buf[32];
756 snprintf(buf, sizeof(buf), "chain-%d", i);
757 string tag = buf;
758 librados::ObjectWriteOperation op;
759 cls_rgw_gc_obj_info info;
760
761 cls_rgw_obj obj1, obj2;
762 create_obj(obj1, i, 1);
763 create_obj(obj2, i, 2);
764 info.chain.objs.push_back(obj1);
765 info.chain.objs.push_back(obj2);
766
767 op.create(false); // create object
768
769 info.tag = tag;
770 cls_rgw_gc_set_entry(op, 0, info);
771
772 ASSERT_EQ(0, ioctx.operate(oid, &op));
773 }
774
775 bool truncated;
776 list<cls_rgw_gc_obj_info> entries;
777 list<cls_rgw_gc_obj_info> entries2;
778 string marker;
779 string next_marker;
780
781 /* list chains, verify truncated */
782 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 8, true, entries, &truncated, next_marker));
783 ASSERT_EQ(8, (int)entries.size());
784 ASSERT_EQ(1, truncated);
785
786 marker = next_marker;
787 next_marker.clear();
788
789 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 8, true, entries2, &truncated, next_marker));
790 ASSERT_EQ(2, (int)entries2.size());
791 ASSERT_EQ(0, truncated);
792
793 entries.splice(entries.end(), entries2);
794
795 /* verify all chains are valid */
796 list<cls_rgw_gc_obj_info>::iterator iter = entries.begin();
797 for (int i = 0; i < 10; i++, ++iter) {
798 cls_rgw_gc_obj_info& entry = *iter;
799
800 /* create expected chain name */
801 char buf[32];
802 snprintf(buf, sizeof(buf), "chain-%d", i);
803 string tag = buf;
804
805 /* verify chain name as expected */
806 ASSERT_EQ(entry.tag, tag);
807
808 /* verify expected num of objects in chain */
809 ASSERT_EQ(2, (int)entry.chain.objs.size());
810
811 list<cls_rgw_obj>::iterator oiter = entry.chain.objs.begin();
812 cls_rgw_obj obj1, obj2;
813
814 /* create expected objects */
815 create_obj(obj1, i, 1);
816 create_obj(obj2, i, 2);
817
818 /* assign returned object names */
819 cls_rgw_obj& ret_obj1 = *oiter++;
820 cls_rgw_obj& ret_obj2 = *oiter;
821
822 /* verify objects are as expected */
823 ASSERT_EQ(1, (int)cmp_objs(obj1, ret_obj1));
824 ASSERT_EQ(1, (int)cmp_objs(obj2, ret_obj2));
825 }
826}
827
9f95a23c 828TEST_F(cls_rgw, gc_defer)
7c673cae
FG
829{
830 librados::IoCtx ioctx;
831 librados::Rados rados;
832
833 string gc_pool_name = get_temp_pool_name();
834 /* create pool */
835 ASSERT_EQ("", create_one_pool_pp(gc_pool_name, rados));
836 ASSERT_EQ(0, rados.ioctx_create(gc_pool_name.c_str(), ioctx));
837
838 string oid = "obj";
839 string tag = "mychain";
840
841 librados::ObjectWriteOperation op;
842 cls_rgw_gc_obj_info info;
843
844 op.create(false);
845
846 info.tag = tag;
847
848 /* create chain */
849 cls_rgw_gc_set_entry(op, 0, info);
850
851 ASSERT_EQ(0, ioctx.operate(oid, &op));
852
853 bool truncated;
854 list<cls_rgw_gc_obj_info> entries;
855 string marker;
31f18b77 856 string next_marker;
7c673cae
FG
857
858 /* list chains, verify num entries as expected */
31f18b77 859 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 1, true, entries, &truncated, next_marker));
7c673cae
FG
860 ASSERT_EQ(1, (int)entries.size());
861 ASSERT_EQ(0, truncated);
862
863 librados::ObjectWriteOperation op2;
864
865 /* defer chain */
866 cls_rgw_gc_defer_entry(op2, 5, tag);
867 ASSERT_EQ(0, ioctx.operate(oid, &op2));
868
869 entries.clear();
31f18b77 870 next_marker.clear();
7c673cae
FG
871
872 /* verify list doesn't show deferred entry (this may fail if cluster is thrashing) */
31f18b77 873 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 1, true, entries, &truncated, next_marker));
7c673cae
FG
874 ASSERT_EQ(0, (int)entries.size());
875 ASSERT_EQ(0, truncated);
876
877 /* wait enough */
878 sleep(5);
31f18b77 879 next_marker.clear();
7c673cae
FG
880
881 /* verify list shows deferred entry */
31f18b77 882 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 1, true, entries, &truncated, next_marker));
7c673cae
FG
883 ASSERT_EQ(1, (int)entries.size());
884 ASSERT_EQ(0, truncated);
885
886 librados::ObjectWriteOperation op3;
11fdf7f2 887 vector<string> tags;
7c673cae
FG
888 tags.push_back(tag);
889
890 /* remove chain */
891 cls_rgw_gc_remove(op3, tags);
892 ASSERT_EQ(0, ioctx.operate(oid, &op3));
893
894 entries.clear();
31f18b77 895 next_marker.clear();
7c673cae
FG
896
897 /* verify entry was removed */
31f18b77 898 ASSERT_EQ(0, cls_rgw_gc_list(ioctx, oid, marker, 1, true, entries, &truncated, next_marker));
7c673cae
FG
899 ASSERT_EQ(0, (int)entries.size());
900 ASSERT_EQ(0, truncated);
901
902 /* remove pool */
903 ioctx.close();
904 ASSERT_EQ(0, destroy_one_pool_pp(gc_pool_name, rados));
905}
906
11fdf7f2
TL
907auto populate_usage_log_info(std::string user, std::string payer, int total_usage_entries)
908{
909 rgw_usage_log_info info;
910
911 for (int i=0; i < total_usage_entries; i++){
912 auto bucket = str_int("bucket", i);
913 info.entries.emplace_back(rgw_usage_log_entry(user, payer, bucket));
914 }
915
916 return info;
917}
918
919auto gen_usage_log_info(std::string payer, std::string bucket, int total_usage_entries)
920{
921 rgw_usage_log_info info;
922 for (int i=0; i < total_usage_entries; i++){
923 auto user = str_int("user", i);
924 info.entries.emplace_back(rgw_usage_log_entry(user, payer, bucket));
925 }
926
927 return info;
928}
929
9f95a23c 930TEST_F(cls_rgw, usage_basic)
b32b8144
FG
931{
932 string oid="usage.1";
933 string user="user1";
934 uint64_t start_epoch{0}, end_epoch{(uint64_t) -1};
11fdf7f2 935 int total_usage_entries = 512;
b32b8144 936 uint64_t max_entries = 2000;
11fdf7f2 937 string payer;
b32b8144 938
11fdf7f2 939 auto info = populate_usage_log_info(user, payer, total_usage_entries);
b32b8144
FG
940 ObjectWriteOperation op;
941 cls_rgw_usage_log_add(op, info);
942 ASSERT_EQ(0, ioctx.operate(oid, &op));
943
944 string read_iter;
945 map <rgw_user_bucket, rgw_usage_log_entry> usage, usage2;
946 bool truncated;
947
948
11fdf7f2 949 int ret = cls_rgw_usage_log_read(ioctx, oid, user, "", start_epoch, end_epoch,
b32b8144
FG
950 max_entries, read_iter, usage, &truncated);
951 // read the entries, and see that we have all the added entries
952 ASSERT_EQ(0, ret);
953 ASSERT_FALSE(truncated);
11fdf7f2 954 ASSERT_EQ(static_cast<uint64_t>(total_usage_entries), usage.size());
b32b8144
FG
955
956 // delete and read to assert that we've deleted all the values
11fdf7f2 957 ASSERT_EQ(0, cls_rgw_usage_log_trim(ioctx, oid, user, "", start_epoch, end_epoch));
b32b8144
FG
958
959
11fdf7f2 960 ret = cls_rgw_usage_log_read(ioctx, oid, user, "", start_epoch, end_epoch,
b32b8144
FG
961 max_entries, read_iter, usage2, &truncated);
962 ASSERT_EQ(0, ret);
11fdf7f2
TL
963 ASSERT_EQ(0u, usage2.size());
964
965 // add and read to assert that bucket option is valid for usage reading
966 string bucket1 = "bucket-usage-1";
967 string bucket2 = "bucket-usage-2";
968 info = gen_usage_log_info(payer, bucket1, 100);
969 cls_rgw_usage_log_add(op, info);
970 ASSERT_EQ(0, ioctx.operate(oid, &op));
971
972 info = gen_usage_log_info(payer, bucket2, 100);
973 cls_rgw_usage_log_add(op, info);
974 ASSERT_EQ(0, ioctx.operate(oid, &op));
975 ret = cls_rgw_usage_log_read(ioctx, oid, "", bucket1, start_epoch, end_epoch,
976 max_entries, read_iter, usage2, &truncated);
977 ASSERT_EQ(0, ret);
978 ASSERT_EQ(100u, usage2.size());
979
980 // delete and read to assert that bucket option is valid for usage trim
981 ASSERT_EQ(0, cls_rgw_usage_log_trim(ioctx, oid, "", bucket1, start_epoch, end_epoch));
982
983 ret = cls_rgw_usage_log_read(ioctx, oid, "", bucket1, start_epoch, end_epoch,
984 max_entries, read_iter, usage2, &truncated);
985 ASSERT_EQ(0, ret);
986 ASSERT_EQ(0u, usage2.size());
987 ASSERT_EQ(0, cls_rgw_usage_log_trim(ioctx, oid, "", bucket2, start_epoch, end_epoch));
988}
989
9f95a23c 990TEST_F(cls_rgw, usage_clear_no_obj)
11fdf7f2
TL
991{
992 string user="user1";
993 string oid="usage.10";
994 librados::ObjectWriteOperation op;
995 cls_rgw_usage_log_clear(op);
996 int ret = ioctx.operate(oid, &op);
997 ASSERT_EQ(0, ret);
b32b8144
FG
998
999}
7c673cae 1000
9f95a23c 1001TEST_F(cls_rgw, usage_clear)
11fdf7f2
TL
1002{
1003 string user="user1";
1004 string payer;
1005 string oid="usage.10";
1006 librados::ObjectWriteOperation op;
1007 int max_entries=2000;
1008
1009 auto info = populate_usage_log_info(user, payer, max_entries);
1010
1011 cls_rgw_usage_log_add(op, info);
1012 ASSERT_EQ(0, ioctx.operate(oid, &op));
1013
1014 ObjectWriteOperation op2;
1015 cls_rgw_usage_log_clear(op2);
1016 int ret = ioctx.operate(oid, &op2);
1017 ASSERT_EQ(0, ret);
1018
1019 map <rgw_user_bucket, rgw_usage_log_entry> usage;
1020 bool truncated;
1021 uint64_t start_epoch{0}, end_epoch{(uint64_t) -1};
1022 string read_iter;
1023 ret = cls_rgw_usage_log_read(ioctx, oid, user, "", start_epoch, end_epoch,
1024 max_entries, read_iter, usage, &truncated);
1025 ASSERT_EQ(0, ret);
1026 ASSERT_EQ(0u, usage.size());
11fdf7f2
TL
1027}
1028
9f95a23c
TL
1029static int bilog_list(librados::IoCtx& ioctx, const std::string& oid,
1030 cls_rgw_bi_log_list_ret *result)
1031{
1032 int retcode = 0;
1033 librados::ObjectReadOperation op;
1034 cls_rgw_bilog_list(op, "", 128, result, &retcode);
1035 int ret = ioctx.operate(oid, &op, nullptr);
1036 if (ret < 0) {
1037 return ret;
1038 }
1039 return retcode;
1040}
11fdf7f2 1041
9f95a23c
TL
1042static int bilog_trim(librados::IoCtx& ioctx, const std::string& oid,
1043 const std::string& start_marker,
1044 const std::string& end_marker)
1045{
1046 librados::ObjectWriteOperation op;
1047 cls_rgw_bilog_trim(op, start_marker, end_marker);
1048 return ioctx.operate(oid, &op);
1049}
7c673cae 1050
9f95a23c 1051TEST_F(cls_rgw, bi_log_trim)
7c673cae 1052{
9f95a23c
TL
1053 string bucket_oid = str_int("bucket", 6);
1054
1055 ObjectWriteOperation op;
1056 cls_rgw_bucket_init_index(op);
1057 ASSERT_EQ(0, ioctx.operate(bucket_oid, &op));
1058
1059 // create 10 versioned entries. this generates instance and olh bi entries,
1060 // allowing us to check that bilog trim doesn't remove any of those
1061 for (int i = 0; i < 10; i++) {
1062 cls_rgw_obj_key obj{str_int("obj", i), "inst"};
1063 string tag = str_int("tag", i);
1064 string loc = str_int("loc", i);
1065
1066 index_prepare(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, obj, loc);
1067 rgw_bucket_dir_entry_meta meta;
1068 index_complete(ioctx, bucket_oid, CLS_RGW_OP_ADD, tag, 1, obj, meta);
1069 }
1070 // bi list
1071 {
1072 list<rgw_cls_bi_entry> entries;
1073 bool truncated{false};
1074 ASSERT_EQ(0, cls_rgw_bi_list(ioctx, bucket_oid, "", "", 128,
1075 &entries, &truncated));
1076 // prepare/complete/instance/olh entry for each
1077 EXPECT_EQ(40u, entries.size());
1078 EXPECT_FALSE(truncated);
1079 }
1080 // bilog list
1081 vector<rgw_bi_log_entry> bilog1;
1082 {
1083 cls_rgw_bi_log_list_ret bilog;
1084 ASSERT_EQ(0, bilog_list(ioctx, bucket_oid, &bilog));
1085 // complete/olh entry for each
1086 EXPECT_EQ(20u, bilog.entries.size());
1087
1088 bilog1.assign(std::make_move_iterator(bilog.entries.begin()),
1089 std::make_move_iterator(bilog.entries.end()));
1090 }
1091 // trim front of bilog
1092 {
1093 const std::string from = "";
1094 const std::string to = bilog1[0].id;
1095 ASSERT_EQ(0, bilog_trim(ioctx, bucket_oid, from, to));
1096 cls_rgw_bi_log_list_ret bilog;
1097 ASSERT_EQ(0, bilog_list(ioctx, bucket_oid, &bilog));
1098 EXPECT_EQ(19u, bilog.entries.size());
1099 EXPECT_EQ(bilog1[1].id, bilog.entries.begin()->id);
1100 ASSERT_EQ(-ENODATA, bilog_trim(ioctx, bucket_oid, from, to));
1101 }
1102 // trim back of bilog
1103 {
1104 const std::string from = bilog1[18].id;
1105 const std::string to = "9";
1106 ASSERT_EQ(0, bilog_trim(ioctx, bucket_oid, from, to));
1107 cls_rgw_bi_log_list_ret bilog;
1108 ASSERT_EQ(0, bilog_list(ioctx, bucket_oid, &bilog));
1109 EXPECT_EQ(18u, bilog.entries.size());
1110 EXPECT_EQ(bilog1[18].id, bilog.entries.rbegin()->id);
1111 ASSERT_EQ(-ENODATA, bilog_trim(ioctx, bucket_oid, from, to));
1112 }
1113 // trim middle of bilog
1114 {
1115 const std::string from = bilog1[13].id;
1116 const std::string to = bilog1[14].id;
1117 ASSERT_EQ(0, bilog_trim(ioctx, bucket_oid, from, to));
1118 cls_rgw_bi_log_list_ret bilog;
1119 ASSERT_EQ(0, bilog_list(ioctx, bucket_oid, &bilog));
1120 EXPECT_EQ(17u, bilog.entries.size());
1121 ASSERT_EQ(-ENODATA, bilog_trim(ioctx, bucket_oid, from, to));
1122 }
1123 // trim full bilog
1124 {
1125 const std::string from = "";
1126 const std::string to = "9";
1127 ASSERT_EQ(0, bilog_trim(ioctx, bucket_oid, from, to));
1128 cls_rgw_bi_log_list_ret bilog;
1129 ASSERT_EQ(0, bilog_list(ioctx, bucket_oid, &bilog));
1130 EXPECT_EQ(0u, bilog.entries.size());
1131 ASSERT_EQ(-ENODATA, bilog_trim(ioctx, bucket_oid, from, to));
1132 }
1133 // bi list should be the same
1134 {
1135 list<rgw_cls_bi_entry> entries;
1136 bool truncated{false};
1137 ASSERT_EQ(0, cls_rgw_bi_list(ioctx, bucket_oid, "", "", 128,
1138 &entries, &truncated));
1139 EXPECT_EQ(40u, entries.size());
1140 EXPECT_FALSE(truncated);
1141 }
7c673cae 1142}