]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/test_mock_InstanceReplayer.cc
import 15.2.4
[ceph.git] / ceph / src / test / rbd_mirror / test_mock_InstanceReplayer.cc
CommitLineData
7c673cae
FG
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"
d2e6a577
FG
6#include "test/rbd_mirror/mock/MockContextWQ.h"
7#include "test/rbd_mirror/mock/MockSafeTimer.h"
7c673cae 8#include "tools/rbd_mirror/ImageReplayer.h"
31f18b77 9#include "tools/rbd_mirror/InstanceWatcher.h"
7c673cae 10#include "tools/rbd_mirror/InstanceReplayer.h"
c07f9fc5 11#include "tools/rbd_mirror/ServiceDaemon.h"
7c673cae 12#include "tools/rbd_mirror/Threads.h"
c07f9fc5 13#include "tools/rbd_mirror/image_replayer/Types.h"
7c673cae
FG
14
15namespace librbd {
16
17namespace {
18
19struct MockTestImageCtx : public MockImageCtx {
20 MockTestImageCtx(librbd::ImageCtx &image_ctx)
21 : librbd::MockImageCtx(image_ctx) {
22 }
23};
24
25} // anonymous namespace
26
27} // namespace librbd
28
29namespace rbd {
30namespace mirror {
31
32template <>
33struct Threads<librbd::MockTestImageCtx> {
d2e6a577 34 MockSafeTimer *timer;
9f95a23c
TL
35 ceph::mutex &timer_lock;
36 ceph::condition_variable timer_cond;
d2e6a577
FG
37
38 MockContextWQ *work_queue;
7c673cae
FG
39
40 Threads(Threads<librbd::ImageCtx> *threads)
d2e6a577
FG
41 : timer(new MockSafeTimer()),
42 timer_lock(threads->timer_lock),
43 work_queue(new MockContextWQ()) {
44 }
45 ~Threads() {
46 delete timer;
47 delete work_queue;
7c673cae
FG
48 }
49};
50
c07f9fc5
FG
51template<>
52struct ServiceDaemon<librbd::MockTestImageCtx> {
9f95a23c
TL
53 MOCK_METHOD4(add_or_update_namespace_attribute,
54 void(int64_t, const std::string&, const std::string&,
c07f9fc5
FG
55 const service_daemon::AttributeValue&));
56};
57
31f18b77
FG
58template<>
59struct InstanceWatcher<librbd::MockTestImageCtx> {
60};
61
7c673cae
FG
62template<>
63struct ImageReplayer<librbd::MockTestImageCtx> {
64 static ImageReplayer* s_instance;
65 std::string global_image_id;
66
67 static ImageReplayer *create(
9f95a23c
TL
68 librados::IoCtx &local_io_ctx, const std::string &local_mirror_uuid,
69 const std::string &global_image_id,
70 Threads<librbd::MockTestImageCtx> *threads,
71 InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
72 MirrorStatusUpdater<librbd::MockTestImageCtx>* local_status_updater,
73 journal::CacheManagerHandler *cache_manager_handler,
74 PoolMetaCache* pool_meta_cache) {
11fdf7f2 75 ceph_assert(s_instance != nullptr);
7c673cae
FG
76 s_instance->global_image_id = global_image_id;
77 return s_instance;
78 }
79
80 ImageReplayer() {
11fdf7f2 81 ceph_assert(s_instance == nullptr);
7c673cae
FG
82 s_instance = this;
83 }
84
85 virtual ~ImageReplayer() {
11fdf7f2 86 ceph_assert(s_instance == this);
7c673cae
FG
87 s_instance = nullptr;
88 }
89
90 MOCK_METHOD0(destroy, void());
91 MOCK_METHOD2(start, void(Context *, bool));
92 MOCK_METHOD2(stop, void(Context *, bool));
1911f103 93 MOCK_METHOD1(restart, void(Context*));
7c673cae 94 MOCK_METHOD0(flush, void());
9f95a23c
TL
95 MOCK_METHOD1(print_status, void(Formatter *));
96 MOCK_METHOD1(add_peer, void(const Peer<librbd::MockTestImageCtx>& peer));
7c673cae
FG
97 MOCK_METHOD0(get_global_image_id, const std::string &());
98 MOCK_METHOD0(get_local_image_id, const std::string &());
99 MOCK_METHOD0(is_running, bool());
100 MOCK_METHOD0(is_stopped, bool());
101 MOCK_METHOD0(is_blacklisted, bool());
c07f9fc5 102
d2e6a577
FG
103 MOCK_CONST_METHOD0(is_finished, bool());
104 MOCK_METHOD1(set_finished, void(bool));
105
c07f9fc5 106 MOCK_CONST_METHOD0(get_health_state, image_replayer::HealthState());
7c673cae
FG
107};
108
7c673cae
FG
109ImageReplayer<librbd::MockTestImageCtx>* ImageReplayer<librbd::MockTestImageCtx>::s_instance = nullptr;
110
9f95a23c
TL
111template<>
112struct MirrorStatusUpdater<librbd::MockTestImageCtx> {
113};
114
7c673cae
FG
115} // namespace mirror
116} // namespace rbd
117
118// template definitions
119#include "tools/rbd_mirror/InstanceReplayer.cc"
120
121namespace rbd {
122namespace mirror {
123
124using ::testing::_;
3efd9988 125using ::testing::DoAll;
7c673cae
FG
126using ::testing::InSequence;
127using ::testing::Invoke;
128using ::testing::Return;
3efd9988 129using ::testing::ReturnArg;
7c673cae 130using ::testing::ReturnRef;
c07f9fc5 131using ::testing::WithArg;
7c673cae
FG
132
133class TestMockInstanceReplayer : public TestMockFixture {
134public:
d2e6a577 135 typedef Threads<librbd::MockTestImageCtx> MockThreads;
7c673cae
FG
136 typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
137 typedef InstanceReplayer<librbd::MockTestImageCtx> MockInstanceReplayer;
31f18b77 138 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
9f95a23c 139 typedef MirrorStatusUpdater<librbd::MockTestImageCtx> MockMirrorStatusUpdater;
c07f9fc5 140 typedef ServiceDaemon<librbd::MockTestImageCtx> MockServiceDaemon;
7c673cae 141
d2e6a577
FG
142 void expect_work_queue(MockThreads &mock_threads) {
143 EXPECT_CALL(*mock_threads.work_queue, queue(_, _))
144 .WillOnce(Invoke([this](Context *ctx, int r) {
145 m_threads->work_queue->queue(ctx, r);
146 }));
7c673cae
FG
147 }
148
d2e6a577
FG
149 void expect_add_event_after(MockThreads &mock_threads,
150 Context** timer_ctx = nullptr) {
151 EXPECT_CALL(*mock_threads.timer, add_event_after(_, _))
3efd9988
FG
152 .WillOnce(DoAll(
153 WithArg<1>(Invoke([this, &mock_threads, timer_ctx](Context *ctx) {
9f95a23c 154 ceph_assert(ceph_mutex_is_locked(mock_threads.timer_lock));
d2e6a577
FG
155 if (timer_ctx != nullptr) {
156 *timer_ctx = ctx;
9f95a23c 157 mock_threads.timer_cond.notify_one();
d2e6a577
FG
158 } else {
159 m_threads->work_queue->queue(
9f95a23c
TL
160 new LambdaContext([&mock_threads, ctx](int) {
161 std::lock_guard timer_lock{mock_threads.timer_lock};
d2e6a577
FG
162 ctx->complete(0);
163 }), 0);
164 }
3efd9988
FG
165 })),
166 ReturnArg<1>()));
7c673cae
FG
167 }
168
d2e6a577
FG
169 void expect_cancel_event(MockThreads &mock_threads, bool canceled) {
170 EXPECT_CALL(*mock_threads.timer, cancel_event(_))
171 .WillOnce(Return(canceled));
c07f9fc5 172 }
7c673cae
FG
173};
174
175TEST_F(TestMockInstanceReplayer, AcquireReleaseImage) {
d2e6a577 176 MockThreads mock_threads(m_threads);
c07f9fc5 177 MockServiceDaemon mock_service_daemon;
9f95a23c 178 MockMirrorStatusUpdater mock_status_updater;
31f18b77 179 MockInstanceWatcher mock_instance_watcher;
7c673cae
FG
180 MockImageReplayer mock_image_replayer;
181 MockInstanceReplayer instance_replayer(
9f95a23c
TL
182 m_local_io_ctx, "local_mirror_uuid",
183 &mock_threads, &mock_service_daemon, &mock_status_updater, nullptr,
184 nullptr);
7c673cae
FG
185 std::string global_image_id("global_image_id");
186
187 EXPECT_CALL(mock_image_replayer, get_global_image_id())
188 .WillRepeatedly(ReturnRef(global_image_id));
c07f9fc5 189
7c673cae 190 InSequence seq;
d2e6a577
FG
191 expect_work_queue(mock_threads);
192 Context *timer_ctx = nullptr;
193 expect_add_event_after(mock_threads, &timer_ctx);
7c673cae 194 instance_replayer.init();
9f95a23c 195 instance_replayer.add_peer({"peer_uuid", m_remote_io_ctx, {}, nullptr});
7c673cae
FG
196
197 // Acquire
198
199 C_SaferCond on_acquire;
9f95a23c 200 EXPECT_CALL(mock_image_replayer, add_peer(_));
d2e6a577
FG
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));
1911f103
TL
204 EXPECT_CALL(mock_image_replayer, start(_, false))
205 .WillOnce(CompleteContext(0));
d2e6a577 206 expect_work_queue(mock_threads);
7c673cae 207
31f18b77 208 instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
31f18b77 209 &on_acquire);
7c673cae
FG
210 ASSERT_EQ(0, on_acquire.wait());
211
212 // Release
213
214 C_SaferCond on_release;
215
7c673cae
FG
216 EXPECT_CALL(mock_image_replayer, is_stopped())
217 .WillOnce(Return(false));
218 EXPECT_CALL(mock_image_replayer, is_running())
219 .WillOnce(Return(false));
d2e6a577
FG
220 expect_work_queue(mock_threads);
221 expect_add_event_after(mock_threads);
222 expect_work_queue(mock_threads);
7c673cae
FG
223 EXPECT_CALL(mock_image_replayer, is_stopped())
224 .WillOnce(Return(false));
225 EXPECT_CALL(mock_image_replayer, is_running())
226 .WillOnce(Return(true));
227 EXPECT_CALL(mock_image_replayer, stop(_, false))
228 .WillOnce(CompleteContext(0));
d2e6a577 229 expect_work_queue(mock_threads);
7c673cae
FG
230 EXPECT_CALL(mock_image_replayer, is_stopped())
231 .WillOnce(Return(true));
d2e6a577 232 expect_work_queue(mock_threads);
7c673cae
FG
233 EXPECT_CALL(mock_image_replayer, destroy());
234
d2e6a577 235 instance_replayer.release_image("global_image_id", &on_release);
7c673cae
FG
236 ASSERT_EQ(0, on_release.wait());
237
d2e6a577
FG
238 expect_work_queue(mock_threads);
239 expect_cancel_event(mock_threads, true);
240 expect_work_queue(mock_threads);
7c673cae 241 instance_replayer.shut_down();
d2e6a577
FG
242 ASSERT_TRUE(timer_ctx != nullptr);
243 delete timer_ctx;
7c673cae
FG
244}
245
d2e6a577
FG
246TEST_F(TestMockInstanceReplayer, RemoveFinishedImage) {
247 MockThreads mock_threads(m_threads);
248 MockServiceDaemon mock_service_daemon;
9f95a23c 249 MockMirrorStatusUpdater mock_status_updater;
d2e6a577
FG
250 MockInstanceWatcher mock_instance_watcher;
251 MockImageReplayer mock_image_replayer;
252 MockInstanceReplayer instance_replayer(
9f95a23c
TL
253 m_local_io_ctx, "local_mirror_uuid",
254 &mock_threads, &mock_service_daemon, &mock_status_updater, nullptr,
255 nullptr);
d2e6a577
FG
256 std::string global_image_id("global_image_id");
257
258 EXPECT_CALL(mock_image_replayer, get_global_image_id())
259 .WillRepeatedly(ReturnRef(global_image_id));
260
261 InSequence seq;
262 expect_work_queue(mock_threads);
263 Context *timer_ctx1 = nullptr;
264 expect_add_event_after(mock_threads, &timer_ctx1);
265 instance_replayer.init();
9f95a23c 266 instance_replayer.add_peer({"peer_uuid", m_remote_io_ctx, {}, nullptr});
d2e6a577
FG
267
268 // Acquire
269
270 C_SaferCond on_acquire;
9f95a23c 271 EXPECT_CALL(mock_image_replayer, add_peer(_));
d2e6a577
FG
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));
1911f103
TL
275 EXPECT_CALL(mock_image_replayer, start(_, false))
276 .WillOnce(CompleteContext(0));
d2e6a577
FG
277 expect_work_queue(mock_threads);
278
279 instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
280 &on_acquire);
281 ASSERT_EQ(0, on_acquire.wait());
282
283 // periodic start timer
284 Context *timer_ctx2 = nullptr;
285 expect_add_event_after(mock_threads, &timer_ctx2);
286
287 Context *start_image_replayers_ctx = nullptr;
288 EXPECT_CALL(*mock_threads.work_queue, queue(_, 0))
289 .WillOnce(Invoke([&start_image_replayers_ctx](Context *ctx, int r) {
290 start_image_replayers_ctx = ctx;
291 }));
292
293 ASSERT_TRUE(timer_ctx1 != nullptr);
294 {
9f95a23c 295 std::lock_guard timer_locker{mock_threads.timer_lock};
d2e6a577
FG
296 timer_ctx1->complete(0);
297 }
298
299 // remove finished image replayer
300 EXPECT_CALL(mock_image_replayer, get_health_state()).WillOnce(
301 Return(image_replayer::HEALTH_STATE_OK));
302 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
303 EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
304 EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(true));
305 EXPECT_CALL(mock_image_replayer, destroy());
9f95a23c
TL
306 EXPECT_CALL(mock_service_daemon,
307 add_or_update_namespace_attribute(_, _, _, _)).Times(3);
d2e6a577
FG
308
309 ASSERT_TRUE(start_image_replayers_ctx != nullptr);
310 start_image_replayers_ctx->complete(0);
311
312 // shut down
313 expect_work_queue(mock_threads);
314 expect_cancel_event(mock_threads, true);
315 expect_work_queue(mock_threads);
316 instance_replayer.shut_down();
317 ASSERT_TRUE(timer_ctx2 != nullptr);
318 delete timer_ctx2;
319}
11fdf7f2
TL
320
321TEST_F(TestMockInstanceReplayer, Reacquire) {
322 MockThreads mock_threads(m_threads);
323 MockServiceDaemon mock_service_daemon;
9f95a23c 324 MockMirrorStatusUpdater mock_status_updater;
11fdf7f2
TL
325 MockInstanceWatcher mock_instance_watcher;
326 MockImageReplayer mock_image_replayer;
327 MockInstanceReplayer instance_replayer(
9f95a23c
TL
328 m_local_io_ctx, "local_mirror_uuid",
329 &mock_threads, &mock_service_daemon, &mock_status_updater, nullptr,
330 nullptr);
11fdf7f2
TL
331 std::string global_image_id("global_image_id");
332
333 EXPECT_CALL(mock_image_replayer, get_global_image_id())
334 .WillRepeatedly(ReturnRef(global_image_id));
335
336 InSequence seq;
337 expect_work_queue(mock_threads);
338 Context *timer_ctx = nullptr;
339 expect_add_event_after(mock_threads, &timer_ctx);
340 instance_replayer.init();
9f95a23c 341 instance_replayer.add_peer({"peer_uuid", m_remote_io_ctx, {}, nullptr});
11fdf7f2
TL
342
343 // Acquire
344
9f95a23c 345 EXPECT_CALL(mock_image_replayer, add_peer(_));
11fdf7f2
TL
346 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
347 EXPECT_CALL(mock_image_replayer, is_blacklisted()).WillOnce(Return(false));
348 EXPECT_CALL(mock_image_replayer, is_finished()).WillOnce(Return(false));
1911f103
TL
349 EXPECT_CALL(mock_image_replayer, start(_, false))
350 .WillOnce(CompleteContext(0));
11fdf7f2
TL
351 expect_work_queue(mock_threads);
352
353 C_SaferCond on_acquire1;
354 instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
355 &on_acquire1);
356 ASSERT_EQ(0, on_acquire1.wait());
357
358 // Re-acquire
359 EXPECT_CALL(mock_image_replayer, set_finished(false));
1911f103
TL
360 EXPECT_CALL(mock_image_replayer, restart(_))
361 .WillOnce(CompleteContext(0));
11fdf7f2
TL
362 expect_work_queue(mock_threads);
363
364 C_SaferCond on_acquire2;
365 instance_replayer.acquire_image(&mock_instance_watcher, global_image_id,
366 &on_acquire2);
367 ASSERT_EQ(0, on_acquire2.wait());
368
369 expect_work_queue(mock_threads);
370 expect_cancel_event(mock_threads, true);
371 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
372 expect_work_queue(mock_threads);
373 expect_work_queue(mock_threads);
374 EXPECT_CALL(mock_image_replayer, is_stopped()).WillOnce(Return(true));
375 EXPECT_CALL(mock_image_replayer, destroy());
376 instance_replayer.shut_down();
377 ASSERT_TRUE(timer_ctx != nullptr);
378 delete timer_ctx;
379}
380
7c673cae
FG
381} // namespace mirror
382} // namespace rbd