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
44 class ProgressContext
;
47 struct ImageSync
<librbd::MockTestImageCtx
> {
48 static ImageSync
* s_instance
;
49 Context
*on_finish
= nullptr;
51 static ImageSync
* create(
52 librbd::MockTestImageCtx
*local_image_ctx
,
53 librbd::MockTestImageCtx
*remote_image_ctx
,
54 SafeTimer
*timer
, Mutex
*timer_lock
, const std::string
&mirror_uuid
,
55 ::journal::MockJournaler
*journaler
,
56 librbd::journal::MirrorPeerClientMeta
*client_meta
, ContextWQ
*work_queue
,
57 InstanceWatcher
<librbd::MockTestImageCtx
> *instance_watcher
,
58 Context
*on_finish
, ProgressContext
*progress_ctx
) {
59 assert(s_instance
!= nullptr);
60 s_instance
->on_finish
= on_finish
;
65 assert(s_instance
== nullptr);
72 MOCK_METHOD0(get
, void());
73 MOCK_METHOD0(put
, void());
74 MOCK_METHOD0(send
, void());
75 MOCK_METHOD0(cancel
, void());
78 ImageSync
<librbd::MockTestImageCtx
>*
79 ImageSync
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
82 struct InstanceWatcher
<librbd::MockTestImageCtx
> {
85 namespace image_replayer
{
88 struct CloseImageRequest
<librbd::MockTestImageCtx
> {
89 static CloseImageRequest
* s_instance
;
90 librbd::MockTestImageCtx
**image_ctx
= nullptr;
91 Context
*on_finish
= nullptr;
93 static CloseImageRequest
* create(librbd::MockTestImageCtx
**image_ctx
,
95 assert(s_instance
!= nullptr);
96 s_instance
->image_ctx
= image_ctx
;
97 s_instance
->on_finish
= on_finish
;
98 s_instance
->construct(*image_ctx
);
102 CloseImageRequest() {
103 assert(s_instance
== nullptr);
106 ~CloseImageRequest() {
107 s_instance
= nullptr;
110 MOCK_METHOD1(construct
, void(librbd::MockTestImageCtx
*image_ctx
));
111 MOCK_METHOD0(send
, void());
115 struct CreateImageRequest
<librbd::MockTestImageCtx
> {
116 static CreateImageRequest
* s_instance
;
117 std::string
*local_image_id
= nullptr;
118 Context
*on_finish
= nullptr;
120 static CreateImageRequest
* create(librados::IoCtx
&local_io_ctx
,
121 ContextWQ
*work_queue
,
122 const std::string
&global_image_id
,
123 const std::string
&remote_mirror_uuid
,
124 const std::string
&local_image_name
,
125 librbd::MockTestImageCtx
*remote_image_ctx
,
126 std::string
*local_image_id
,
127 Context
*on_finish
) {
128 assert(s_instance
!= nullptr);
129 s_instance
->local_image_id
= local_image_id
;
130 s_instance
->on_finish
= on_finish
;
134 CreateImageRequest() {
135 assert(s_instance
== nullptr);
138 ~CreateImageRequest() {
139 s_instance
= nullptr;
142 MOCK_METHOD0(send
, void());
146 struct IsPrimaryRequest
<librbd::MockTestImageCtx
> {
147 static IsPrimaryRequest
* s_instance
;
148 bool *primary
= nullptr;
149 Context
*on_finish
= nullptr;
151 static IsPrimaryRequest
* create(librbd::MockTestImageCtx
*image_ctx
,
152 bool *primary
, Context
*on_finish
) {
153 assert(s_instance
!= nullptr);
154 s_instance
->primary
= primary
;
155 s_instance
->on_finish
= on_finish
;
160 assert(s_instance
== nullptr);
163 ~IsPrimaryRequest() {
164 s_instance
= nullptr;
167 MOCK_METHOD0(send
, void());
171 struct OpenImageRequest
<librbd::MockTestImageCtx
> {
172 static OpenImageRequest
* s_instance
;
173 librbd::MockTestImageCtx
**image_ctx
= nullptr;
174 Context
*on_finish
= nullptr;
176 static OpenImageRequest
* create(librados::IoCtx
&io_ctx
,
177 librbd::MockTestImageCtx
**image_ctx
,
178 const std::string
&image_id
,
179 bool read_only
, Context
*on_finish
) {
180 assert(s_instance
!= nullptr);
181 s_instance
->image_ctx
= image_ctx
;
182 s_instance
->on_finish
= on_finish
;
183 s_instance
->construct(io_ctx
, image_id
);
188 assert(s_instance
== nullptr);
191 ~OpenImageRequest() {
192 s_instance
= nullptr;
195 MOCK_METHOD2(construct
, void(librados::IoCtx
&io_ctx
,
196 const std::string
&image_id
));
197 MOCK_METHOD0(send
, void());
201 struct OpenLocalImageRequest
<librbd::MockTestImageCtx
> {
202 static OpenLocalImageRequest
* s_instance
;
203 librbd::MockTestImageCtx
**image_ctx
= nullptr;
204 Context
*on_finish
= nullptr;
206 static OpenLocalImageRequest
* create(librados::IoCtx
&local_io_ctx
,
207 librbd::MockTestImageCtx
**local_image_ctx
,
208 const std::string
&local_image_id
,
209 ContextWQ
*work_queue
,
210 Context
*on_finish
) {
211 assert(s_instance
!= nullptr);
212 s_instance
->image_ctx
= local_image_ctx
;
213 s_instance
->on_finish
= on_finish
;
214 s_instance
->construct(local_io_ctx
, local_image_id
);
218 OpenLocalImageRequest() {
219 assert(s_instance
== nullptr);
222 ~OpenLocalImageRequest() {
223 s_instance
= nullptr;
226 MOCK_METHOD2(construct
, void(librados::IoCtx
&io_ctx
,
227 const std::string
&image_id
));
228 MOCK_METHOD0(send
, void());
231 CloseImageRequest
<librbd::MockTestImageCtx
>*
232 CloseImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
233 CreateImageRequest
<librbd::MockTestImageCtx
>*
234 CreateImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
235 IsPrimaryRequest
<librbd::MockTestImageCtx
>*
236 IsPrimaryRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
237 OpenImageRequest
<librbd::MockTestImageCtx
>*
238 OpenImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
239 OpenLocalImageRequest
<librbd::MockTestImageCtx
>*
240 OpenLocalImageRequest
<librbd::MockTestImageCtx
>::s_instance
= nullptr;
242 } // namespace image_replayer
243 } // namespace mirror
246 // template definitions
247 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
248 template class rbd::mirror::image_replayer::BootstrapRequest
<librbd::MockTestImageCtx
>;
252 namespace image_replayer
{
255 using ::testing::DoAll
;
256 using ::testing::InSequence
;
257 using ::testing::Invoke
;
258 using ::testing::Return
;
259 using ::testing::SetArgPointee
;
260 using ::testing::StrEq
;
261 using ::testing::WithArg
;
263 MATCHER_P(IsSameIoCtx
, io_ctx
, "") {
264 return &get_mock_io_ctx(arg
) == &get_mock_io_ctx(*io_ctx
);
267 class TestMockImageReplayerBootstrapRequest
: public TestMockFixture
{
269 typedef BootstrapRequest
<librbd::MockTestImageCtx
> MockBootstrapRequest
;
270 typedef CloseImageRequest
<librbd::MockTestImageCtx
> MockCloseImageRequest
;
271 typedef CreateImageRequest
<librbd::MockTestImageCtx
> MockCreateImageRequest
;
272 typedef ImageSync
<librbd::MockTestImageCtx
> MockImageSync
;
273 typedef InstanceWatcher
<librbd::MockTestImageCtx
> MockInstanceWatcher
;
274 typedef IsPrimaryRequest
<librbd::MockTestImageCtx
> MockIsPrimaryRequest
;
275 typedef OpenImageRequest
<librbd::MockTestImageCtx
> MockOpenImageRequest
;
276 typedef OpenLocalImageRequest
<librbd::MockTestImageCtx
> MockOpenLocalImageRequest
;
277 typedef std::list
<cls::journal::Tag
> Tags
;
279 void SetUp() override
{
280 TestMockFixture::SetUp();
283 ASSERT_EQ(0, create_image(rbd
, m_remote_io_ctx
, m_image_name
, m_image_size
));
284 ASSERT_EQ(0, open_image(m_remote_io_ctx
, m_image_name
, &m_remote_image_ctx
));
287 void create_local_image() {
289 ASSERT_EQ(0, create_image(rbd
, m_local_io_ctx
, m_image_name
, m_image_size
));
290 ASSERT_EQ(0, open_image(m_local_io_ctx
, m_image_name
, &m_local_image_ctx
));
293 void expect_journaler_get_client(::journal::MockJournaler
&mock_journaler
,
294 const std::string
&client_id
,
295 cls::journal::Client
&client
, int r
) {
296 EXPECT_CALL(mock_journaler
, get_client(StrEq(client_id
), _
, _
))
297 .WillOnce(DoAll(WithArg
<1>(Invoke([client
](cls::journal::Client
*out_client
) {
298 *out_client
= client
;
300 WithArg
<2>(Invoke([this, r
](Context
*on_finish
) {
301 m_threads
->work_queue
->queue(on_finish
, r
);
305 void expect_journaler_get_tags(::journal::MockJournaler
&mock_journaler
,
306 uint64_t tag_class
, const Tags
& tags
,
308 EXPECT_CALL(mock_journaler
, get_tags(tag_class
, _
, _
))
309 .WillOnce(DoAll(WithArg
<1>(Invoke([tags
](Tags
*out_tags
) {
312 WithArg
<2>(Invoke([this, r
](Context
*on_finish
) {
313 m_threads
->work_queue
->queue(on_finish
, r
);
317 void expect_journaler_register_client(::journal::MockJournaler
&mock_journaler
,
318 const librbd::journal::ClientData
&client_data
,
321 ::encode(client_data
, bl
);
323 EXPECT_CALL(mock_journaler
, register_client(ContentsEqual(bl
), _
))
324 .WillOnce(WithArg
<1>(Invoke([this, r
](Context
*on_finish
) {
325 m_threads
->work_queue
->queue(on_finish
, r
);
329 void expect_journaler_update_client(::journal::MockJournaler
&mock_journaler
,
330 const librbd::journal::ClientData
&client_data
,
333 ::encode(client_data
, bl
);
335 EXPECT_CALL(mock_journaler
, update_client(ContentsEqual(bl
), _
))
336 .WillOnce(WithArg
<1>(Invoke([this, r
](Context
*on_finish
) {
337 m_threads
->work_queue
->queue(on_finish
, r
);
341 void expect_open_image(MockOpenImageRequest
&mock_open_image_request
,
342 librados::IoCtx
&io_ctx
, const std::string
&image_id
,
343 librbd::MockTestImageCtx
&mock_image_ctx
, int r
) {
344 EXPECT_CALL(mock_open_image_request
, construct(IsSameIoCtx(&io_ctx
), image_id
));
345 EXPECT_CALL(mock_open_image_request
, send())
346 .WillOnce(Invoke([this, &mock_open_image_request
, &mock_image_ctx
, r
]() {
347 *mock_open_image_request
.image_ctx
= &mock_image_ctx
;
348 m_threads
->work_queue
->queue(mock_open_image_request
.on_finish
, r
);
352 void expect_open_local_image(MockOpenLocalImageRequest
&mock_open_local_image_request
,
353 librados::IoCtx
&io_ctx
, const std::string
&image_id
,
354 librbd::MockTestImageCtx
*mock_image_ctx
, int r
) {
355 EXPECT_CALL(mock_open_local_image_request
,
356 construct(IsSameIoCtx(&io_ctx
), image_id
));
357 EXPECT_CALL(mock_open_local_image_request
, send())
358 .WillOnce(Invoke([this, &mock_open_local_image_request
, mock_image_ctx
, r
]() {
359 *mock_open_local_image_request
.image_ctx
= mock_image_ctx
;
360 m_threads
->work_queue
->queue(mock_open_local_image_request
.on_finish
,
365 void expect_close_image(MockCloseImageRequest
&mock_close_image_request
,
366 librbd::MockTestImageCtx
&mock_image_ctx
, int r
) {
367 EXPECT_CALL(mock_close_image_request
, construct(&mock_image_ctx
));
368 EXPECT_CALL(mock_close_image_request
, send())
369 .WillOnce(Invoke([this, &mock_close_image_request
, r
]() {
370 *mock_close_image_request
.image_ctx
= nullptr;
371 m_threads
->work_queue
->queue(mock_close_image_request
.on_finish
, r
);
375 void expect_is_primary(MockIsPrimaryRequest
&mock_is_primary_request
,
376 bool primary
, int r
) {
377 EXPECT_CALL(mock_is_primary_request
, send())
378 .WillOnce(Invoke([this, &mock_is_primary_request
, primary
, r
]() {
379 *mock_is_primary_request
.primary
= primary
;
380 m_threads
->work_queue
->queue(mock_is_primary_request
.on_finish
, r
);
384 void expect_journal_get_tag_tid(librbd::MockJournal
&mock_journal
,
386 EXPECT_CALL(mock_journal
, get_tag_tid()).WillOnce(Return(tag_tid
));
389 void expect_journal_get_tag_data(librbd::MockJournal
&mock_journal
,
390 const librbd::journal::TagData
&tag_data
) {
391 EXPECT_CALL(mock_journal
, get_tag_data()).WillOnce(Return(tag_data
));
394 void expect_is_resync_requested(librbd::MockJournal
&mock_journal
,
395 bool do_resync
, int r
) {
396 EXPECT_CALL(mock_journal
, is_resync_requested(_
))
397 .WillOnce(DoAll(SetArgPointee
<0>(do_resync
),
401 void expect_create_image(MockCreateImageRequest
&mock_create_image_request
,
402 const std::string
&image_id
, int r
) {
403 EXPECT_CALL(mock_create_image_request
, send())
404 .WillOnce(Invoke([this, &mock_create_image_request
, image_id
, r
]() {
405 *mock_create_image_request
.local_image_id
= image_id
;
406 m_threads
->work_queue
->queue(mock_create_image_request
.on_finish
, r
);
410 void expect_image_sync(MockImageSync
&mock_image_sync
, int r
) {
411 EXPECT_CALL(mock_image_sync
, get());
412 EXPECT_CALL(mock_image_sync
, send())
413 .WillOnce(Invoke([this, &mock_image_sync
, r
]() {
414 m_threads
->work_queue
->queue(mock_image_sync
.on_finish
, r
);
416 EXPECT_CALL(mock_image_sync
, put());
419 bufferlist
encode_tag_data(const librbd::journal::TagData
&tag_data
) {
421 ::encode(tag_data
, bl
);
425 MockBootstrapRequest
*create_request(MockInstanceWatcher
*mock_instance_watcher
,
426 ::journal::MockJournaler
&mock_journaler
,
427 const std::string
&local_image_id
,
428 const std::string
&remote_image_id
,
429 const std::string
&global_image_id
,
430 const std::string
&local_mirror_uuid
,
431 const std::string
&remote_mirror_uuid
,
432 Context
*on_finish
) {
433 return new MockBootstrapRequest(m_local_io_ctx
,
435 mock_instance_watcher
,
436 &m_local_test_image_ctx
,
440 m_threads
->work_queue
,
442 &m_threads
->timer_lock
,
446 &m_mirror_peer_client_meta
,
447 on_finish
, &m_do_resync
);
450 librbd::ImageCtx
*m_remote_image_ctx
;
451 librbd::ImageCtx
*m_local_image_ctx
= nullptr;
452 librbd::MockTestImageCtx
*m_local_test_image_ctx
= nullptr;
453 librbd::journal::MirrorPeerClientMeta m_mirror_peer_client_meta
;
457 TEST_F(TestMockImageReplayerBootstrapRequest
, NonPrimaryRemoteSyncingState
) {
458 create_local_image();
462 // lookup remote image tag class
463 cls::journal::Client client
;
464 librbd::journal::ClientData client_data
{
465 librbd::journal::ImageClientMeta
{123}};
466 ::encode(client_data
, client
.data
);
467 ::journal::MockJournaler mock_journaler
;
468 expect_journaler_get_client(mock_journaler
,
469 librbd::Journal
<>::IMAGE_CLIENT_ID
,
472 // lookup local peer in remote journal
473 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
474 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
475 mock_local_image_ctx
.id
};
476 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
477 client_data
.client_meta
= mirror_peer_client_meta
;
479 ::encode(client_data
, client
.data
);
480 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
483 // open the remote image
484 librbd::MockJournal mock_journal
;
485 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
486 MockOpenImageRequest mock_open_image_request
;
487 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
488 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
489 MockIsPrimaryRequest mock_is_primary_request
;
490 expect_is_primary(mock_is_primary_request
, false, 0);
492 // switch the state to replaying
493 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
494 client_data
.client_meta
= mirror_peer_client_meta
;
495 expect_journaler_update_client(mock_journaler
, client_data
, 0);
497 MockCloseImageRequest mock_close_image_request
;
498 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
501 MockInstanceWatcher mock_instance_watcher
;
502 MockBootstrapRequest
*request
= create_request(
503 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
504 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
505 "remote mirror uuid", &ctx
);
507 ASSERT_EQ(-EREMOTEIO
, ctx
.wait());
510 TEST_F(TestMockImageReplayerBootstrapRequest
, RemoteDemotePromote
) {
511 create_local_image();
515 // lookup remote image tag class
516 cls::journal::Client client
;
517 librbd::journal::ClientData client_data
{
518 librbd::journal::ImageClientMeta
{123}};
519 ::encode(client_data
, client
.data
);
520 ::journal::MockJournaler mock_journaler
;
521 expect_journaler_get_client(mock_journaler
,
522 librbd::Journal
<>::IMAGE_CLIENT_ID
,
525 // lookup local peer in remote journal
526 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
527 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
528 mock_local_image_ctx
.id
};
529 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
530 client_data
.client_meta
= mirror_peer_client_meta
;
532 ::encode(client_data
, client
.data
);
533 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
536 // open the remote image
537 librbd::MockJournal mock_journal
;
538 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
539 MockOpenImageRequest mock_open_image_request
;
540 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
541 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
542 MockIsPrimaryRequest mock_is_primary_request
;
543 expect_is_primary(mock_is_primary_request
, true, 0);
545 // open the local image
546 mock_local_image_ctx
.journal
= &mock_journal
;
547 MockOpenLocalImageRequest mock_open_local_image_request
;
548 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
549 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
550 expect_is_resync_requested(mock_journal
, false, 0);
552 // remote demotion / promotion event
554 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
555 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
557 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
558 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
560 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
561 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
563 {5, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
564 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
567 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
568 expect_journal_get_tag_tid(mock_journal
, 345);
569 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
571 MockCloseImageRequest mock_close_image_request
;
572 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
575 MockInstanceWatcher mock_instance_watcher
;
576 MockBootstrapRequest
*request
= create_request(
577 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
578 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
579 "remote mirror uuid", &ctx
);
581 ASSERT_EQ(0, ctx
.wait());
584 TEST_F(TestMockImageReplayerBootstrapRequest
, MultipleRemoteDemotePromotes
) {
585 create_local_image();
589 // lookup remote image tag class
590 cls::journal::Client client
;
591 librbd::journal::ClientData client_data
{
592 librbd::journal::ImageClientMeta
{123}};
593 ::encode(client_data
, client
.data
);
594 ::journal::MockJournaler mock_journaler
;
595 expect_journaler_get_client(mock_journaler
,
596 librbd::Journal
<>::IMAGE_CLIENT_ID
,
599 // lookup local peer in remote journal
600 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
601 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
602 mock_local_image_ctx
.id
};
603 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
604 client_data
.client_meta
= mirror_peer_client_meta
;
606 ::encode(client_data
, client
.data
);
607 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
610 // open the remote image
611 librbd::MockJournal mock_journal
;
612 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
613 MockOpenImageRequest mock_open_image_request
;
614 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
615 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
616 MockIsPrimaryRequest mock_is_primary_request
;
617 expect_is_primary(mock_is_primary_request
, true, 0);
619 // open the local image
620 mock_local_image_ctx
.journal
= &mock_journal
;
621 MockOpenLocalImageRequest mock_open_local_image_request
;
622 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
623 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
624 expect_is_resync_requested(mock_journal
, false, 0);
626 // remote demotion / promotion event
628 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
629 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
631 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
632 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
634 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
635 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
637 {5, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
638 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
640 {6, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
641 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
643 {7, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
644 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
646 {8, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
647 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
650 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
651 expect_journal_get_tag_tid(mock_journal
, 345);
652 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
653 "remote mirror uuid", true, 4, 1});
655 MockCloseImageRequest mock_close_image_request
;
656 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
659 MockInstanceWatcher mock_instance_watcher
;
660 MockBootstrapRequest
*request
= create_request(
661 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
662 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
663 "remote mirror uuid", &ctx
);
665 ASSERT_EQ(0, ctx
.wait());
668 TEST_F(TestMockImageReplayerBootstrapRequest
, LocalDemoteRemotePromote
) {
669 create_local_image();
673 // lookup remote image tag class
674 cls::journal::Client client
;
675 librbd::journal::ClientData client_data
{
676 librbd::journal::ImageClientMeta
{123}};
677 ::encode(client_data
, client
.data
);
678 ::journal::MockJournaler mock_journaler
;
679 expect_journaler_get_client(mock_journaler
,
680 librbd::Journal
<>::IMAGE_CLIENT_ID
,
683 // lookup local peer in remote journal
684 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
685 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
686 mock_local_image_ctx
.id
};
687 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
688 client_data
.client_meta
= mirror_peer_client_meta
;
690 ::encode(client_data
, client
.data
);
691 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
694 // open the remote image
695 librbd::MockJournal mock_journal
;
696 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
697 MockOpenImageRequest mock_open_image_request
;
698 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
699 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
700 MockIsPrimaryRequest mock_is_primary_request
;
701 expect_is_primary(mock_is_primary_request
, true, 0);
703 // open the local image
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 MockBootstrapRequest
*request
= create_request(
733 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
734 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
735 "remote mirror uuid", &ctx
);
737 ASSERT_EQ(0, ctx
.wait());
740 TEST_F(TestMockImageReplayerBootstrapRequest
, SplitBrainForcePromote
) {
741 create_local_image();
745 // lookup remote image tag class
746 cls::journal::Client client
;
747 librbd::journal::ClientData client_data
{
748 librbd::journal::ImageClientMeta
{123}};
749 ::encode(client_data
, client
.data
);
750 ::journal::MockJournaler mock_journaler
;
751 expect_journaler_get_client(mock_journaler
,
752 librbd::Journal
<>::IMAGE_CLIENT_ID
,
755 // lookup local peer in remote journal
756 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
757 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
758 mock_local_image_ctx
.id
};
759 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
760 client_data
.client_meta
= mirror_peer_client_meta
;
762 ::encode(client_data
, client
.data
);
763 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
766 // open the remote image
767 librbd::MockJournal mock_journal
;
768 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
769 MockOpenImageRequest mock_open_image_request
;
770 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
771 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
772 MockIsPrimaryRequest mock_is_primary_request
;
773 expect_is_primary(mock_is_primary_request
, true, 0);
775 // open the local image
776 mock_local_image_ctx
.journal
= &mock_journal
;
777 MockOpenLocalImageRequest mock_open_local_image_request
;
778 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
779 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
780 expect_is_resync_requested(mock_journal
, false, 0);
782 // remote demotion / promotion event
784 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
785 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
787 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
788 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
791 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
792 expect_journal_get_tag_tid(mock_journal
, 345);
793 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::LOCAL_MIRROR_UUID
,
794 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
797 MockCloseImageRequest mock_close_image_request
;
798 expect_close_image(mock_close_image_request
, mock_local_image_ctx
, 0);
799 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
802 MockInstanceWatcher mock_instance_watcher
;
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", &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 // lookup local peer in remote journal
828 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
829 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
830 mock_local_image_ctx
.id
};
831 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
832 client_data
.client_meta
= mirror_peer_client_meta
;
834 ::encode(client_data
, client
.data
);
835 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
838 // open the remote image
839 librbd::MockJournal mock_journal
;
840 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
841 MockOpenImageRequest mock_open_image_request
;
842 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
843 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
844 MockIsPrimaryRequest mock_is_primary_request
;
845 expect_is_primary(mock_is_primary_request
, true, 0);
847 // open the local image
848 mock_local_image_ctx
.journal
= &mock_journal
;
849 MockOpenLocalImageRequest mock_open_local_image_request
;
850 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
851 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
853 // resync is requested
854 expect_is_resync_requested(mock_journal
, true, 0);
857 MockCloseImageRequest mock_close_image_request
;
858 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
861 MockInstanceWatcher mock_instance_watcher
;
862 MockBootstrapRequest
*request
= create_request(
863 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
864 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
865 "remote mirror uuid", &ctx
);
868 ASSERT_EQ(0, ctx
.wait());
869 ASSERT_TRUE(m_do_resync
);
872 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemote
) {
873 create_local_image();
877 // lookup remote image tag class
878 cls::journal::Client client
;
879 librbd::journal::ClientData client_data
{
880 librbd::journal::ImageClientMeta
{123}};
881 ::encode(client_data
, client
.data
);
882 ::journal::MockJournaler mock_journaler
;
883 expect_journaler_get_client(mock_journaler
,
884 librbd::Journal
<>::IMAGE_CLIENT_ID
,
887 // lookup local peer in remote journal
889 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
892 // register missing client in remote journal
893 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
894 client_data
.client_meta
= mirror_peer_client_meta
;
895 expect_journaler_register_client(mock_journaler
, client_data
, 0);
897 // open the remote image
898 librbd::MockJournal mock_journal
;
899 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
900 MockOpenImageRequest mock_open_image_request
;
901 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
902 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
903 MockIsPrimaryRequest mock_is_primary_request
;
904 expect_is_primary(mock_is_primary_request
, true, 0);
906 // create the local image
907 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
908 mock_local_image_ctx
.journal
= &mock_journal
;
910 MockCreateImageRequest mock_create_image_request
;
911 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
913 // open the local image
914 MockOpenLocalImageRequest mock_open_local_image_request
;
915 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
916 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
917 expect_is_resync_requested(mock_journal
, false, 0);
919 // update client state back to syncing
920 mirror_peer_client_meta
= {mock_local_image_ctx
.id
};
921 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
922 client_data
.client_meta
= mirror_peer_client_meta
;
924 ::encode(client_data
, client
.data
);
925 expect_journaler_update_client(mock_journaler
, client_data
, 0);
927 // sync the remote image to the local image
928 MockImageSync mock_image_sync
;
929 expect_image_sync(mock_image_sync
, 0);
931 MockCloseImageRequest mock_close_image_request
;
932 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
935 MockInstanceWatcher mock_instance_watcher
;
936 MockBootstrapRequest
*request
= create_request(
937 &mock_instance_watcher
, mock_journaler
, "",
938 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
939 "remote mirror uuid", &ctx
);
941 ASSERT_EQ(0, ctx
.wait());
944 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemoteLocalDeleted
) {
945 create_local_image();
949 // lookup remote image tag class
950 cls::journal::Client client
;
951 librbd::journal::ClientData client_data
{
952 librbd::journal::ImageClientMeta
{123}};
953 ::encode(client_data
, client
.data
);
954 ::journal::MockJournaler mock_journaler
;
955 expect_journaler_get_client(mock_journaler
,
956 librbd::Journal
<>::IMAGE_CLIENT_ID
,
959 // lookup local peer in remote journal
960 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
962 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
963 client_data
.client_meta
= mirror_peer_client_meta
;
965 ::encode(client_data
, client
.data
);
966 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
969 // open the remote image
970 librbd::MockJournal mock_journal
;
971 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
972 MockOpenImageRequest mock_open_image_request
;
973 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
974 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
975 MockIsPrimaryRequest mock_is_primary_request
;
976 expect_is_primary(mock_is_primary_request
, true, 0);
978 // open the missing local image
979 MockOpenLocalImageRequest mock_open_local_image_request
;
980 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
981 "missing image id", nullptr, -ENOENT
);
983 // create the missing local image
984 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
985 mock_local_image_ctx
.journal
= &mock_journal
;
987 MockCreateImageRequest mock_create_image_request
;
988 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
990 // open the local image
991 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
992 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
993 expect_is_resync_requested(mock_journal
, false, 0);
995 // update client state back to syncing
996 mirror_peer_client_meta
= {mock_local_image_ctx
.id
};
997 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
998 client_data
.client_meta
= mirror_peer_client_meta
;
1000 ::encode(client_data
, client
.data
);
1001 expect_journaler_update_client(mock_journaler
, client_data
, 0);
1003 // sync the remote image to the local image
1004 MockImageSync mock_image_sync
;
1005 expect_image_sync(mock_image_sync
, 0);
1007 MockCloseImageRequest mock_close_image_request
;
1008 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
1011 MockInstanceWatcher mock_instance_watcher
;
1012 MockBootstrapRequest
*request
= create_request(
1013 &mock_instance_watcher
, mock_journaler
, "",
1014 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
1015 "remote mirror uuid", &ctx
);
1017 ASSERT_EQ(0, ctx
.wait());
1020 } // namespace image_replayer
1021 } // namespace mirror