From 577f2113910b7f28f6b468fc5b2710a38fae8062 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Sun, 15 Mar 2020 17:50:59 -0400 Subject: [PATCH] test: add ceph_test_cls_cmpomap Signed-off-by: Casey Bodley --- qa/suites/rgw/verify/tasks/cls.yaml | 1 + qa/workunits/cls/test_cls_cmpomap.sh | 5 + src/test/CMakeLists.txt | 1 + src/test/cls_cmpomap/CMakeLists.txt | 3 + src/test/cls_cmpomap/test_cls_cmpomap.cc | 668 +++++++++++++++++++++++ 5 files changed, 678 insertions(+) create mode 100755 qa/workunits/cls/test_cls_cmpomap.sh create mode 100644 src/test/cls_cmpomap/CMakeLists.txt create mode 100644 src/test/cls_cmpomap/test_cls_cmpomap.cc diff --git a/qa/suites/rgw/verify/tasks/cls.yaml b/qa/suites/rgw/verify/tasks/cls.yaml index 446e9347a6c..722de67205a 100644 --- a/qa/suites/rgw/verify/tasks/cls.yaml +++ b/qa/suites/rgw/verify/tasks/cls.yaml @@ -6,6 +6,7 @@ tasks: - cls/test_cls_log.sh - cls/test_cls_refcount.sh - cls/test_cls_rgw.sh + - cls/test_cls_cmpomap.sh - rgw/test_rgw_gc_log.sh - rgw/test_rgw_obj.sh - rgw/test_rgw_throttle.sh diff --git a/qa/workunits/cls/test_cls_cmpomap.sh b/qa/workunits/cls/test_cls_cmpomap.sh new file mode 100755 index 00000000000..af079f6e69c --- /dev/null +++ b/qa/workunits/cls/test_cls_cmpomap.sh @@ -0,0 +1,5 @@ +#!/bin/sh -e + +ceph_test_cls_cmpomap + +exit 0 diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 3239f5cd7af..5c3e5d5afa9 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -23,6 +23,7 @@ add_subdirectory(cls_lua) add_subdirectory(cls_rgw_gc) add_subdirectory(cls_queue) add_subdirectory(cls_2pc_queue) +add_subdirectory(cls_cmpomap) add_subdirectory(common) add_subdirectory(compressor) add_subdirectory(crush) diff --git a/src/test/cls_cmpomap/CMakeLists.txt b/src/test/cls_cmpomap/CMakeLists.txt new file mode 100644 index 00000000000..471b5e7f716 --- /dev/null +++ b/src/test/cls_cmpomap/CMakeLists.txt @@ -0,0 +1,3 @@ +add_executable(ceph_test_cls_cmpomap test_cls_cmpomap.cc) +target_link_libraries(ceph_test_cls_cmpomap cls_cmpomap_client librados radostest-cxx ${UNITTEST_LIBS}) +install(TARGETS ceph_test_cls_cmpomap DESTINATION ${CMAKE_INSTALL_BINDIR}) diff --git a/src/test/cls_cmpomap/test_cls_cmpomap.cc b/src/test/cls_cmpomap/test_cls_cmpomap.cc new file mode 100644 index 00000000000..c10939b9626 --- /dev/null +++ b/src/test/cls_cmpomap/test_cls_cmpomap.cc @@ -0,0 +1,668 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab ft=cpp + +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 Red Hat, Inc + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + */ + +#include "cls/cmpomap/client.h" +#include "test/librados/test_cxx.h" +#include "gtest/gtest.h" + +#include + +// create/destroy a pool that's shared by all tests in the process +struct RadosEnv : public ::testing::Environment { + static std::optional pool_name; + public: + static librados::Rados rados; + static librados::IoCtx ioctx; + + void SetUp() override { + // create pool + std::string name = get_temp_pool_name(); + ASSERT_EQ("", create_one_pool_pp(name, rados)); + pool_name = name; + ASSERT_EQ(rados.ioctx_create(name.c_str(), ioctx), 0); + } + void TearDown() override { + ioctx.close(); + if (pool_name) { + ASSERT_EQ(destroy_one_pool_pp(*pool_name, rados), 0); + } + } +}; +std::optional RadosEnv::pool_name; +librados::Rados RadosEnv::rados; +librados::IoCtx RadosEnv::ioctx; + +auto *const rados_env = ::testing::AddGlobalTestEnvironment(new RadosEnv); + +namespace cls::cmpomap { + +// test fixture with helper functions +class CmpOmap : public ::testing::Test { + protected: + librados::IoCtx& ioctx = RadosEnv::ioctx; + + int do_cmp_vals(const std::string& oid, Mode mode, + Op comparison, ComparisonMap values, + std::optional def = std::nullopt) + { + librados::ObjectReadOperation op; + int ret = cmp_vals(op, mode, comparison, + std::move(values), std::move(def)); + if (ret < 0) { + return ret; + } + return ioctx.operate(oid, &op, nullptr); + } + + int do_cmp_set_vals(const std::string& oid, Mode mode, + Op comparison, ComparisonMap values, + std::optional def = std::nullopt) + { + librados::ObjectWriteOperation op; + int ret = cmp_set_vals(op, mode, comparison, + std::move(values), std::move(def)); + if (ret < 0) { + return ret; + } + return ioctx.operate(oid, &op); + } + + int do_cmp_rm_keys(const std::string& oid, Mode mode, + Op comparison, ComparisonMap values) + { + librados::ObjectWriteOperation op; + int ret = cmp_rm_keys(op, mode, comparison, std::move(values)); + if (ret < 0) { + return ret; + } + return ioctx.operate(oid, &op); + } + + int get_vals(const std::string& oid, std::map* vals) + { + std::string marker; + bool more = false; + do { + std::map tmp; + int r = ioctx.omap_get_vals2(oid, marker, 1000, &tmp, &more); + if (r < 0) { + return r; + } + if (!tmp.empty()) { + marker = tmp.rbegin()->first; + vals->merge(std::move(tmp)); + } + } while (more); + return 0; + } +}; + +TEST_F(CmpOmap, cmp_vals_noexist_str) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + + // compare a nonempty value against a missing key with no default + const bufferlist input = string_buffer("a"); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::EQ, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::NE, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GT, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GTE, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LT, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LTE, {{key, input}}), -ECANCELED); +} + +TEST_F(CmpOmap, cmp_vals_noexist_str_default) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + + // compare a nonempty value against a missing key with nonempty default + const bufferlist input = string_buffer("a"); + const bufferlist def = string_buffer("b"); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::EQ, {{key, input}}, def), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::NE, {{key, input}}, def), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GT, {{key, input}}, def), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GTE, {{key, input}}, def), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LT, {{key, input}}, def), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LTE, {{key, input}}, def), 0); +} + +TEST_F(CmpOmap, cmp_vals_noexist_u64) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + + // 0 != nullopt + const bufferlist input = u64_buffer(0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, input}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, input}}), -ECANCELED); +} + +TEST_F(CmpOmap, cmp_vals_noexist_u64_default) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + + // 1 == noexist + const bufferlist input = u64_buffer(1); + const bufferlist def = u64_buffer(2); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, input}}, def), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, input}}, def), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, input}}, def), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, input}}, def), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, input}}, def), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, input}}, def), 0); +} + +TEST_F(CmpOmap, cmp_vals_str) +{ + const std::string oid = __PRETTY_FUNCTION__; + const std::string key = "key"; + ASSERT_EQ(ioctx.omap_set(oid, {{key, string_buffer("bbb")}}), 0); + { + // empty < existing + const bufferlist empty; + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::EQ, {{key, empty}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::NE, {{key, empty}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GT, {{key, empty}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GTE, {{key, empty}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LT, {{key, empty}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LTE, {{key, empty}}), 0); + } + { + // value < existing + const bufferlist value = string_buffer("aaa"); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::EQ, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::NE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GT, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GTE, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LT, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LTE, {{key, value}}), 0); + } + { + // value > existing + const bufferlist value = string_buffer("bbbb"); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::EQ, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::NE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GT, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::GTE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LT, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::String, Op::LTE, {{key, value}}), -ECANCELED); + } +} + +TEST_F(CmpOmap, cmp_vals_u64) +{ + const std::string oid = __PRETTY_FUNCTION__; + const std::string key = "key"; + ASSERT_EQ(ioctx.omap_set(oid, {{key, u64_buffer(42)}}), 0); + { + // 0 < existing + const bufferlist value = u64_buffer(0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, value}}), 0); + } + { + // 42 == existing + const bufferlist value = u64_buffer(42); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, value}}), 0); + } + { + // uint64-max > existing + uint64_t v = std::numeric_limits::max(); + const bufferlist value = u64_buffer(v); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, value}}), 0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, value}}), -ECANCELED); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, value}}), -ECANCELED); + } +} + +TEST_F(CmpOmap, cmp_vals_u64_invalid_input) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + const bufferlist empty; // empty buffer can't be decoded as u64 + const bufferlist def = u64_buffer(0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, empty}}, def), -EINVAL); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, empty}}, def), -EINVAL); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, empty}}, def), -EINVAL); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, empty}}, def), -EINVAL); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, empty}}, def), -EINVAL); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, empty}}, def), -EINVAL); +} + +TEST_F(CmpOmap, cmp_vals_u64_invalid_default) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + const bufferlist input = u64_buffer(0); + const bufferlist def; // empty buffer can't be decoded as u64 + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, input}}, def), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, input}}, def), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, input}}, def), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, input}}, def), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, input}}, def), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, input}}, def), -EIO); +} + +TEST_F(CmpOmap, cmp_vals_u64_invalid_value) +{ + const std::string oid = __PRETTY_FUNCTION__; + ASSERT_EQ(ioctx.create(oid, true), 0); + const std::string key = "key"; + ASSERT_EQ(ioctx.omap_set(oid, {{key, string_buffer("bbb")}}), 0); + const bufferlist input = u64_buffer(0); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::EQ, {{key, input}}), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::NE, {{key, input}}), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GT, {{key, input}}), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::GTE, {{key, input}}), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LT, {{key, input}}), -EIO); + EXPECT_EQ(do_cmp_vals(oid, Mode::U64, Op::LTE, {{key, input}}), -EIO); +} + +TEST_F(CmpOmap, cmp_vals_at_max_keys) +{ + ComparisonMap comparisons; + const bufferlist empty; + for (uint32_t i = 0; i < max_keys; i++) { + comparisons.emplace(std::to_string(i), empty); + } + librados::ObjectReadOperation op; + EXPECT_EQ(cmp_vals(op, Mode::String, Op::EQ, std::move(comparisons), empty), 0); +} + +TEST_F(CmpOmap, cmp_vals_over_max_keys) +{ + ComparisonMap comparisons; + const bufferlist empty; + for (uint32_t i = 0; i < max_keys + 1; i++) { + comparisons.emplace(std::to_string(i), empty); + } + librados::ObjectReadOperation op; + EXPECT_EQ(cmp_vals(op, Mode::String, Op::EQ, std::move(comparisons), empty), -E2BIG); +} + +TEST_F(CmpOmap, cmp_set_vals_noexist_str) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value = string_buffer("bbb"); + + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::EQ, {{"eq", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::NE, {{"ne", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::GT, {{"gt", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::GTE, {{"gte", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::LT, {{"lt", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::LTE, {{"lte", value}}), 0); + + std::map vals; + EXPECT_EQ(get_vals(oid, &vals), -ENOENT); // never got created +} + +TEST_F(CmpOmap, cmp_set_vals_noexist_str_default) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value = string_buffer("bbb"); + const bufferlist def; + + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::EQ, {{"eq", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::NE, {{"ne", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::GT, {{"gt", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::GTE, {{"gte", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::LT, {{"lt", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::String, Op::LTE, {{"lte", value}}, def), 0); + + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + EXPECT_EQ(vals.count("eq"), 0); + EXPECT_EQ(vals.count("ne"), 1); + EXPECT_EQ(vals.count("gt"), 1); + EXPECT_EQ(vals.count("gte"), 1); + EXPECT_EQ(vals.count("lt"), 0); + EXPECT_EQ(vals.count("lte"), 0); +} + +TEST_F(CmpOmap, cmp_set_vals_noexist_u64) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value = u64_buffer(0); + + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::EQ, {{"eq", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::NE, {{"ne", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::GT, {{"gt", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::GTE, {{"gte", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::LT, {{"lt", value}}), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::LTE, {{"lte", value}}), 0); + + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), -ENOENT); +} + +TEST_F(CmpOmap, cmp_set_vals_noexist_u64_default) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value = u64_buffer(0); + const bufferlist def = u64_buffer(0); + + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::EQ, {{"eq", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::NE, {{"ne", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::GT, {{"gt", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::GTE, {{"gte", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::LT, {{"lt", value}}, def), 0); + EXPECT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::LTE, {{"lte", value}}, def), 0); + + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + EXPECT_EQ(vals.count("eq"), 1); + EXPECT_EQ(vals.count("ne"), 0); + EXPECT_EQ(vals.count("gt"), 0); + EXPECT_EQ(vals.count("gte"), 1); + EXPECT_EQ(vals.count("lt"), 0); + EXPECT_EQ(vals.count("lte"), 1); +} + +TEST_F(CmpOmap, cmp_set_vals_str) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value1 = string_buffer("bbb"); + const bufferlist value2 = string_buffer("ccc"); + { + std::map vals = { + {"eq", value1}, + {"ne", value1}, + {"gt", value1}, + {"gte", value1}, + {"lt", value1}, + {"lte", value1}, + }; + ASSERT_EQ(ioctx.omap_set(oid, vals), 0); + } + + ASSERT_EQ(do_cmp_set_vals(oid, Mode::String, Op::EQ, {{"eq", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::String, Op::NE, {{"ne", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::String, Op::GT, {{"gt", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::String, Op::GTE, {{"gte", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::String, Op::LT, {{"lt", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::String, Op::LTE, {{"lte", value2}}), 0); + + { + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + ASSERT_EQ(vals.size(), 6); + EXPECT_EQ(value1, vals["eq"]); + EXPECT_EQ(value2, vals["ne"]); + EXPECT_EQ(value2, vals["gt"]); + EXPECT_EQ(value2, vals["gte"]); + EXPECT_EQ(value1, vals["lt"]); + EXPECT_EQ(value1, vals["lte"]); + } +} + +TEST_F(CmpOmap, cmp_set_vals_u64) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value1 = u64_buffer(0); + const bufferlist value2 = u64_buffer(42); + { + std::map vals = { + {"eq", value1}, + {"ne", value1}, + {"gt", value1}, + {"gte", value1}, + {"lt", value1}, + {"lte", value1}, + }; + ASSERT_EQ(ioctx.omap_set(oid, vals), 0); + } + + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::EQ, {{"eq", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::NE, {{"ne", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::GT, {{"gt", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::GTE, {{"gte", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::LT, {{"lt", value2}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::LTE, {{"lte", value2}}), 0); + + { + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + ASSERT_EQ(vals.size(), 6); + EXPECT_EQ(value1, vals["eq"]); + EXPECT_EQ(value2, vals["ne"]); + EXPECT_EQ(value2, vals["gt"]); + EXPECT_EQ(value2, vals["gte"]); + EXPECT_EQ(value1, vals["lt"]); + EXPECT_EQ(value1, vals["lte"]); + } +} + +TEST_F(CmpOmap, cmp_set_vals_u64_einval) +{ + const std::string oid = __PRETTY_FUNCTION__; + const std::string key = "key"; + const bufferlist value1 = u64_buffer(0); + const bufferlist value2 = string_buffer("ccc"); + ASSERT_EQ(ioctx.omap_set(oid, {{key, value1}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::EQ, {{key, value2}}), -EINVAL); +} + +TEST_F(CmpOmap, cmp_set_vals_u64_eio) +{ + const std::string oid = __PRETTY_FUNCTION__; + const std::string key = "key"; + const bufferlist value1 = string_buffer("ccc"); + const bufferlist value2 = u64_buffer(0); + ASSERT_EQ(ioctx.omap_set(oid, {{key, value1}}), 0); + ASSERT_EQ(do_cmp_set_vals(oid, Mode::U64, Op::EQ, {{key, value2}}), 0); + { + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + ASSERT_EQ(vals.size(), 1); + EXPECT_EQ(value1, vals[key]); + } +} + +TEST_F(CmpOmap, cmp_set_vals_at_max_keys) +{ + ComparisonMap comparisons; + const bufferlist value = u64_buffer(0); + for (uint32_t i = 0; i < max_keys; i++) { + comparisons.emplace(std::to_string(i), value); + } + librados::ObjectWriteOperation op; + EXPECT_EQ(cmp_set_vals(op, Mode::U64, Op::EQ, std::move(comparisons), std::nullopt), 0); +} + +TEST_F(CmpOmap, cmp_set_vals_over_max_keys) +{ + ComparisonMap comparisons; + const bufferlist value = u64_buffer(0); + for (uint32_t i = 0; i < max_keys + 1; i++) { + comparisons.emplace(std::to_string(i), value); + } + librados::ObjectWriteOperation op; + EXPECT_EQ(cmp_set_vals(op, Mode::U64, Op::EQ, std::move(comparisons), std::nullopt), -E2BIG); +} + +TEST_F(CmpOmap, cmp_rm_keys_noexist_str) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist empty; + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::EQ, {{"eq", empty}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::NE, {{"ne", empty}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::GT, {{"gt", empty}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::GTE, {{"gte", empty}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::LT, {{"lt", empty}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::LTE, {{"lte", empty}}), 0); + + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), -ENOENT); +} + +TEST_F(CmpOmap, cmp_rm_keys_noexist_u64) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value = u64_buffer(0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::EQ, {{"eq", value}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::NE, {{"ne", value}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::GT, {{"gt", value}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::GTE, {{"gte", value}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::LT, {{"lt", value}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::LTE, {{"lte", value}}), 0); + + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), -ENOENT); +} + +TEST_F(CmpOmap, cmp_rm_keys_str) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value1 = string_buffer("bbb"); + const bufferlist value2 = string_buffer("ccc"); + { + std::map vals = { + {"eq", value1}, + {"ne", value1}, + {"gt", value1}, + {"gte", value1}, + {"lt", value1}, + {"lte", value1}, + }; + ASSERT_EQ(ioctx.omap_set(oid, vals), 0); + } + + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::EQ, {{"eq", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::NE, {{"ne", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::GT, {{"gt", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::GTE, {{"gte", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::LT, {{"lt", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::String, Op::LTE, {{"lte", value2}}), 0); + + { + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + EXPECT_EQ(vals.count("eq"), 1); + EXPECT_EQ(vals.count("ne"), 0); + EXPECT_EQ(vals.count("gt"), 0); + EXPECT_EQ(vals.count("gte"), 0); + EXPECT_EQ(vals.count("lt"), 1); + EXPECT_EQ(vals.count("lte"), 1); + } +} + +TEST_F(CmpOmap, cmp_rm_keys_u64) +{ + const std::string oid = __PRETTY_FUNCTION__; + const bufferlist value1 = u64_buffer(0); + const bufferlist value2 = u64_buffer(42); + { + std::map vals = { + {"eq", value1}, + {"ne", value1}, + {"gt", value1}, + {"gte", value1}, + {"lt", value1}, + {"lte", value1}, + }; + ASSERT_EQ(ioctx.omap_set(oid, vals), 0); + } + + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::EQ, {{"eq", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::NE, {{"ne", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::GT, {{"gt", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::GTE, {{"gte", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::LT, {{"lt", value2}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::LTE, {{"lte", value2}}), 0); + + { + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + EXPECT_EQ(vals.count("eq"), 1); + EXPECT_EQ(vals.count("ne"), 0); + EXPECT_EQ(vals.count("gt"), 0); + EXPECT_EQ(vals.count("gte"), 0); + EXPECT_EQ(vals.count("lt"), 1); + EXPECT_EQ(vals.count("lte"), 1); + } +} + +TEST_F(CmpOmap, cmp_rm_keys_u64_einval) +{ + const std::string oid = __PRETTY_FUNCTION__; + const std::string key = "key"; + const bufferlist value1 = u64_buffer(0); + const bufferlist value2 = string_buffer("ccc"); + ASSERT_EQ(ioctx.omap_set(oid, {{key, value1}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::EQ, {{key, value2}}), -EINVAL); +} + +TEST_F(CmpOmap, cmp_rm_keys_u64_eio) +{ + const std::string oid = __PRETTY_FUNCTION__; + const std::string key = "key"; + const bufferlist value1 = string_buffer("ccc"); + const bufferlist value2 = u64_buffer(0); + ASSERT_EQ(ioctx.omap_set(oid, {{key, value1}}), 0); + ASSERT_EQ(do_cmp_rm_keys(oid, Mode::U64, Op::EQ, {{key, value2}}), 0); + { + std::map vals; + ASSERT_EQ(get_vals(oid, &vals), 0); + EXPECT_EQ(vals.count(key), 1); + } +} + +TEST_F(CmpOmap, cmp_rm_keys_at_max_keys) +{ + ComparisonMap comparisons; + const bufferlist value = u64_buffer(0); + for (uint32_t i = 0; i < max_keys; i++) { + comparisons.emplace(std::to_string(i), value); + } + librados::ObjectWriteOperation op; + EXPECT_EQ(cmp_rm_keys(op, Mode::U64, Op::EQ, std::move(comparisons)), 0); +} + +TEST_F(CmpOmap, cmp_rm_keys_over_max_keys) +{ + ComparisonMap comparisons; + const bufferlist value = u64_buffer(0); + for (uint32_t i = 0; i < max_keys + 1; i++) { + comparisons.emplace(std::to_string(i), value); + } + librados::ObjectWriteOperation op; + EXPECT_EQ(cmp_rm_keys(op, Mode::U64, Op::EQ, std::move(comparisons)), -E2BIG); +} + +} // namespace cls::cmpomap -- 2.39.5