1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "cls/journal/cls_journal_types.h"
5 #include "librbd/journal/Types.h"
6 #include "librbd/journal/TypeTraits.h"
7 #include "tools/rbd_mirror/ImageDeleter.h"
8 #include "tools/rbd_mirror/ImageReplayer.h"
9 #include "tools/rbd_mirror/InstanceWatcher.h"
10 #include "tools/rbd_mirror/MirrorStatusUpdater.h"
11 #include "tools/rbd_mirror/Threads.h"
12 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
13 #include "tools/rbd_mirror/image_replayer/Replayer.h"
14 #include "tools/rbd_mirror/image_replayer/ReplayerListener.h"
15 #include "tools/rbd_mirror/image_replayer/StateBuilder.h"
16 #include "tools/rbd_mirror/image_replayer/Utils.h"
17 #include "test/rbd_mirror/test_mock_fixture.h"
18 #include "test/librbd/mock/MockImageCtx.h"
19 #include "test/rbd_mirror/mock/MockContextWQ.h"
20 #include "test/rbd_mirror/mock/MockSafeTimer.h"
26 struct MockTestImageCtx
: public MockImageCtx
{
27 MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
28 : librbd::MockImageCtx(image_ctx
) {
32 } // anonymous namespace
40 struct ImageDeleter
<librbd::MockTestImageCtx
> {
41 static ImageDeleter
* s_instance
;
43 static void trash_move(librados::IoCtx
& local_io_ctx
,
44 const std::string
& global_image_id
, bool resync
,
45 MockContextWQ
* work_queue
, Context
* on_finish
) {
46 ceph_assert(s_instance
!= nullptr);
47 s_instance
->trash_move(global_image_id
, resync
, on_finish
);
50 MOCK_METHOD3(trash_move
, void(const std::string
&, bool, Context
*));
57 ImageDeleter
<librbd::MockTestImageCtx
>* ImageDeleter
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
60 struct MirrorStatusUpdater
<librbd::MockTestImageCtx
> {
62 MOCK_METHOD1(exists
, bool(const std::string
&));
63 MOCK_METHOD3(set_mirror_image_status
,
64 void(const std::string
&, const cls::rbd::MirrorImageSiteStatus
&,
66 MOCK_METHOD2(remove_refresh_mirror_image_status
, void(const std::string
&,
68 MOCK_METHOD3(remove_mirror_image_status
, void(const std::string
&, bool,
73 struct Threads
<librbd::MockTestImageCtx
> {
75 ceph::mutex
&timer_lock
;
77 MockContextWQ
*work_queue
;
79 Threads(Threads
<librbd::ImageCtx
> *threads
)
80 : timer(new MockSafeTimer()),
81 timer_lock(threads
->timer_lock
),
82 work_queue(new MockContextWQ()) {
91 class InstanceWatcher
<librbd::MockTestImageCtx
> {
94 namespace image_replayer
{
97 struct BootstrapRequest
<librbd::MockTestImageCtx
> {
98 static BootstrapRequest
* s_instance
;
100 StateBuilder
<librbd::MockTestImageCtx
>** state_builder
= nullptr;
101 bool *do_resync
= nullptr;
102 Context
*on_finish
= nullptr;
104 static BootstrapRequest
* create(
105 Threads
<librbd::MockTestImageCtx
>* threads
,
106 librados::IoCtx
&local_io_ctx
,
107 librados::IoCtx
& remote_io_ctx
,
108 rbd::mirror::InstanceWatcher
<librbd::MockTestImageCtx
> *instance_watcher
,
109 const std::string
&global_image_id
,
110 const std::string
&local_mirror_uuid
,
111 const RemotePoolMeta
& remote_pool_meta
,
112 ::journal::CacheManagerHandler
*cache_manager_handler
,
113 PoolMetaCache
* pool_meta_cache
,
114 rbd::mirror::ProgressContext
*progress_ctx
,
115 StateBuilder
<librbd::MockTestImageCtx
>** state_builder
,
116 bool *do_resync
, Context
*on_finish
) {
117 ceph_assert(s_instance
!= nullptr);
118 s_instance
->state_builder
= state_builder
;
119 s_instance
->do_resync
= do_resync
;
120 s_instance
->on_finish
= on_finish
;
125 ceph_assert(s_instance
== nullptr);
129 ~BootstrapRequest() {
130 ceph_assert(s_instance
== this);
131 s_instance
= nullptr;
140 std::string
get_local_image_name() const {
141 return "local image name";
144 inline bool is_syncing() const {
148 MOCK_METHOD0(send
, void());
149 MOCK_METHOD0(cancel
, void());
152 struct MockReplayer
: public Replayer
{
153 image_replayer::ReplayerListener
* replayer_listener
;
155 MOCK_METHOD0(destroy
, void());
157 MOCK_METHOD1(init
, void(Context
*));
158 MOCK_METHOD1(shut_down
, void(Context
*));
159 MOCK_METHOD1(flush
, void(Context
*));
161 MOCK_METHOD2(get_replay_status
, bool(std::string
*, Context
*));
163 MOCK_CONST_METHOD0(is_replaying
, bool());
164 MOCK_CONST_METHOD0(is_resync_requested
, bool());
165 MOCK_CONST_METHOD0(get_error_code
, int());
166 MOCK_CONST_METHOD0(get_error_description
, std::string());
170 struct StateBuilder
<librbd::MockTestImageCtx
> {
171 static StateBuilder
* s_instance
;
173 librbd::MockTestImageCtx
* local_image_ctx
= nullptr;
174 std::string local_image_id
;
175 std::string remote_image_id
;
180 MOCK_METHOD1(close
, void(Context
*));
181 MOCK_METHOD5(create_replayer
, Replayer
*(Threads
<librbd::MockTestImageCtx
>*,
182 InstanceWatcher
<librbd::MockTestImageCtx
>*,
183 const std::string
&, PoolMetaCache
*,
191 BootstrapRequest
<librbd::MockTestImageCtx
>* BootstrapRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
192 StateBuilder
<librbd::MockTestImageCtx
>* StateBuilder
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
194 } // namespace image_replayer
195 } // namespace mirror
198 // template definitions
199 #include "tools/rbd_mirror/ImageReplayer.cc"
205 using ::testing::AtLeast
;
206 using ::testing::DoAll
;
207 using ::testing::InSequence
;
208 using ::testing::Invoke
;
209 using ::testing::MatcherCast
;
210 using ::testing::Return
;
211 using ::testing::ReturnArg
;
212 using ::testing::SetArgPointee
;
213 using ::testing::WithArg
;
215 class TestMockImageReplayer
: public TestMockFixture
{
217 typedef Threads
<librbd::MockTestImageCtx
> MockThreads
;
218 typedef ImageDeleter
<librbd::MockTestImageCtx
> MockImageDeleter
;
219 typedef MirrorStatusUpdater
<librbd::MockTestImageCtx
> MockMirrorStatusUpdater
;
220 typedef image_replayer::BootstrapRequest
<librbd::MockTestImageCtx
> MockBootstrapRequest
;
221 typedef image_replayer::StateBuilder
<librbd::MockTestImageCtx
> MockStateBuilder
;
222 typedef image_replayer::MockReplayer MockReplayer
;
223 typedef ImageReplayer
<librbd::MockTestImageCtx
> MockImageReplayer
;
224 typedef InstanceWatcher
<librbd::MockTestImageCtx
> MockInstanceWatcher
;
226 void SetUp() override
{
227 TestMockFixture::SetUp();
230 ASSERT_EQ(0, create_image(rbd
, m_remote_io_ctx
, m_image_name
, m_image_size
));
231 ASSERT_EQ(0, open_image(m_remote_io_ctx
, m_image_name
, &m_remote_image_ctx
));
234 void TearDown() override
{
235 delete m_image_replayer
;
237 TestMockFixture::TearDown();
240 void create_local_image() {
242 ASSERT_EQ(0, create_image(rbd
, m_local_io_ctx
, m_image_name
, m_image_size
));
243 ASSERT_EQ(0, open_image(m_local_io_ctx
, m_image_name
, &m_local_image_ctx
));
246 void expect_work_queue_repeatedly(MockThreads
&mock_threads
) {
247 EXPECT_CALL(*mock_threads
.work_queue
, queue(_
, _
))
248 .WillRepeatedly(Invoke([this](Context
*ctx
, int r
) {
249 m_threads
->work_queue
->queue(ctx
, r
);
253 void expect_add_event_after_repeatedly(MockThreads
&mock_threads
) {
254 EXPECT_CALL(*mock_threads
.timer
, add_event_after(_
, _
))
256 DoAll(Invoke([this](double seconds
, Context
*ctx
) {
257 m_threads
->timer
->add_event_after(seconds
, ctx
);
260 EXPECT_CALL(*mock_threads
.timer
, cancel_event(_
))
262 Invoke([this](Context
*ctx
) {
263 return m_threads
->timer
->cancel_event(ctx
);
267 void expect_trash_move(MockImageDeleter
& mock_image_deleter
,
268 const std::string
& global_image_id
,
269 bool ignore_orphan
, int r
) {
270 EXPECT_CALL(mock_image_deleter
,
271 trash_move(global_image_id
, ignore_orphan
, _
))
272 .WillOnce(WithArg
<2>(Invoke([this, r
](Context
* ctx
) {
273 m_threads
->work_queue
->queue(ctx
, r
);
277 bufferlist
encode_tag_data(const librbd::journal::TagData
&tag_data
) {
279 encode(tag_data
, bl
);
283 void expect_send(MockBootstrapRequest
& mock_bootstrap_request
,
284 MockStateBuilder
& mock_state_builder
,
285 librbd::MockTestImageCtx
& mock_local_image_ctx
,
286 bool do_resync
, bool set_local_image
, int r
) {
287 EXPECT_CALL(mock_bootstrap_request
, send())
288 .WillOnce(Invoke([this, &mock_bootstrap_request
, &mock_state_builder
,
289 &mock_local_image_ctx
, set_local_image
, do_resync
,
291 if (r
== 0 || r
== -ENOLINK
) {
292 mock_state_builder
.local_image_id
= mock_local_image_ctx
.id
;
293 mock_state_builder
.remote_image_id
= m_remote_image_ctx
->id
;
294 *mock_bootstrap_request
.state_builder
= &mock_state_builder
;
297 mock_state_builder
.local_image_ctx
= &mock_local_image_ctx
;
298 *mock_bootstrap_request
.do_resync
= do_resync
;
300 if (r
< 0 && r
!= -ENOENT
) {
301 mock_state_builder
.remote_image_id
= "";
304 *mock_bootstrap_request
.state_builder
= &mock_state_builder
;
306 if (set_local_image
) {
307 mock_state_builder
.local_image_id
= mock_local_image_ctx
.id
;
309 mock_bootstrap_request
.on_finish
->complete(r
);
313 void expect_create_replayer(MockStateBuilder
& mock_state_builder
,
314 MockReplayer
& mock_replayer
) {
315 EXPECT_CALL(mock_state_builder
, create_replayer(_
, _
, _
, _
, _
))
316 .WillOnce(WithArg
<4>(
317 Invoke([&mock_replayer
]
318 (image_replayer::ReplayerListener
* replayer_listener
) {
319 mock_replayer
.replayer_listener
= replayer_listener
;
320 return &mock_replayer
;
324 void expect_close(MockStateBuilder
& mock_state_builder
, int r
) {
325 EXPECT_CALL(mock_state_builder
, close(_
))
326 .WillOnce(Invoke([this, r
](Context
* ctx
) {
327 m_threads
->work_queue
->queue(ctx
, r
);
331 void expect_init(MockReplayer
& mock_replayer
, int r
) {
332 EXPECT_CALL(mock_replayer
, init(_
))
333 .WillOnce(Invoke([this, r
](Context
* ctx
) {
334 m_threads
->work_queue
->queue(ctx
, r
);
338 void expect_shut_down(MockReplayer
& mock_replayer
, int r
) {
339 EXPECT_CALL(mock_replayer
, shut_down(_
))
340 .WillOnce(Invoke([this, r
](Context
* ctx
) {
341 m_threads
->work_queue
->queue(ctx
, r
);
343 EXPECT_CALL(mock_replayer
, destroy());
346 void expect_get_replay_status(MockReplayer
& mock_replayer
) {
347 EXPECT_CALL(mock_replayer
, get_replay_status(_
, _
))
348 .WillRepeatedly(DoAll(WithArg
<1>(CompleteContext(-EEXIST
)),
352 void expect_set_mirror_image_status_repeatedly() {
353 EXPECT_CALL(m_local_status_updater
, set_mirror_image_status(_
, _
, _
))
354 .WillRepeatedly(Invoke([](auto, auto, auto){}));
355 EXPECT_CALL(m_remote_status_updater
, set_mirror_image_status(_
, _
, _
))
356 .WillRepeatedly(Invoke([](auto, auto, auto){}));
359 void expect_mirror_image_status_exists(bool exists
) {
360 EXPECT_CALL(m_local_status_updater
, exists(_
))
361 .WillOnce(Return(exists
));
362 EXPECT_CALL(m_remote_status_updater
, exists(_
))
363 .WillOnce(Return(exists
));
366 void create_image_replayer(MockThreads
&mock_threads
) {
367 m_image_replayer
= new MockImageReplayer(
368 m_local_io_ctx
, "local_mirror_uuid", "global image id",
369 &mock_threads
, &m_instance_watcher
, &m_local_status_updater
, nullptr,
371 m_image_replayer
->add_peer({"peer_uuid", m_remote_io_ctx
,
372 {"remote mirror uuid",
373 "remote mirror peer uuid"},
374 &m_remote_status_updater
});
377 void wait_for_stopped() {
378 for (int i
= 0; i
< 10000; i
++) {
379 if (m_image_replayer
->is_stopped()) {
384 ASSERT_TRUE(m_image_replayer
->is_stopped());
387 librbd::ImageCtx
*m_remote_image_ctx
;
388 librbd::ImageCtx
*m_local_image_ctx
= nullptr;
389 MockInstanceWatcher m_instance_watcher
;
390 MockMirrorStatusUpdater m_local_status_updater
;
391 MockMirrorStatusUpdater m_remote_status_updater
;
392 MockImageReplayer
*m_image_replayer
= nullptr;
395 TEST_F(TestMockImageReplayer
, StartStop
) {
398 create_local_image();
399 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
401 MockThreads
mock_threads(m_threads
);
402 expect_work_queue_repeatedly(mock_threads
);
403 expect_add_event_after_repeatedly(mock_threads
);
405 MockImageDeleter mock_image_deleter
;
406 MockReplayer mock_replayer
;
408 expect_get_replay_status(mock_replayer
);
409 expect_set_mirror_image_status_repeatedly();
412 MockBootstrapRequest mock_bootstrap_request
;
413 MockStateBuilder mock_state_builder
;
414 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
417 expect_create_replayer(mock_state_builder
, mock_replayer
);
418 expect_init(mock_replayer
, 0);
420 create_image_replayer(mock_threads
);
422 C_SaferCond start_ctx
;
423 m_image_replayer
->start(&start_ctx
);
424 ASSERT_EQ(0, start_ctx
.wait());
425 ASSERT_EQ(image_replayer::HEALTH_STATE_OK
,
426 m_image_replayer
->get_health_state());
429 expect_shut_down(mock_replayer
, 0);
430 expect_close(mock_state_builder
, 0);
431 expect_mirror_image_status_exists(false);
433 C_SaferCond stop_ctx
;
434 m_image_replayer
->stop(&stop_ctx
);
435 ASSERT_EQ(0, stop_ctx
.wait());
436 ASSERT_EQ(image_replayer::HEALTH_STATE_OK
,
437 m_image_replayer
->get_health_state());
440 TEST_F(TestMockImageReplayer
, LocalImagePrimary
) {
441 create_local_image();
442 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
444 MockThreads
mock_threads(m_threads
);
445 expect_work_queue_repeatedly(mock_threads
);
446 expect_add_event_after_repeatedly(mock_threads
);
448 MockImageDeleter mock_image_deleter
;
449 MockBootstrapRequest mock_bootstrap_request
;
451 expect_set_mirror_image_status_repeatedly();
455 MockStateBuilder mock_state_builder
;
456 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
457 false, false, -ENOMSG
);
459 expect_mirror_image_status_exists(false);
461 create_image_replayer(mock_threads
);
463 C_SaferCond start_ctx
;
464 m_image_replayer
->start(&start_ctx
);
465 ASSERT_EQ(0, start_ctx
.wait());
468 TEST_F(TestMockImageReplayer
, MetadataCleanup
) {
471 create_local_image();
472 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
474 MockThreads
mock_threads(m_threads
);
475 expect_work_queue_repeatedly(mock_threads
);
476 expect_add_event_after_repeatedly(mock_threads
);
478 MockImageDeleter mock_image_deleter
;
479 MockBootstrapRequest mock_bootstrap_request
;
480 MockReplayer mock_replayer
;
482 expect_get_replay_status(mock_replayer
);
483 expect_set_mirror_image_status_repeatedly();
487 MockStateBuilder mock_state_builder
;
488 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
489 false, true, -ENOLINK
);
491 expect_close(mock_state_builder
, 0);
492 expect_trash_move(mock_image_deleter
, "global image id", false, 0);
493 expect_mirror_image_status_exists(false);
495 create_image_replayer(mock_threads
);
497 C_SaferCond start_ctx
;
498 m_image_replayer
->start(&start_ctx
);
499 ASSERT_EQ(0, start_ctx
.wait());
502 TEST_F(TestMockImageReplayer
, BootstrapRemoteDeleted
) {
503 create_local_image();
504 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
506 MockThreads
mock_threads(m_threads
);
507 expect_work_queue_repeatedly(mock_threads
);
508 expect_add_event_after_repeatedly(mock_threads
);
510 MockImageDeleter mock_image_deleter
;
512 expect_set_mirror_image_status_repeatedly();
516 MockBootstrapRequest mock_bootstrap_request
;
517 MockStateBuilder mock_state_builder
;
518 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
519 false, false, -ENOLINK
);
521 expect_close(mock_state_builder
, 0);
523 expect_trash_move(mock_image_deleter
, "global image id", false, 0);
524 expect_mirror_image_status_exists(false);
526 create_image_replayer(mock_threads
);
528 C_SaferCond start_ctx
;
529 m_image_replayer
->start(&start_ctx
);
530 ASSERT_EQ(0, start_ctx
.wait());
533 TEST_F(TestMockImageReplayer
, BootstrapResyncRequested
) {
534 create_local_image();
535 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
537 MockThreads
mock_threads(m_threads
);
538 expect_work_queue_repeatedly(mock_threads
);
539 expect_add_event_after_repeatedly(mock_threads
);
541 MockImageDeleter mock_image_deleter
;
543 expect_set_mirror_image_status_repeatedly();
547 MockBootstrapRequest mock_bootstrap_request
;
548 MockStateBuilder mock_state_builder
;
549 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
552 expect_close(mock_state_builder
, 0);
554 expect_trash_move(mock_image_deleter
, "global image id", true, 0);
555 expect_mirror_image_status_exists(false);
557 create_image_replayer(mock_threads
);
559 C_SaferCond start_ctx
;
560 m_image_replayer
->start(&start_ctx
);
561 ASSERT_EQ(0, start_ctx
.wait());
564 TEST_F(TestMockImageReplayer
, BootstrapError
) {
565 create_local_image();
566 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
568 MockThreads
mock_threads(m_threads
);
569 expect_work_queue_repeatedly(mock_threads
);
570 expect_add_event_after_repeatedly(mock_threads
);
572 MockImageDeleter mock_image_deleter
;
573 MockBootstrapRequest mock_bootstrap_request
;
575 expect_set_mirror_image_status_repeatedly();
578 MockStateBuilder mock_state_builder
;
579 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
580 false, false, -EINVAL
);
582 expect_mirror_image_status_exists(false);
584 create_image_replayer(mock_threads
);
586 C_SaferCond start_ctx
;
587 m_image_replayer
->start(&start_ctx
);
588 ASSERT_EQ(-EINVAL
, start_ctx
.wait());
591 TEST_F(TestMockImageReplayer
, BootstrapCancel
) {
592 create_local_image();
593 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
595 MockThreads
mock_threads(m_threads
);
596 expect_work_queue_repeatedly(mock_threads
);
597 expect_add_event_after_repeatedly(mock_threads
);
599 MockImageDeleter mock_image_deleter
;
601 expect_set_mirror_image_status_repeatedly();
605 create_image_replayer(mock_threads
);
607 MockBootstrapRequest mock_bootstrap_request
;
608 MockStateBuilder mock_state_builder
;
609 EXPECT_CALL(mock_bootstrap_request
, send())
610 .WillOnce(Invoke([this, &mock_bootstrap_request
]() {
611 m_image_replayer
->stop(nullptr);
612 mock_bootstrap_request
.on_finish
->complete(-ECANCELED
);
614 EXPECT_CALL(mock_bootstrap_request
, cancel());
616 expect_mirror_image_status_exists(false);
618 C_SaferCond start_ctx
;
619 m_image_replayer
->start(&start_ctx
);
620 ASSERT_EQ(-ECANCELED
, start_ctx
.wait());
623 TEST_F(TestMockImageReplayer
, BootstrapRemoteDeletedCancel
) {
624 create_local_image();
625 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
627 MockThreads
mock_threads(m_threads
);
628 expect_work_queue_repeatedly(mock_threads
);
629 expect_add_event_after_repeatedly(mock_threads
);
631 MockImageDeleter mock_image_deleter
;
633 expect_set_mirror_image_status_repeatedly();
637 MockBootstrapRequest mock_bootstrap_request
;
638 MockStateBuilder mock_state_builder
;
639 EXPECT_CALL(mock_bootstrap_request
, send())
640 .WillOnce(Invoke([this, &mock_bootstrap_request
, &mock_state_builder
,
641 &mock_local_image_ctx
]() {
642 mock_state_builder
.local_image_id
= mock_local_image_ctx
.id
;
643 mock_state_builder
.remote_image_id
= "";
644 *mock_bootstrap_request
.state_builder
= &mock_state_builder
;
645 m_image_replayer
->stop(nullptr);
646 mock_bootstrap_request
.on_finish
->complete(-ENOLINK
);
648 EXPECT_CALL(mock_bootstrap_request
, cancel());
650 expect_close(mock_state_builder
, 0);
652 expect_trash_move(mock_image_deleter
, "global image id", false, 0);
653 expect_mirror_image_status_exists(false);
655 create_image_replayer(mock_threads
);
657 C_SaferCond start_ctx
;
658 m_image_replayer
->start(&start_ctx
);
659 ASSERT_EQ(-ECANCELED
, start_ctx
.wait());
662 TEST_F(TestMockImageReplayer
, StopError
) {
665 create_local_image();
666 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
668 MockThreads
mock_threads(m_threads
);
669 expect_work_queue_repeatedly(mock_threads
);
670 expect_add_event_after_repeatedly(mock_threads
);
672 MockImageDeleter mock_image_deleter
;
673 MockBootstrapRequest mock_bootstrap_request
;
674 MockReplayer mock_replayer
;
676 expect_get_replay_status(mock_replayer
);
677 expect_set_mirror_image_status_repeatedly();
680 MockStateBuilder mock_state_builder
;
681 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
684 expect_create_replayer(mock_state_builder
, mock_replayer
);
685 expect_init(mock_replayer
, 0);
687 create_image_replayer(mock_threads
);
689 C_SaferCond start_ctx
;
690 m_image_replayer
->start(&start_ctx
);
691 ASSERT_EQ(0, start_ctx
.wait());
693 // STOP (errors are ignored)
695 expect_shut_down(mock_replayer
, -EINVAL
);
696 expect_close(mock_state_builder
, -EINVAL
);
697 expect_mirror_image_status_exists(false);
699 C_SaferCond stop_ctx
;
700 m_image_replayer
->stop(&stop_ctx
);
701 ASSERT_EQ(0, stop_ctx
.wait());
704 TEST_F(TestMockImageReplayer
, ReplayerError
) {
705 create_local_image();
706 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
708 MockThreads
mock_threads(m_threads
);
709 expect_work_queue_repeatedly(mock_threads
);
710 expect_add_event_after_repeatedly(mock_threads
);
712 MockImageDeleter mock_image_deleter
;
713 MockBootstrapRequest mock_bootstrap_request
;
714 MockReplayer mock_replayer
;
716 expect_set_mirror_image_status_repeatedly();
719 MockStateBuilder mock_state_builder
;
720 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
723 expect_create_replayer(mock_state_builder
, mock_replayer
);
724 expect_init(mock_replayer
, -EINVAL
);
725 EXPECT_CALL(mock_replayer
, get_error_description())
726 .WillOnce(Return("FAIL"));
728 EXPECT_CALL(mock_replayer
, destroy());
729 expect_close(mock_state_builder
, -EINVAL
);
731 expect_mirror_image_status_exists(false);
732 create_image_replayer(mock_threads
);
734 C_SaferCond start_ctx
;
735 m_image_replayer
->start(&start_ctx
);
736 ASSERT_EQ(-EINVAL
, start_ctx
.wait());
739 TEST_F(TestMockImageReplayer
, ReplayerResync
) {
741 create_local_image();
742 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
744 MockThreads
mock_threads(m_threads
);
745 expect_work_queue_repeatedly(mock_threads
);
746 expect_add_event_after_repeatedly(mock_threads
);
748 MockImageDeleter mock_image_deleter
;
749 MockBootstrapRequest mock_bootstrap_request
;
750 MockReplayer mock_replayer
;
752 expect_get_replay_status(mock_replayer
);
753 expect_set_mirror_image_status_repeatedly();
756 MockStateBuilder mock_state_builder
;
757 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
760 expect_create_replayer(mock_state_builder
, mock_replayer
);
761 expect_init(mock_replayer
, 0);
763 create_image_replayer(mock_threads
);
765 C_SaferCond start_ctx
;
766 m_image_replayer
->start(&start_ctx
);
767 ASSERT_EQ(0, start_ctx
.wait());
770 EXPECT_CALL(mock_replayer
, is_resync_requested())
771 .WillOnce(Return(true));
772 expect_shut_down(mock_replayer
, 0);
773 expect_close(mock_state_builder
, 0);
774 expect_trash_move(mock_image_deleter
, "global image id", true, 0);
775 expect_mirror_image_status_exists(false);
776 mock_replayer
.replayer_listener
->handle_notification();
777 ASSERT_FALSE(m_image_replayer
->is_running());
782 TEST_F(TestMockImageReplayer
, ReplayerInterrupted
) {
784 create_local_image();
785 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
787 MockThreads
mock_threads(m_threads
);
788 expect_work_queue_repeatedly(mock_threads
);
789 expect_add_event_after_repeatedly(mock_threads
);
791 MockImageDeleter mock_image_deleter
;
792 MockBootstrapRequest mock_bootstrap_request
;
793 MockReplayer mock_replayer
;
795 expect_get_replay_status(mock_replayer
);
796 expect_set_mirror_image_status_repeatedly();
799 MockStateBuilder mock_state_builder
;
800 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
803 expect_create_replayer(mock_state_builder
, mock_replayer
);
804 expect_init(mock_replayer
, 0);
806 create_image_replayer(mock_threads
);
808 C_SaferCond start_ctx
;
809 m_image_replayer
->start(&start_ctx
);
810 ASSERT_EQ(0, start_ctx
.wait());
813 EXPECT_CALL(mock_replayer
, is_resync_requested())
814 .WillOnce(Return(false));
815 EXPECT_CALL(mock_replayer
, is_replaying())
816 .WillOnce(Return(false));
817 EXPECT_CALL(mock_replayer
, get_error_code())
818 .WillOnce(Return(-EINVAL
));
819 EXPECT_CALL(mock_replayer
, get_error_description())
820 .WillOnce(Return("INVALID"));
821 expect_shut_down(mock_replayer
, 0);
822 expect_close(mock_state_builder
, 0);
823 expect_mirror_image_status_exists(false);
824 mock_replayer
.replayer_listener
->handle_notification();
825 ASSERT_FALSE(m_image_replayer
->is_running());
830 TEST_F(TestMockImageReplayer
, ReplayerRenamed
) {
832 create_local_image();
833 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
835 MockThreads
mock_threads(m_threads
);
836 expect_work_queue_repeatedly(mock_threads
);
837 expect_add_event_after_repeatedly(mock_threads
);
839 MockImageDeleter mock_image_deleter
;
840 MockBootstrapRequest mock_bootstrap_request
;
841 MockReplayer mock_replayer
;
843 expect_get_replay_status(mock_replayer
);
844 expect_set_mirror_image_status_repeatedly();
847 MockStateBuilder mock_state_builder
;
848 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
851 expect_create_replayer(mock_state_builder
, mock_replayer
);
852 expect_init(mock_replayer
, 0);
854 create_image_replayer(mock_threads
);
856 C_SaferCond start_ctx
;
857 m_image_replayer
->start(&start_ctx
);
858 ASSERT_EQ(0, start_ctx
.wait());
861 EXPECT_CALL(mock_replayer
, is_resync_requested())
862 .WillOnce(Return(false));
863 EXPECT_CALL(mock_replayer
, is_replaying())
864 .WillOnce(Return(true));
865 mock_local_image_ctx
.name
= "NEW NAME";
866 mock_replayer
.replayer_listener
->handle_notification();
869 expect_shut_down(mock_replayer
, 0);
870 expect_close(mock_state_builder
, 0);
871 expect_mirror_image_status_exists(false);
873 C_SaferCond stop_ctx
;
874 m_image_replayer
->stop(&stop_ctx
);
875 ASSERT_EQ(0, stop_ctx
.wait());
877 auto image_spec
= image_replayer::util::compute_image_spec(
878 m_local_io_ctx
, "NEW NAME");
879 ASSERT_EQ(image_spec
, m_image_replayer
->get_name());
882 TEST_F(TestMockImageReplayer
, StopJoinInterruptedReplayer
) {
884 create_local_image();
885 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
887 MockThreads
mock_threads(m_threads
);
888 expect_work_queue_repeatedly(mock_threads
);
889 expect_add_event_after_repeatedly(mock_threads
);
891 MockReplayer mock_replayer
;
892 expect_get_replay_status(mock_replayer
);
893 expect_set_mirror_image_status_repeatedly();
896 MockBootstrapRequest mock_bootstrap_request
;
897 MockStateBuilder mock_state_builder
;
898 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
901 expect_create_replayer(mock_state_builder
, mock_replayer
);
902 expect_init(mock_replayer
, 0);
904 create_image_replayer(mock_threads
);
906 C_SaferCond start_ctx
;
907 m_image_replayer
->start(&start_ctx
);
908 ASSERT_EQ(0, start_ctx
.wait());
911 EXPECT_CALL(mock_replayer
, is_resync_requested())
912 .WillOnce(Return(false));
913 EXPECT_CALL(mock_replayer
, is_replaying())
914 .WillOnce(Return(false));
915 EXPECT_CALL(mock_replayer
, get_error_code())
916 .WillOnce(Return(-EINVAL
));
917 EXPECT_CALL(mock_replayer
, get_error_description())
918 .WillOnce(Return("INVALID"));
919 const double DELAY
= 10;
920 EXPECT_CALL(mock_replayer
, shut_down(_
))
921 .WillOnce(Invoke([this, DELAY
](Context
* ctx
) {
922 std::lock_guard
l(m_threads
->timer_lock
);
923 m_threads
->timer
->add_event_after(DELAY
, ctx
);
925 EXPECT_CALL(mock_replayer
, destroy());
926 expect_close(mock_state_builder
, 0);
927 expect_mirror_image_status_exists(false);
929 mock_replayer
.replayer_listener
->handle_notification();
930 ASSERT_FALSE(m_image_replayer
->is_running());
932 C_SaferCond stop_ctx
;
933 m_image_replayer
->stop(&stop_ctx
);
934 ASSERT_EQ(ETIMEDOUT
, stop_ctx
.wait_for(DELAY
* 3 / 4));
935 ASSERT_EQ(0, stop_ctx
.wait_for(DELAY
));
938 TEST_F(TestMockImageReplayer
, StopJoinRequestedStop
) {
940 create_local_image();
941 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
943 MockThreads
mock_threads(m_threads
);
944 expect_work_queue_repeatedly(mock_threads
);
945 expect_add_event_after_repeatedly(mock_threads
);
947 MockReplayer mock_replayer
;
948 expect_get_replay_status(mock_replayer
);
949 expect_set_mirror_image_status_repeatedly();
952 MockBootstrapRequest mock_bootstrap_request
;
953 MockStateBuilder mock_state_builder
;
954 expect_send(mock_bootstrap_request
, mock_state_builder
, mock_local_image_ctx
,
957 expect_create_replayer(mock_state_builder
, mock_replayer
);
958 expect_init(mock_replayer
, 0);
960 create_image_replayer(mock_threads
);
962 C_SaferCond start_ctx
;
963 m_image_replayer
->start(&start_ctx
);
964 ASSERT_EQ(0, start_ctx
.wait());
967 const double DELAY
= 10;
968 EXPECT_CALL(mock_replayer
, shut_down(_
))
969 .WillOnce(Invoke([this, DELAY
](Context
* ctx
) {
970 std::lock_guard
l(m_threads
->timer_lock
);
971 m_threads
->timer
->add_event_after(DELAY
, ctx
);
973 EXPECT_CALL(mock_replayer
, destroy());
974 expect_close(mock_state_builder
, 0);
975 expect_mirror_image_status_exists(false);
977 C_SaferCond stop_ctx1
;
978 m_image_replayer
->stop(&stop_ctx1
);
980 C_SaferCond stop_ctx2
;
981 m_image_replayer
->stop(&stop_ctx2
);
982 ASSERT_EQ(ETIMEDOUT
, stop_ctx2
.wait_for(DELAY
* 3 / 4));
983 ASSERT_EQ(0, stop_ctx2
.wait_for(DELAY
));
985 ASSERT_EQ(0, stop_ctx1
.wait_for(0));
988 } // namespace mirror