X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftest%2Frgw%2Ftest_rgw_period_history.cc;fp=src%2Fceph%2Fsrc%2Ftest%2Frgw%2Ftest_rgw_period_history.cc;h=efedd269c4892cd883ed3c6d749df9ee042e776a;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/test/rgw/test_rgw_period_history.cc b/src/ceph/src/test/rgw/test_rgw_period_history.cc new file mode 100644 index 0000000..efedd26 --- /dev/null +++ b/src/ceph/src/test/rgw/test_rgw_period_history.cc @@ -0,0 +1,331 @@ +// -*- 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/rgw_period_history.h" +#include "rgw/rgw_rados.h" +#include "global/global_init.h" +#include "common/ceph_argparse.h" +#include +#include + +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 std::string& id, RGWPeriod& period) 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; +class RecordingPuller : public RGWPeriodHistory::Puller { + const int error; + public: + RecordingPuller(int error) : error(error) {} + Ids ids; + int pull(const std::string& id, RGWPeriod& period) 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 std::string& id, RGWPeriod& period) override { + // relies on numeric period ids to divine the realm_epoch + auto realm_epoch = boost::lexical_cast(id); + auto predecessor = boost::lexical_cast(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); + + // create a disjoint history at 1 and verify that periods are requested + // backwards from current_period + auto c1 = history.attach(make_period("1", 1, "")); + 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(make_period("1", 1, "")); + 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(make_period("1", 1, "")); + 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(make_period("1", 1, "")); + 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); + + // create a disjoint history at 9 and verify that periods are requested + // backwards down to current_period + auto c9 = history.attach(make_period("9", 9, "8")); + ASSERT_FALSE(c9); + ASSERT_EQ(-EFAULT, c9.get_error()); + ASSERT_EQ(Ids{"8"}, puller.ids); + + auto c8 = history.attach(make_period("8", 8, "7")); + ASSERT_FALSE(c8); + ASSERT_EQ(-EFAULT, c8.get_error()); + ASSERT_EQ(Ids({"8", "7"}), puller.ids); + + auto c7 = history.attach(make_period("7", 7, "6")); + ASSERT_FALSE(c7); + ASSERT_EQ(-EFAULT, c7.get_error()); + ASSERT_EQ(Ids({"8", "7", "6"}), puller.ids); + + auto c6 = history.attach(make_period("6", 6, "5")); + 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); + + auto c1 = history.attach(make_period("1", 1, "")); + 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); + + auto c9 = history.attach(make_period("9", 9, "8")); + 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) +{ + vector args; + argv_to_vec(argc, (const char **)argv, args); + + auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT, + CODE_ENVIRONMENT_UTILITY, 0); + common_init_finish(g_ceph_context); + + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +}