diff options
Diffstat (limited to 'src/test/cls_refcount/test_cls_refcount.cc')
-rw-r--r-- | src/test/cls_refcount/test_cls_refcount.cc | 778 |
1 files changed, 778 insertions, 0 deletions
diff --git a/src/test/cls_refcount/test_cls_refcount.cc b/src/test/cls_refcount/test_cls_refcount.cc new file mode 100644 index 000000000..2868b48b6 --- /dev/null +++ b/src/test/cls_refcount/test_cls_refcount.cc @@ -0,0 +1,778 @@ +// -*- 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_cxx.h" + +#include <errno.h> +#include <string> +#include <vector> + +using namespace std; + +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<string> 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<string, bool> refs_map; + for (list<string>::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<string> 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<string, bool> refs_map; + for (list<string>::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<string> 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<string, bool> refs_map; + for (list<string>::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<string> 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<string, bool> refs_map; + for (list<string>::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)); +} + +TEST(cls_rgw, test_implicit_ec) /* 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_ec_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<string> 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<string, bool> refs_map; + for (list<string>::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_ec_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_ec) /* 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_ec_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<string> 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<string, bool> refs_map; + for (list<string>::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_ec_pool_pp(pool_name, rados)); +} + + +TEST(cls_rgw, test_put_snap_ec) { + librados::Rados rados; + librados::IoCtx ioctx; + string pool_name = get_temp_pool_name(); + + /* create pool */ + ASSERT_EQ("", create_one_ec_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_ec_pool_pp(pool_name, rados)); +} + +TEST(cls_rgw, test_explicit_ec) /* 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_ec_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<string> 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<string, bool> refs_map; + for (list<string>::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_ec_pool_pp(pool_name, rados)); +} + +TEST(cls_rgw, set_ec) /* 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_ec_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<string> 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<string, bool> refs_map; + for (list<string>::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_ec_pool_pp(pool_name, rados)); +} |