1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/rbd_mirror/test_mock_fixture.h"
5 #include "librbd/journal/TypeTraits.h"
6 #include "tools/rbd_mirror/InstanceWatcher.h"
7 #include "tools/rbd_mirror/Threads.h"
8 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.h"
9 #include "tools/rbd_mirror/image_replayer/CloseImageRequest.h"
10 #include "tools/rbd_mirror/image_replayer/CreateImageRequest.h"
11 #include "tools/rbd_mirror/image_replayer/IsPrimaryRequest.h"
12 #include "tools/rbd_mirror/image_replayer/OpenImageRequest.h"
13 #include "tools/rbd_mirror/image_replayer/OpenLocalImageRequest.h"
14 #include "test/journal/mock/MockJournaler.h"
15 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
16 #include "test/librbd/mock/MockImageCtx.h"
17 #include "test/librbd/mock/MockJournal.h"
23 struct MockTestImageCtx
: public librbd::MockImageCtx
{
24 MockTestImageCtx(librbd::ImageCtx
&image_ctx
)
25 : librbd::MockImageCtx(image_ctx
) {
29 } // anonymous namespace
34 struct TypeTraits
<librbd::MockTestImageCtx
> {
35 typedef ::journal::MockJournaler Journaler
;
38 } // namespace journal
42 static std::string s_image_id
;
45 std::string generate_image_id
<MockTestImageCtx
>(librados::IoCtx
&) {
46 assert(!s_image_id
.empty());
56 class ProgressContext
;
59 struct ImageSync
<librbd::MockTestImageCtx
> {
60 static ImageSync
* s_instance
;
61 Context
*on_finish
= nullptr;
63 static ImageSync
* create(
64 librbd::MockTestImageCtx
*local_image_ctx
,
65 librbd::MockTestImageCtx
*remote_image_ctx
,
66 SafeTimer
*timer
, Mutex
*timer_lock
, const std::string
&mirror_uuid
,
67 ::journal::MockJournaler
*journaler
,
68 librbd::journal::MirrorPeerClientMeta
*client_meta
, ContextWQ
*work_queue
,
69 InstanceWatcher
<librbd::MockTestImageCtx
> *instance_watcher
,
70 Context
*on_finish
, ProgressContext
*progress_ctx
) {
71 assert(s_instance
!= nullptr);
72 s_instance
->on_finish
= on_finish
;
77 assert(s_instance
== nullptr);
84 MOCK_METHOD0(get
, void());
85 MOCK_METHOD0(put
, void());
86 MOCK_METHOD0(send
, void());
87 MOCK_METHOD0(cancel
, void());
90 ImageSync
<librbd::MockTestImageCtx
>*
91 ImageSync
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
94 struct InstanceWatcher
<librbd::MockTestImageCtx
> {
97 namespace image_replayer
{
100 struct CloseImageRequest
<librbd::MockTestImageCtx
> {
101 static CloseImageRequest
* s_instance
;
102 librbd::MockTestImageCtx
**image_ctx
= nullptr;
103 Context
*on_finish
= nullptr;
105 static CloseImageRequest
* create(librbd::MockTestImageCtx
**image_ctx
,
106 Context
*on_finish
) {
107 assert(s_instance
!= nullptr);
108 s_instance
->image_ctx
= image_ctx
;
109 s_instance
->on_finish
= on_finish
;
110 s_instance
->construct(*image_ctx
);
114 CloseImageRequest() {
115 assert(s_instance
== nullptr);
118 ~CloseImageRequest() {
119 s_instance
= nullptr;
122 MOCK_METHOD1(construct
, void(librbd::MockTestImageCtx
*image_ctx
));
123 MOCK_METHOD0(send
, void());
127 struct CreateImageRequest
<librbd::MockTestImageCtx
> {
128 static CreateImageRequest
* s_instance
;
129 Context
*on_finish
= nullptr;
131 static CreateImageRequest
* create(librados::IoCtx
&local_io_ctx
,
132 ContextWQ
*work_queue
,
133 const std::string
&global_image_id
,
134 const std::string
&remote_mirror_uuid
,
135 const std::string
&local_image_name
,
136 const std::string
&local_image_id
,
137 librbd::MockTestImageCtx
*remote_image_ctx
,
138 Context
*on_finish
) {
139 assert(s_instance
!= nullptr);
140 s_instance
->on_finish
= on_finish
;
141 s_instance
->construct(local_image_id
);
145 CreateImageRequest() {
146 assert(s_instance
== nullptr);
149 ~CreateImageRequest() {
150 s_instance
= nullptr;
153 MOCK_METHOD1(construct
, void(const std::string
&));
154 MOCK_METHOD0(send
, void());
158 struct IsPrimaryRequest
<librbd::MockTestImageCtx
> {
159 static IsPrimaryRequest
* s_instance
;
160 bool *primary
= nullptr;
161 Context
*on_finish
= nullptr;
163 static IsPrimaryRequest
* create(librbd::MockTestImageCtx
*image_ctx
,
164 bool *primary
, Context
*on_finish
) {
165 assert(s_instance
!= nullptr);
166 s_instance
->primary
= primary
;
167 s_instance
->on_finish
= on_finish
;
172 assert(s_instance
== nullptr);
175 ~IsPrimaryRequest() {
176 s_instance
= nullptr;
179 MOCK_METHOD0(send
, void());
183 struct OpenImageRequest
<librbd::MockTestImageCtx
> {
184 static OpenImageRequest
* s_instance
;
185 librbd::MockTestImageCtx
**image_ctx
= nullptr;
186 Context
*on_finish
= nullptr;
188 static OpenImageRequest
* create(librados::IoCtx
&io_ctx
,
189 librbd::MockTestImageCtx
**image_ctx
,
190 const std::string
&image_id
,
191 bool read_only
, Context
*on_finish
) {
192 assert(s_instance
!= nullptr);
193 s_instance
->image_ctx
= image_ctx
;
194 s_instance
->on_finish
= on_finish
;
195 s_instance
->construct(io_ctx
, image_id
);
200 assert(s_instance
== nullptr);
203 ~OpenImageRequest() {
204 s_instance
= nullptr;
207 MOCK_METHOD2(construct
, void(librados::IoCtx
&io_ctx
,
208 const std::string
&image_id
));
209 MOCK_METHOD0(send
, void());
213 struct OpenLocalImageRequest
<librbd::MockTestImageCtx
> {
214 static OpenLocalImageRequest
* s_instance
;
215 librbd::MockTestImageCtx
**image_ctx
= nullptr;
216 Context
*on_finish
= nullptr;
218 static OpenLocalImageRequest
* create(librados::IoCtx
&local_io_ctx
,
219 librbd::MockTestImageCtx
**local_image_ctx
,
220 const std::string
&local_image_id
,
221 ContextWQ
*work_queue
,
222 Context
*on_finish
) {
223 assert(s_instance
!= nullptr);
224 s_instance
->image_ctx
= local_image_ctx
;
225 s_instance
->on_finish
= on_finish
;
226 s_instance
->construct(local_io_ctx
, local_image_id
);
230 OpenLocalImageRequest() {
231 assert(s_instance
== nullptr);
234 ~OpenLocalImageRequest() {
235 s_instance
= nullptr;
238 MOCK_METHOD2(construct
, void(librados::IoCtx
&io_ctx
,
239 const std::string
&image_id
));
240 MOCK_METHOD0(send
, void());
243 CloseImageRequest
<librbd::MockTestImageCtx
>*
244 CloseImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
245 CreateImageRequest
<librbd::MockTestImageCtx
>*
246 CreateImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
247 IsPrimaryRequest
<librbd::MockTestImageCtx
>*
248 IsPrimaryRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
249 OpenImageRequest
<librbd::MockTestImageCtx
>*
250 OpenImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
251 OpenLocalImageRequest
<librbd::MockTestImageCtx
>*
252 OpenLocalImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
254 } // namespace image_replayer
255 } // namespace mirror
258 // template definitions
259 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
263 namespace image_replayer
{
266 using ::testing::DoAll
;
267 using ::testing::InSequence
;
268 using ::testing::Invoke
;
269 using ::testing::Return
;
270 using ::testing::SetArgPointee
;
271 using ::testing::StrEq
;
272 using ::testing::WithArg
;
274 MATCHER_P(IsSameIoCtx
, io_ctx
, "") {
275 return &get_mock_io_ctx(arg
) == &get_mock_io_ctx(*io_ctx
);
278 class TestMockImageReplayerBootstrapRequest
: public TestMockFixture
{
280 typedef BootstrapRequest
<librbd::MockTestImageCtx
> MockBootstrapRequest
;
281 typedef CloseImageRequest
<librbd::MockTestImageCtx
> MockCloseImageRequest
;
282 typedef CreateImageRequest
<librbd::MockTestImageCtx
> MockCreateImageRequest
;
283 typedef ImageSync
<librbd::MockTestImageCtx
> MockImageSync
;
284 typedef InstanceWatcher
<librbd::MockTestImageCtx
> MockInstanceWatcher
;
285 typedef IsPrimaryRequest
<librbd::MockTestImageCtx
> MockIsPrimaryRequest
;
286 typedef OpenImageRequest
<librbd::MockTestImageCtx
> MockOpenImageRequest
;
287 typedef OpenLocalImageRequest
<librbd::MockTestImageCtx
> MockOpenLocalImageRequest
;
288 typedef std::list
<cls::journal::Tag
> Tags
;
290 void SetUp() override
{
291 TestMockFixture::SetUp();
294 ASSERT_EQ(0, create_image(rbd
, m_remote_io_ctx
, m_image_name
, m_image_size
));
295 ASSERT_EQ(0, open_image(m_remote_io_ctx
, m_image_name
, &m_remote_image_ctx
));
298 void create_local_image() {
300 ASSERT_EQ(0, create_image(rbd
, m_local_io_ctx
, m_image_name
, m_image_size
));
301 ASSERT_EQ(0, open_image(m_local_io_ctx
, m_image_name
, &m_local_image_ctx
));
304 void expect_journaler_get_client(::journal::MockJournaler
&mock_journaler
,
305 const std::string
&client_id
,
306 cls::journal::Client
&client
, int r
) {
307 EXPECT_CALL(mock_journaler
, get_client(StrEq(client_id
), _
, _
))
308 .WillOnce(DoAll(WithArg
<1>(Invoke([client
](cls::journal::Client
*out_client
) {
309 *out_client
= client
;
311 WithArg
<2>(Invoke([this, r
](Context
*on_finish
) {
312 m_threads
->work_queue
->queue(on_finish
, r
);
316 void expect_journaler_get_tags(::journal::MockJournaler
&mock_journaler
,
317 uint64_t tag_class
, const Tags
& tags
,
319 EXPECT_CALL(mock_journaler
, get_tags(tag_class
, _
, _
))
320 .WillOnce(DoAll(WithArg
<1>(Invoke([tags
](Tags
*out_tags
) {
323 WithArg
<2>(Invoke([this, r
](Context
*on_finish
) {
324 m_threads
->work_queue
->queue(on_finish
, r
);
328 void expect_journaler_register_client(::journal::MockJournaler
&mock_journaler
,
329 const librbd::journal::ClientData
&client_data
,
332 ::encode(client_data
, bl
);
334 EXPECT_CALL(mock_journaler
, register_client(ContentsEqual(bl
), _
))
335 .WillOnce(WithArg
<1>(Invoke([this, r
](Context
*on_finish
) {
336 m_threads
->work_queue
->queue(on_finish
, r
);
340 void expect_journaler_unregister_client(::journal::MockJournaler
&mock_journaler
,
342 EXPECT_CALL(mock_journaler
, unregister_client(_
))
343 .WillOnce(Invoke([this, r
](Context
*on_finish
) {
344 m_threads
->work_queue
->queue(on_finish
, r
);
348 void expect_journaler_update_client(::journal::MockJournaler
&mock_journaler
,
349 const librbd::journal::ClientData
&client_data
,
352 ::encode(client_data
, bl
);
354 EXPECT_CALL(mock_journaler
, update_client(ContentsEqual(bl
), _
))
355 .WillOnce(WithArg
<1>(Invoke([this, r
](Context
*on_finish
) {
356 m_threads
->work_queue
->queue(on_finish
, r
);
360 void expect_open_image(MockOpenImageRequest
&mock_open_image_request
,
361 librados::IoCtx
&io_ctx
, const std::string
&image_id
,
362 librbd::MockTestImageCtx
&mock_image_ctx
, int r
) {
363 EXPECT_CALL(mock_open_image_request
, construct(IsSameIoCtx(&io_ctx
), image_id
));
364 EXPECT_CALL(mock_open_image_request
, send())
365 .WillOnce(Invoke([this, &mock_open_image_request
, &mock_image_ctx
, r
]() {
366 *mock_open_image_request
.image_ctx
= &mock_image_ctx
;
367 m_threads
->work_queue
->queue(mock_open_image_request
.on_finish
, r
);
371 void expect_open_local_image(MockOpenLocalImageRequest
&mock_open_local_image_request
,
372 librados::IoCtx
&io_ctx
, const std::string
&image_id
,
373 librbd::MockTestImageCtx
*mock_image_ctx
, int r
) {
374 EXPECT_CALL(mock_open_local_image_request
,
375 construct(IsSameIoCtx(&io_ctx
), image_id
));
376 EXPECT_CALL(mock_open_local_image_request
, send())
377 .WillOnce(Invoke([this, &mock_open_local_image_request
, mock_image_ctx
, r
]() {
378 *mock_open_local_image_request
.image_ctx
= mock_image_ctx
;
379 m_threads
->work_queue
->queue(mock_open_local_image_request
.on_finish
,
384 void expect_close_image(MockCloseImageRequest
&mock_close_image_request
,
385 librbd::MockTestImageCtx
&mock_image_ctx
, int r
) {
386 EXPECT_CALL(mock_close_image_request
, construct(&mock_image_ctx
));
387 EXPECT_CALL(mock_close_image_request
, send())
388 .WillOnce(Invoke([this, &mock_close_image_request
, r
]() {
389 *mock_close_image_request
.image_ctx
= nullptr;
390 m_threads
->work_queue
->queue(mock_close_image_request
.on_finish
, r
);
394 void expect_is_primary(MockIsPrimaryRequest
&mock_is_primary_request
,
395 bool primary
, int r
) {
396 EXPECT_CALL(mock_is_primary_request
, send())
397 .WillOnce(Invoke([this, &mock_is_primary_request
, primary
, r
]() {
398 *mock_is_primary_request
.primary
= primary
;
399 m_threads
->work_queue
->queue(mock_is_primary_request
.on_finish
, r
);
403 void expect_journal_get_tag_tid(librbd::MockJournal
&mock_journal
,
405 EXPECT_CALL(mock_journal
, get_tag_tid()).WillOnce(Return(tag_tid
));
408 void expect_journal_get_tag_data(librbd::MockJournal
&mock_journal
,
409 const librbd::journal::TagData
&tag_data
) {
410 EXPECT_CALL(mock_journal
, get_tag_data()).WillOnce(Return(tag_data
));
413 void expect_is_resync_requested(librbd::MockJournal
&mock_journal
,
414 bool do_resync
, int r
) {
415 EXPECT_CALL(mock_journal
, is_resync_requested(_
))
416 .WillOnce(DoAll(SetArgPointee
<0>(do_resync
),
420 void expect_create_image(MockCreateImageRequest
&mock_create_image_request
,
421 const std::string
&image_id
, int r
) {
422 EXPECT_CALL(mock_create_image_request
, construct(image_id
));
423 EXPECT_CALL(mock_create_image_request
, send())
424 .WillOnce(Invoke([this, &mock_create_image_request
, r
]() {
425 m_threads
->work_queue
->queue(mock_create_image_request
.on_finish
, r
);
429 void expect_image_sync(MockImageSync
&mock_image_sync
, int r
) {
430 EXPECT_CALL(mock_image_sync
, get());
431 EXPECT_CALL(mock_image_sync
, send())
432 .WillOnce(Invoke([this, &mock_image_sync
, r
]() {
433 m_threads
->work_queue
->queue(mock_image_sync
.on_finish
, r
);
435 EXPECT_CALL(mock_image_sync
, put());
438 bufferlist
encode_tag_data(const librbd::journal::TagData
&tag_data
) {
440 ::encode(tag_data
, bl
);
444 MockBootstrapRequest
*create_request(MockInstanceWatcher
*mock_instance_watcher
,
445 ::journal::MockJournaler
&mock_journaler
,
446 const std::string
&local_image_id
,
447 const std::string
&remote_image_id
,
448 const std::string
&global_image_id
,
449 const std::string
&local_mirror_uuid
,
450 const std::string
&remote_mirror_uuid
,
451 cls::journal::ClientState
*client_state
,
452 librbd::journal::MirrorPeerClientMeta
*mirror_peer_client_meta
,
453 Context
*on_finish
) {
454 return new MockBootstrapRequest(m_local_io_ctx
,
456 mock_instance_watcher
,
457 &m_local_test_image_ctx
,
461 m_threads
->work_queue
,
463 &m_threads
->timer_lock
,
467 client_state
, mirror_peer_client_meta
,
468 on_finish
, &m_do_resync
);
471 librbd::ImageCtx
*m_remote_image_ctx
;
472 librbd::ImageCtx
*m_local_image_ctx
= nullptr;
473 librbd::MockTestImageCtx
*m_local_test_image_ctx
= nullptr;
477 TEST_F(TestMockImageReplayerBootstrapRequest
, NonPrimaryRemoteSyncingState
) {
478 create_local_image();
482 // lookup remote image tag class
483 cls::journal::Client client
;
484 librbd::journal::ClientData client_data
{
485 librbd::journal::ImageClientMeta
{123}};
486 ::encode(client_data
, client
.data
);
487 ::journal::MockJournaler mock_journaler
;
488 expect_journaler_get_client(mock_journaler
,
489 librbd::Journal
<>::IMAGE_CLIENT_ID
,
492 // open the remote image
493 librbd::MockJournal mock_journal
;
494 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
495 MockOpenImageRequest mock_open_image_request
;
496 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
497 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
499 // test if remote image is primary
500 MockIsPrimaryRequest mock_is_primary_request
;
501 expect_is_primary(mock_is_primary_request
, false, 0);
503 // switch the state to replaying
504 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
505 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
506 mock_local_image_ctx
.id
};
507 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
508 client_data
.client_meta
= mirror_peer_client_meta
;
509 expect_journaler_update_client(mock_journaler
, client_data
, 0);
511 MockCloseImageRequest mock_close_image_request
;
512 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
515 MockInstanceWatcher mock_instance_watcher
;
516 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
517 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
518 MockBootstrapRequest
*request
= create_request(
519 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
520 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
521 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
523 ASSERT_EQ(-EREMOTEIO
, ctx
.wait());
526 TEST_F(TestMockImageReplayerBootstrapRequest
, NonPrimaryRemoteNotTagOwner
) {
527 create_local_image();
531 // lookup remote image tag class
532 cls::journal::Client client
;
533 librbd::journal::ClientData client_data
{
534 librbd::journal::ImageClientMeta
{123}};
535 encode(client_data
, client
.data
);
536 ::journal::MockJournaler mock_journaler
;
537 expect_journaler_get_client(mock_journaler
,
538 librbd::Journal
<>::IMAGE_CLIENT_ID
,
541 // open the remote image
542 librbd::MockJournal mock_journal
;
543 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
544 MockOpenImageRequest mock_open_image_request
;
545 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
546 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
548 // test if remote image is primary
549 MockIsPrimaryRequest mock_is_primary_request
;
550 expect_is_primary(mock_is_primary_request
, false, 0);
552 // open the local image
553 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
554 mock_local_image_ctx
.journal
= &mock_journal
;
555 MockOpenLocalImageRequest mock_open_local_image_request
;
556 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
557 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
558 expect_is_resync_requested(mock_journal
, false, 0);
560 expect_journal_get_tag_tid(mock_journal
, 345);
561 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::LOCAL_MIRROR_UUID
,
562 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
565 MockCloseImageRequest mock_close_image_request
;
566 expect_close_image(mock_close_image_request
, mock_local_image_ctx
, 0);
567 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
570 MockInstanceWatcher mock_instance_watcher
;
571 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
572 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
573 mock_local_image_ctx
.id
};
574 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
575 MockBootstrapRequest
*request
= create_request(
576 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
577 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
578 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
580 ASSERT_EQ(-EREMOTEIO
, ctx
.wait());
583 TEST_F(TestMockImageReplayerBootstrapRequest
, RemoteDemotePromote
) {
584 create_local_image();
588 // lookup remote image tag class
589 cls::journal::Client client
;
590 librbd::journal::ClientData client_data
{
591 librbd::journal::ImageClientMeta
{123}};
592 ::encode(client_data
, client
.data
);
593 ::journal::MockJournaler mock_journaler
;
594 expect_journaler_get_client(mock_journaler
,
595 librbd::Journal
<>::IMAGE_CLIENT_ID
,
598 // open the remote image
599 librbd::MockJournal mock_journal
;
600 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
601 MockOpenImageRequest mock_open_image_request
;
602 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
603 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
605 // test if remote image is primary
606 MockIsPrimaryRequest mock_is_primary_request
;
607 expect_is_primary(mock_is_primary_request
, false, 0);
609 // open the local image
610 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
611 mock_local_image_ctx
.journal
= &mock_journal
;
612 MockOpenLocalImageRequest mock_open_local_image_request
;
613 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
614 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
615 expect_is_resync_requested(mock_journal
, false, 0);
617 expect_journal_get_tag_tid(mock_journal
, 345);
618 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
620 // remote demotion / promotion event
622 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
623 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
625 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
626 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
628 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
629 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
631 {5, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
632 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
635 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
637 MockCloseImageRequest mock_close_image_request
;
638 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
641 MockInstanceWatcher mock_instance_watcher
;
642 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
643 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
644 mock_local_image_ctx
.id
};
645 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
646 MockBootstrapRequest
*request
= create_request(
647 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
648 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
649 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
651 ASSERT_EQ(0, ctx
.wait());
654 TEST_F(TestMockImageReplayerBootstrapRequest
, MultipleRemoteDemotePromotes
) {
655 create_local_image();
659 // lookup remote image tag class
660 cls::journal::Client client
;
661 librbd::journal::ClientData client_data
{
662 librbd::journal::ImageClientMeta
{123}};
663 ::encode(client_data
, client
.data
);
664 ::journal::MockJournaler mock_journaler
;
665 expect_journaler_get_client(mock_journaler
,
666 librbd::Journal
<>::IMAGE_CLIENT_ID
,
669 // open the remote image
670 librbd::MockJournal mock_journal
;
671 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
672 MockOpenImageRequest mock_open_image_request
;
673 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
674 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
676 // test if remote image is primary
677 MockIsPrimaryRequest mock_is_primary_request
;
678 expect_is_primary(mock_is_primary_request
, true, 0);
680 // open the local image
681 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
682 mock_local_image_ctx
.journal
= &mock_journal
;
683 MockOpenLocalImageRequest mock_open_local_image_request
;
684 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
685 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
686 expect_is_resync_requested(mock_journal
, false, 0);
688 expect_journal_get_tag_tid(mock_journal
, 345);
689 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
690 "remote mirror uuid", true, 4, 1});
692 // remote demotion / promotion event
694 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
695 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
697 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
698 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
700 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
701 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
703 {5, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
704 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
706 {6, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
707 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
709 {7, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
710 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
712 {8, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
713 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
716 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
718 MockCloseImageRequest mock_close_image_request
;
719 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
722 MockInstanceWatcher mock_instance_watcher
;
723 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
724 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
725 mock_local_image_ctx
.id
};
726 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
727 MockBootstrapRequest
*request
= create_request(
728 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
729 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
730 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
732 ASSERT_EQ(0, ctx
.wait());
735 TEST_F(TestMockImageReplayerBootstrapRequest
, LocalDemoteRemotePromote
) {
736 create_local_image();
740 // lookup remote image tag class
741 cls::journal::Client client
;
742 librbd::journal::ClientData client_data
{
743 librbd::journal::ImageClientMeta
{123}};
744 ::encode(client_data
, client
.data
);
745 ::journal::MockJournaler mock_journaler
;
746 expect_journaler_get_client(mock_journaler
,
747 librbd::Journal
<>::IMAGE_CLIENT_ID
,
750 // open the remote image
751 librbd::MockJournal mock_journal
;
752 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
753 MockOpenImageRequest mock_open_image_request
;
754 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
755 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
757 // test if remote image is primary
758 MockIsPrimaryRequest mock_is_primary_request
;
759 expect_is_primary(mock_is_primary_request
, true, 0);
761 // open the local image
762 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
763 mock_local_image_ctx
.journal
= &mock_journal
;
764 MockOpenLocalImageRequest mock_open_local_image_request
;
765 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
766 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
767 expect_is_resync_requested(mock_journal
, false, 0);
769 expect_journal_get_tag_tid(mock_journal
, 346);
770 expect_journal_get_tag_data(mock_journal
,
771 {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
772 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
775 // remote demotion / promotion event
777 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
779 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
780 "local mirror uuid", true, 345, 1})},
781 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
782 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
785 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
787 MockCloseImageRequest mock_close_image_request
;
788 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
791 MockInstanceWatcher mock_instance_watcher
;
792 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
793 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
794 mock_local_image_ctx
.id
};
795 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
796 MockBootstrapRequest
*request
= create_request(
797 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
798 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
799 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
801 ASSERT_EQ(0, ctx
.wait());
804 TEST_F(TestMockImageReplayerBootstrapRequest
, SplitBrainForcePromote
) {
805 create_local_image();
809 // lookup remote image tag class
810 cls::journal::Client client
;
811 librbd::journal::ClientData client_data
{
812 librbd::journal::ImageClientMeta
{123}};
813 ::encode(client_data
, client
.data
);
814 ::journal::MockJournaler mock_journaler
;
815 expect_journaler_get_client(mock_journaler
,
816 librbd::Journal
<>::IMAGE_CLIENT_ID
,
819 // open the remote image
820 librbd::MockJournal mock_journal
;
821 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
822 MockOpenImageRequest mock_open_image_request
;
823 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
824 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
826 // test if remote image is primary
827 MockIsPrimaryRequest mock_is_primary_request
;
828 expect_is_primary(mock_is_primary_request
, true, 0);
830 // open the local image
831 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
832 mock_local_image_ctx
.journal
= &mock_journal
;
833 MockOpenLocalImageRequest mock_open_local_image_request
;
834 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
835 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
836 expect_is_resync_requested(mock_journal
, false, 0);
838 expect_journal_get_tag_tid(mock_journal
, 345);
839 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::LOCAL_MIRROR_UUID
,
840 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
843 // remote demotion / promotion event
845 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
846 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
848 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
849 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
852 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
854 MockCloseImageRequest mock_close_image_request
;
855 expect_close_image(mock_close_image_request
, mock_local_image_ctx
, 0);
856 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
859 MockInstanceWatcher mock_instance_watcher
;
860 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
861 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
862 mock_local_image_ctx
.id
};
863 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
864 MockBootstrapRequest
*request
= create_request(
865 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
866 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
867 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
869 ASSERT_EQ(-EEXIST
, ctx
.wait());
870 ASSERT_EQ(NULL
, m_local_test_image_ctx
);
873 TEST_F(TestMockImageReplayerBootstrapRequest
, ResyncRequested
) {
874 create_local_image();
878 // lookup remote image tag class
879 cls::journal::Client client
;
880 librbd::journal::ClientData client_data
{
881 librbd::journal::ImageClientMeta
{123}};
882 ::encode(client_data
, client
.data
);
883 ::journal::MockJournaler mock_journaler
;
884 expect_journaler_get_client(mock_journaler
,
885 librbd::Journal
<>::IMAGE_CLIENT_ID
,
888 // open the remote image
889 librbd::MockJournal mock_journal
;
890 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
891 MockOpenImageRequest mock_open_image_request
;
892 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
893 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
895 // test if remote image is primary
896 MockIsPrimaryRequest mock_is_primary_request
;
897 expect_is_primary(mock_is_primary_request
, true, 0);
899 // open the local image
900 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
901 mock_local_image_ctx
.journal
= &mock_journal
;
902 MockOpenLocalImageRequest mock_open_local_image_request
;
903 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
904 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
906 // resync is requested
907 expect_is_resync_requested(mock_journal
, true, 0);
909 expect_journal_get_tag_tid(mock_journal
, 345);
910 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
912 MockCloseImageRequest mock_close_image_request
;
913 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
916 MockInstanceWatcher mock_instance_watcher
;
917 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
918 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
919 mock_local_image_ctx
.id
};
920 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
921 MockBootstrapRequest
*request
= create_request(
922 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
923 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
924 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
927 ASSERT_EQ(0, ctx
.wait());
928 ASSERT_TRUE(m_do_resync
);
931 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemote
) {
932 create_local_image();
936 // lookup remote image tag class
937 cls::journal::Client client
;
938 librbd::journal::ClientData client_data
{
939 librbd::journal::ImageClientMeta
{123}};
940 ::encode(client_data
, client
.data
);
941 ::journal::MockJournaler mock_journaler
;
942 expect_journaler_get_client(mock_journaler
,
943 librbd::Journal
<>::IMAGE_CLIENT_ID
,
946 // open the remote image
947 librbd::MockJournal mock_journal
;
948 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
949 MockOpenImageRequest mock_open_image_request
;
950 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
951 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
953 // test if remote image is primary
954 MockIsPrimaryRequest mock_is_primary_request
;
955 expect_is_primary(mock_is_primary_request
, true, 0);
957 // update client state back to syncing
958 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
959 mock_local_image_ctx
.journal
= &mock_journal
;
961 librbd::util::s_image_id
= mock_local_image_ctx
.id
;
962 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
963 mirror_peer_client_meta
.image_id
= mock_local_image_ctx
.id
;
964 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
965 client_data
.client_meta
= mirror_peer_client_meta
;
967 ::encode(client_data
, client
.data
);
968 expect_journaler_update_client(mock_journaler
, client_data
, 0);
970 // create the local image
971 MockCreateImageRequest mock_create_image_request
;
972 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
974 // open the local image
975 MockOpenLocalImageRequest mock_open_local_image_request
;
976 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
977 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
978 expect_is_resync_requested(mock_journal
, false, 0);
980 expect_journal_get_tag_tid(mock_journal
, 345);
981 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
983 // sync the remote image to the local image
984 MockImageSync mock_image_sync
;
985 expect_image_sync(mock_image_sync
, 0);
987 MockCloseImageRequest mock_close_image_request
;
988 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
991 MockInstanceWatcher mock_instance_watcher
;
992 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
993 mirror_peer_client_meta
.image_id
= "";
994 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
995 MockBootstrapRequest
*request
= create_request(
996 &mock_instance_watcher
, mock_journaler
, "",
997 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
998 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
1000 ASSERT_EQ(0, ctx
.wait());
1003 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemoteLocalDeleted
) {
1004 create_local_image();
1008 // lookup remote image tag class
1009 cls::journal::Client client
;
1010 librbd::journal::ClientData client_data
{
1011 librbd::journal::ImageClientMeta
{123}};
1012 ::encode(client_data
, client
.data
);
1013 ::journal::MockJournaler mock_journaler
;
1014 expect_journaler_get_client(mock_journaler
,
1015 librbd::Journal
<>::IMAGE_CLIENT_ID
,
1018 // open the remote image
1019 librbd::MockJournal mock_journal
;
1020 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
1021 MockOpenImageRequest mock_open_image_request
;
1022 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
1023 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
1025 // test if remote image is primary
1026 MockIsPrimaryRequest mock_is_primary_request
;
1027 expect_is_primary(mock_is_primary_request
, true, 0);
1029 // open the missing local image
1030 MockOpenLocalImageRequest mock_open_local_image_request
;
1031 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
1032 "missing image id", nullptr, -ENOENT
);
1034 // re-register the client
1035 expect_journaler_unregister_client(mock_journaler
, 0);
1036 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
1037 mirror_peer_client_meta
.image_id
= "";
1038 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
1039 client_data
.client_meta
= mirror_peer_client_meta
;
1040 expect_journaler_register_client(mock_journaler
, client_data
, 0);
1042 // test if remote image is primary
1043 expect_is_primary(mock_is_primary_request
, true, 0);
1045 // update client state back to syncing
1046 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
1047 mock_local_image_ctx
.journal
= &mock_journal
;
1049 librbd::util::s_image_id
= mock_local_image_ctx
.id
;
1050 mirror_peer_client_meta
.image_id
= mock_local_image_ctx
.id
;
1051 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
1052 client_data
.client_meta
= mirror_peer_client_meta
;
1053 client
.data
.clear();
1054 ::encode(client_data
, client
.data
);
1055 expect_journaler_update_client(mock_journaler
, client_data
, 0);
1057 // create the missing local image
1058 MockCreateImageRequest mock_create_image_request
;
1059 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
1061 // open the local image
1062 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
1063 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
1064 expect_is_resync_requested(mock_journal
, false, 0);
1066 expect_journal_get_tag_tid(mock_journal
, 345);
1067 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
1069 // sync the remote image to the local image
1070 MockImageSync mock_image_sync
;
1071 expect_image_sync(mock_image_sync
, 0);
1073 MockCloseImageRequest mock_close_image_request
;
1074 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
1077 MockInstanceWatcher mock_instance_watcher
;
1078 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
1079 mirror_peer_client_meta
.image_id
= "missing image id";
1080 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
1081 MockBootstrapRequest
*request
= create_request(
1082 &mock_instance_watcher
, mock_journaler
, "missing image id",
1083 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
1084 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
1086 ASSERT_EQ(0, ctx
.wait());
1089 } // namespace image_replayer
1090 } // namespace mirror