]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/rbd_mirror/image_replayer/test_mock_BootstrapRequest.cc
c7b995387e1d3b8e8f0dcf9d3064c028fb7ba008
[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 } // namespace librbd
40
41 namespace rbd {
42 namespace mirror {
43
44 class ProgressContext;
45
46 template<>
47 struct ImageSync<librbd::MockTestImageCtx> {
48 static ImageSync* s_instance;
49 Context *on_finish = nullptr;
50
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;
61 return s_instance;
62 }
63
64 ImageSync() {
65 assert(s_instance == nullptr);
66 s_instance = this;
67 }
68 ~ImageSync() {
69 s_instance = nullptr;
70 }
71
72 MOCK_METHOD0(get, void());
73 MOCK_METHOD0(put, void());
74 MOCK_METHOD0(send, void());
75 MOCK_METHOD0(cancel, void());
76 };
77
78 ImageSync<librbd::MockTestImageCtx>*
79 ImageSync<librbd::MockTestImageCtx>::s_instance = nullptr;
80
81 template<>
82 struct InstanceWatcher<librbd::MockTestImageCtx> {
83 };
84
85 namespace image_replayer {
86
87 template<>
88 struct CloseImageRequest<librbd::MockTestImageCtx> {
89 static CloseImageRequest* s_instance;
90 librbd::MockTestImageCtx **image_ctx = nullptr;
91 Context *on_finish = nullptr;
92
93 static CloseImageRequest* create(librbd::MockTestImageCtx **image_ctx,
94 Context *on_finish) {
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);
99 return s_instance;
100 }
101
102 CloseImageRequest() {
103 assert(s_instance == nullptr);
104 s_instance = this;
105 }
106 ~CloseImageRequest() {
107 s_instance = nullptr;
108 }
109
110 MOCK_METHOD1(construct, void(librbd::MockTestImageCtx *image_ctx));
111 MOCK_METHOD0(send, void());
112 };
113
114 template<>
115 struct CreateImageRequest<librbd::MockTestImageCtx> {
116 static CreateImageRequest* s_instance;
117 std::string *local_image_id = nullptr;
118 Context *on_finish = nullptr;
119
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;
131 return s_instance;
132 }
133
134 CreateImageRequest() {
135 assert(s_instance == nullptr);
136 s_instance = this;
137 }
138 ~CreateImageRequest() {
139 s_instance = nullptr;
140 }
141
142 MOCK_METHOD0(send, void());
143 };
144
145 template<>
146 struct IsPrimaryRequest<librbd::MockTestImageCtx> {
147 static IsPrimaryRequest* s_instance;
148 bool *primary = nullptr;
149 Context *on_finish = nullptr;
150
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;
156 return s_instance;
157 }
158
159 IsPrimaryRequest() {
160 assert(s_instance == nullptr);
161 s_instance = this;
162 }
163 ~IsPrimaryRequest() {
164 s_instance = nullptr;
165 }
166
167 MOCK_METHOD0(send, void());
168 };
169
170 template<>
171 struct OpenImageRequest<librbd::MockTestImageCtx> {
172 static OpenImageRequest* s_instance;
173 librbd::MockTestImageCtx **image_ctx = nullptr;
174 Context *on_finish = nullptr;
175
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);
184 return s_instance;
185 }
186
187 OpenImageRequest() {
188 assert(s_instance == nullptr);
189 s_instance = this;
190 }
191 ~OpenImageRequest() {
192 s_instance = nullptr;
193 }
194
195 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
196 const std::string &image_id));
197 MOCK_METHOD0(send, void());
198 };
199
200 template<>
201 struct OpenLocalImageRequest<librbd::MockTestImageCtx> {
202 static OpenLocalImageRequest* s_instance;
203 librbd::MockTestImageCtx **image_ctx = nullptr;
204 Context *on_finish = nullptr;
205
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);
215 return s_instance;
216 }
217
218 OpenLocalImageRequest() {
219 assert(s_instance == nullptr);
220 s_instance = this;
221 }
222 ~OpenLocalImageRequest() {
223 s_instance = nullptr;
224 }
225
226 MOCK_METHOD2(construct, void(librados::IoCtx &io_ctx,
227 const std::string &image_id));
228 MOCK_METHOD0(send, void());
229 };
230
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;
241
242 } // namespace image_replayer
243 } // namespace mirror
244 } // namespace rbd
245
246 // template definitions
247 #include "tools/rbd_mirror/image_replayer/BootstrapRequest.cc"
248
249 namespace rbd {
250 namespace mirror {
251 namespace image_replayer {
252
253 using ::testing::_;
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;
261
262 MATCHER_P(IsSameIoCtx, io_ctx, "") {
263 return &get_mock_io_ctx(arg) == &get_mock_io_ctx(*io_ctx);
264 }
265
266 class TestMockImageReplayerBootstrapRequest : public TestMockFixture {
267 public:
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;
277
278 void SetUp() override {
279 TestMockFixture::SetUp();
280
281 librbd::RBD rbd;
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));
284 }
285
286 void create_local_image() {
287 librbd::RBD rbd;
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));
290 }
291
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;
298 })),
299 WithArg<2>(Invoke([this, r](Context *on_finish) {
300 m_threads->work_queue->queue(on_finish, r);
301 }))));
302 }
303
304 void expect_journaler_get_tags(::journal::MockJournaler &mock_journaler,
305 uint64_t tag_class, const Tags& tags,
306 int r) {
307 EXPECT_CALL(mock_journaler, get_tags(tag_class, _, _))
308 .WillOnce(DoAll(WithArg<1>(Invoke([tags](Tags *out_tags) {
309 *out_tags = tags;
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_register_client(::journal::MockJournaler &mock_journaler,
317 const librbd::journal::ClientData &client_data,
318 int r) {
319 bufferlist bl;
320 ::encode(client_data, bl);
321
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);
325 })));
326 }
327
328 void expect_journaler_update_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, update_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_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);
348 }));
349 }
350
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,
360 r);
361 }));
362 }
363
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);
371 }));
372 }
373
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);
380 }));
381 }
382
383 void expect_journal_get_tag_tid(librbd::MockJournal &mock_journal,
384 uint64_t tag_tid) {
385 EXPECT_CALL(mock_journal, get_tag_tid()).WillOnce(Return(tag_tid));
386 }
387
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));
391 }
392
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),
397 Return(r)));
398 }
399
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);
406 }));
407 }
408
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);
414 }));
415 EXPECT_CALL(mock_image_sync, put());
416 }
417
418 bufferlist encode_tag_data(const librbd::journal::TagData &tag_data) {
419 bufferlist bl;
420 ::encode(tag_data, bl);
421 return bl;
422 }
423
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,
433 m_remote_io_ctx,
434 mock_instance_watcher,
435 &m_local_test_image_ctx,
436 local_image_id,
437 remote_image_id,
438 global_image_id,
439 m_threads->work_queue,
440 m_threads->timer,
441 &m_threads->timer_lock,
442 local_mirror_uuid,
443 remote_mirror_uuid,
444 &mock_journaler,
445 &m_mirror_peer_client_meta,
446 on_finish, &m_do_resync);
447 }
448
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;
453 bool m_do_resync;
454 };
455
456 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
457 create_local_image();
458
459 InSequence seq;
460
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,
469 client, 0);
470
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;
477 client.data.clear();
478 ::encode(client_data, client.data);
479 expect_journaler_get_client(mock_journaler, "local mirror uuid",
480 client, 0);
481
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);
490
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);
495
496 MockCloseImageRequest mock_close_image_request;
497 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
498
499 C_SaferCond ctx;
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);
505 request->send();
506 ASSERT_EQ(-EREMOTEIO, ctx.wait());
507 }
508
509 TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
510 create_local_image();
511
512 InSequence seq;
513
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,
522 client, 0);
523
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;
530 client.data.clear();
531 ::encode(client_data, client.data);
532 expect_journaler_get_client(mock_journaler, "local mirror uuid",
533 client, 0);
534
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);
543
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);
550
551 // remote demotion / promotion event
552 Tags tags = {
553 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
554 librbd::Journal<>::LOCAL_MIRROR_UUID,
555 true, 1, 99})},
556 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
557 librbd::Journal<>::LOCAL_MIRROR_UUID,
558 true, 2, 1})},
559 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
560 librbd::Journal<>::ORPHAN_MIRROR_UUID,
561 true, 2, 1})},
562 {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
563 librbd::Journal<>::ORPHAN_MIRROR_UUID,
564 true, 4, 369})}
565 };
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"});
569
570 MockCloseImageRequest mock_close_image_request;
571 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
572
573 C_SaferCond ctx;
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);
579 request->send();
580 ASSERT_EQ(0, ctx.wait());
581 }
582
583 TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
584 create_local_image();
585
586 InSequence seq;
587
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,
596 client, 0);
597
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;
604 client.data.clear();
605 ::encode(client_data, client.data);
606 expect_journaler_get_client(mock_journaler, "local mirror uuid",
607 client, 0);
608
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);
617
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);
624
625 // remote demotion / promotion event
626 Tags tags = {
627 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
628 librbd::Journal<>::LOCAL_MIRROR_UUID,
629 true, 1, 99})},
630 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
631 librbd::Journal<>::LOCAL_MIRROR_UUID,
632 true, 2, 1})},
633 {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
634 librbd::Journal<>::ORPHAN_MIRROR_UUID,
635 true, 3, 1})},
636 {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
637 librbd::Journal<>::LOCAL_MIRROR_UUID,
638 true, 4, 1})},
639 {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
640 librbd::Journal<>::ORPHAN_MIRROR_UUID,
641 true, 5, 1})},
642 {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
643 librbd::Journal<>::LOCAL_MIRROR_UUID,
644 true, 6, 1})},
645 {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
646 librbd::Journal<>::ORPHAN_MIRROR_UUID,
647 true, 7, 1})}
648 };
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});
653
654 MockCloseImageRequest mock_close_image_request;
655 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
656
657 C_SaferCond ctx;
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);
663 request->send();
664 ASSERT_EQ(0, ctx.wait());
665 }
666
667 TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
668 create_local_image();
669
670 InSequence seq;
671
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,
680 client, 0);
681
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;
688 client.data.clear();
689 ::encode(client_data, client.data);
690 expect_journaler_get_client(mock_journaler, "local mirror uuid",
691 client, 0);
692
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);
701
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);
708
709 // remote demotion / promotion event
710 Tags tags = {
711 {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
712 true, 344, 99})},
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,
717 true, 3, 1})}
718 };
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,
724 true, 345, 1});
725
726 MockCloseImageRequest mock_close_image_request;
727 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
728
729 C_SaferCond ctx;
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);
735 request->send();
736 ASSERT_EQ(0, ctx.wait());
737 }
738
739 TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
740 create_local_image();
741
742 InSequence seq;
743
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,
752 client, 0);
753
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;
760 client.data.clear();
761 ::encode(client_data, client.data);
762 expect_journaler_get_client(mock_journaler, "local mirror uuid",
763 client, 0);
764
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);
773
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);
780
781 // remote demotion / promotion event
782 Tags tags = {
783 {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
784 librbd::Journal<>::LOCAL_MIRROR_UUID,
785 true, 1, 99})},
786 {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
787 librbd::Journal<>::LOCAL_MIRROR_UUID,
788 true, 2, 1})}
789 };
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,
794 true, 344, 0});
795
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);
799
800 C_SaferCond ctx;
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);
806 request->send();
807 ASSERT_EQ(-EEXIST, ctx.wait());
808 ASSERT_EQ(NULL, m_local_test_image_ctx);
809 }
810
811 TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
812 create_local_image();
813
814 InSequence seq;
815
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,
824 client, 0);
825
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;
832 client.data.clear();
833 ::encode(client_data, client.data);
834 expect_journaler_get_client(mock_journaler, "local mirror uuid",
835 client, 0);
836
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);
845
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);
851
852 // resync is requested
853 expect_is_resync_requested(mock_journal, true, 0);
854
855
856 MockCloseImageRequest mock_close_image_request;
857 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
858
859 C_SaferCond ctx;
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);
865 m_do_resync = false;
866 request->send();
867 ASSERT_EQ(0, ctx.wait());
868 ASSERT_TRUE(m_do_resync);
869 }
870
871 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
872 create_local_image();
873
874 InSequence seq;
875
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,
884 client, 0);
885
886 // lookup local peer in remote journal
887 client = {};
888 expect_journaler_get_client(mock_journaler, "local mirror uuid",
889 client, -ENOENT);
890
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);
895
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);
904
905 // create the local image
906 librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
907 mock_local_image_ctx.journal = &mock_journal;
908
909 MockCreateImageRequest mock_create_image_request;
910 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
911
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);
917
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;
922 client.data.clear();
923 ::encode(client_data, client.data);
924 expect_journaler_update_client(mock_journaler, client_data, 0);
925
926 // sync the remote image to the local image
927 MockImageSync mock_image_sync;
928 expect_image_sync(mock_image_sync, 0);
929
930 MockCloseImageRequest mock_close_image_request;
931 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
932
933 C_SaferCond ctx;
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);
939 request->send();
940 ASSERT_EQ(0, ctx.wait());
941 }
942
943 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
944 create_local_image();
945
946 InSequence seq;
947
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,
956 client, 0);
957
958 // lookup local peer in remote journal
959 librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
960 "missing image id"};
961 mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
962 client_data.client_meta = mirror_peer_client_meta;
963 client.data.clear();
964 ::encode(client_data, client.data);
965 expect_journaler_get_client(mock_journaler, "local mirror uuid",
966 client, 0);
967
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);
976
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);
981
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;
985
986 MockCreateImageRequest mock_create_image_request;
987 expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
988
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);
993
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;
998 client.data.clear();
999 ::encode(client_data, client.data);
1000 expect_journaler_update_client(mock_journaler, client_data, 0);
1001
1002 // sync the remote image to the local image
1003 MockImageSync mock_image_sync;
1004 expect_image_sync(mock_image_sync, 0);
1005
1006 MockCloseImageRequest mock_close_image_request;
1007 expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
1008
1009 C_SaferCond ctx;
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);
1015 request->send();
1016 ASSERT_EQ(0, ctx.wait());
1017 }
1018
1019 } // namespace image_replayer
1020 } // namespace mirror
1021 } // namespace rbd