Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / rgw / test_rgw_period_history.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2015 Red Hat
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation. See file COPYING.
12  *
13  */
14 #include "rgw/rgw_period_history.h"
15 #include "rgw/rgw_rados.h"
16 #include "global/global_init.h"
17 #include "common/ceph_argparse.h"
18 #include <boost/lexical_cast.hpp>
19 #include <gtest/gtest.h>
20
21 namespace {
22
23 // construct a period with the given fields
24 RGWPeriod make_period(const std::string& id, epoch_t realm_epoch,
25                       const std::string& predecessor)
26 {
27   RGWPeriod period(id);
28   period.set_realm_epoch(realm_epoch);
29   period.set_predecessor(predecessor);
30   return period;
31 }
32
33 const auto current_period = make_period("5", 5, "4");
34
35 // mock puller that throws an exception if it's called
36 struct ErrorPuller : public RGWPeriodHistory::Puller {
37   int pull(const std::string& id, RGWPeriod& period) override {
38     throw std::runtime_error("unexpected call to pull");
39   }
40 };
41 ErrorPuller puller; // default puller
42
43 // mock puller that records the period ids requested and returns an error
44 using Ids = std::vector<std::string>;
45 class RecordingPuller : public RGWPeriodHistory::Puller {
46   const int error;
47  public:
48   RecordingPuller(int error) : error(error) {}
49   Ids ids;
50   int pull(const std::string& id, RGWPeriod& period) override {
51     ids.push_back(id);
52     return error;
53   }
54 };
55
56 // mock puller that returns a fake period by parsing the period id
57 struct NumericPuller : public RGWPeriodHistory::Puller {
58   int pull(const std::string& id, RGWPeriod& period) override {
59     // relies on numeric period ids to divine the realm_epoch
60     auto realm_epoch = boost::lexical_cast<epoch_t>(id);
61     auto predecessor = boost::lexical_cast<std::string>(realm_epoch-1);
62     period = make_period(id, realm_epoch, predecessor);
63     return 0;
64   }
65 };
66
67 } // anonymous namespace
68
69 // for ASSERT_EQ()
70 bool operator==(const RGWPeriod& lhs, const RGWPeriod& rhs)
71 {
72   return lhs.get_id() == rhs.get_id()
73       && lhs.get_realm_epoch() == rhs.get_realm_epoch();
74 }
75
76 TEST(PeriodHistory, InsertBefore)
77 {
78   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
79
80   // inserting right before current_period 5 will attach to history
81   auto c = history.insert(make_period("4", 4, "3"));
82   ASSERT_TRUE(c);
83   ASSERT_FALSE(c.has_prev());
84   ASSERT_TRUE(c.has_next());
85
86   // cursor can traverse forward to current_period
87   c.next();
88   ASSERT_EQ(5u, c.get_epoch());
89   ASSERT_EQ(current_period, c.get_period());
90 }
91
92 TEST(PeriodHistory, InsertAfter)
93 {
94   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
95
96   // inserting right after current_period 5 will attach to history
97   auto c = history.insert(make_period("6", 6, "5"));
98   ASSERT_TRUE(c);
99   ASSERT_TRUE(c.has_prev());
100   ASSERT_FALSE(c.has_next());
101
102   // cursor can traverse back to current_period
103   c.prev();
104   ASSERT_EQ(5u, c.get_epoch());
105   ASSERT_EQ(current_period, c.get_period());
106 }
107
108 TEST(PeriodHistory, InsertWayBefore)
109 {
110   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
111
112   // inserting way before current_period 5 will not attach to history
113   auto c = history.insert(make_period("1", 1, ""));
114   ASSERT_FALSE(c);
115   ASSERT_EQ(0, c.get_error());
116 }
117
118 TEST(PeriodHistory, InsertWayAfter)
119 {
120   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
121
122   // inserting way after current_period 5 will not attach to history
123   auto c = history.insert(make_period("9", 9, "8"));
124   ASSERT_FALSE(c);
125   ASSERT_EQ(0, c.get_error());
126 }
127
128 TEST(PeriodHistory, PullPredecessorsBeforeCurrent)
129 {
130   RecordingPuller puller{-EFAULT};
131   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
132
133   // create a disjoint history at 1 and verify that periods are requested
134   // backwards from current_period
135   auto c1 = history.attach(make_period("1", 1, ""));
136   ASSERT_FALSE(c1);
137   ASSERT_EQ(-EFAULT, c1.get_error());
138   ASSERT_EQ(Ids{"4"}, puller.ids);
139
140   auto c4 = history.insert(make_period("4", 4, "3"));
141   ASSERT_TRUE(c4);
142
143   c1 = history.attach(make_period("1", 1, ""));
144   ASSERT_FALSE(c1);
145   ASSERT_EQ(-EFAULT, c1.get_error());
146   ASSERT_EQ(Ids({"4", "3"}), puller.ids);
147
148   auto c3 = history.insert(make_period("3", 3, "2"));
149   ASSERT_TRUE(c3);
150
151   c1 = history.attach(make_period("1", 1, ""));
152   ASSERT_FALSE(c1);
153   ASSERT_EQ(-EFAULT, c1.get_error());
154   ASSERT_EQ(Ids({"4", "3", "2"}), puller.ids);
155
156   auto c2 = history.insert(make_period("2", 2, "1"));
157   ASSERT_TRUE(c2);
158
159   c1 = history.attach(make_period("1", 1, ""));
160   ASSERT_TRUE(c1);
161   ASSERT_EQ(Ids({"4", "3", "2"}), puller.ids);
162 }
163
164 TEST(PeriodHistory, PullPredecessorsAfterCurrent)
165 {
166   RecordingPuller puller{-EFAULT};
167   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
168
169   // create a disjoint history at 9 and verify that periods are requested
170   // backwards down to current_period
171   auto c9 = history.attach(make_period("9", 9, "8"));
172   ASSERT_FALSE(c9);
173   ASSERT_EQ(-EFAULT, c9.get_error());
174   ASSERT_EQ(Ids{"8"}, puller.ids);
175
176   auto c8 = history.attach(make_period("8", 8, "7"));
177   ASSERT_FALSE(c8);
178   ASSERT_EQ(-EFAULT, c8.get_error());
179   ASSERT_EQ(Ids({"8", "7"}), puller.ids);
180
181   auto c7 = history.attach(make_period("7", 7, "6"));
182   ASSERT_FALSE(c7);
183   ASSERT_EQ(-EFAULT, c7.get_error());
184   ASSERT_EQ(Ids({"8", "7", "6"}), puller.ids);
185
186   auto c6 = history.attach(make_period("6", 6, "5"));
187   ASSERT_TRUE(c6);
188   ASSERT_EQ(Ids({"8", "7", "6"}), puller.ids);
189 }
190
191 TEST(PeriodHistory, MergeBeforeCurrent)
192 {
193   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
194
195   auto c = history.get_current();
196   ASSERT_FALSE(c.has_prev());
197
198   // create a disjoint history at 3
199   auto c3 = history.insert(make_period("3", 3, "2"));
200   ASSERT_FALSE(c3);
201
202   // insert the missing period to merge 3 and 5
203   auto c4 = history.insert(make_period("4", 4, "3"));
204   ASSERT_TRUE(c4);
205   ASSERT_TRUE(c4.has_prev());
206   ASSERT_TRUE(c4.has_next());
207
208   // verify that the merge didn't destroy the original cursor's history
209   ASSERT_EQ(current_period, c.get_period());
210   ASSERT_TRUE(c.has_prev());
211 }
212
213 TEST(PeriodHistory, MergeAfterCurrent)
214 {
215   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
216
217   auto c = history.get_current();
218   ASSERT_FALSE(c.has_next());
219
220   // create a disjoint history at 7
221   auto c7 = history.insert(make_period("7", 7, "6"));
222   ASSERT_FALSE(c7);
223
224   // insert the missing period to merge 5 and 7
225   auto c6 = history.insert(make_period("6", 6, "5"));
226   ASSERT_TRUE(c6);
227   ASSERT_TRUE(c6.has_prev());
228   ASSERT_TRUE(c6.has_next());
229
230   // verify that the merge didn't destroy the original cursor's history
231   ASSERT_EQ(current_period, c.get_period());
232   ASSERT_TRUE(c.has_next());
233 }
234
235 TEST(PeriodHistory, MergeWithoutCurrent)
236 {
237   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
238
239   // create a disjoint history at 7
240   auto c7 = history.insert(make_period("7", 7, "6"));
241   ASSERT_FALSE(c7);
242
243   // create a disjoint history at 9
244   auto c9 = history.insert(make_period("9", 9, "8"));
245   ASSERT_FALSE(c9);
246
247   // insert the missing period to merge 7 and 9
248   auto c8 = history.insert(make_period("8", 8, "7"));
249   ASSERT_FALSE(c8); // not connected to current_period yet
250
251   // insert the missing period to merge 5 and 7-9
252   auto c = history.insert(make_period("6", 6, "5"));
253   ASSERT_TRUE(c);
254   ASSERT_TRUE(c.has_next());
255
256   // verify that we merged all periods from 5-9
257   c.next();
258   ASSERT_EQ(7u, c.get_epoch());
259   ASSERT_TRUE(c.has_next());
260   c.next();
261   ASSERT_EQ(8u, c.get_epoch());
262   ASSERT_TRUE(c.has_next());
263   c.next();
264   ASSERT_EQ(9u, c.get_epoch());
265   ASSERT_FALSE(c.has_next());
266 }
267
268 TEST(PeriodHistory, AttachBefore)
269 {
270   NumericPuller puller;
271   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
272
273   auto c1 = history.attach(make_period("1", 1, ""));
274   ASSERT_TRUE(c1);
275
276   // verify that we pulled and merged all periods from 1-5
277   auto c = history.get_current();
278   ASSERT_TRUE(c);
279   ASSERT_TRUE(c.has_prev());
280   c.prev();
281   ASSERT_EQ(4u, c.get_epoch());
282   ASSERT_TRUE(c.has_prev());
283   c.prev();
284   ASSERT_EQ(3u, c.get_epoch());
285   ASSERT_TRUE(c.has_prev());
286   c.prev();
287   ASSERT_EQ(2u, c.get_epoch());
288   ASSERT_TRUE(c.has_prev());
289   c.prev();
290   ASSERT_EQ(1u, c.get_epoch());
291   ASSERT_FALSE(c.has_prev());
292 }
293
294 TEST(PeriodHistory, AttachAfter)
295 {
296   NumericPuller puller;
297   RGWPeriodHistory history(g_ceph_context, &puller, current_period);
298
299   auto c9 = history.attach(make_period("9", 9, "8"));
300   ASSERT_TRUE(c9);
301
302   // verify that we pulled and merged all periods from 5-9
303   auto c = history.get_current();
304   ASSERT_TRUE(c);
305   ASSERT_TRUE(c.has_next());
306   c.next();
307   ASSERT_EQ(6u, c.get_epoch());
308   ASSERT_TRUE(c.has_next());
309   c.next();
310   ASSERT_EQ(7u, c.get_epoch());
311   ASSERT_TRUE(c.has_next());
312   c.next();
313   ASSERT_EQ(8u, c.get_epoch());
314   ASSERT_TRUE(c.has_next());
315   c.next();
316   ASSERT_EQ(9u, c.get_epoch());
317   ASSERT_FALSE(c.has_next());
318 }
319
320 int main(int argc, char** argv)
321 {
322   vector<const char*> args;
323   argv_to_vec(argc, (const char **)argv, args);
324
325   auto cct = global_init(NULL, args, CEPH_ENTITY_TYPE_CLIENT,
326                          CODE_ENVIRONMENT_UTILITY, 0);
327   common_init_finish(g_ceph_context);
328
329   ::testing::InitGoogleTest(&argc, argv);
330   return RUN_ALL_TESTS();
331 }