]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/rbd_mirror/test_mock_ImageReplayer.cc
update sources to v12.1.0
[ceph.git] / ceph / src / test / rbd_mirror / test_mock_ImageReplayer.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 "cls/journal/cls_journal_types.h"
5#include "librbd/journal/Replay.h"
6#include "librbd/journal/Types.h"
7#include "tools/rbd_mirror/ImageReplayer.h"
31f18b77 8#include "tools/rbd_mirror/InstanceWatcher.h"
7c673cae
FG
9#include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
10#include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
11#include "tools/rbd_mirror/image_replayer/EventPreprocessor.h"
12#include "tools/rbd_mirror/image_replayer/PrepareLocalImageRequest.h"
7c673cae
FG
13#include "test/rbd_mirror/test_mock_fixture.h"
14#include "test/journal/mock/MockJournaler.h"
15#include "test/librbd/mock/MockImageCtx.h"
16#include "test/librbd/mock/MockJournal.h"
17
18namespace librbd {
19
20namespace {
21
22struct MockTestJournal;
23
24struct MockTestImageCtx : public MockImageCtx {
25 MockTestImageCtx(librbd::ImageCtx &image_ctx)
26 : librbd::MockImageCtx(image_ctx) {
27 }
28 MockTestJournal *journal = nullptr;
29};
30
31struct MockTestJournal : public MockJournal {
32 MOCK_METHOD2(start_external_replay, void(journal::Replay<MockTestImageCtx> **,
33 Context *on_start));
34 MOCK_METHOD0(stop_external_replay, void());
35};
36
37} // anonymous namespace
38
39namespace journal {
40
41template<>
42struct Replay<MockTestImageCtx> {
43 MOCK_METHOD2(decode, int(bufferlist::iterator *, EventEntry *));
44 MOCK_METHOD3(process, void(const EventEntry &, Context *, Context *));
45 MOCK_METHOD1(flush, void(Context*));
46 MOCK_METHOD2(shut_down, void(bool, Context*));
47};
48
49template <>
50struct TypeTraits<MockTestImageCtx> {
51 typedef ::journal::MockJournalerProxy Journaler;
52 typedef ::journal::MockReplayEntryProxy ReplayEntry;
53};
54
55struct MirrorPeerClientMeta;
56
57} // namespace journal
58} // namespace librbd
59
60namespace rbd {
61namespace mirror {
62
63template<>
31f18b77 64class InstanceWatcher<librbd::MockTestImageCtx> {
7c673cae
FG
65};
66
67namespace image_replayer {
68
69using ::testing::_;
70using ::testing::AtLeast;
71using ::testing::DoAll;
72using ::testing::InSequence;
73using ::testing::Invoke;
74using ::testing::MatcherCast;
75using ::testing::Return;
76using ::testing::SetArgPointee;
77using ::testing::WithArg;
78
79template<>
80struct PrepareLocalImageRequest<librbd::MockTestImageCtx> {
81 static PrepareLocalImageRequest* s_instance;
82 std::string *local_image_id = nullptr;
83 std::string *tag_owner = nullptr;
84 Context *on_finish = nullptr;
85
86 static PrepareLocalImageRequest* create(librados::IoCtx &,
87 const std::string &global_image_id,
88 std::string *local_image_id,
89 std::string *tag_owner,
90 ContextWQ *work_queue,
91 Context *on_finish) {
92 assert(s_instance != nullptr);
93 s_instance->local_image_id = local_image_id;
94 s_instance->tag_owner = tag_owner;
95 s_instance->on_finish = on_finish;
96 return s_instance;
97 }
98
99 PrepareLocalImageRequest() {
100 s_instance = this;
101 }
102
103 MOCK_METHOD0(send, void());
104};
105
106template<>
107struct BootstrapRequest<librbd::MockTestImageCtx> {
108 static BootstrapRequest* s_instance;
109 librbd::MockTestImageCtx **image_ctx = nullptr;
110 Context *on_finish = nullptr;
111 bool *do_resync = nullptr;
112
31f18b77
FG
113 static BootstrapRequest* create(
114 librados::IoCtx &local_io_ctx, librados::IoCtx &remote_io_ctx,
115 rbd::mirror::InstanceWatcher<librbd::MockTestImageCtx> *instance_watcher,
116 librbd::MockTestImageCtx **local_image_ctx,
117 const std::string &local_image_name, const std::string &remote_image_id,
118 const std::string &global_image_id, ContextWQ *work_queue,
119 SafeTimer *timer, Mutex *timer_lock, const std::string &local_mirror_uuid,
120 const std::string &remote_mirror_uuid,
121 ::journal::MockJournalerProxy *journaler,
122 librbd::journal::MirrorPeerClientMeta *client_meta,
123 Context *on_finish, bool *do_resync,
124 rbd::mirror::ProgressContext *progress_ctx = nullptr) {
7c673cae
FG
125 assert(s_instance != nullptr);
126 s_instance->image_ctx = local_image_ctx;
127 s_instance->on_finish = on_finish;
128 s_instance->do_resync = do_resync;
129 return s_instance;
130 }
131
132 BootstrapRequest() {
133 assert(s_instance == nullptr);
134 s_instance = this;
135 }
136
137 ~BootstrapRequest() {
138 assert(s_instance == this);
139 s_instance = nullptr;
140 }
141
142 void put() {
143 }
144
145 void get() {
146 }
147
148 MOCK_METHOD0(send, void());
149 MOCK_METHOD0(cancel, void());
150};
151
152template<>
153struct CloseImageRequest<librbd::MockTestImageCtx> {
154 static CloseImageRequest* s_instance;
155 librbd::MockTestImageCtx **image_ctx = nullptr;
156 Context *on_finish = nullptr;
157
158 static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx,
159 Context *on_finish) {
160 assert(s_instance != nullptr);
161 s_instance->image_ctx = image_ctx;
162 s_instance->on_finish = on_finish;
163 return s_instance;
164 }
165
166 CloseImageRequest() {
167 assert(s_instance == nullptr);
168 s_instance = this;
169 }
170
171 ~CloseImageRequest() {
172 assert(s_instance == this);
173 s_instance = nullptr;
174 }
175
176 MOCK_METHOD0(send, void());
177};
178
179template<>
180struct EventPreprocessor<librbd::MockTestImageCtx> {
181 static EventPreprocessor *s_instance;
182
183 static EventPreprocessor *create(librbd::MockTestImageCtx &local_image_ctx,
184 ::journal::MockJournalerProxy &remote_journaler,
185 const std::string &local_mirror_uuid,
186 librbd::journal::MirrorPeerClientMeta *client_meta,
187 ContextWQ *work_queue) {
188 assert(s_instance != nullptr);
189 return s_instance;
190 }
191
192 static void destroy(EventPreprocessor* processor) {
193 }
194
195 EventPreprocessor() {
196 assert(s_instance == nullptr);
197 s_instance = this;
198 }
199
200 ~EventPreprocessor() {
201 assert(s_instance == this);
202 s_instance = nullptr;
203 }
204
205 MOCK_METHOD1(is_required, bool(const librbd::journal::EventEntry &));
206 MOCK_METHOD2(preprocess, void(librbd::journal::EventEntry *, Context *));
207};
208
209template<>
210struct ReplayStatusFormatter<librbd::MockTestImageCtx> {
211 static ReplayStatusFormatter* s_instance;
212
213 static ReplayStatusFormatter* create(::journal::MockJournalerProxy *journaler,
214 const std::string &mirror_uuid) {
215 assert(s_instance != nullptr);
216 return s_instance;
217 }
218
219 static void destroy(ReplayStatusFormatter* formatter) {
220 }
221
222 ReplayStatusFormatter() {
223 assert(s_instance == nullptr);
224 s_instance = this;
225 }
226
227 ~ReplayStatusFormatter() {
228 assert(s_instance == this);
229 s_instance = nullptr;
230 }
231
232 MOCK_METHOD2(get_or_send_update, bool(std::string *description, Context *on_finish));
233};
234
235BootstrapRequest<librbd::MockTestImageCtx>* BootstrapRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
236CloseImageRequest<librbd::MockTestImageCtx>* CloseImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
237EventPreprocessor<librbd::MockTestImageCtx>* EventPreprocessor<librbd::MockTestImageCtx>::s_instance = nullptr;
238PrepareLocalImageRequest<librbd::MockTestImageCtx>* PrepareLocalImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
239ReplayStatusFormatter<librbd::MockTestImageCtx>* ReplayStatusFormatter<librbd::MockTestImageCtx>::s_instance = nullptr;
240
241} // namespace image_replayer
242} // namespace mirror
243} // namespace rbd
244
245// template definitions
246#include "tools/rbd_mirror/ImageReplayer.cc"
7c673cae
FG
247
248namespace rbd {
249namespace mirror {
250
251class TestMockImageReplayer : public TestMockFixture {
252public:
253 typedef BootstrapRequest<librbd::MockTestImageCtx> MockBootstrapRequest;
254 typedef CloseImageRequest<librbd::MockTestImageCtx> MockCloseImageRequest;
255 typedef EventPreprocessor<librbd::MockTestImageCtx> MockEventPreprocessor;
256 typedef PrepareLocalImageRequest<librbd::MockTestImageCtx> MockPrepareLocalImageRequest;
257 typedef ReplayStatusFormatter<librbd::MockTestImageCtx> MockReplayStatusFormatter;
258 typedef librbd::journal::Replay<librbd::MockTestImageCtx> MockReplay;
259 typedef ImageReplayer<librbd::MockTestImageCtx> MockImageReplayer;
31f18b77 260 typedef InstanceWatcher<librbd::MockTestImageCtx> MockInstanceWatcher;
7c673cae
FG
261
262 void SetUp() override {
263 TestMockFixture::SetUp();
264
265 librbd::RBD rbd;
266 ASSERT_EQ(0, create_image(rbd, m_remote_io_ctx, m_image_name, m_image_size));
267 ASSERT_EQ(0, open_image(m_remote_io_ctx, m_image_name, &m_remote_image_ctx));
268
269 m_image_deleter.reset(new rbd::mirror::ImageDeleter(m_threads->work_queue,
270 m_threads->timer,
271 &m_threads->timer_lock));
7c673cae 272 m_image_replayer = new MockImageReplayer(
31f18b77 273 m_threads, m_image_deleter, &m_instance_watcher,
7c673cae
FG
274 rbd::mirror::RadosRef(new librados::Rados(m_local_io_ctx)),
275 "local_mirror_uuid", m_local_io_ctx.get_id(), "global image id");
276 m_image_replayer->add_remote_image(
277 "remote_mirror_uuid", m_remote_image_ctx->id, m_remote_io_ctx);
278 }
279
280 void TearDown() override {
281 delete m_image_replayer;
282
283 TestMockFixture::TearDown();
284 }
285
286 void create_local_image() {
287 librbd::RBD rbd;
288 ASSERT_EQ(0, create_image(rbd, m_local_io_ctx, m_image_name, m_image_size));
289 ASSERT_EQ(0, open_image(m_local_io_ctx, m_image_name, &m_local_image_ctx));
290 }
291
292 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
293 bufferlist bl;
294 ::encode(tag_data, bl);
295 return bl;
296 }
297
298 void expect_get_or_send_update(
299 MockReplayStatusFormatter &mock_replay_status_formatter) {
300 EXPECT_CALL(mock_replay_status_formatter, get_or_send_update(_, _))
301 .WillRepeatedly(DoAll(WithArg<1>(CompleteContext(-EEXIST)),
302 Return(true)));
303 }
304
305 void expect_send(MockPrepareLocalImageRequest &mock_request,
306 const std::string &local_image_id,
307 const std::string &tag_owner,
308 int r) {
309 EXPECT_CALL(mock_request, send())
310 .WillOnce(Invoke([&mock_request, local_image_id, tag_owner, r]() {
311 if (r == 0) {
312 *mock_request.local_image_id = local_image_id;
313 *mock_request.tag_owner = tag_owner;
314 }
315 mock_request.on_finish->complete(r);
316 }));
317 }
318
319 void expect_send(MockBootstrapRequest &mock_bootstrap_request,
320 librbd::MockTestImageCtx &mock_local_image_ctx,
321 bool do_resync, int r) {
322 EXPECT_CALL(mock_bootstrap_request, send())
323 .WillOnce(Invoke([&mock_bootstrap_request, &mock_local_image_ctx,
324 do_resync, r]() {
325 if (r == 0) {
326 *mock_bootstrap_request.image_ctx = &mock_local_image_ctx;
327 *mock_bootstrap_request.do_resync = do_resync;
328 }
329 mock_bootstrap_request.on_finish->complete(r);
330 }));
331 }
332
333 void expect_start_external_replay(librbd::MockTestJournal &mock_journal,
334 MockReplay *mock_replay, int r) {
335 EXPECT_CALL(mock_journal, start_external_replay(_, _))
336 .WillOnce(DoAll(SetArgPointee<0>(mock_replay),
337 WithArg<1>(CompleteContext(r))));
338 }
339
340 void expect_init(::journal::MockJournaler &mock_journaler, int r) {
341 EXPECT_CALL(mock_journaler, init(_))
342 .WillOnce(CompleteContext(r));
343 }
344
345 void expect_get_cached_client(::journal::MockJournaler &mock_journaler,
346 int r) {
347 librbd::journal::ImageClientMeta image_client_meta;
348 image_client_meta.tag_class = 0;
349
350 librbd::journal::ClientData client_data;
351 client_data.client_meta = image_client_meta;
352
353 cls::journal::Client client;
354 ::encode(client_data, client.data);
355
356 EXPECT_CALL(mock_journaler, get_cached_client("local_mirror_uuid", _))
357 .WillOnce(DoAll(SetArgPointee<1>(client),
358 Return(r)));
359 }
360
361 void expect_stop_replay(::journal::MockJournaler &mock_journaler, int r) {
362 EXPECT_CALL(mock_journaler, stop_replay(_))
363 .WillOnce(CompleteContext(r));
364 }
365
31f18b77
FG
366 void expect_flush(MockReplay &mock_replay, int r) {
367 EXPECT_CALL(mock_replay, flush(_)).WillOnce(CompleteContext(r));
368 }
369
7c673cae
FG
370 void expect_shut_down(MockReplay &mock_replay, bool cancel_ops, int r) {
371 EXPECT_CALL(mock_replay, shut_down(cancel_ops, _))
372 .WillOnce(WithArg<1>(CompleteContext(r)));
373 }
374
375 void expect_shut_down(journal::MockJournaler &mock_journaler, int r) {
376 EXPECT_CALL(mock_journaler, shut_down(_))
377 .WillOnce(CompleteContext(r));
378 }
379
380 void expect_send(MockCloseImageRequest &mock_close_image_request, int r) {
381 EXPECT_CALL(mock_close_image_request, send())
382 .WillOnce(Invoke([&mock_close_image_request, r]() {
383 *mock_close_image_request.image_ctx = nullptr;
384 mock_close_image_request.on_finish->complete(r);
385 }));
386 }
387
388 void expect_get_commit_tid_in_debug(
389 ::journal::MockReplayEntry &mock_replay_entry) {
390 // It is used in debug messages and depends on debug level
391 EXPECT_CALL(mock_replay_entry, get_commit_tid())
392 .Times(AtLeast(0))
393 .WillRepeatedly(Return(0));
394 }
395
396 void expect_committed(::journal::MockJournaler &mock_journaler, int times) {
397 EXPECT_CALL(mock_journaler, committed(
398 MatcherCast<const ::journal::MockReplayEntryProxy&>(_)))
399 .Times(times);
400 }
401
402 void expect_try_pop_front(::journal::MockJournaler &mock_journaler,
403 uint64_t replay_tag_tid, bool entries_available) {
404 EXPECT_CALL(mock_journaler, try_pop_front(_, _))
405 .WillOnce(DoAll(SetArgPointee<0>(::journal::MockReplayEntryProxy()),
406 SetArgPointee<1>(replay_tag_tid),
407 Return(entries_available)));
408 }
409
410 void expect_try_pop_front_return_no_entries(
411 ::journal::MockJournaler &mock_journaler, Context *on_finish) {
412 EXPECT_CALL(mock_journaler, try_pop_front(_, _))
413 .WillOnce(DoAll(Invoke([on_finish](::journal::MockReplayEntryProxy *e,
414 uint64_t *t) {
415 on_finish->complete(0);
416 }),
417 Return(false)));
418 }
419
420 void expect_get_tag(::journal::MockJournaler &mock_journaler,
421 const cls::journal::Tag &tag, int r) {
422 EXPECT_CALL(mock_journaler, get_tag(_, _, _))
423 .WillOnce(DoAll(SetArgPointee<1>(tag),
424 WithArg<2>(CompleteContext(r))));
425 }
426
427 void expect_allocate_tag(librbd::MockTestJournal &mock_journal, int r) {
428 EXPECT_CALL(mock_journal, allocate_tag(_, _, _))
429 .WillOnce(WithArg<2>(CompleteContext(r)));
430 }
431
432 void expect_preprocess(MockEventPreprocessor &mock_event_preprocessor,
433 bool required, int r) {
434 EXPECT_CALL(mock_event_preprocessor, is_required(_))
435 .WillOnce(Return(required));
436 if (required) {
437 EXPECT_CALL(mock_event_preprocessor, preprocess(_, _))
438 .WillOnce(WithArg<1>(CompleteContext(r)));
439 }
440 }
441
442 void expect_process(MockReplay &mock_replay,
443 int on_ready_r, int on_commit_r) {
444 EXPECT_CALL(mock_replay, process(_, _, _))
445 .WillOnce(DoAll(WithArg<1>(CompleteContext(on_ready_r)),
446 WithArg<2>(CompleteContext(on_commit_r))));
447 }
448
449 librbd::ImageCtx *m_remote_image_ctx;
450 librbd::ImageCtx *m_local_image_ctx = nullptr;
451 std::shared_ptr<rbd::mirror::ImageDeleter> m_image_deleter;
31f18b77 452 MockInstanceWatcher m_instance_watcher;
7c673cae
FG
453 MockImageReplayer *m_image_replayer;
454};
455
456TEST_F(TestMockImageReplayer, StartStop) {
457 // START
458
459 create_local_image();
460 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
461
462 librbd::MockTestJournal mock_local_journal;
463 mock_local_image_ctx.journal = &mock_local_journal;
464
465 journal::MockJournaler mock_remote_journaler;
466 MockPrepareLocalImageRequest mock_prepare_local_image_request;
467 MockBootstrapRequest mock_bootstrap_request;
468 MockReplay mock_local_replay;
469 MockEventPreprocessor mock_event_preprocessor;
470 MockReplayStatusFormatter mock_replay_status_formatter;
471
472 expect_get_or_send_update(mock_replay_status_formatter);
473
474 InSequence seq;
475 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
476 "remote mirror uuid", 0);
477 EXPECT_CALL(mock_remote_journaler, construct());
478 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
479
480 EXPECT_CALL(mock_local_journal, add_listener(_));
481
482 expect_init(mock_remote_journaler, 0);
483
484 EXPECT_CALL(mock_remote_journaler, add_listener(_));
485 expect_get_cached_client(mock_remote_journaler, 0);
486
487 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
488
489 EXPECT_CALL(mock_remote_journaler, start_live_replay(_, _));
490
491 C_SaferCond start_ctx;
492 m_image_replayer->start(&start_ctx);
493 ASSERT_EQ(0, start_ctx.wait());
494
495 // STOP
496
497 MockCloseImageRequest mock_close_local_image_request;
498
7c673cae 499 expect_shut_down(mock_local_replay, true, 0);
7c673cae
FG
500 EXPECT_CALL(mock_local_journal, remove_listener(_));
501 EXPECT_CALL(mock_local_journal, stop_external_replay());
31f18b77 502 expect_send(mock_close_local_image_request, 0);
7c673cae 503
31f18b77 504 expect_stop_replay(mock_remote_journaler, 0);
7c673cae
FG
505 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
506 expect_shut_down(mock_remote_journaler, 0);
507
7c673cae
FG
508 C_SaferCond stop_ctx;
509 m_image_replayer->stop(&stop_ctx);
510 ASSERT_EQ(0, stop_ctx.wait());
511}
512
513TEST_F(TestMockImageReplayer, LocalImagePrimary) {
514 create_local_image();
515 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
516
517 MockPrepareLocalImageRequest mock_prepare_local_image_request;
518 MockReplayStatusFormatter mock_replay_status_formatter;
519
520 expect_get_or_send_update(mock_replay_status_formatter);
521
522 InSequence seq;
523 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
524 "", 0);
525
526 C_SaferCond start_ctx;
527 m_image_replayer->start(&start_ctx);
528 ASSERT_EQ(0, start_ctx.wait());
529}
530
531TEST_F(TestMockImageReplayer, LocalImageDNE) {
532 create_local_image();
533 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
534
535 journal::MockJournaler mock_remote_journaler;
536 MockPrepareLocalImageRequest mock_prepare_local_image_request;
537 MockBootstrapRequest mock_bootstrap_request;
538 MockReplayStatusFormatter mock_replay_status_formatter;
539
540 expect_get_or_send_update(mock_replay_status_formatter);
541
542 InSequence seq;
543 expect_send(mock_prepare_local_image_request, "", "", -ENOENT);
544 EXPECT_CALL(mock_remote_journaler, construct());
545 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, -EREMOTEIO);
546
547 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
548 expect_shut_down(mock_remote_journaler, 0);
549
550 C_SaferCond start_ctx;
551 m_image_replayer->start(&start_ctx);
552 ASSERT_EQ(0, start_ctx.wait());
553}
554
555TEST_F(TestMockImageReplayer, PrepareLocalImageError) {
556 create_local_image();
557 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
558
559 MockPrepareLocalImageRequest mock_prepare_local_image_request;
560 MockReplayStatusFormatter mock_replay_status_formatter;
561
562 expect_get_or_send_update(mock_replay_status_formatter);
563
564 InSequence seq;
565 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
566 "remote mirror uuid", -EINVAL);
567
568 C_SaferCond start_ctx;
569 m_image_replayer->start(&start_ctx);
570 ASSERT_EQ(-EINVAL, start_ctx.wait());
571}
572
573TEST_F(TestMockImageReplayer, BootstrapError) {
574
575 create_local_image();
576 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
577
578 journal::MockJournaler mock_remote_journaler;
579 MockPrepareLocalImageRequest mock_prepare_local_image_request;
580 MockBootstrapRequest mock_bootstrap_request;
581 MockReplayStatusFormatter mock_replay_status_formatter;
582
583 expect_get_or_send_update(mock_replay_status_formatter);
584
585 InSequence seq;
586 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
587 "remote mirror uuid", 0);
588 EXPECT_CALL(mock_remote_journaler, construct());
589 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, -EINVAL);
590
591 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
592 expect_shut_down(mock_remote_journaler, 0);
593
594 C_SaferCond start_ctx;
595 m_image_replayer->start(&start_ctx);
596 ASSERT_EQ(-EINVAL, start_ctx.wait());
597}
598
599TEST_F(TestMockImageReplayer, StartExternalReplayError) {
600 // START
601
602 create_local_image();
603 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
604
605 librbd::MockTestJournal mock_local_journal;
606 mock_local_image_ctx.journal = &mock_local_journal;
607
608 journal::MockJournaler mock_remote_journaler;
609 MockPrepareLocalImageRequest mock_prepare_local_image_request;
610 MockBootstrapRequest mock_bootstrap_request;
611 MockReplay mock_local_replay;
612 MockEventPreprocessor mock_event_preprocessor;
613 MockReplayStatusFormatter mock_replay_status_formatter;
614
615 expect_get_or_send_update(mock_replay_status_formatter);
616
617 InSequence seq;
618 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
619 "remote mirror uuid", 0);
620 EXPECT_CALL(mock_remote_journaler, construct());
621 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
622
623 EXPECT_CALL(mock_local_journal, add_listener(_));
624
625 expect_init(mock_remote_journaler, 0);
626
627 EXPECT_CALL(mock_remote_journaler, add_listener(_));
628 expect_get_cached_client(mock_remote_journaler, 0);
629
630 expect_start_external_replay(mock_local_journal, nullptr, -EINVAL);
631
632 MockCloseImageRequest mock_close_local_image_request;
7c673cae 633 EXPECT_CALL(mock_local_journal, remove_listener(_));
31f18b77 634 expect_send(mock_close_local_image_request, 0);
7c673cae
FG
635
636 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
637 expect_shut_down(mock_remote_journaler, 0);
638
7c673cae
FG
639 C_SaferCond start_ctx;
640 m_image_replayer->start(&start_ctx);
641 ASSERT_EQ(-EINVAL, start_ctx.wait());
642}
643
644TEST_F(TestMockImageReplayer, StopError) {
645 // START
646
647 create_local_image();
648 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
649
650 librbd::MockTestJournal mock_local_journal;
651 mock_local_image_ctx.journal = &mock_local_journal;
652
653 journal::MockJournaler mock_remote_journaler;
654 MockPrepareLocalImageRequest mock_prepare_local_image_request;
655 MockBootstrapRequest mock_bootstrap_request;
656 MockReplay mock_local_replay;
657 MockEventPreprocessor mock_event_preprocessor;
658 MockReplayStatusFormatter mock_replay_status_formatter;
659
660 expect_get_or_send_update(mock_replay_status_formatter);
661
662 InSequence seq;
663 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
664 "remote mirror uuid", 0);
665 EXPECT_CALL(mock_remote_journaler, construct());
666 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
667
668 EXPECT_CALL(mock_local_journal, add_listener(_));
669
670 expect_init(mock_remote_journaler, 0);
671
672 EXPECT_CALL(mock_remote_journaler, add_listener(_));
673 expect_get_cached_client(mock_remote_journaler, 0);
674
675 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
676
677 EXPECT_CALL(mock_remote_journaler, start_live_replay(_, _));
678
679 C_SaferCond start_ctx;
680 m_image_replayer->start(&start_ctx);
681 ASSERT_EQ(0, start_ctx.wait());
682
683 // STOP (errors are ignored)
684
685 MockCloseImageRequest mock_close_local_image_request;
686
7c673cae 687 expect_shut_down(mock_local_replay, true, -EINVAL);
7c673cae
FG
688 EXPECT_CALL(mock_local_journal, remove_listener(_));
689 EXPECT_CALL(mock_local_journal, stop_external_replay());
31f18b77 690 expect_send(mock_close_local_image_request, -EINVAL);
7c673cae 691
31f18b77 692 expect_stop_replay(mock_remote_journaler, -EINVAL);
7c673cae
FG
693 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
694 expect_shut_down(mock_remote_journaler, -EINVAL);
695
7c673cae
FG
696 C_SaferCond stop_ctx;
697 m_image_replayer->stop(&stop_ctx);
698 ASSERT_EQ(0, stop_ctx.wait());
699}
700
701TEST_F(TestMockImageReplayer, Replay) {
702 // START
703
704 create_local_image();
705 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
706
707 librbd::MockTestJournal mock_local_journal;
708 mock_local_image_ctx.journal = &mock_local_journal;
709
710 journal::MockJournaler mock_remote_journaler;
711 MockPrepareLocalImageRequest mock_prepare_local_image_request;
712 MockBootstrapRequest mock_bootstrap_request;
713 MockReplay mock_local_replay;
714 MockEventPreprocessor mock_event_preprocessor;
715 MockReplayStatusFormatter mock_replay_status_formatter;
716 ::journal::MockReplayEntry mock_replay_entry;
717
718 expect_get_or_send_update(mock_replay_status_formatter);
719 expect_get_commit_tid_in_debug(mock_replay_entry);
720 expect_committed(mock_remote_journaler, 2);
721
722 InSequence seq;
723 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
724 "remote mirror uuid", 0);
725 EXPECT_CALL(mock_remote_journaler, construct());
726 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
727
728 EXPECT_CALL(mock_local_journal, add_listener(_));
729
730 expect_init(mock_remote_journaler, 0);
731
732 EXPECT_CALL(mock_remote_journaler, add_listener(_));
733 expect_get_cached_client(mock_remote_journaler, 0);
734
735 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
736
737 EXPECT_CALL(mock_remote_journaler, start_live_replay(_, _));
738
739 C_SaferCond start_ctx;
740 m_image_replayer->start(&start_ctx);
741 ASSERT_EQ(0, start_ctx.wait());
742
743 // REPLAY
744
745 cls::journal::Tag tag =
746 {1, 0, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
747 librbd::Journal<>::LOCAL_MIRROR_UUID,
748 true, 0, 0})};
749
750 expect_try_pop_front(mock_remote_journaler, tag.tid, true);
751
752 // replay_flush
753 expect_shut_down(mock_local_replay, false, 0);
754 EXPECT_CALL(mock_local_journal, stop_external_replay());
755 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
756 expect_get_tag(mock_remote_journaler, tag, 0);
757 expect_allocate_tag(mock_local_journal, 0);
758
759 // process
760 EXPECT_CALL(mock_replay_entry, get_data());
761 EXPECT_CALL(mock_local_replay, decode(_, _))
762 .WillOnce(Return(0));
763 expect_preprocess(mock_event_preprocessor, false, 0);
764 expect_process(mock_local_replay, 0, 0);
765
766 // the next event with preprocess
767 expect_try_pop_front(mock_remote_journaler, tag.tid, true);
768 EXPECT_CALL(mock_replay_entry, get_data());
769 EXPECT_CALL(mock_local_replay, decode(_, _))
770 .WillOnce(Return(0));
771 expect_preprocess(mock_event_preprocessor, true, 0);
772 expect_process(mock_local_replay, 0, 0);
773
774 // attempt to process the next event
775 C_SaferCond replay_ctx;
776 expect_try_pop_front_return_no_entries(mock_remote_journaler, &replay_ctx);
777
778 // fire
779 m_image_replayer->handle_replay_ready();
780 ASSERT_EQ(0, replay_ctx.wait());
781
782 // STOP
783
784 MockCloseImageRequest mock_close_local_image_request;
7c673cae 785 expect_shut_down(mock_local_replay, true, 0);
7c673cae
FG
786 EXPECT_CALL(mock_local_journal, remove_listener(_));
787 EXPECT_CALL(mock_local_journal, stop_external_replay());
31f18b77 788 expect_send(mock_close_local_image_request, 0);
7c673cae 789
31f18b77 790 expect_stop_replay(mock_remote_journaler, 0);
7c673cae
FG
791 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
792 expect_shut_down(mock_remote_journaler, 0);
793
7c673cae
FG
794 C_SaferCond stop_ctx;
795 m_image_replayer->stop(&stop_ctx);
796 ASSERT_EQ(0, stop_ctx.wait());
797}
798
799TEST_F(TestMockImageReplayer, DecodeError) {
800 // START
801
802 create_local_image();
803 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
804
805 librbd::MockTestJournal mock_local_journal;
806 mock_local_image_ctx.journal = &mock_local_journal;
807
808 journal::MockJournaler mock_remote_journaler;
809 MockPrepareLocalImageRequest mock_prepare_local_image_request;
810 MockBootstrapRequest mock_bootstrap_request;
811 MockReplay mock_local_replay;
812 MockEventPreprocessor mock_event_preprocessor;
813 MockReplayStatusFormatter mock_replay_status_formatter;
814 ::journal::MockReplayEntry mock_replay_entry;
815
816 expect_get_or_send_update(mock_replay_status_formatter);
817 expect_get_commit_tid_in_debug(mock_replay_entry);
818
819 InSequence seq;
820 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
821 "remote mirror uuid", 0);
822 EXPECT_CALL(mock_remote_journaler, construct());
823 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
824
825 EXPECT_CALL(mock_local_journal, add_listener(_));
826
827 expect_init(mock_remote_journaler, 0);
828
829 EXPECT_CALL(mock_remote_journaler, add_listener(_));
830 expect_get_cached_client(mock_remote_journaler, 0);
831
832 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
833
834 EXPECT_CALL(mock_remote_journaler, start_live_replay(_, _));
835
836 C_SaferCond start_ctx;
837 m_image_replayer->start(&start_ctx);
838 ASSERT_EQ(0, start_ctx.wait());
839
840 // REPLAY
841
842 cls::journal::Tag tag =
843 {1, 0, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
844 librbd::Journal<>::LOCAL_MIRROR_UUID,
845 true, 0, 0})};
846
847 expect_try_pop_front(mock_remote_journaler, tag.tid, true);
848
849 // replay_flush
850 expect_shut_down(mock_local_replay, false, 0);
851 EXPECT_CALL(mock_local_journal, stop_external_replay());
852 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
853 expect_get_tag(mock_remote_journaler, tag, 0);
854 expect_allocate_tag(mock_local_journal, 0);
855
856 // process
857 EXPECT_CALL(mock_replay_entry, get_data());
858 EXPECT_CALL(mock_local_replay, decode(_, _))
859 .WillOnce(Return(-EINVAL));
860
861 // stop on error
7c673cae 862 expect_shut_down(mock_local_replay, true, 0);
7c673cae
FG
863 EXPECT_CALL(mock_local_journal, remove_listener(_));
864 EXPECT_CALL(mock_local_journal, stop_external_replay());
865
7c673cae
FG
866 MockCloseImageRequest mock_close_local_image_request;
867 C_SaferCond close_ctx;
868 EXPECT_CALL(mock_close_local_image_request, send())
869 .WillOnce(Invoke([&mock_close_local_image_request, &close_ctx]() {
870 *mock_close_local_image_request.image_ctx = nullptr;
871 mock_close_local_image_request.on_finish->complete(0);
872 close_ctx.complete(0);
873 }));
874
31f18b77
FG
875 expect_stop_replay(mock_remote_journaler, 0);
876 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
877 expect_shut_down(mock_remote_journaler, 0);
878
7c673cae
FG
879 // fire
880 m_image_replayer->handle_replay_ready();
881 ASSERT_EQ(0, close_ctx.wait());
882
883 while (!m_image_replayer->is_stopped()) {
884 usleep(1000);
885 }
886}
887
888TEST_F(TestMockImageReplayer, DelayedReplay) {
889
890 // START
891
892 create_local_image();
893 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
894
895 librbd::MockTestJournal mock_local_journal;
896 mock_local_image_ctx.journal = &mock_local_journal;
897
898 journal::MockJournaler mock_remote_journaler;
899 MockPrepareLocalImageRequest mock_prepare_local_image_request;
900 MockBootstrapRequest mock_bootstrap_request;
901 MockReplay mock_local_replay;
902 MockEventPreprocessor mock_event_preprocessor;
903 MockReplayStatusFormatter mock_replay_status_formatter;
904 ::journal::MockReplayEntry mock_replay_entry;
905
906 expect_get_or_send_update(mock_replay_status_formatter);
907 expect_get_commit_tid_in_debug(mock_replay_entry);
908 expect_committed(mock_remote_journaler, 1);
909
910 InSequence seq;
911 expect_send(mock_prepare_local_image_request, mock_local_image_ctx.id,
912 "remote mirror uuid", 0);
913 EXPECT_CALL(mock_remote_journaler, construct());
914 expect_send(mock_bootstrap_request, mock_local_image_ctx, false, 0);
915
916 EXPECT_CALL(mock_local_journal, add_listener(_));
917
918 expect_init(mock_remote_journaler, 0);
919
920 EXPECT_CALL(mock_remote_journaler, add_listener(_));
921 expect_get_cached_client(mock_remote_journaler, 0);
922
923 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
924
925 EXPECT_CALL(mock_remote_journaler, start_live_replay(_, _));
926
927 C_SaferCond start_ctx;
928 m_image_replayer->start(&start_ctx);
929 ASSERT_EQ(0, start_ctx.wait());
930
931 // REPLAY
932
933 cls::journal::Tag tag =
934 {1, 0, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
935 librbd::Journal<>::LOCAL_MIRROR_UUID,
936 true, 0, 0})};
937
938 expect_try_pop_front(mock_remote_journaler, tag.tid, true);
939
940 // replay_flush
941 expect_shut_down(mock_local_replay, false, 0);
942 EXPECT_CALL(mock_local_journal, stop_external_replay());
943 expect_start_external_replay(mock_local_journal, &mock_local_replay, 0);
944 expect_get_tag(mock_remote_journaler, tag, 0);
945 expect_allocate_tag(mock_local_journal, 0);
946
947 // process with delay
948 EXPECT_CALL(mock_replay_entry, get_data());
949 librbd::journal::EventEntry event_entry(
950 librbd::journal::AioDiscardEvent(123, 345, false), ceph_clock_now());
951 EXPECT_CALL(mock_local_replay, decode(_, _))
952 .WillOnce(DoAll(SetArgPointee<1>(event_entry),
953 Return(0)));
954 expect_preprocess(mock_event_preprocessor, false, 0);
955 expect_process(mock_local_replay, 0, 0);
956
957 // attempt to process the next event
958 C_SaferCond replay_ctx;
959 expect_try_pop_front_return_no_entries(mock_remote_journaler, &replay_ctx);
960
961 // fire
962 mock_local_image_ctx.mirroring_replay_delay = 2;
963 m_image_replayer->handle_replay_ready();
964 ASSERT_EQ(0, replay_ctx.wait());
965
966 // add a pending (delayed) entry before stop
967 expect_try_pop_front(mock_remote_journaler, tag.tid, true);
968 EXPECT_CALL(mock_replay_entry, get_data());
969 C_SaferCond decode_ctx;
970 EXPECT_CALL(mock_local_replay, decode(_, _))
971 .WillOnce(DoAll(Invoke([&decode_ctx](bufferlist::iterator* it,
972 librbd::journal::EventEntry *e) {
973 decode_ctx.complete(0);
974 }),
975 Return(0)));
976
977 mock_local_image_ctx.mirroring_replay_delay = 10;
978 m_image_replayer->handle_replay_ready();
979 ASSERT_EQ(0, decode_ctx.wait());
980
981 // STOP
982
983 MockCloseImageRequest mock_close_local_image_request;
984
7c673cae 985 expect_shut_down(mock_local_replay, true, 0);
7c673cae
FG
986 EXPECT_CALL(mock_local_journal, remove_listener(_));
987 EXPECT_CALL(mock_local_journal, stop_external_replay());
31f18b77 988 expect_send(mock_close_local_image_request, 0);
7c673cae 989
31f18b77 990 expect_stop_replay(mock_remote_journaler, 0);
7c673cae
FG
991 EXPECT_CALL(mock_remote_journaler, remove_listener(_));
992 expect_shut_down(mock_remote_journaler, 0);
993
7c673cae
FG
994 C_SaferCond stop_ctx;
995 m_image_replayer->stop(&stop_ctx);
996 ASSERT_EQ(0, stop_ctx.wait());
997}
998
999} // namespace mirror
1000} // namespace rbd