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"
251 namespace image_replayer
{
254 using ::testing::DoAll
;
255 using ::testing::InSequence
;
256 using ::testing::Invoke
;
257 using ::testing::Return
;
258 using ::testing::SetArgPointee
;
259 using ::testing::StrEq
;
260 using ::testing::WithArg
;
262 MATCHER_P(IsSameIoCtx
, io_ctx
, "") {
263 return &get_mock_io_ctx(arg
) == &get_mock_io_ctx(*io_ctx
);
266 class TestMockImageReplayerBootstrapRequest
: public TestMockFixture
{
268 typedef BootstrapRequest
<librbd::MockTestImageCtx
> MockBootstrapRequest
;
269 typedef CloseImageRequest
<librbd::MockTestImageCtx
> MockCloseImageRequest
;
270 typedef CreateImageRequest
<librbd::MockTestImageCtx
> MockCreateImageRequest
;
271 typedef ImageSync
<librbd::MockTestImageCtx
> MockImageSync
;
272 typedef InstanceWatcher
<librbd::MockTestImageCtx
> MockInstanceWatcher
;
273 typedef IsPrimaryRequest
<librbd::MockTestImageCtx
> MockIsPrimaryRequest
;
274 typedef OpenImageRequest
<librbd::MockTestImageCtx
> MockOpenImageRequest
;
275 typedef OpenLocalImageRequest
<librbd::MockTestImageCtx
> MockOpenLocalImageRequest
;
276 typedef std::list
<cls::journal::Tag
> Tags
;
278 void SetUp() override
{
279 TestMockFixture::SetUp();
282 ASSERT_EQ(0, create_image(rbd
, m_remote_io_ctx
, m_image_name
, m_image_size
));
283 ASSERT_EQ(0, open_image(m_remote_io_ctx
, m_image_name
, &m_remote_image_ctx
));
286 void create_local_image() {
288 ASSERT_EQ(0, create_image(rbd
, m_local_io_ctx
, m_image_name
, m_image_size
));
289 ASSERT_EQ(0, open_image(m_local_io_ctx
, m_image_name
, &m_local_image_ctx
));
292 void expect_journaler_get_client(::journal::MockJournaler
&mock_journaler
,
293 const std::string
&client_id
,
294 cls::journal::Client
&client
, int r
) {
295 EXPECT_CALL(mock_journaler
, get_client(StrEq(client_id
), _
, _
))
296 .WillOnce(DoAll(WithArg
<1>(Invoke([client
](cls::journal::Client
*out_client
) {
297 *out_client
= client
;
299 WithArg
<2>(Invoke([this, r
](Context
*on_finish
) {
300 m_threads
->work_queue
->queue(on_finish
, r
);
304 void expect_journaler_get_tags(::journal::MockJournaler
&mock_journaler
,
305 uint64_t tag_class
, const Tags
& tags
,
307 EXPECT_CALL(mock_journaler
, get_tags(tag_class
, _
, _
))
308 .WillOnce(DoAll(WithArg
<1>(Invoke([tags
](Tags
*out_tags
) {
311 WithArg
<2>(Invoke([this, r
](Context
*on_finish
) {
312 m_threads
->work_queue
->queue(on_finish
, r
);
316 void expect_journaler_register_client(::journal::MockJournaler
&mock_journaler
,
317 const librbd::journal::ClientData
&client_data
,
320 ::encode(client_data
, bl
);
322 EXPECT_CALL(mock_journaler
, register_client(ContentsEqual(bl
), _
))
323 .WillOnce(WithArg
<1>(Invoke([this, r
](Context
*on_finish
) {
324 m_threads
->work_queue
->queue(on_finish
, r
);
328 void expect_journaler_update_client(::journal::MockJournaler
&mock_journaler
,
329 const librbd::journal::ClientData
&client_data
,
332 ::encode(client_data
, bl
);
334 EXPECT_CALL(mock_journaler
, update_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_open_image(MockOpenImageRequest
&mock_open_image_request
,
341 librados::IoCtx
&io_ctx
, const std::string
&image_id
,
342 librbd::MockTestImageCtx
&mock_image_ctx
, int r
) {
343 EXPECT_CALL(mock_open_image_request
, construct(IsSameIoCtx(&io_ctx
), image_id
));
344 EXPECT_CALL(mock_open_image_request
, send())
345 .WillOnce(Invoke([this, &mock_open_image_request
, &mock_image_ctx
, r
]() {
346 *mock_open_image_request
.image_ctx
= &mock_image_ctx
;
347 m_threads
->work_queue
->queue(mock_open_image_request
.on_finish
, r
);
351 void expect_open_local_image(MockOpenLocalImageRequest
&mock_open_local_image_request
,
352 librados::IoCtx
&io_ctx
, const std::string
&image_id
,
353 librbd::MockTestImageCtx
*mock_image_ctx
, int r
) {
354 EXPECT_CALL(mock_open_local_image_request
,
355 construct(IsSameIoCtx(&io_ctx
), image_id
));
356 EXPECT_CALL(mock_open_local_image_request
, send())
357 .WillOnce(Invoke([this, &mock_open_local_image_request
, mock_image_ctx
, r
]() {
358 *mock_open_local_image_request
.image_ctx
= mock_image_ctx
;
359 m_threads
->work_queue
->queue(mock_open_local_image_request
.on_finish
,
364 void expect_close_image(MockCloseImageRequest
&mock_close_image_request
,
365 librbd::MockTestImageCtx
&mock_image_ctx
, int r
) {
366 EXPECT_CALL(mock_close_image_request
, construct(&mock_image_ctx
));
367 EXPECT_CALL(mock_close_image_request
, send())
368 .WillOnce(Invoke([this, &mock_close_image_request
, r
]() {
369 *mock_close_image_request
.image_ctx
= nullptr;
370 m_threads
->work_queue
->queue(mock_close_image_request
.on_finish
, r
);
374 void expect_is_primary(MockIsPrimaryRequest
&mock_is_primary_request
,
375 bool primary
, int r
) {
376 EXPECT_CALL(mock_is_primary_request
, send())
377 .WillOnce(Invoke([this, &mock_is_primary_request
, primary
, r
]() {
378 *mock_is_primary_request
.primary
= primary
;
379 m_threads
->work_queue
->queue(mock_is_primary_request
.on_finish
, r
);
383 void expect_journal_get_tag_tid(librbd::MockJournal
&mock_journal
,
385 EXPECT_CALL(mock_journal
, get_tag_tid()).WillOnce(Return(tag_tid
));
388 void expect_journal_get_tag_data(librbd::MockJournal
&mock_journal
,
389 const librbd::journal::TagData
&tag_data
) {
390 EXPECT_CALL(mock_journal
, get_tag_data()).WillOnce(Return(tag_data
));
393 void expect_is_resync_requested(librbd::MockJournal
&mock_journal
,
394 bool do_resync
, int r
) {
395 EXPECT_CALL(mock_journal
, is_resync_requested(_
))
396 .WillOnce(DoAll(SetArgPointee
<0>(do_resync
),
400 void expect_create_image(MockCreateImageRequest
&mock_create_image_request
,
401 const std::string
&image_id
, int r
) {
402 EXPECT_CALL(mock_create_image_request
, send())
403 .WillOnce(Invoke([this, &mock_create_image_request
, image_id
, r
]() {
404 *mock_create_image_request
.local_image_id
= image_id
;
405 m_threads
->work_queue
->queue(mock_create_image_request
.on_finish
, r
);
409 void expect_image_sync(MockImageSync
&mock_image_sync
, int r
) {
410 EXPECT_CALL(mock_image_sync
, get());
411 EXPECT_CALL(mock_image_sync
, send())
412 .WillOnce(Invoke([this, &mock_image_sync
, r
]() {
413 m_threads
->work_queue
->queue(mock_image_sync
.on_finish
, r
);
415 EXPECT_CALL(mock_image_sync
, put());
418 bufferlist
encode_tag_data(const librbd::journal::TagData
&tag_data
) {
420 ::encode(tag_data
, bl
);
424 MockBootstrapRequest
*create_request(MockInstanceWatcher
*mock_instance_watcher
,
425 ::journal::MockJournaler
&mock_journaler
,
426 const std::string
&local_image_id
,
427 const std::string
&remote_image_id
,
428 const std::string
&global_image_id
,
429 const std::string
&local_mirror_uuid
,
430 const std::string
&remote_mirror_uuid
,
431 Context
*on_finish
) {
432 return new MockBootstrapRequest(m_local_io_ctx
,
434 mock_instance_watcher
,
435 &m_local_test_image_ctx
,
439 m_threads
->work_queue
,
441 &m_threads
->timer_lock
,
445 &m_mirror_peer_client_meta
,
446 on_finish
, &m_do_resync
);
449 librbd::ImageCtx
*m_remote_image_ctx
;
450 librbd::ImageCtx
*m_local_image_ctx
= nullptr;
451 librbd::MockTestImageCtx
*m_local_test_image_ctx
= nullptr;
452 librbd::journal::MirrorPeerClientMeta m_mirror_peer_client_meta
;
456 TEST_F(TestMockImageReplayerBootstrapRequest
, NonPrimaryRemoteSyncingState
) {
457 create_local_image();
461 // lookup remote image tag class
462 cls::journal::Client client
;
463 librbd::journal::ClientData client_data
{
464 librbd::journal::ImageClientMeta
{123}};
465 ::encode(client_data
, client
.data
);
466 ::journal::MockJournaler mock_journaler
;
467 expect_journaler_get_client(mock_journaler
,
468 librbd::Journal
<>::IMAGE_CLIENT_ID
,
471 // lookup local peer in remote journal
472 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
473 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
474 mock_local_image_ctx
.id
};
475 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
476 client_data
.client_meta
= mirror_peer_client_meta
;
478 ::encode(client_data
, client
.data
);
479 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
482 // open the remote image
483 librbd::MockJournal mock_journal
;
484 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
485 MockOpenImageRequest mock_open_image_request
;
486 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
487 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
488 MockIsPrimaryRequest mock_is_primary_request
;
489 expect_is_primary(mock_is_primary_request
, false, 0);
491 // switch the state to replaying
492 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
493 client_data
.client_meta
= mirror_peer_client_meta
;
494 expect_journaler_update_client(mock_journaler
, client_data
, 0);
496 MockCloseImageRequest mock_close_image_request
;
497 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
500 MockInstanceWatcher mock_instance_watcher
;
501 MockBootstrapRequest
*request
= create_request(
502 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
503 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
504 "remote mirror uuid", &ctx
);
506 ASSERT_EQ(-EREMOTEIO
, ctx
.wait());
509 TEST_F(TestMockImageReplayerBootstrapRequest
, RemoteDemotePromote
) {
510 create_local_image();
514 // lookup remote image tag class
515 cls::journal::Client client
;
516 librbd::journal::ClientData client_data
{
517 librbd::journal::ImageClientMeta
{123}};
518 ::encode(client_data
, client
.data
);
519 ::journal::MockJournaler mock_journaler
;
520 expect_journaler_get_client(mock_journaler
,
521 librbd::Journal
<>::IMAGE_CLIENT_ID
,
524 // lookup local peer in remote journal
525 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
526 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
527 mock_local_image_ctx
.id
};
528 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
529 client_data
.client_meta
= mirror_peer_client_meta
;
531 ::encode(client_data
, client
.data
);
532 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
535 // open the remote image
536 librbd::MockJournal mock_journal
;
537 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
538 MockOpenImageRequest mock_open_image_request
;
539 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
540 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
541 MockIsPrimaryRequest mock_is_primary_request
;
542 expect_is_primary(mock_is_primary_request
, true, 0);
544 // open the local image
545 mock_local_image_ctx
.journal
= &mock_journal
;
546 MockOpenLocalImageRequest mock_open_local_image_request
;
547 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
548 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
549 expect_is_resync_requested(mock_journal
, false, 0);
551 // remote demotion / promotion event
553 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
554 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
556 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
557 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
559 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
560 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
562 {5, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
563 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
566 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
567 expect_journal_get_tag_tid(mock_journal
, 345);
568 expect_journal_get_tag_data(mock_journal
, {"remote mirror uuid"});
570 MockCloseImageRequest mock_close_image_request
;
571 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
574 MockInstanceWatcher mock_instance_watcher
;
575 MockBootstrapRequest
*request
= create_request(
576 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
577 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
578 "remote mirror uuid", &ctx
);
580 ASSERT_EQ(0, ctx
.wait());
583 TEST_F(TestMockImageReplayerBootstrapRequest
, MultipleRemoteDemotePromotes
) {
584 create_local_image();
588 // lookup remote image tag class
589 cls::journal::Client client
;
590 librbd::journal::ClientData client_data
{
591 librbd::journal::ImageClientMeta
{123}};
592 ::encode(client_data
, client
.data
);
593 ::journal::MockJournaler mock_journaler
;
594 expect_journaler_get_client(mock_journaler
,
595 librbd::Journal
<>::IMAGE_CLIENT_ID
,
598 // lookup local peer in remote journal
599 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
600 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
601 mock_local_image_ctx
.id
};
602 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
603 client_data
.client_meta
= mirror_peer_client_meta
;
605 ::encode(client_data
, client
.data
);
606 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
609 // open the remote image
610 librbd::MockJournal mock_journal
;
611 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
612 MockOpenImageRequest mock_open_image_request
;
613 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
614 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
615 MockIsPrimaryRequest mock_is_primary_request
;
616 expect_is_primary(mock_is_primary_request
, true, 0);
618 // open the local image
619 mock_local_image_ctx
.journal
= &mock_journal
;
620 MockOpenLocalImageRequest mock_open_local_image_request
;
621 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
622 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
623 expect_is_resync_requested(mock_journal
, false, 0);
625 // remote demotion / promotion event
627 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
628 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
630 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
631 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
633 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
634 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
636 {5, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
637 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
639 {6, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
640 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
642 {7, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
643 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
645 {8, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
646 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
649 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
650 expect_journal_get_tag_tid(mock_journal
, 345);
651 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
652 "remote mirror uuid", true, 4, 1});
654 MockCloseImageRequest mock_close_image_request
;
655 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
658 MockInstanceWatcher mock_instance_watcher
;
659 MockBootstrapRequest
*request
= create_request(
660 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
661 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
662 "remote mirror uuid", &ctx
);
664 ASSERT_EQ(0, ctx
.wait());
667 TEST_F(TestMockImageReplayerBootstrapRequest
, LocalDemoteRemotePromote
) {
668 create_local_image();
672 // lookup remote image tag class
673 cls::journal::Client client
;
674 librbd::journal::ClientData client_data
{
675 librbd::journal::ImageClientMeta
{123}};
676 ::encode(client_data
, client
.data
);
677 ::journal::MockJournaler mock_journaler
;
678 expect_journaler_get_client(mock_journaler
,
679 librbd::Journal
<>::IMAGE_CLIENT_ID
,
682 // lookup local peer in remote journal
683 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
684 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
685 mock_local_image_ctx
.id
};
686 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
687 client_data
.client_meta
= mirror_peer_client_meta
;
689 ::encode(client_data
, client
.data
);
690 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
693 // open the remote image
694 librbd::MockJournal mock_journal
;
695 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
696 MockOpenImageRequest mock_open_image_request
;
697 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
698 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
699 MockIsPrimaryRequest mock_is_primary_request
;
700 expect_is_primary(mock_is_primary_request
, true, 0);
702 // open the local image
703 mock_local_image_ctx
.journal
= &mock_journal
;
704 MockOpenLocalImageRequest mock_open_local_image_request
;
705 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
706 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
707 expect_is_resync_requested(mock_journal
, false, 0);
709 // remote demotion / promotion event
711 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
713 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
714 "local mirror uuid", true, 345, 1})},
715 {4, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
716 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
719 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
720 expect_journal_get_tag_tid(mock_journal
, 346);
721 expect_journal_get_tag_data(mock_journal
,
722 {librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
723 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
726 MockCloseImageRequest mock_close_image_request
;
727 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
730 MockInstanceWatcher mock_instance_watcher
;
731 MockBootstrapRequest
*request
= create_request(
732 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
733 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
734 "remote mirror uuid", &ctx
);
736 ASSERT_EQ(0, ctx
.wait());
739 TEST_F(TestMockImageReplayerBootstrapRequest
, SplitBrainForcePromote
) {
740 create_local_image();
744 // lookup remote image tag class
745 cls::journal::Client client
;
746 librbd::journal::ClientData client_data
{
747 librbd::journal::ImageClientMeta
{123}};
748 ::encode(client_data
, client
.data
);
749 ::journal::MockJournaler mock_journaler
;
750 expect_journaler_get_client(mock_journaler
,
751 librbd::Journal
<>::IMAGE_CLIENT_ID
,
754 // lookup local peer in remote journal
755 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
756 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
757 mock_local_image_ctx
.id
};
758 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
759 client_data
.client_meta
= mirror_peer_client_meta
;
761 ::encode(client_data
, client
.data
);
762 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
765 // open the remote image
766 librbd::MockJournal mock_journal
;
767 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
768 MockOpenImageRequest mock_open_image_request
;
769 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
770 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
771 MockIsPrimaryRequest mock_is_primary_request
;
772 expect_is_primary(mock_is_primary_request
, true, 0);
774 // open the local image
775 mock_local_image_ctx
.journal
= &mock_journal
;
776 MockOpenLocalImageRequest mock_open_local_image_request
;
777 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
778 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
779 expect_is_resync_requested(mock_journal
, false, 0);
781 // remote demotion / promotion event
783 {2, 123, encode_tag_data({librbd::Journal
<>::LOCAL_MIRROR_UUID
,
784 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
786 {3, 123, encode_tag_data({librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
787 librbd::Journal
<>::LOCAL_MIRROR_UUID
,
790 expect_journaler_get_tags(mock_journaler
, 123, tags
, 0);
791 expect_journal_get_tag_tid(mock_journal
, 345);
792 expect_journal_get_tag_data(mock_journal
, {librbd::Journal
<>::LOCAL_MIRROR_UUID
,
793 librbd::Journal
<>::ORPHAN_MIRROR_UUID
,
796 MockCloseImageRequest mock_close_image_request
;
797 expect_close_image(mock_close_image_request
, mock_local_image_ctx
, 0);
798 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
801 MockInstanceWatcher mock_instance_watcher
;
802 MockBootstrapRequest
*request
= create_request(
803 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
804 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
805 "remote mirror uuid", &ctx
);
807 ASSERT_EQ(-EEXIST
, ctx
.wait());
808 ASSERT_EQ(NULL
, m_local_test_image_ctx
);
811 TEST_F(TestMockImageReplayerBootstrapRequest
, ResyncRequested
) {
812 create_local_image();
816 // lookup remote image tag class
817 cls::journal::Client client
;
818 librbd::journal::ClientData client_data
{
819 librbd::journal::ImageClientMeta
{123}};
820 ::encode(client_data
, client
.data
);
821 ::journal::MockJournaler mock_journaler
;
822 expect_journaler_get_client(mock_journaler
,
823 librbd::Journal
<>::IMAGE_CLIENT_ID
,
826 // lookup local peer in remote journal
827 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
828 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
829 mock_local_image_ctx
.id
};
830 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
831 client_data
.client_meta
= mirror_peer_client_meta
;
833 ::encode(client_data
, client
.data
);
834 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
837 // open the remote image
838 librbd::MockJournal mock_journal
;
839 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
840 MockOpenImageRequest mock_open_image_request
;
841 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
842 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
843 MockIsPrimaryRequest mock_is_primary_request
;
844 expect_is_primary(mock_is_primary_request
, true, 0);
846 // open the local image
847 mock_local_image_ctx
.journal
= &mock_journal
;
848 MockOpenLocalImageRequest mock_open_local_image_request
;
849 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
850 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
852 // resync is requested
853 expect_is_resync_requested(mock_journal
, true, 0);
856 MockCloseImageRequest mock_close_image_request
;
857 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
860 MockInstanceWatcher mock_instance_watcher
;
861 MockBootstrapRequest
*request
= create_request(
862 &mock_instance_watcher
, mock_journaler
, mock_local_image_ctx
.id
,
863 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
864 "remote mirror uuid", &ctx
);
867 ASSERT_EQ(0, ctx
.wait());
868 ASSERT_TRUE(m_do_resync
);
871 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemote
) {
872 create_local_image();
876 // lookup remote image tag class
877 cls::journal::Client client
;
878 librbd::journal::ClientData client_data
{
879 librbd::journal::ImageClientMeta
{123}};
880 ::encode(client_data
, client
.data
);
881 ::journal::MockJournaler mock_journaler
;
882 expect_journaler_get_client(mock_journaler
,
883 librbd::Journal
<>::IMAGE_CLIENT_ID
,
886 // lookup local peer in remote journal
888 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
891 // register missing client in remote journal
892 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
;
893 client_data
.client_meta
= mirror_peer_client_meta
;
894 expect_journaler_register_client(mock_journaler
, client_data
, 0);
896 // open the remote image
897 librbd::MockJournal mock_journal
;
898 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
899 MockOpenImageRequest mock_open_image_request
;
900 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
901 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
902 MockIsPrimaryRequest mock_is_primary_request
;
903 expect_is_primary(mock_is_primary_request
, true, 0);
905 // create the local image
906 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
907 mock_local_image_ctx
.journal
= &mock_journal
;
909 MockCreateImageRequest mock_create_image_request
;
910 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
912 // open the local image
913 MockOpenLocalImageRequest mock_open_local_image_request
;
914 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
915 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
916 expect_is_resync_requested(mock_journal
, false, 0);
918 // update client state back to syncing
919 mirror_peer_client_meta
= {mock_local_image_ctx
.id
};
920 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
921 client_data
.client_meta
= mirror_peer_client_meta
;
923 ::encode(client_data
, client
.data
);
924 expect_journaler_update_client(mock_journaler
, client_data
, 0);
926 // sync the remote image to the local image
927 MockImageSync mock_image_sync
;
928 expect_image_sync(mock_image_sync
, 0);
930 MockCloseImageRequest mock_close_image_request
;
931 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
934 MockInstanceWatcher mock_instance_watcher
;
935 MockBootstrapRequest
*request
= create_request(
936 &mock_instance_watcher
, mock_journaler
, "",
937 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
938 "remote mirror uuid", &ctx
);
940 ASSERT_EQ(0, ctx
.wait());
943 TEST_F(TestMockImageReplayerBootstrapRequest
, PrimaryRemoteLocalDeleted
) {
944 create_local_image();
948 // lookup remote image tag class
949 cls::journal::Client client
;
950 librbd::journal::ClientData client_data
{
951 librbd::journal::ImageClientMeta
{123}};
952 ::encode(client_data
, client
.data
);
953 ::journal::MockJournaler mock_journaler
;
954 expect_journaler_get_client(mock_journaler
,
955 librbd::Journal
<>::IMAGE_CLIENT_ID
,
958 // lookup local peer in remote journal
959 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta
{
961 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_REPLAYING
;
962 client_data
.client_meta
= mirror_peer_client_meta
;
964 ::encode(client_data
, client
.data
);
965 expect_journaler_get_client(mock_journaler
, "local mirror uuid",
968 // open the remote image
969 librbd::MockJournal mock_journal
;
970 librbd::MockTestImageCtx
mock_remote_image_ctx(*m_remote_image_ctx
);
971 MockOpenImageRequest mock_open_image_request
;
972 expect_open_image(mock_open_image_request
, m_remote_io_ctx
,
973 mock_remote_image_ctx
.id
, mock_remote_image_ctx
, 0);
974 MockIsPrimaryRequest mock_is_primary_request
;
975 expect_is_primary(mock_is_primary_request
, true, 0);
977 // open the missing local image
978 MockOpenLocalImageRequest mock_open_local_image_request
;
979 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
980 "missing image id", nullptr, -ENOENT
);
982 // create the missing local image
983 librbd::MockTestImageCtx
mock_local_image_ctx(*m_local_image_ctx
);
984 mock_local_image_ctx
.journal
= &mock_journal
;
986 MockCreateImageRequest mock_create_image_request
;
987 expect_create_image(mock_create_image_request
, mock_local_image_ctx
.id
, 0);
989 // open the local image
990 expect_open_local_image(mock_open_local_image_request
, m_local_io_ctx
,
991 mock_local_image_ctx
.id
, &mock_local_image_ctx
, 0);
992 expect_is_resync_requested(mock_journal
, false, 0);
994 // update client state back to syncing
995 mirror_peer_client_meta
= {mock_local_image_ctx
.id
};
996 mirror_peer_client_meta
.state
= librbd::journal::MIRROR_PEER_STATE_SYNCING
;
997 client_data
.client_meta
= mirror_peer_client_meta
;
999 ::encode(client_data
, client
.data
);
1000 expect_journaler_update_client(mock_journaler
, client_data
, 0);
1002 // sync the remote image to the local image
1003 MockImageSync mock_image_sync
;
1004 expect_image_sync(mock_image_sync
, 0);
1006 MockCloseImageRequest mock_close_image_request
;
1007 expect_close_image(mock_close_image_request
, mock_remote_image_ctx
, 0);
1010 MockInstanceWatcher mock_instance_watcher
;
1011 MockBootstrapRequest
*request
= create_request(
1012 &mock_instance_watcher
, mock_journaler
, "",
1013 mock_remote_image_ctx
.id
, "global image id", "local mirror uuid",
1014 "remote mirror uuid", &ctx
);
1016 ASSERT_EQ(0, ctx
.wait());
1019 } // namespace image_replayer
1020 } // namespace mirror