summaryrefslogtreecommitdiffstats
path: root/src/test/rgw/test_rgw_period_history.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/test/rgw/test_rgw_period_history.cc
parentInitial commit. (diff)
downloadceph-upstream/18.2.2.tar.xz
ceph-upstream/18.2.2.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/rgw/test_rgw_period_history.cc')
-rw-r--r--src/test/rgw/test_rgw_period_history.cc336
1 files changed, 336 insertions, 0 deletions
diff --git a/src/test/rgw/test_rgw_period_history.cc b/src/test/rgw/test_rgw_period_history.cc
new file mode 100644
index 000000000..25ea87d3a
--- /dev/null
+++ b/src/test/rgw/test_rgw_period_history.cc
@@ -0,0 +1,336 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2015 Red Hat
+ *
+ * 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 "rgw_period_history.h"
+#include "rgw_rados.h"
+#include "rgw_zone.h"
+#include "global/global_init.h"
+#include "common/ceph_argparse.h"
+#include <boost/lexical_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+namespace {
+
+// construct a period with the given fields
+RGWPeriod make_period(const std::string& id, epoch_t realm_epoch,
+ const std::string& predecessor)
+{
+ RGWPeriod period(id);
+ period.set_realm_epoch(realm_epoch);
+ period.set_predecessor(predecessor);
+ return period;
+}
+
+const auto current_period = make_period("5", 5, "4");
+
+// mock puller that throws an exception if it's called
+struct ErrorPuller : public RGWPeriodHistory::Puller {
+ int pull(const DoutPrefixProvider *dpp, const std::string& id, RGWPeriod& period, optional_yield) override {
+ throw std::runtime_error("unexpected call to pull");
+ }
+};
+ErrorPuller puller; // default puller
+
+// mock puller that records the period ids requested and returns an error
+using Ids = std::vector<std::string>;
+class RecordingPuller : public RGWPeriodHistory::Puller {
+ const int error;
+ public:
+ explicit RecordingPuller(int error) : error(error) {}
+ Ids ids;
+ int pull(const DoutPrefixProvider *dpp, const std::string& id, RGWPeriod& period, optional_yield) override {
+ ids.push_back(id);
+ return error;
+ }
+};
+
+// mock puller that returns a fake period by parsing the period id
+struct NumericPuller : public RGWPeriodHistory::Puller {
+ int pull(const DoutPrefixProvider *dpp, const std::string& id, RGWPeriod& period, optional_yield) override {
+ // relies on numeric period ids to divine the realm_epoch
+ auto realm_epoch = boost::lexical_cast<epoch_t>(id);
+ auto predecessor = boost::lexical_cast<std::string>(realm_epoch-1);
+ period = make_period(id, realm_epoch, predecessor);
+ return 0;
+ }
+};
+
+} // anonymous namespace
+
+// for ASSERT_EQ()
+bool operator==(const RGWPeriod& lhs, const RGWPeriod& rhs)
+{
+ return lhs.get_id() == rhs.get_id()
+ && lhs.get_realm_epoch() == rhs.get_realm_epoch();
+}
+
+TEST(PeriodHistory, InsertBefore)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ // inserting right before current_period 5 will attach to history
+ auto c = history.insert(make_period("4", 4, "3"));
+ ASSERT_TRUE(c);
+ ASSERT_FALSE(c.has_prev());
+ ASSERT_TRUE(c.has_next());
+
+ // cursor can traverse forward to current_period
+ c.next();
+ ASSERT_EQ(5u, c.get_epoch());
+ ASSERT_EQ(current_period, c.get_period());
+}
+
+TEST(PeriodHistory, InsertAfter)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ // inserting right after current_period 5 will attach to history
+ auto c = history.insert(make_period("6", 6, "5"));
+ ASSERT_TRUE(c);
+ ASSERT_TRUE(c.has_prev());
+ ASSERT_FALSE(c.has_next());
+
+ // cursor can traverse back to current_period
+ c.prev();
+ ASSERT_EQ(5u, c.get_epoch());
+ ASSERT_EQ(current_period, c.get_period());
+}
+
+TEST(PeriodHistory, InsertWayBefore)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ // inserting way before current_period 5 will not attach to history
+ auto c = history.insert(make_period("1", 1, ""));
+ ASSERT_FALSE(c);
+ ASSERT_EQ(0, c.get_error());
+}
+
+TEST(PeriodHistory, InsertWayAfter)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ // inserting way after current_period 5 will not attach to history
+ auto c = history.insert(make_period("9", 9, "8"));
+ ASSERT_FALSE(c);
+ ASSERT_EQ(0, c.get_error());
+}
+
+TEST(PeriodHistory, PullPredecessorsBeforeCurrent)
+{
+ RecordingPuller puller{-EFAULT};
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+ const DoutPrefix dp(g_ceph_context, 1, "test rgw period history: ");
+
+ // create a disjoint history at 1 and verify that periods are requested
+ // backwards from current_period
+ auto c1 = history.attach(&dp, make_period("1", 1, ""), null_yield);
+ ASSERT_FALSE(c1);
+ ASSERT_EQ(-EFAULT, c1.get_error());
+ ASSERT_EQ(Ids{"4"}, puller.ids);
+
+ auto c4 = history.insert(make_period("4", 4, "3"));
+ ASSERT_TRUE(c4);
+
+ c1 = history.attach(&dp, make_period("1", 1, ""), null_yield);
+ ASSERT_FALSE(c1);
+ ASSERT_EQ(-EFAULT, c1.get_error());
+ ASSERT_EQ(Ids({"4", "3"}), puller.ids);
+
+ auto c3 = history.insert(make_period("3", 3, "2"));
+ ASSERT_TRUE(c3);
+
+ c1 = history.attach(&dp, make_period("1", 1, ""), null_yield);
+ ASSERT_FALSE(c1);
+ ASSERT_EQ(-EFAULT, c1.get_error());
+ ASSERT_EQ(Ids({"4", "3", "2"}), puller.ids);
+
+ auto c2 = history.insert(make_period("2", 2, "1"));
+ ASSERT_TRUE(c2);
+
+ c1 = history.attach(&dp, make_period("1", 1, ""), null_yield);
+ ASSERT_TRUE(c1);
+ ASSERT_EQ(Ids({"4", "3", "2"}), puller.ids);
+}
+
+TEST(PeriodHistory, PullPredecessorsAfterCurrent)
+{
+ RecordingPuller puller{-EFAULT};
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+ const DoutPrefix dp(g_ceph_context, 1, "test rgw period history: ");
+
+ // create a disjoint history at 9 and verify that periods are requested
+ // backwards down to current_period
+ auto c9 = history.attach(&dp, make_period("9", 9, "8"), null_yield);
+ ASSERT_FALSE(c9);
+ ASSERT_EQ(-EFAULT, c9.get_error());
+ ASSERT_EQ(Ids{"8"}, puller.ids);
+
+ auto c8 = history.attach(&dp, make_period("8", 8, "7"), null_yield);
+ ASSERT_FALSE(c8);
+ ASSERT_EQ(-EFAULT, c8.get_error());
+ ASSERT_EQ(Ids({"8", "7"}), puller.ids);
+
+ auto c7 = history.attach(&dp, make_period("7", 7, "6"), null_yield);
+ ASSERT_FALSE(c7);
+ ASSERT_EQ(-EFAULT, c7.get_error());
+ ASSERT_EQ(Ids({"8", "7", "6"}), puller.ids);
+
+ auto c6 = history.attach(&dp, make_period("6", 6, "5"), null_yield);
+ ASSERT_TRUE(c6);
+ ASSERT_EQ(Ids({"8", "7", "6"}), puller.ids);
+}
+
+TEST(PeriodHistory, MergeBeforeCurrent)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ auto c = history.get_current();
+ ASSERT_FALSE(c.has_prev());
+
+ // create a disjoint history at 3
+ auto c3 = history.insert(make_period("3", 3, "2"));
+ ASSERT_FALSE(c3);
+
+ // insert the missing period to merge 3 and 5
+ auto c4 = history.insert(make_period("4", 4, "3"));
+ ASSERT_TRUE(c4);
+ ASSERT_TRUE(c4.has_prev());
+ ASSERT_TRUE(c4.has_next());
+
+ // verify that the merge didn't destroy the original cursor's history
+ ASSERT_EQ(current_period, c.get_period());
+ ASSERT_TRUE(c.has_prev());
+}
+
+TEST(PeriodHistory, MergeAfterCurrent)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ auto c = history.get_current();
+ ASSERT_FALSE(c.has_next());
+
+ // create a disjoint history at 7
+ auto c7 = history.insert(make_period("7", 7, "6"));
+ ASSERT_FALSE(c7);
+
+ // insert the missing period to merge 5 and 7
+ auto c6 = history.insert(make_period("6", 6, "5"));
+ ASSERT_TRUE(c6);
+ ASSERT_TRUE(c6.has_prev());
+ ASSERT_TRUE(c6.has_next());
+
+ // verify that the merge didn't destroy the original cursor's history
+ ASSERT_EQ(current_period, c.get_period());
+ ASSERT_TRUE(c.has_next());
+}
+
+TEST(PeriodHistory, MergeWithoutCurrent)
+{
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+
+ // create a disjoint history at 7
+ auto c7 = history.insert(make_period("7", 7, "6"));
+ ASSERT_FALSE(c7);
+
+ // create a disjoint history at 9
+ auto c9 = history.insert(make_period("9", 9, "8"));
+ ASSERT_FALSE(c9);
+
+ // insert the missing period to merge 7 and 9
+ auto c8 = history.insert(make_period("8", 8, "7"));
+ ASSERT_FALSE(c8); // not connected to current_period yet
+
+ // insert the missing period to merge 5 and 7-9
+ auto c = history.insert(make_period("6", 6, "5"));
+ ASSERT_TRUE(c);
+ ASSERT_TRUE(c.has_next());
+
+ // verify that we merged all periods from 5-9
+ c.next();
+ ASSERT_EQ(7u, c.get_epoch());
+ ASSERT_TRUE(c.has_next());
+ c.next();
+ ASSERT_EQ(8u, c.get_epoch());
+ ASSERT_TRUE(c.has_next());
+ c.next();
+ ASSERT_EQ(9u, c.get_epoch());
+ ASSERT_FALSE(c.has_next());
+}
+
+TEST(PeriodHistory, AttachBefore)
+{
+ NumericPuller puller;
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+ const DoutPrefix dp(g_ceph_context, 1, "test rgw period history: ");
+
+ auto c1 = history.attach(&dp, make_period("1", 1, ""), null_yield);
+ ASSERT_TRUE(c1);
+
+ // verify that we pulled and merged all periods from 1-5
+ auto c = history.get_current();
+ ASSERT_TRUE(c);
+ ASSERT_TRUE(c.has_prev());
+ c.prev();
+ ASSERT_EQ(4u, c.get_epoch());
+ ASSERT_TRUE(c.has_prev());
+ c.prev();
+ ASSERT_EQ(3u, c.get_epoch());
+ ASSERT_TRUE(c.has_prev());
+ c.prev();
+ ASSERT_EQ(2u, c.get_epoch());
+ ASSERT_TRUE(c.has_prev());
+ c.prev();
+ ASSERT_EQ(1u, c.get_epoch());
+ ASSERT_FALSE(c.has_prev());
+}
+
+TEST(PeriodHistory, AttachAfter)
+{
+ NumericPuller puller;
+ RGWPeriodHistory history(g_ceph_context, &puller, current_period);
+ const DoutPrefix dp(g_ceph_context, 1, "test rgw period history: ");
+
+ auto c9 = history.attach(&dp, make_period("9", 9, "8"), null_yield);
+ ASSERT_TRUE(c9);
+
+ // verify that we pulled and merged all periods from 5-9
+ auto c = history.get_current();
+ ASSERT_TRUE(c);
+ ASSERT_TRUE(c.has_next());
+ c.next();
+ ASSERT_EQ(6u, c.get_epoch());
+ ASSERT_TRUE(c.has_next());
+ c.next();
+ ASSERT_EQ(7u, c.get_epoch());
+ ASSERT_TRUE(c.has_next());
+ c.next();
+ ASSERT_EQ(8u, c.get_epoch());
+ ASSERT_TRUE(c.has_next());
+ c.next();
+ ASSERT_EQ(9u, c.get_epoch());
+ ASSERT_FALSE(c.has_next());
+}
+
+int main(int argc, char** argv)
+{
+ auto args = argv_to_vec(argc, argv);
+ auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
+ CODE_ENVIRONMENT_UTILITY,
+ CINIT_FLAG_NO_DEFAULT_CONFIG_FILE);
+ common_init_finish(g_ceph_context);
+
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}