Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / rbd_mirror / test_mock_InstanceReplayer.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include "test/librbd/mock/MockImageCtx.h"
5 #include "test/rbd_mirror/test_mock_fixture.h"
6 #include "test/rbd_mirror/mock/MockContextWQ.h"
7 #include "test/rbd_mirror/mock/MockSafeTimer.h"
8 #include "tools/rbd_mirror/ImageDeleter.h"
9 #include "tools/rbd_mirror/ImageReplayer.h"
10 #include "tools/rbd_mirror/InstanceWatcher.h"
11 #include "tools/rbd_mirror/InstanceReplayer.h"
12 #include "tools/rbd_mirror/ServiceDaemon.h"
13 #include "tools/rbd_mirror/Threads.h"
14 #include "tools/rbd_mirror/image_replayer/Types.h"
15
16 namespace librbd {
17
18 namespace {
19
20 struct MockTestImageCtx : public MockImageCtx {
21   MockTestImageCtx(librbd::ImageCtx &image_ctx)
22     : librbd::MockImageCtx(image_ctx) {
23   }
24 };
25
26 } // anonymous namespace
27
28 } // namespace librbd
29
30 namespace rbd {
31 namespace mirror {
32
33 template <>
34 struct Threads<librbd::MockTestImageCtx> {
35   MockSafeTimer *timer;
36   Mutex &timer_lock;
37   Cond timer_cond;
38
39   MockContextWQ *work_queue;
40
41   Threads(Threads<librbd::ImageCtx> *threads)
42     : timer(new MockSafeTimer()),
43       timer_lock(threads->timer_lock),
44       work_queue(new MockContextWQ()) {
45   }
46   ~Threads() {
47     delete timer;
48     delete work_queue;
49   }
50 };
51
52 template <>
53 struct ImageDeleter<librbd::MockTestImageCtx> {
54 };
55
56 template<>
57 struct ServiceDaemon<librbd::MockTestImageCtx> {
58   MOCK_METHOD3(add_or_update_attribute,
59                void(int64_t, const std::string&,
60                     const service_daemon::AttributeValue&));
61 };
62
63 template<>
64 struct InstanceWatcher<librbd::MockTestImageCtx> {
65 };
66
67 template<>
68 struct ImageReplayer<librbd::MockTestImageCtx> {
69   static ImageReplayer* s_instance;
70   std::string global_image_id;
71
72   static ImageReplayer *create(
73     Threads<librbd::MockTestImageCtx> *threads,
74     ImageDeleter<librbd::MockTestImageCtx>* image_deleter,
75     InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
76     RadosRef local, const std::string &local_mirror_uuid, int64_t local_pool_id,
77     const std::string &global_image_id) {
78     assert(s_instance != nullptr);
79     s_instance->global_image_id = global_image_id;
80     return s_instance;
81   }
82
83   ImageReplayer() {
84     assert(s_instance == nullptr);
85     s_instance = this;
86   }
87
88   virtual ~ImageReplayer() {
89     assert(s_instance == this);
90     s_instance = nullptr;
91   }
92
93   MOCK_METHOD0(destroy, void());
94   MOCK_METHOD2(start, void(Context *, bool));
95   MOCK_METHOD2(stop, void(Context *, bool));
96   MOCK_METHOD0(restart, void());
97   MOCK_METHOD0(flush, void());
98   MOCK_METHOD2(print_status, void(Formatter *, stringstream *));
99   MOCK_METHOD2(add_peer, void(const std::string &, librados::IoCtx &));
100   MOCK_METHOD0(get_global_image_id, const std::string &());
101   MOCK_METHOD0(get_local_image_id, const std::string &());
102   MOCK_METHOD0(is_running, bool());
103   MOCK_METHOD0(is_stopped, bool());
104   MOCK_METHOD0(is_blacklisted, bool());
105
106   MOCK_CONST_METHOD0(is_finished, bool());
107   MOCK_METHOD1(set_finished, void(bool));
108
109   MOCK_CONST_METHOD0(get_health_state, image_replayer::HealthState());
110 };
111
112 ImageReplayer<librbd::MockTestImageCtx>* ImageReplayer<librbd::MockTestImageCtx>::s_instance = nullptr;
113
114 } // namespace mirror
115 } // namespace rbd
116
117 // template definitions
118 #include "tools/rbd_mirror/InstanceReplayer.cc"
119
120 namespace rbd {
121 namespace mirror {
122
123 using ::testing::_;
124 using ::testing::DoAll;
125 using ::testing::InSequence;
126 using ::testing::Invoke;
127 using ::testing::Return;
128 using ::testing::ReturnArg;
129 using ::testing::ReturnRef;
130 using ::testing::WithArg;
131
132 class TestMockInstanceReplayer : public TestMockFixture {
133 public:
134   typedef Threads<librbd::MockTestImageCtx> MockThreads;
135   typedef ImageDeleter<librbd::MockTestImageCtx> MockImageDeleter;
136   typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
137   typedef InstanceReplayer<librbd::MockTestImageCtx> MockInstanceReplayer;
138   typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
139   typedef ServiceDaemon<librbd::MockTestImageCtx> MockServiceDaemon;
140
141   void expect_work_queue(MockThreads &mock_threads) {
142     EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
143       .WillOnce(Invoke([this](Context *ctx, int r) {
144           m_threads->work_queue->queue(ctx, r);
145         }));
146   }
147
148   void expect_add_event_after(MockThreads &mock_threads,
149                               Context** timer_ctx = nullptr) {
150     EXPECT_CALL(*mock_threads.timer, add_event_after(_, _))
151       .WillOnce(DoAll(
152         WithArg<1>(Invoke([this, &mock_threads, timer_ctx](Context *ctx) {
153           assert(mock_threads.timer_lock.is_locked());
154           if (timer_ctx != nullptr) {
155             *timer_ctx = ctx;
156             mock_threads.timer_cond.SignalOne();
157           } else {
158             m_threads->work_queue->queue(
159               new FunctionContext([&mock_threads, ctx](int) {
160                 Mutex::Locker timer_lock(mock_threads.timer_lock);
161                 ctx->complete(0);
162               }), 0);
163           }
164         })),
165         ReturnArg<1>()));
166   }
167
168   void expect_cancel_event(MockThreads &mock_threads, bool canceled) {
169     EXPECT_CALL(*mock_threads.timer, cancel_event(_))
170       .WillOnce(Return(canceled));
171   }
172 };
173
174 TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) {
175   MockThreads mock_threads(m_threads);
176   MockServiceDaemon mock_service_daemon;
177   MockImageDeleter mock_image_deleter;
178   MockInstanceWatcher mock_instance_watcher;
179   MockImageReplayer mock_image_replayer;
180   MockInstanceReplayer instance_replayer(
181     &mock_threads, &mock_service_daemon, &mock_image_deleter,
182     rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)),
183     "local_mirror_uuid", m_local_io_ctx.get_id());
184   std::string global_image_id("global_image_id");
185
186   EXPECT_CALL(mock_image_replayer, get_global_image_id())
187     .WillRepeatedly(ReturnRef(global_image_id));
188
189   InSequence seq;
190   expect_work_queue(mock_threads);
191   Context *timer_ctx = nullptr;
192   expect_add_event_after(mock_threads, &timer_ctx);
193   instance_replayer.init();
194   instance_replayer.add_peer("peer_uuid", m_remote_io_ctx);
195
196   // Acquire
197
198   C_SaferCond on_acquire;
199   EXPECT_CALL(mock_image_replayer, add_peer("peer_uuid", _));
200   EXPECT_CALL(mock_image_replayer, set_finished(false));
201   EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
202   EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
203   EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false));
204   EXPECT_CALL(mock_image_replayer, start(nullptr, false));
205   expect_work_queue(mock_threads);
206
207   instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
208                                   &on_acquire);
209   ASSERT_EQ(0, on_acquire.wait());
210
211   // Release
212
213   C_SaferCond on_release;
214
215   EXPECT_CALL(mock_image_replayer, is_stopped())
216     .WillOnce(Return(false));
217   EXPECT_CALL(mock_image_replayer, is_running())
218     .WillOnce(Return(false));
219   expect_work_queue(mock_threads);
220   expect_add_event_after(mock_threads);
221   expect_work_queue(mock_threads);
222   EXPECT_CALL(mock_image_replayer, is_stopped())
223     .WillOnce(Return(false));
224   EXPECT_CALL(mock_image_replayer, is_running())
225     .WillOnce(Return(true));
226   EXPECT_CALL(mock_image_replayer, stop(_, false))
227     .WillOnce(CompleteContext(0));
228   expect_work_queue(mock_threads);
229   EXPECT_CALL(mock_image_replayer, is_stopped())
230     .WillOnce(Return(true));
231   expect_work_queue(mock_threads);
232   EXPECT_CALL(mock_image_replayer, destroy());
233
234   instance_replayer.release_image("global_image_id", &on_release);
235   ASSERT_EQ(0, on_release.wait());
236
237   expect_work_queue(mock_threads);
238   expect_cancel_event(mock_threads, true);
239   expect_work_queue(mock_threads);
240   instance_replayer.shut_down();
241   ASSERT_TRUE(timer_ctx != nullptr);
242   delete timer_ctx;
243 }
244
245 TEST_F(TestMockInstanceReplayer, RemoveFinishedImage) {
246   MockThreads mock_threads(m_threads);
247   MockServiceDaemon mock_service_daemon;
248   MockImageDeleter mock_image_deleter;
249   MockInstanceWatcher mock_instance_watcher;
250   MockImageReplayer mock_image_replayer;
251   MockInstanceReplayer instance_replayer(
252     &mock_threads, &mock_service_daemon, &mock_image_deleter,
253     rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)),
254     "local_mirror_uuid", m_local_io_ctx.get_id());
255   std::string global_image_id("global_image_id");
256
257   EXPECT_CALL(mock_image_replayer, get_global_image_id())
258     .WillRepeatedly(ReturnRef(global_image_id));
259
260   InSequence seq;
261   expect_work_queue(mock_threads);
262   Context *timer_ctx1 = nullptr;
263   expect_add_event_after(mock_threads, &timer_ctx1);
264   instance_replayer.init();
265   instance_replayer.add_peer("peer_uuid", m_remote_io_ctx);
266
267   // Acquire
268
269   C_SaferCond on_acquire;
270   EXPECT_CALL(mock_image_replayer, add_peer("peer_uuid", _));
271   EXPECT_CALL(mock_image_replayer, set_finished(false));
272   EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
273   EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
274   EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false));
275   EXPECT_CALL(mock_image_replayer, start(nullptr, false));
276   expect_work_queue(mock_threads);
277
278   instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
279                                   &on_acquire);
280   ASSERT_EQ(0, on_acquire.wait());
281
282   // periodic start timer
283   Context *timer_ctx2 = nullptr;
284   expect_add_event_after(mock_threads, &timer_ctx2);
285
286   Context *start_image_replayers_ctx = nullptr;
287   EXPECT_CALL(*mock_threads.work_queue, queue(_, 0))
288     .WillOnce(Invoke([&start_image_replayers_ctx](Context *ctx, int r) {
289                 start_image_replayers_ctx = ctx;
290               }));
291
292   ASSERT_TRUE(timer_ctx1 != nullptr);
293   {
294     Mutex::Locker timer_locker(mock_threads.timer_lock);
295     timer_ctx1->complete(0);
296   }
297
298   // remove finished image replayer
299   EXPECT_CALL(mock_image_replayer, get_health_state()).WillOnce(
300     Return(image_replayer::HEALTH_STATE_OK));
301   EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
302   EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
303   EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(true));
304   EXPECT_CALL(mock_image_replayer, destroy());
305   EXPECT_CALL(mock_service_daemon,add_or_update_attribute(_, _, _)).Times(3);
306
307   ASSERT_TRUE(start_image_replayers_ctx != nullptr);
308   start_image_replayers_ctx->complete(0);
309
310   // shut down
311   expect_work_queue(mock_threads);
312   expect_cancel_event(mock_threads, true);
313   expect_work_queue(mock_threads);
314   instance_replayer.shut_down();
315   ASSERT_TRUE(timer_ctx2 != nullptr);
316   delete timer_ctx2;
317 }
318 } // namespace mirror
319 } // namespace rbd