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
, RemoteDemotePromote
) {
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
, true, 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 // remote demotion / promotion event
562 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
563 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
565 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
566 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
568 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
569 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
571 {5, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
572 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
575 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
576 expect_journal_get_tag_tid(mock_journal
, 345);
577 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
579 MockCloseImageRequest mock_close_image_request
;
580 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
583 MockInstanceWatcher mock_instance_watcher
;
584 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
585 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
586 mock_local_image_ctx
.id
};
587 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
588 MockBootstrapRequest
*request
= create_request(
589 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
590 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
591 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
593 ASSERT_EQ(0, ctx
.wait());
596 TEST_F(TestMockImageReplayerBootstrapRequest
, MultipleRemoteDemotePromotes
) {
597 create_local_image();
601 // lookup remote image tag class
602 cls::journal::Client client
;
603 librbd::journal::ClientData client_data
{
604 librbd::journal::ImageClientMeta
{123}};
605 ::encode(client_data
, client
.data
);
606 ::journal::MockJournaler mock_journaler
;
607 expect_journaler_get_client(mock_journaler
,
608 librbd::Journal
<>::IMAGE_CLIENT_ID
,
611 // open the remote image
612 librbd::MockJournal mock_journal
;
613 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
614 MockOpenImageRequest mock_open_image_request
;
615 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
616 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
618 // test if remote image is primary
619 MockIsPrimaryRequest mock_is_primary_request
;
620 expect_is_primary(mock_is_primary_request
, true, 0);
622 // open the local image
623 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
624 mock_local_image_ctx
.journal
= &mock_journal
;
625 MockOpenLocalImageRequest mock_open_local_image_request
;
626 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
627 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
628 expect_is_resync_requested(mock_journal
, false, 0);
630 // remote demotion / promotion event
632 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
633 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
635 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
636 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
638 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
639 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
641 {5, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
642 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
644 {6, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
645 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
647 {7, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
648 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
650 {8, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
651 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
654 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
655 expect_journal_get_tag_tid(mock_journal
, 345);
656 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
657 "remote mirror uuid", true, 4, 1});
659 MockCloseImageRequest mock_close_image_request
;
660 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
663 MockInstanceWatcher mock_instance_watcher
;
664 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
665 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
666 mock_local_image_ctx
.id
};
667 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
668 MockBootstrapRequest
*request
= create_request(
669 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
670 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
671 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
673 ASSERT_EQ(0, ctx
.wait());
676 TEST_F(TestMockImageReplayerBootstrapRequest
, LocalDemoteRemotePromote
) {
677 create_local_image();
681 // lookup remote image tag class
682 cls::journal::Client client
;
683 librbd::journal::ClientData client_data
{
684 librbd::journal::ImageClientMeta
{123}};
685 ::encode(client_data
, client
.data
);
686 ::journal::MockJournaler mock_journaler
;
687 expect_journaler_get_client(mock_journaler
,
688 librbd::Journal
<>::IMAGE_CLIENT_ID
,
691 // open the remote image
692 librbd::MockJournal mock_journal
;
693 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
694 MockOpenImageRequest mock_open_image_request
;
695 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
696 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
698 // test if remote image is primary
699 MockIsPrimaryRequest mock_is_primary_request
;
700 expect_is_primary(mock_is_primary_request
, true, 0);
702 // open the local image
703 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
704 mock_local_image_ctx
.journal
= &mock_journal
;
705 MockOpenLocalImageRequest mock_open_local_image_request
;
706 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
707 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
708 expect_is_resync_requested(mock_journal
, false, 0);
710 // remote demotion / promotion event
712 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
714 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
715 "local mirror uuid", true, 345, 1})},
716 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
717 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
720 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
721 expect_journal_get_tag_tid(mock_journal
, 346);
722 expect_journal_get_tag_data(mock_journal
,
723 {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
724 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
727 MockCloseImageRequest mock_close_image_request
;
728 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
731 MockInstanceWatcher mock_instance_watcher
;
732 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
733 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
734 mock_local_image_ctx
.id
};
735 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
736 MockBootstrapRequest
*request
= create_request(
737 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
738 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
739 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
741 ASSERT_EQ(0, ctx
.wait());
744 TEST_F(TestMockImageReplayerBootstrapRequest
, SplitBrainForcePromote
) {
745 create_local_image();
749 // lookup remote image tag class
750 cls::journal::Client client
;
751 librbd::journal::ClientData client_data
{
752 librbd::journal::ImageClientMeta
{123}};
753 ::encode(client_data
, client
.data
);
754 ::journal::MockJournaler mock_journaler
;
755 expect_journaler_get_client(mock_journaler
,
756 librbd::Journal
<>::IMAGE_CLIENT_ID
,
759 // open the remote image
760 librbd::MockJournal mock_journal
;
761 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
762 MockOpenImageRequest mock_open_image_request
;
763 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
764 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
766 // test if remote image is primary
767 MockIsPrimaryRequest mock_is_primary_request
;
768 expect_is_primary(mock_is_primary_request
, true, 0);
770 // open the local image
771 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
772 mock_local_image_ctx
.journal
= &mock_journal
;
773 MockOpenLocalImageRequest mock_open_local_image_request
;
774 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
775 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
776 expect_is_resync_requested(mock_journal
, false, 0);
778 // remote demotion / promotion event
780 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
781 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
783 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
784 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
787 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
788 expect_journal_get_tag_tid(mock_journal
, 345);
789 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::LOCAL_MIRROR_UUID
,
790 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
793 MockCloseImageRequest mock_close_image_request
;
794 expect_close_image(mock_close_image_request
, mock_local_image_ctx
, 0);
795 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
798 MockInstanceWatcher mock_instance_watcher
;
799 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
800 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
801 mock_local_image_ctx
.id
};
802 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
803 MockBootstrapRequest
*request
= create_request(
804 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
805 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
806 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
808 ASSERT_EQ(-EEXIST
, ctx
.wait());
809 ASSERT_EQ(NULL
, m_local_test_image_ctx
);
812 TEST_F(TestMockImageReplayerBootstrapRequest
, ResyncRequested
) {
813 create_local_image();
817 // lookup remote image tag class
818 cls::journal::Client client
;
819 librbd::journal::ClientData client_data
{
820 librbd::journal::ImageClientMeta
{123}};
821 ::encode(client_data
, client
.data
);
822 ::journal::MockJournaler mock_journaler
;
823 expect_journaler_get_client(mock_journaler
,
824 librbd::Journal
<>::IMAGE_CLIENT_ID
,
827 // open the remote image
828 librbd::MockJournal mock_journal
;
829 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
830 MockOpenImageRequest mock_open_image_request
;
831 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
832 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
834 // test if remote image is primary
835 MockIsPrimaryRequest mock_is_primary_request
;
836 expect_is_primary(mock_is_primary_request
, true, 0);
838 // open the local image
839 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
840 mock_local_image_ctx
.journal
= &mock_journal
;
841 MockOpenLocalImageRequest mock_open_local_image_request
;
842 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
843 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
845 // resync is requested
846 expect_is_resync_requested(mock_journal
, true, 0);
849 MockCloseImageRequest mock_close_image_request
;
850 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
853 MockInstanceWatcher mock_instance_watcher
;
854 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
855 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
856 mock_local_image_ctx
.id
};
857 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
858 MockBootstrapRequest
*request
= create_request(
859 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
860 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
861 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
864 ASSERT_EQ(0, ctx
.wait());
865 ASSERT_TRUE(m_do_resync
);
868 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemote
) {
869 create_local_image();
873 // lookup remote image tag class
874 cls::journal::Client client
;
875 librbd::journal::ClientData client_data
{
876 librbd::journal::ImageClientMeta
{123}};
877 ::encode(client_data
, client
.data
);
878 ::journal::MockJournaler mock_journaler
;
879 expect_journaler_get_client(mock_journaler
,
880 librbd::Journal
<>::IMAGE_CLIENT_ID
,
883 // open the remote image
884 librbd::MockJournal mock_journal
;
885 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
886 MockOpenImageRequest mock_open_image_request
;
887 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
888 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
890 // test if remote image is primary
891 MockIsPrimaryRequest mock_is_primary_request
;
892 expect_is_primary(mock_is_primary_request
, true, 0);
894 // update client state back to syncing
895 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
896 mock_local_image_ctx
.journal
= &mock_journal
;
898 librbd::util::s_image_id
= mock_local_image_ctx
.id
;
899 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
900 mirror_peer_client_meta
.image_id
= mock_local_image_ctx
.id
;
901 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
902 client_data
.client_meta
= mirror_peer_client_meta
;
904 ::encode(client_data
, client
.data
);
905 expect_journaler_update_client(mock_journaler
, client_data
, 0);
907 // create the local image
908 MockCreateImageRequest mock_create_image_request
;
909 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
911 // open the local image
912 MockOpenLocalImageRequest mock_open_local_image_request
;
913 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
914 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
915 expect_is_resync_requested(mock_journal
, false, 0);
917 // sync the remote image to the local image
918 MockImageSync mock_image_sync
;
919 expect_image_sync(mock_image_sync
, 0);
921 MockCloseImageRequest mock_close_image_request
;
922 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
925 MockInstanceWatcher mock_instance_watcher
;
926 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
927 mirror_peer_client_meta
.image_id
= "";
928 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
929 MockBootstrapRequest
*request
= create_request(
930 &mock_instance_watcher
, mock_journaler
, "",
931 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
932 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
934 ASSERT_EQ(0, ctx
.wait());
937 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemoteLocalDeleted
) {
938 create_local_image();
942 // lookup remote image tag class
943 cls::journal::Client client
;
944 librbd::journal::ClientData client_data
{
945 librbd::journal::ImageClientMeta
{123}};
946 ::encode(client_data
, client
.data
);
947 ::journal::MockJournaler mock_journaler
;
948 expect_journaler_get_client(mock_journaler
,
949 librbd::Journal
<>::IMAGE_CLIENT_ID
,
952 // open the remote image
953 librbd::MockJournal mock_journal
;
954 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
955 MockOpenImageRequest mock_open_image_request
;
956 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
957 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
959 // test if remote image is primary
960 MockIsPrimaryRequest mock_is_primary_request
;
961 expect_is_primary(mock_is_primary_request
, true, 0);
963 // open the missing local image
964 MockOpenLocalImageRequest mock_open_local_image_request
;
965 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
966 "missing image id", nullptr, -ENOENT
);
968 // re-register the client
969 expect_journaler_unregister_client(mock_journaler
, 0);
970 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
971 mirror_peer_client_meta
.image_id
= "";
972 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
973 client_data
.client_meta
= mirror_peer_client_meta
;
974 expect_journaler_register_client(mock_journaler
, client_data
, 0);
976 // test if remote image is primary
977 expect_is_primary(mock_is_primary_request
, true, 0);
979 // update client state back to syncing
980 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
981 mock_local_image_ctx
.journal
= &mock_journal
;
983 librbd::util::s_image_id
= mock_local_image_ctx
.id
;
984 mirror_peer_client_meta
.image_id
= mock_local_image_ctx
.id
;
985 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
986 client_data
.client_meta
= mirror_peer_client_meta
;
988 ::encode(client_data
, client
.data
);
989 expect_journaler_update_client(mock_journaler
, client_data
, 0);
991 // create the missing local image
992 MockCreateImageRequest mock_create_image_request
;
993 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
995 // open the local image
996 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
997 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
998 expect_is_resync_requested(mock_journal
, false, 0);
1000 // sync the remote image to the local image
1001 MockImageSync mock_image_sync
;
1002 expect_image_sync(mock_image_sync
, 0);
1004 MockCloseImageRequest mock_close_image_request
;
1005 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
1008 MockInstanceWatcher mock_instance_watcher
;
1009 cls::journal::ClientState client_state
= cls::journal::CLIENT_STATE_CONNECTED
;
1010 mirror_peer_client_meta
.image_id
= "missing image id";
1011 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
1012 MockBootstrapRequest
*request
= create_request(
1013 &mock_instance_watcher
, mock_journaler
, "missing image id",
1014 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
1015 "remote mirror uuid", &client_state
, &mirror_peer_client_meta
, &ctx
);
1017 ASSERT_EQ(0, ctx
.wait());
1020 } // namespace image_replayer
1021 } // namespace mirror