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 Context
*on_finish
) {
452 return new MockBootstrapRequest(m_local_io_ctx
,
454 mock_instance_watcher
,
455 &m_local_test_image_ctx
,
459 m_threads
->work_queue
,
461 &m_threads
->timer_lock
,
465 &m_mirror_peer_client_meta
,
466 on_finish
, &m_do_resync
);
469 librbd::ImageCtx
*m_remote_image_ctx
;
470 librbd::ImageCtx
*m_local_image_ctx
= nullptr;
471 librbd::MockTestImageCtx
*m_local_test_image_ctx
= nullptr;
472 librbd::journal::MirrorPeerClientMeta m_mirror_peer_client_meta
;
476 TEST_F(TestMockImageReplayerBootstrapRequest
, NonPrimaryRemoteSyncingState
) {
477 create_local_image();
481 // lookup remote image tag class
482 cls::journal::Client client
;
483 librbd::journal::ClientData client_data
{
484 librbd::journal::ImageClientMeta
{123}};
485 ::encode(client_data
, client
.data
);
486 ::journal::MockJournaler mock_journaler
;
487 expect_journaler_get_client(mock_journaler
,
488 librbd::Journal
<>::IMAGE_CLIENT_ID
,
491 // open the remote image
492 librbd::MockJournal mock_journal
;
493 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
494 MockOpenImageRequest mock_open_image_request
;
495 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
496 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
498 // lookup local peer in remote journal
499 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
500 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
501 mock_local_image_ctx
.id
};
502 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
503 client_data
.client_meta
= mirror_peer_client_meta
;
505 ::encode(client_data
, client
.data
);
506 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
509 // test if remote image is primary
510 MockIsPrimaryRequest mock_is_primary_request
;
511 expect_is_primary(mock_is_primary_request
, false, 0);
513 // switch the state to replaying
514 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
515 client_data
.client_meta
= mirror_peer_client_meta
;
516 expect_journaler_update_client(mock_journaler
, client_data
, 0);
518 MockCloseImageRequest mock_close_image_request
;
519 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
522 MockInstanceWatcher mock_instance_watcher
;
523 MockBootstrapRequest
*request
= create_request(
524 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
525 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
526 "remote mirror uuid", &ctx
);
528 ASSERT_EQ(-EREMOTEIO
, ctx
.wait());
531 TEST_F(TestMockImageReplayerBootstrapRequest
, RemoteDemotePromote
) {
532 create_local_image();
536 // lookup remote image tag class
537 cls::journal::Client client
;
538 librbd::journal::ClientData client_data
{
539 librbd::journal::ImageClientMeta
{123}};
540 ::encode(client_data
, client
.data
);
541 ::journal::MockJournaler mock_journaler
;
542 expect_journaler_get_client(mock_journaler
,
543 librbd::Journal
<>::IMAGE_CLIENT_ID
,
546 // open the remote image
547 librbd::MockJournal mock_journal
;
548 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
549 MockOpenImageRequest mock_open_image_request
;
550 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
551 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
553 // lookup local peer in remote journal
554 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
555 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
556 mock_local_image_ctx
.id
};
557 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
558 client_data
.client_meta
= mirror_peer_client_meta
;
560 ::encode(client_data
, client
.data
);
561 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
564 // test if remote image is primary
565 MockIsPrimaryRequest mock_is_primary_request
;
566 expect_is_primary(mock_is_primary_request
, true, 0);
568 // open the local image
569 mock_local_image_ctx
.journal
= &mock_journal
;
570 MockOpenLocalImageRequest mock_open_local_image_request
;
571 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
572 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
573 expect_is_resync_requested(mock_journal
, false, 0);
575 // remote demotion / promotion event
577 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
578 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
580 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
581 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
583 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
584 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
586 {5, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
587 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
590 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
591 expect_journal_get_tag_tid(mock_journal
, 345);
592 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
594 MockCloseImageRequest mock_close_image_request
;
595 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
598 MockInstanceWatcher mock_instance_watcher
;
599 MockBootstrapRequest
*request
= create_request(
600 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
601 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
602 "remote mirror uuid", &ctx
);
604 ASSERT_EQ(0, ctx
.wait());
607 TEST_F(TestMockImageReplayerBootstrapRequest
, MultipleRemoteDemotePromotes
) {
608 create_local_image();
612 // lookup remote image tag class
613 cls::journal::Client client
;
614 librbd::journal::ClientData client_data
{
615 librbd::journal::ImageClientMeta
{123}};
616 ::encode(client_data
, client
.data
);
617 ::journal::MockJournaler mock_journaler
;
618 expect_journaler_get_client(mock_journaler
,
619 librbd::Journal
<>::IMAGE_CLIENT_ID
,
622 // open the remote image
623 librbd::MockJournal mock_journal
;
624 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
625 MockOpenImageRequest mock_open_image_request
;
626 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
627 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
629 // lookup local peer in remote journal
630 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
631 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
632 mock_local_image_ctx
.id
};
633 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
634 client_data
.client_meta
= mirror_peer_client_meta
;
636 ::encode(client_data
, client
.data
);
637 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
640 // test if remote image is primary
641 MockIsPrimaryRequest mock_is_primary_request
;
642 expect_is_primary(mock_is_primary_request
, true, 0);
644 // open the local image
645 mock_local_image_ctx
.journal
= &mock_journal
;
646 MockOpenLocalImageRequest mock_open_local_image_request
;
647 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
648 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
649 expect_is_resync_requested(mock_journal
, false, 0);
651 // remote demotion / promotion event
653 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
654 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
656 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
657 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
659 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
660 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
662 {5, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
663 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
665 {6, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
666 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
668 {7, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
669 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
671 {8, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
672 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
675 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
676 expect_journal_get_tag_tid(mock_journal
, 345);
677 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
678 "remote mirror uuid", true, 4, 1});
680 MockCloseImageRequest mock_close_image_request
;
681 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
684 MockInstanceWatcher mock_instance_watcher
;
685 MockBootstrapRequest
*request
= create_request(
686 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
687 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
688 "remote mirror uuid", &ctx
);
690 ASSERT_EQ(0, ctx
.wait());
693 TEST_F(TestMockImageReplayerBootstrapRequest
, LocalDemoteRemotePromote
) {
694 create_local_image();
698 // lookup remote image tag class
699 cls::journal::Client client
;
700 librbd::journal::ClientData client_data
{
701 librbd::journal::ImageClientMeta
{123}};
702 ::encode(client_data
, client
.data
);
703 ::journal::MockJournaler mock_journaler
;
704 expect_journaler_get_client(mock_journaler
,
705 librbd::Journal
<>::IMAGE_CLIENT_ID
,
708 // open the remote image
709 librbd::MockJournal mock_journal
;
710 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
711 MockOpenImageRequest mock_open_image_request
;
712 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
713 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
715 // lookup local peer in remote journal
716 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
717 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
718 mock_local_image_ctx
.id
};
719 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
720 client_data
.client_meta
= mirror_peer_client_meta
;
722 ::encode(client_data
, client
.data
);
723 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
726 // test if remote image is primary
727 MockIsPrimaryRequest mock_is_primary_request
;
728 expect_is_primary(mock_is_primary_request
, true, 0);
730 // open the local image
731 mock_local_image_ctx
.journal
= &mock_journal
;
732 MockOpenLocalImageRequest mock_open_local_image_request
;
733 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
734 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
735 expect_is_resync_requested(mock_journal
, false, 0);
737 // remote demotion / promotion event
739 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
741 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
742 "local mirror uuid", true, 345, 1})},
743 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
744 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
747 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
748 expect_journal_get_tag_tid(mock_journal
, 346);
749 expect_journal_get_tag_data(mock_journal
,
750 {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
751 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
754 MockCloseImageRequest mock_close_image_request
;
755 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
758 MockInstanceWatcher mock_instance_watcher
;
759 MockBootstrapRequest
*request
= create_request(
760 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
761 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
762 "remote mirror uuid", &ctx
);
764 ASSERT_EQ(0, ctx
.wait());
767 TEST_F(TestMockImageReplayerBootstrapRequest
, SplitBrainForcePromote
) {
768 create_local_image();
772 // lookup remote image tag class
773 cls::journal::Client client
;
774 librbd::journal::ClientData client_data
{
775 librbd::journal::ImageClientMeta
{123}};
776 ::encode(client_data
, client
.data
);
777 ::journal::MockJournaler mock_journaler
;
778 expect_journaler_get_client(mock_journaler
,
779 librbd::Journal
<>::IMAGE_CLIENT_ID
,
782 // open the remote image
783 librbd::MockJournal mock_journal
;
784 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
785 MockOpenImageRequest mock_open_image_request
;
786 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
787 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
789 // lookup local peer in remote journal
790 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
791 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
792 mock_local_image_ctx
.id
};
793 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
794 client_data
.client_meta
= mirror_peer_client_meta
;
796 ::encode(client_data
, client
.data
);
797 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
800 // test if remote image is primary
801 MockIsPrimaryRequest mock_is_primary_request
;
802 expect_is_primary(mock_is_primary_request
, true, 0);
804 // open the local image
805 mock_local_image_ctx
.journal
= &mock_journal
;
806 MockOpenLocalImageRequest mock_open_local_image_request
;
807 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
808 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
809 expect_is_resync_requested(mock_journal
, false, 0);
811 // remote demotion / promotion event
813 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
814 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
816 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
817 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
820 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
821 expect_journal_get_tag_tid(mock_journal
, 345);
822 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::LOCAL_MIRROR_UUID
,
823 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
826 MockCloseImageRequest mock_close_image_request
;
827 expect_close_image(mock_close_image_request
, mock_local_image_ctx
, 0);
828 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
831 MockInstanceWatcher mock_instance_watcher
;
832 MockBootstrapRequest
*request
= create_request(
833 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
834 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
835 "remote mirror uuid", &ctx
);
837 ASSERT_EQ(-EEXIST
, ctx
.wait());
838 ASSERT_EQ(NULL
, m_local_test_image_ctx
);
841 TEST_F(TestMockImageReplayerBootstrapRequest
, ResyncRequested
) {
842 create_local_image();
846 // lookup remote image tag class
847 cls::journal::Client client
;
848 librbd::journal::ClientData client_data
{
849 librbd::journal::ImageClientMeta
{123}};
850 ::encode(client_data
, client
.data
);
851 ::journal::MockJournaler mock_journaler
;
852 expect_journaler_get_client(mock_journaler
,
853 librbd::Journal
<>::IMAGE_CLIENT_ID
,
856 // open the remote image
857 librbd::MockJournal mock_journal
;
858 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
859 MockOpenImageRequest mock_open_image_request
;
860 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
861 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
863 // lookup local peer in remote journal
864 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
865 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
866 mock_local_image_ctx
.id
};
867 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
868 client_data
.client_meta
= mirror_peer_client_meta
;
870 ::encode(client_data
, client
.data
);
871 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
874 // test if remote image is primary
875 MockIsPrimaryRequest mock_is_primary_request
;
876 expect_is_primary(mock_is_primary_request
, true, 0);
878 // open the local image
879 mock_local_image_ctx
.journal
= &mock_journal
;
880 MockOpenLocalImageRequest mock_open_local_image_request
;
881 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
882 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
884 // resync is requested
885 expect_is_resync_requested(mock_journal
, true, 0);
888 MockCloseImageRequest mock_close_image_request
;
889 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
892 MockInstanceWatcher mock_instance_watcher
;
893 MockBootstrapRequest
*request
= create_request(
894 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
895 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
896 "remote mirror uuid", &ctx
);
899 ASSERT_EQ(0, ctx
.wait());
900 ASSERT_TRUE(m_do_resync
);
903 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemote
) {
904 create_local_image();
908 // lookup remote image tag class
909 cls::journal::Client client
;
910 librbd::journal::ClientData client_data
{
911 librbd::journal::ImageClientMeta
{123}};
912 ::encode(client_data
, client
.data
);
913 ::journal::MockJournaler mock_journaler
;
914 expect_journaler_get_client(mock_journaler
,
915 librbd::Journal
<>::IMAGE_CLIENT_ID
,
918 // open the remote image
919 librbd::MockJournal mock_journal
;
920 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
921 MockOpenImageRequest mock_open_image_request
;
922 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
923 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
925 // lookup local peer in remote journal
927 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
930 // register missing client in remote journal
931 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
932 client_data
.client_meta
= mirror_peer_client_meta
;
933 expect_journaler_register_client(mock_journaler
, client_data
, 0);
935 // test if remote image is primary
936 MockIsPrimaryRequest mock_is_primary_request
;
937 expect_is_primary(mock_is_primary_request
, true, 0);
939 // update client state back to syncing
940 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
941 mock_local_image_ctx
.journal
= &mock_journal
;
943 librbd::util::s_image_id
= mock_local_image_ctx
.id
;
944 mirror_peer_client_meta
= {mock_local_image_ctx
.id
};
945 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
946 client_data
.client_meta
= mirror_peer_client_meta
;
948 ::encode(client_data
, client
.data
);
949 expect_journaler_update_client(mock_journaler
, client_data
, 0);
951 // create the local image
952 MockCreateImageRequest mock_create_image_request
;
953 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
955 // open the local image
956 MockOpenLocalImageRequest mock_open_local_image_request
;
957 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
958 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
959 expect_is_resync_requested(mock_journal
, false, 0);
961 // sync the remote image to the local image
962 MockImageSync mock_image_sync
;
963 expect_image_sync(mock_image_sync
, 0);
965 MockCloseImageRequest mock_close_image_request
;
966 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
969 MockInstanceWatcher mock_instance_watcher
;
970 MockBootstrapRequest
*request
= create_request(
971 &mock_instance_watcher
, mock_journaler
, "",
972 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
973 "remote mirror uuid", &ctx
);
975 ASSERT_EQ(0, ctx
.wait());
978 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemoteLocalDeleted
) {
979 create_local_image();
983 // lookup remote image tag class
984 cls::journal::Client client
;
985 librbd::journal::ClientData client_data
{
986 librbd::journal::ImageClientMeta
{123}};
987 ::encode(client_data
, client
.data
);
988 ::journal::MockJournaler mock_journaler
;
989 expect_journaler_get_client(mock_journaler
,
990 librbd::Journal
<>::IMAGE_CLIENT_ID
,
993 // open the remote image
994 librbd::MockJournal mock_journal
;
995 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
996 MockOpenImageRequest mock_open_image_request
;
997 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
998 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
1000 // lookup local peer in remote journal
1001 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
1002 "missing image id"};
1003 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
1004 client_data
.client_meta
= mirror_peer_client_meta
;
1005 client
.data
.clear();
1006 ::encode(client_data
, client
.data
);
1007 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
1010 // test if remote image is primary
1011 MockIsPrimaryRequest mock_is_primary_request
;
1012 expect_is_primary(mock_is_primary_request
, true, 0);
1014 // open the missing local image
1015 MockOpenLocalImageRequest mock_open_local_image_request
;
1016 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
1017 "missing image id", nullptr, -ENOENT
);
1019 // re-register the client
1020 expect_journaler_unregister_client(mock_journaler
, 0);
1021 mirror_peer_client_meta
= {};
1022 client_data
.client_meta
= mirror_peer_client_meta
;
1023 expect_journaler_register_client(mock_journaler
, client_data
, 0);
1025 // test if remote image is primary
1026 expect_is_primary(mock_is_primary_request
, true, 0);
1028 // update client state back to syncing
1029 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
1030 mock_local_image_ctx
.journal
= &mock_journal
;
1032 librbd::util::s_image_id
= mock_local_image_ctx
.id
;
1033 mirror_peer_client_meta
= {mock_local_image_ctx
.id
};
1034 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
1035 client_data
.client_meta
= mirror_peer_client_meta
;
1036 client
.data
.clear();
1037 ::encode(client_data
, client
.data
);
1038 expect_journaler_update_client(mock_journaler
, client_data
, 0);
1040 // create the missing local image
1041 MockCreateImageRequest mock_create_image_request
;
1042 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
1044 // open the local image
1045 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
1046 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
1047 expect_is_resync_requested(mock_journal
, false, 0);
1049 // sync the remote image to the local image
1050 MockImageSync mock_image_sync
;
1051 expect_image_sync(mock_image_sync
, 0);
1053 MockCloseImageRequest mock_close_image_request
;
1054 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
1057 MockInstanceWatcher mock_instance_watcher
;
1058 MockBootstrapRequest
*request
= create_request(
1059 &mock_instance_watcher
, mock_journaler
, "",
1060 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
1061 "remote mirror uuid", &ctx
);
1063 ASSERT_EQ(0, ctx
.wait());
1066 } // namespace image_replayer
1067 } // namespace mirror