// -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab #include "include/types.h" #include "cls/refcount/cls_refcount_client.h" #include "gtest/gtest.h" #include "test/librados/test.h" #include #include #include static librados::ObjectWriteOperation *new_op() { return new librados::ObjectWriteOperation(); } TEST(cls_rgw, test_implicit) /* test refcount using implicit referencing of newly created objects */ { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; string oldtag = "oldtag"; string newtag = "newtag"; /* get on a missing object will fail */ librados::ObjectWriteOperation *op = new_op(); cls_refcount_get(*op, newtag, true); ASSERT_EQ(-ENOENT, ioctx.operate(oid, op)); delete op; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* read reference, should return a single wildcard entry */ list refs; ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(1, (int)refs.size()); string wildcard_tag; string tag = refs.front(); ASSERT_EQ(wildcard_tag, tag); /* take another reference, verify */ op = new_op(); cls_refcount_get(*op, newtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(2, (int)refs.size()); map refs_map; for (list::iterator iter = refs.begin(); iter != refs.end(); ++iter) { refs_map[*iter] = true; } ASSERT_EQ(1, (int)refs_map.count(wildcard_tag)); ASSERT_EQ(1, (int)refs_map.count(newtag)); delete op; /* drop reference to oldtag */ op = new_op(); cls_refcount_put(*op, oldtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(1, (int)refs.size()); tag = refs.front(); ASSERT_EQ(newtag, tag); delete op; /* drop oldtag reference again, op should return success, wouldn't do anything */ op = new_op(); cls_refcount_put(*op, oldtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(1, (int)refs.size()); tag = refs.front(); ASSERT_EQ(newtag, tag); delete op; /* drop newtag reference, make sure object removed */ op = new_op(); cls_refcount_put(*op, newtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(-ENOENT, ioctx.stat(oid, NULL, NULL)); delete op; /* remove pool */ ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } /* * similar to test_implicit, just changes the order of the tags removal * see issue #20107 */ TEST(cls_rgw, test_implicit_idempotent) /* test refcount using implicit referencing of newly created objects */ { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; string oldtag = "oldtag"; string newtag = "newtag"; /* get on a missing object will fail */ librados::ObjectWriteOperation *op = new_op(); cls_refcount_get(*op, newtag, true); ASSERT_EQ(-ENOENT, ioctx.operate(oid, op)); delete op; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* read reference, should return a single wildcard entry */ list refs; ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(1, (int)refs.size()); string wildcard_tag; string tag = refs.front(); ASSERT_EQ(wildcard_tag, tag); /* take another reference, verify */ op = new_op(); cls_refcount_get(*op, newtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(2, (int)refs.size()); map refs_map; for (list::iterator iter = refs.begin(); iter != refs.end(); ++iter) { refs_map[*iter] = true; } ASSERT_EQ(1, (int)refs_map.count(wildcard_tag)); ASSERT_EQ(1, (int)refs_map.count(newtag)); delete op; /* drop reference to newtag */ op = new_op(); cls_refcount_put(*op, newtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(1, (int)refs.size()); tag = refs.front(); ASSERT_EQ(string(), tag); delete op; /* drop newtag reference again, op should return success, wouldn't do anything */ op = new_op(); cls_refcount_put(*op, newtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs, true)); ASSERT_EQ(1, (int)refs.size()); tag = refs.front(); ASSERT_EQ(string(), tag); delete op; /* drop oldtag reference, make sure object removed */ op = new_op(); cls_refcount_put(*op, oldtag, true); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(-ENOENT, ioctx.stat(oid, NULL, NULL)); delete op; /* remove pool */ ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(cls_rgw, test_put_snap) { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); bufferlist bl; bl.append("hi there"); ASSERT_EQ(0, ioctx.write("foo", bl, bl.length(), 0)); ASSERT_EQ(0, ioctx.snap_create("snapfoo")); ASSERT_EQ(0, ioctx.remove("foo")); sleep(2); ASSERT_EQ(0, ioctx.snap_create("snapbar")); librados::ObjectWriteOperation *op = new_op(); cls_refcount_put(*op, "notag", true); ASSERT_EQ(-ENOENT, ioctx.operate("foo", op)); EXPECT_EQ(0, ioctx.snap_remove("snapfoo")); EXPECT_EQ(0, ioctx.snap_remove("snapbar")); delete op; /* remove pool */ ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(cls_rgw, test_explicit) /* test refcount using implicit referencing of newly created objects */ { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* read reference, should return a single wildcard entry */ list refs; ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs)); ASSERT_EQ(0, (int)refs.size()); /* take first reference, verify */ string newtag = "newtag"; librados::ObjectWriteOperation *op = new_op(); cls_refcount_get(*op, newtag); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs)); ASSERT_EQ(1, (int)refs.size()); map refs_map; for (list::iterator iter = refs.begin(); iter != refs.end(); ++iter) { refs_map[*iter] = true; } ASSERT_EQ(1, (int)refs_map.count(newtag)); delete op; /* try to drop reference to unexisting tag */ string nosuchtag = "nosuchtag"; op = new_op(); cls_refcount_put(*op, nosuchtag); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs)); ASSERT_EQ(1, (int)refs.size()); string tag = refs.front(); ASSERT_EQ(newtag, tag); delete op; /* drop newtag reference, make sure object removed */ op = new_op(); cls_refcount_put(*op, newtag); ASSERT_EQ(0, ioctx.operate(oid, op)); ASSERT_EQ(-ENOENT, ioctx.stat(oid, NULL, NULL)); delete op; /* remove pool */ ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); } TEST(cls_rgw, set) /* test refcount using implicit referencing of newly created objects */ { librados::Rados rados; librados::IoCtx ioctx; string pool_name = get_temp_pool_name(); /* create pool */ ASSERT_EQ("", create_one_pool_pp(pool_name, rados)); ASSERT_EQ(0, rados.ioctx_create(pool_name.c_str(), ioctx)); /* add chains */ string oid = "obj"; /* create object */ ASSERT_EQ(0, ioctx.create(oid, true)); /* read reference, should return a single wildcard entry */ list tag_refs, refs; #define TAGS_NUM 5 string tags[TAGS_NUM]; char buf[16]; for (int i = 0; i < TAGS_NUM; i++) { snprintf(buf, sizeof(buf), "tag%d", i); tags[i] = buf; tag_refs.push_back(tags[i]); } ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs)); ASSERT_EQ(0, (int)refs.size()); /* set reference list, verify */ librados::ObjectWriteOperation *op = new_op(); cls_refcount_set(*op, tag_refs); ASSERT_EQ(0, ioctx.operate(oid, op)); refs.clear(); ASSERT_EQ(0, cls_refcount_read(ioctx, oid, &refs)); ASSERT_EQ(TAGS_NUM, (int)refs.size()); map refs_map; for (list::iterator iter = refs.begin(); iter != refs.end(); ++iter) { refs_map[*iter] = true; } for (int i = 0; i < TAGS_NUM; i++) { ASSERT_EQ(1, (int)refs_map.count(tags[i])); } delete op; /* remove all refs */ for (int i = 0; i < TAGS_NUM; i++) { op = new_op(); cls_refcount_put(*op, tags[i]); ASSERT_EQ(0, ioctx.operate(oid, op)); delete op; } ASSERT_EQ(-ENOENT, ioctx.stat(oid, NULL, NULL)); /* remove pool */ ioctx.close(); ASSERT_EQ(0, destroy_one_pool_pp(pool_name, rados)); }