]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
update sources to v12.2.3
[ceph.git] / ceph / src / test / rbd_mirror / image_replayer / test_mock_BootstrapRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
18
19 namespace librbd {
20
21 namespace {
22
23 struct MockTestImageCtx : public librbd::MockImageCtx {
24 MockTestImageCtx(librbd::ImageCtx &image_ctx)
25 : librbd::MockImageCtx(image_ctx) {
26 }
27 };
28
29 } // anonymous namespace
30
31 namespace journal {
32
33 template <>
34 struct TypeTraits<librbd::MockTestImageCtx> {
35 typedef ::journal::MockJournaler Journaler;
36 };
37
38 } // namespace journal
39
40 namespace util {
41
42 static std::string s_image_id;
43
44 template <>
45 std::string generate_image_id<MockTestImageCtx>(librados::IoCtx&) {
46 assert(!s_image_id.empty());
47 return s_image_id;
48 }
49
50 } // namespace util
51 } // namespace librbd
52
53 namespace rbd {
54 namespace mirror {
55
56 class ProgressContext;
57
58 template<>
59 struct ImageSync<librbd::MockTestImageCtx> {
60 static ImageSync* s_instance;
61 Context *on_finish = nullptr;
62
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;
73 return s_instance;
74 }
75
76 ImageSync() {
77 assert(s_instance == nullptr);
78 s_instance = this;
79 }
80 ~ImageSync() {
81 s_instance = nullptr;
82 }
83
84 MOCK_METHOD0(get, void());
85 MOCK_METHOD0(put, void());
86 MOCK_METHOD0(send, void());
87 MOCK_METHOD0(cancel, void());
88 };
89
90 ImageSync<librbd::MockTestImageCtx>*
91 ImageSync<librbd::MockTestImageCtx>::s_instance = nullptr;
92
93 template<>
94 struct InstanceWatcher<librbd::MockTestImageCtx> {
95 };
96
97 namespace image_replayer {
98
99 template<>
100 struct CloseImageRequest<librbd::MockTestImageCtx> {
101 static CloseImageRequest* s_instance;
102 librbd::MockTestImageCtx **image_ctx = nullptr;
103 Context *on_finish = nullptr;
104
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);
111 return s_instance;
112 }
113
114 CloseImageRequest() {
115 assert(s_instance == nullptr);
116 s_instance = this;
117 }
118 ~CloseImageRequest() {
119 s_instance = nullptr;
120 }
121
122 MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *image_ctx));
123 MOCK_METHOD0(send, void());
124 };
125
126 template<>
127 struct CreateImageRequest<librbd::MockTestImageCtx> {
128 static CreateImageRequest* s_instance;
129 Context *on_finish = nullptr;
130
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);
142 return s_instance;
143 }
144
145 CreateImageRequest() {
146 assert(s_instance == nullptr);
147 s_instance = this;
148 }
149 ~CreateImageRequest() {
150 s_instance = nullptr;
151 }
152
153 MOCK_METHOD1(construct, void(const std::string&));
154 MOCK_METHOD0(send, void());
155 };
156
157 template<>
158 struct IsPrimaryRequest<librbd::MockTestImageCtx> {
159 static IsPrimaryRequest* s_instance;
160 bool *primary = nullptr;
161 Context *on_finish = nullptr;
162
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;
168 return s_instance;
169 }
170
171 IsPrimaryRequest() {
172 assert(s_instance == nullptr);
173 s_instance = this;
174 }
175 ~IsPrimaryRequest() {
176 s_instance = nullptr;
177 }
178
179 MOCK_METHOD0(send, void());
180 };
181
182 template<>
183 struct OpenImageRequest<librbd::MockTestImageCtx> {
184 static OpenImageRequest* s_instance;
185 librbd::MockTestImageCtx **image_ctx = nullptr;
186 Context *on_finish = nullptr;
187
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);
196 return s_instance;
197 }
198
199 OpenImageRequest() {
200 assert(s_instance == nullptr);
201 s_instance = this;
202 }
203 ~OpenImageRequest() {
204 s_instance = nullptr;
205 }
206
207 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
208 const std::string &image_id));
209 MOCK_METHOD0(send, void());
210 };
211
212 template<>
213 struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
214 static OpenLocalImageRequest* s_instance;
215 librbd::MockTestImageCtx **image_ctx = nullptr;
216 Context *on_finish = nullptr;
217
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);
227 return s_instance;
228 }
229
230 OpenLocalImageRequest() {
231 assert(s_instance == nullptr);
232 s_instance = this;
233 }
234 ~OpenLocalImageRequest() {
235 s_instance = nullptr;
236 }
237
238 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
239 const std::string &image_id));
240 MOCK_METHOD0(send, void());
241 };
242
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;
253
254 } // namespace image_replayer
255 } // namespace mirror
256 } // namespace rbd
257
258 // template definitions
259 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
260
261 namespace rbd {
262 namespace mirror {
263 namespace image_replayer {
264
265 using ::testing::_;
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;
273
274 MATCHER_P(IsSameIoCtx, io_ctx, "") {
275 return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx);
276 }
277
278 class TestMockImageReplayerBootstrapRequest : public TestMockFixture {
279 public:
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;
289
290 void SetUp() override {
291 TestMockFixture::SetUp();
292
293 librbd::RBD rbd;
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));
296 }
297
298 void create_local_image() {
299 librbd::RBD rbd;
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));
302 }
303
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;
310 })),
311 WithArg<2>(Invoke([this, r](Context *on_finish) {
312 m_threads->work_queue->queue(on_finish, r);
313 }))));
314 }
315
316 void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler,
317 uint64_t tag_class, const Tags& tags,
318 int r) {
319 EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _))
320 .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) {
321 *out_tags = tags;
322 })),
323 WithArg<2>(Invoke([this, r](Context *on_finish) {
324 m_threads->work_queue->queue(on_finish, r);
325 }))));
326 }
327
328 void expect_journaler_register_client(::journal::MockJournaler &mock_journaler,
329 const librbd::journal::ClientData &client_data,
330 int r) {
331 bufferlist bl;
332 ::encode(client_data, bl);
333
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);
337 })));
338 }
339
340 void expect_journaler_unregister_client(::journal::MockJournaler &mock_journaler,
341 int r) {
342 EXPECT_CALL(mock_journaler, unregister_client(_))
343 .WillOnce(Invoke([this, r](Context *on_finish) {
344 m_threads->work_queue->queue(on_finish, r);
345 }));
346 }
347
348 void expect_journaler_update_client(::journal::MockJournaler &mock_journaler,
349 const librbd::journal::ClientData &client_data,
350 int r) {
351 bufferlist bl;
352 ::encode(client_data, bl);
353
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);
357 })));
358 }
359
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);
368 }));
369 }
370
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,
380 r);
381 }));
382 }
383
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);
391 }));
392 }
393
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);
400 }));
401 }
402
403 void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal,
404 uint64_t tag_tid) {
405 EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid));
406 }
407
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));
411 }
412
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),
417 Return(r)));
418 }
419
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);
426 }));
427 }
428
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);
434 }));
435 EXPECT_CALL(mock_image_sync, put());
436 }
437
438 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
439 bufferlist bl;
440 ::encode(tag_data, bl);
441 return bl;
442 }
443
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,
455 m_remote_io_ctx,
456 mock_instance_watcher,
457 &m_local_test_image_ctx,
458 local_image_id,
459 remote_image_id,
460 global_image_id,
461 m_threads->work_queue,
462 m_threads->timer,
463 &m_threads->timer_lock,
464 local_mirror_uuid,
465 remote_mirror_uuid,
466 &mock_journaler,
467 client_state, mirror_peer_client_meta,
468 on_finish, &m_do_resync);
469 }
470
471 librbd::ImageCtx *m_remote_image_ctx;
472 librbd::ImageCtx *m_local_image_ctx = nullptr;
473 librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
474 bool m_do_resync;
475 };
476
477 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
478 create_local_image();
479
480 InSequence seq;
481
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,
490 client, 0);
491
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);
498
499 // test if remote image is primary
500 MockIsPrimaryRequest mock_is_primary_request;
501 expect_is_primary(mock_is_primary_request, false, 0);
502
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);
510
511 MockCloseImageRequest mock_close_image_request;
512 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
513
514 C_SaferCond ctx;
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);
522 request->send();
523 ASSERT_EQ(-EREMOTEIO, ctx.wait());
524 }
525
526 TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
527 create_local_image();
528
529 InSequence seq;
530
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,
539 client, 0);
540
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);
547
548 // test if remote image is primary
549 MockIsPrimaryRequest mock_is_primary_request;
550 expect_is_primary(mock_is_primary_request, true, 0);
551
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);
559
560 // remote demotion / promotion event
561 Tags tags = {
562 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
563 librbd::Journal<>::LOCAL_MIRROR_UUID,
564 true, 1, 99})},
565 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
566 librbd::Journal<>::LOCAL_MIRROR_UUID,
567 true, 2, 1})},
568 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
569 librbd::Journal<>::ORPHAN_MIRROR_UUID,
570 true, 2, 1})},
571 {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
572 librbd::Journal<>::ORPHAN_MIRROR_UUID,
573 true, 4, 369})}
574 };
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"});
578
579 MockCloseImageRequest mock_close_image_request;
580 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
581
582 C_SaferCond ctx;
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);
592 request->send();
593 ASSERT_EQ(0, ctx.wait());
594 }
595
596 TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
597 create_local_image();
598
599 InSequence seq;
600
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,
609 client, 0);
610
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);
617
618 // test if remote image is primary
619 MockIsPrimaryRequest mock_is_primary_request;
620 expect_is_primary(mock_is_primary_request, true, 0);
621
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);
629
630 // remote demotion / promotion event
631 Tags tags = {
632 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
633 librbd::Journal<>::LOCAL_MIRROR_UUID,
634 true, 1, 99})},
635 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
636 librbd::Journal<>::LOCAL_MIRROR_UUID,
637 true, 2, 1})},
638 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
639 librbd::Journal<>::ORPHAN_MIRROR_UUID,
640 true, 3, 1})},
641 {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
642 librbd::Journal<>::LOCAL_MIRROR_UUID,
643 true, 4, 1})},
644 {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
645 librbd::Journal<>::ORPHAN_MIRROR_UUID,
646 true, 5, 1})},
647 {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
648 librbd::Journal<>::LOCAL_MIRROR_UUID,
649 true, 6, 1})},
650 {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
651 librbd::Journal<>::ORPHAN_MIRROR_UUID,
652 true, 7, 1})}
653 };
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});
658
659 MockCloseImageRequest mock_close_image_request;
660 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
661
662 C_SaferCond ctx;
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);
672 request->send();
673 ASSERT_EQ(0, ctx.wait());
674 }
675
676 TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
677 create_local_image();
678
679 InSequence seq;
680
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,
689 client, 0);
690
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);
697
698 // test if remote image is primary
699 MockIsPrimaryRequest mock_is_primary_request;
700 expect_is_primary(mock_is_primary_request, true, 0);
701
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);
709
710 // remote demotion / promotion event
711 Tags tags = {
712 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
713 true, 344, 99})},
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,
718 true, 3, 1})}
719 };
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,
725 true, 345, 1});
726
727 MockCloseImageRequest mock_close_image_request;
728 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
729
730 C_SaferCond ctx;
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);
740 request->send();
741 ASSERT_EQ(0, ctx.wait());
742 }
743
744 TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
745 create_local_image();
746
747 InSequence seq;
748
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,
757 client, 0);
758
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);
765
766 // test if remote image is primary
767 MockIsPrimaryRequest mock_is_primary_request;
768 expect_is_primary(mock_is_primary_request, true, 0);
769
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);
777
778 // remote demotion / promotion event
779 Tags tags = {
780 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
781 librbd::Journal<>::LOCAL_MIRROR_UUID,
782 true, 1, 99})},
783 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
784 librbd::Journal<>::LOCAL_MIRROR_UUID,
785 true, 2, 1})}
786 };
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,
791 true, 344, 0});
792
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);
796
797 C_SaferCond ctx;
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);
807 request->send();
808 ASSERT_EQ(-EEXIST, ctx.wait());
809 ASSERT_EQ(NULL, m_local_test_image_ctx);
810 }
811
812 TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
813 create_local_image();
814
815 InSequence seq;
816
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,
825 client, 0);
826
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);
833
834 // test if remote image is primary
835 MockIsPrimaryRequest mock_is_primary_request;
836 expect_is_primary(mock_is_primary_request, true, 0);
837
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);
844
845 // resync is requested
846 expect_is_resync_requested(mock_journal, true, 0);
847
848
849 MockCloseImageRequest mock_close_image_request;
850 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
851
852 C_SaferCond ctx;
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);
862 m_do_resync = false;
863 request->send();
864 ASSERT_EQ(0, ctx.wait());
865 ASSERT_TRUE(m_do_resync);
866 }
867
868 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
869 create_local_image();
870
871 InSequence seq;
872
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,
881 client, 0);
882
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);
889
890 // test if remote image is primary
891 MockIsPrimaryRequest mock_is_primary_request;
892 expect_is_primary(mock_is_primary_request, true, 0);
893
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;
897
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;
903 client.data.clear();
904 ::encode(client_data, client.data);
905 expect_journaler_update_client(mock_journaler, client_data, 0);
906
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);
910
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);
916
917 // sync the remote image to the local image
918 MockImageSync mock_image_sync;
919 expect_image_sync(mock_image_sync, 0);
920
921 MockCloseImageRequest mock_close_image_request;
922 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
923
924 C_SaferCond ctx;
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);
933 request->send();
934 ASSERT_EQ(0, ctx.wait());
935 }
936
937 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
938 create_local_image();
939
940 InSequence seq;
941
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,
950 client, 0);
951
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);
958
959 // test if remote image is primary
960 MockIsPrimaryRequest mock_is_primary_request;
961 expect_is_primary(mock_is_primary_request, true, 0);
962
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);
967
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);
975
976 // test if remote image is primary
977 expect_is_primary(mock_is_primary_request, true, 0);
978
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;
982
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;
987 client.data.clear();
988 ::encode(client_data, client.data);
989 expect_journaler_update_client(mock_journaler, client_data, 0);
990
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);
994
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);
999
1000 // sync the remote image to the local image
1001 MockImageSync mock_image_sync;
1002 expect_image_sync(mock_image_sync, 0);
1003
1004 MockCloseImageRequest mock_close_image_request;
1005 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
1006
1007 C_SaferCond ctx;
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);
1016 request->send();
1017 ASSERT_EQ(0, ctx.wait());
1018 }
1019
1020 } // namespace image_replayer
1021 } // namespace mirror
1022 } // namespace rbd