Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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                                        Context *on_finish) {
452     return new MockBootstrapRequest(m_local_io_ctx,
453                                     m_remote_io_ctx,
454                                     mock_instance_watcher,
455                                     &m_local_test_image_ctx,
456                                     local_image_id,
457                                     remote_image_id,
458                                     global_image_id,
459                                     m_threads->work_queue,
460                                     m_threads->timer,
461                                     &m_threads->timer_lock,
462                                     local_mirror_uuid,
463                                     remote_mirror_uuid,
464                                     &mock_journaler,
465                                     &m_mirror_peer_client_meta,
466                                     on_finish, &m_do_resync);
467   }
468
469   librbd::ImageCtx *m_remote_image_ctx;
470   librbd::ImageCtx *m_local_image_ctx = nullptr;
471   librbd::MockTestImageCtx *m_local_test_image_ctx = nullptr;
472   librbd::journal::MirrorPeerClientMeta m_mirror_peer_client_meta;
473   bool m_do_resync;
474 };
475
476 TEST_F(TestMockImageReplayerBootstrapRequest, NonPrimaryRemoteSyncingState) {
477   create_local_image();
478
479   InSequence seq;
480
481   // lookup remote image tag class
482   cls::journal::Client client;
483   librbd::journal::ClientData client_data{
484     librbd::journal::ImageClientMeta{123}};
485   ::encode(client_data, client.data);
486   ::journal::MockJournaler mock_journaler;
487   expect_journaler_get_client(mock_journaler,
488                               librbd::Journal<>::IMAGE_CLIENT_ID,
489                               client, 0);
490
491   // open the remote image
492   librbd::MockJournal mock_journal;
493   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
494   MockOpenImageRequest mock_open_image_request;
495   expect_open_image(mock_open_image_request, m_remote_io_ctx,
496                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
497
498   // lookup local peer in remote journal
499   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
500   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
501     mock_local_image_ctx.id};
502   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
503   client_data.client_meta = mirror_peer_client_meta;
504   client.data.clear();
505   ::encode(client_data, client.data);
506   expect_journaler_get_client(mock_journaler, "local mirror uuid",
507                               client, 0);
508
509   // test if remote image is primary
510   MockIsPrimaryRequest mock_is_primary_request;
511   expect_is_primary(mock_is_primary_request, false, 0);
512
513   // switch the state to replaying
514   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
515   client_data.client_meta = mirror_peer_client_meta;
516   expect_journaler_update_client(mock_journaler, client_data, 0);
517
518   MockCloseImageRequest mock_close_image_request;
519   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
520
521   C_SaferCond ctx;
522   MockInstanceWatcher mock_instance_watcher;
523   MockBootstrapRequest *request = create_request(
524     &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
525     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
526     "remote mirror uuid", &ctx);
527   request->send();
528   ASSERT_EQ(-EREMOTEIO, ctx.wait());
529 }
530
531 TEST_F(TestMockImageReplayerBootstrapRequest, RemoteDemotePromote) {
532   create_local_image();
533
534   InSequence seq;
535
536   // lookup remote image tag class
537   cls::journal::Client client;
538   librbd::journal::ClientData client_data{
539     librbd::journal::ImageClientMeta{123}};
540   ::encode(client_data, client.data);
541   ::journal::MockJournaler mock_journaler;
542   expect_journaler_get_client(mock_journaler,
543                               librbd::Journal<>::IMAGE_CLIENT_ID,
544                               client, 0);
545
546   // open the remote image
547   librbd::MockJournal mock_journal;
548   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
549   MockOpenImageRequest mock_open_image_request;
550   expect_open_image(mock_open_image_request, m_remote_io_ctx,
551                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
552
553   // lookup local peer in remote journal
554   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
555   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
556     mock_local_image_ctx.id};
557   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
558   client_data.client_meta = mirror_peer_client_meta;
559   client.data.clear();
560   ::encode(client_data, client.data);
561   expect_journaler_get_client(mock_journaler, "local mirror uuid",
562                               client, 0);
563
564   // test if remote image is primary
565   MockIsPrimaryRequest mock_is_primary_request;
566   expect_is_primary(mock_is_primary_request, true, 0);
567
568   // open the local image
569   mock_local_image_ctx.journal = &mock_journal;
570   MockOpenLocalImageRequest mock_open_local_image_request;
571   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
572                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
573   expect_is_resync_requested(mock_journal, false, 0);
574
575   // remote demotion / promotion event
576   Tags tags = {
577     {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
578                               librbd::Journal<>::LOCAL_MIRROR_UUID,
579                               true, 1, 99})},
580     {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
581                               librbd::Journal<>::LOCAL_MIRROR_UUID,
582                               true, 2, 1})},
583     {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
584                               librbd::Journal<>::ORPHAN_MIRROR_UUID,
585                               true, 2, 1})},
586     {5, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
587                               librbd::Journal<>::ORPHAN_MIRROR_UUID,
588                               true, 4, 369})}
589   };
590   expect_journaler_get_tags(mock_journaler, 123, tags, 0);
591   expect_journal_get_tag_tid(mock_journal, 345);
592   expect_journal_get_tag_data(mock_journal, {"remote mirror uuid"});
593
594   MockCloseImageRequest mock_close_image_request;
595   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
596
597   C_SaferCond ctx;
598   MockInstanceWatcher mock_instance_watcher;
599   MockBootstrapRequest *request = create_request(
600     &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
601     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
602     "remote mirror uuid", &ctx);
603   request->send();
604   ASSERT_EQ(0, ctx.wait());
605 }
606
607 TEST_F(TestMockImageReplayerBootstrapRequest, MultipleRemoteDemotePromotes) {
608   create_local_image();
609
610   InSequence seq;
611
612   // lookup remote image tag class
613   cls::journal::Client client;
614   librbd::journal::ClientData client_data{
615     librbd::journal::ImageClientMeta{123}};
616   ::encode(client_data, client.data);
617   ::journal::MockJournaler mock_journaler;
618   expect_journaler_get_client(mock_journaler,
619                               librbd::Journal<>::IMAGE_CLIENT_ID,
620                               client, 0);
621
622   // open the remote image
623   librbd::MockJournal mock_journal;
624   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
625   MockOpenImageRequest mock_open_image_request;
626   expect_open_image(mock_open_image_request, m_remote_io_ctx,
627                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
628
629   // lookup local peer in remote journal
630   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
631   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
632     mock_local_image_ctx.id};
633   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
634   client_data.client_meta = mirror_peer_client_meta;
635   client.data.clear();
636   ::encode(client_data, client.data);
637   expect_journaler_get_client(mock_journaler, "local mirror uuid",
638                               client, 0);
639
640   // test if remote image is primary
641   MockIsPrimaryRequest mock_is_primary_request;
642   expect_is_primary(mock_is_primary_request, true, 0);
643
644   // open the local image
645   mock_local_image_ctx.journal = &mock_journal;
646   MockOpenLocalImageRequest mock_open_local_image_request;
647   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
648                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
649   expect_is_resync_requested(mock_journal, false, 0);
650
651   // remote demotion / promotion event
652   Tags tags = {
653     {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
654                               librbd::Journal<>::LOCAL_MIRROR_UUID,
655                               true, 1, 99})},
656     {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
657                               librbd::Journal<>::LOCAL_MIRROR_UUID,
658                               true, 2, 1})},
659     {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
660                               librbd::Journal<>::ORPHAN_MIRROR_UUID,
661                               true, 3, 1})},
662     {5, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
663                               librbd::Journal<>::LOCAL_MIRROR_UUID,
664                               true, 4, 1})},
665     {6, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
666                               librbd::Journal<>::ORPHAN_MIRROR_UUID,
667                               true, 5, 1})},
668     {7, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
669                               librbd::Journal<>::LOCAL_MIRROR_UUID,
670                               true, 6, 1})},
671     {8, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
672                               librbd::Journal<>::ORPHAN_MIRROR_UUID,
673                               true, 7, 1})}
674   };
675   expect_journaler_get_tags(mock_journaler, 123, tags, 0);
676   expect_journal_get_tag_tid(mock_journal, 345);
677   expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::ORPHAN_MIRROR_UUID,
678                                              "remote mirror uuid", true, 4, 1});
679
680   MockCloseImageRequest mock_close_image_request;
681   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
682
683   C_SaferCond ctx;
684   MockInstanceWatcher mock_instance_watcher;
685   MockBootstrapRequest *request = create_request(
686     &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
687     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
688     "remote mirror uuid", &ctx);
689   request->send();
690   ASSERT_EQ(0, ctx.wait());
691 }
692
693 TEST_F(TestMockImageReplayerBootstrapRequest, LocalDemoteRemotePromote) {
694   create_local_image();
695
696   InSequence seq;
697
698   // lookup remote image tag class
699   cls::journal::Client client;
700   librbd::journal::ClientData client_data{
701     librbd::journal::ImageClientMeta{123}};
702   ::encode(client_data, client.data);
703   ::journal::MockJournaler mock_journaler;
704   expect_journaler_get_client(mock_journaler,
705                               librbd::Journal<>::IMAGE_CLIENT_ID,
706                               client, 0);
707
708   // open the remote image
709   librbd::MockJournal mock_journal;
710   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
711   MockOpenImageRequest mock_open_image_request;
712   expect_open_image(mock_open_image_request, m_remote_io_ctx,
713                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
714
715   // lookup local peer in remote journal
716   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
717   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
718     mock_local_image_ctx.id};
719   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
720   client_data.client_meta = mirror_peer_client_meta;
721   client.data.clear();
722   ::encode(client_data, client.data);
723   expect_journaler_get_client(mock_journaler, "local mirror uuid",
724                               client, 0);
725
726   // test if remote image is primary
727   MockIsPrimaryRequest mock_is_primary_request;
728   expect_is_primary(mock_is_primary_request, true, 0);
729
730   // open the local image
731   mock_local_image_ctx.journal = &mock_journal;
732   MockOpenLocalImageRequest mock_open_local_image_request;
733   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
734                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
735   expect_is_resync_requested(mock_journal, false, 0);
736
737   // remote demotion / promotion event
738   Tags tags = {
739     {2, 123, encode_tag_data({"local mirror uuid", "local mirror uuid",
740                               true, 344, 99})},
741     {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
742                               "local mirror uuid", true, 345, 1})},
743     {4, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
744                               librbd::Journal<>::ORPHAN_MIRROR_UUID,
745                               true, 3, 1})}
746   };
747   expect_journaler_get_tags(mock_journaler, 123, tags, 0);
748   expect_journal_get_tag_tid(mock_journal, 346);
749   expect_journal_get_tag_data(mock_journal,
750                               {librbd::Journal<>::ORPHAN_MIRROR_UUID,
751                                librbd::Journal<>::LOCAL_MIRROR_UUID,
752                                true, 345, 1});
753
754   MockCloseImageRequest mock_close_image_request;
755   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
756
757   C_SaferCond ctx;
758   MockInstanceWatcher mock_instance_watcher;
759   MockBootstrapRequest *request = create_request(
760     &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
761     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
762     "remote mirror uuid", &ctx);
763   request->send();
764   ASSERT_EQ(0, ctx.wait());
765 }
766
767 TEST_F(TestMockImageReplayerBootstrapRequest, SplitBrainForcePromote) {
768   create_local_image();
769
770   InSequence seq;
771
772   // lookup remote image tag class
773   cls::journal::Client client;
774   librbd::journal::ClientData client_data{
775     librbd::journal::ImageClientMeta{123}};
776   ::encode(client_data, client.data);
777   ::journal::MockJournaler mock_journaler;
778   expect_journaler_get_client(mock_journaler,
779                               librbd::Journal<>::IMAGE_CLIENT_ID,
780                               client, 0);
781
782   // open the remote image
783   librbd::MockJournal mock_journal;
784   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
785   MockOpenImageRequest mock_open_image_request;
786   expect_open_image(mock_open_image_request, m_remote_io_ctx,
787                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
788
789   // lookup local peer in remote journal
790   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
791   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
792     mock_local_image_ctx.id};
793   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
794   client_data.client_meta = mirror_peer_client_meta;
795   client.data.clear();
796   ::encode(client_data, client.data);
797   expect_journaler_get_client(mock_journaler, "local mirror uuid",
798                               client, 0);
799
800   // test if remote image is primary
801   MockIsPrimaryRequest mock_is_primary_request;
802   expect_is_primary(mock_is_primary_request, true, 0);
803
804   // open the local image
805   mock_local_image_ctx.journal = &mock_journal;
806   MockOpenLocalImageRequest mock_open_local_image_request;
807   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
808                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
809   expect_is_resync_requested(mock_journal, false, 0);
810
811   // remote demotion / promotion event
812   Tags tags = {
813     {2, 123, encode_tag_data({librbd::Journal<>::LOCAL_MIRROR_UUID,
814                               librbd::Journal<>::LOCAL_MIRROR_UUID,
815                               true, 1, 99})},
816     {3, 123, encode_tag_data({librbd::Journal<>::ORPHAN_MIRROR_UUID,
817                               librbd::Journal<>::LOCAL_MIRROR_UUID,
818                               true, 2, 1})}
819   };
820   expect_journaler_get_tags(mock_journaler, 123, tags, 0);
821   expect_journal_get_tag_tid(mock_journal, 345);
822   expect_journal_get_tag_data(mock_journal, {librbd::Journal<>::LOCAL_MIRROR_UUID,
823                                              librbd::Journal<>::ORPHAN_MIRROR_UUID,
824                                              true, 344, 0});
825
826   MockCloseImageRequest mock_close_image_request;
827   expect_close_image(mock_close_image_request, mock_local_image_ctx, 0);
828   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
829
830   C_SaferCond ctx;
831   MockInstanceWatcher mock_instance_watcher;
832   MockBootstrapRequest *request = create_request(
833     &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
834     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
835     "remote mirror uuid", &ctx);
836   request->send();
837   ASSERT_EQ(-EEXIST, ctx.wait());
838   ASSERT_EQ(NULL, m_local_test_image_ctx);
839 }
840
841 TEST_F(TestMockImageReplayerBootstrapRequest, ResyncRequested) {
842   create_local_image();
843
844   InSequence seq;
845
846   // lookup remote image tag class
847   cls::journal::Client client;
848   librbd::journal::ClientData client_data{
849     librbd::journal::ImageClientMeta{123}};
850   ::encode(client_data, client.data);
851   ::journal::MockJournaler mock_journaler;
852   expect_journaler_get_client(mock_journaler,
853                               librbd::Journal<>::IMAGE_CLIENT_ID,
854                               client, 0);
855
856   // open the remote image
857   librbd::MockJournal mock_journal;
858   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
859   MockOpenImageRequest mock_open_image_request;
860   expect_open_image(mock_open_image_request, m_remote_io_ctx,
861                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
862
863   // lookup local peer in remote journal
864   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
865   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
866     mock_local_image_ctx.id};
867   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
868   client_data.client_meta = mirror_peer_client_meta;
869   client.data.clear();
870   ::encode(client_data, client.data);
871   expect_journaler_get_client(mock_journaler, "local mirror uuid",
872                               client, 0);
873
874   // test if remote image is primary
875   MockIsPrimaryRequest mock_is_primary_request;
876   expect_is_primary(mock_is_primary_request, true, 0);
877
878   // open the local image
879   mock_local_image_ctx.journal = &mock_journal;
880   MockOpenLocalImageRequest mock_open_local_image_request;
881   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
882                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
883
884   // resync is requested
885   expect_is_resync_requested(mock_journal, true, 0);
886
887
888   MockCloseImageRequest mock_close_image_request;
889   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
890
891   C_SaferCond ctx;
892   MockInstanceWatcher mock_instance_watcher;
893   MockBootstrapRequest *request = create_request(
894     &mock_instance_watcher, mock_journaler, mock_local_image_ctx.id,
895     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
896     "remote mirror uuid", &ctx);
897   m_do_resync = false;
898   request->send();
899   ASSERT_EQ(0, ctx.wait());
900   ASSERT_TRUE(m_do_resync);
901 }
902
903 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemote) {
904   create_local_image();
905
906   InSequence seq;
907
908   // lookup remote image tag class
909   cls::journal::Client client;
910   librbd::journal::ClientData client_data{
911     librbd::journal::ImageClientMeta{123}};
912   ::encode(client_data, client.data);
913   ::journal::MockJournaler mock_journaler;
914   expect_journaler_get_client(mock_journaler,
915                               librbd::Journal<>::IMAGE_CLIENT_ID,
916                               client, 0);
917
918   // open the remote image
919   librbd::MockJournal mock_journal;
920   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
921   MockOpenImageRequest mock_open_image_request;
922   expect_open_image(mock_open_image_request, m_remote_io_ctx,
923                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
924
925   // lookup local peer in remote journal
926   client = {};
927   expect_journaler_get_client(mock_journaler, "local mirror uuid",
928                               client, -ENOENT);
929
930   // register missing client in remote journal
931   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta;
932   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
933   client_data.client_meta = mirror_peer_client_meta;
934   expect_journaler_register_client(mock_journaler, client_data, 0);
935
936   // test if remote image is primary
937   MockIsPrimaryRequest mock_is_primary_request;
938   expect_is_primary(mock_is_primary_request, true, 0);
939
940   // update client state back to syncing
941   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
942   mock_local_image_ctx.journal = &mock_journal;
943
944   librbd::util::s_image_id = mock_local_image_ctx.id;
945   mirror_peer_client_meta = {mock_local_image_ctx.id};
946   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
947   client_data.client_meta = mirror_peer_client_meta;
948   client.data.clear();
949   ::encode(client_data, client.data);
950   expect_journaler_update_client(mock_journaler, client_data, 0);
951
952   // create the local image
953   MockCreateImageRequest mock_create_image_request;
954   expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
955
956   // open the local image
957   MockOpenLocalImageRequest mock_open_local_image_request;
958   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
959                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
960   expect_is_resync_requested(mock_journal, false, 0);
961
962   // sync the remote image to the local image
963   MockImageSync mock_image_sync;
964   expect_image_sync(mock_image_sync, 0);
965
966   MockCloseImageRequest mock_close_image_request;
967   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
968
969   C_SaferCond ctx;
970   MockInstanceWatcher mock_instance_watcher;
971   MockBootstrapRequest *request = create_request(
972     &mock_instance_watcher, mock_journaler, "",
973     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
974     "remote mirror uuid", &ctx);
975   request->send();
976   ASSERT_EQ(0, ctx.wait());
977 }
978
979 TEST_F(TestMockImageReplayerBootstrapRequest, PrimaryRemoteLocalDeleted) {
980   create_local_image();
981
982   InSequence seq;
983
984   // lookup remote image tag class
985   cls::journal::Client client;
986   librbd::journal::ClientData client_data{
987     librbd::journal::ImageClientMeta{123}};
988   ::encode(client_data, client.data);
989   ::journal::MockJournaler mock_journaler;
990   expect_journaler_get_client(mock_journaler,
991                               librbd::Journal<>::IMAGE_CLIENT_ID,
992                               client, 0);
993
994   // open the remote image
995   librbd::MockJournal mock_journal;
996   librbd::MockTestImageCtx mock_remote_image_ctx(*m_remote_image_ctx);
997   MockOpenImageRequest mock_open_image_request;
998   expect_open_image(mock_open_image_request, m_remote_io_ctx,
999                     mock_remote_image_ctx.id, mock_remote_image_ctx, 0);
1000
1001   // lookup local peer in remote journal
1002   librbd::journal::MirrorPeerClientMeta mirror_peer_client_meta{
1003     "missing image id"};
1004   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
1005   client_data.client_meta = mirror_peer_client_meta;
1006   client.data.clear();
1007   ::encode(client_data, client.data);
1008   expect_journaler_get_client(mock_journaler, "local mirror uuid",
1009                               client, 0);
1010
1011   // test if remote image is primary
1012   MockIsPrimaryRequest mock_is_primary_request;
1013   expect_is_primary(mock_is_primary_request, true, 0);
1014
1015   // open the missing local image
1016   MockOpenLocalImageRequest mock_open_local_image_request;
1017   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
1018                           "missing image id", nullptr, -ENOENT);
1019
1020   // re-register the client
1021   expect_journaler_unregister_client(mock_journaler, 0);
1022   mirror_peer_client_meta = {};
1023   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_REPLAYING;
1024   client_data.client_meta = mirror_peer_client_meta;
1025   expect_journaler_register_client(mock_journaler, client_data, 0);
1026
1027   // test if remote image is primary
1028   expect_is_primary(mock_is_primary_request, true, 0);
1029
1030   // update client state back to syncing
1031   librbd::MockTestImageCtx mock_local_image_ctx(*m_local_image_ctx);
1032   mock_local_image_ctx.journal = &mock_journal;
1033
1034   librbd::util::s_image_id = mock_local_image_ctx.id;
1035   mirror_peer_client_meta = {mock_local_image_ctx.id};
1036   mirror_peer_client_meta.state = librbd::journal::MIRROR_PEER_STATE_SYNCING;
1037   client_data.client_meta = mirror_peer_client_meta;
1038   client.data.clear();
1039   ::encode(client_data, client.data);
1040   expect_journaler_update_client(mock_journaler, client_data, 0);
1041
1042   // create the missing local image
1043   MockCreateImageRequest mock_create_image_request;
1044   expect_create_image(mock_create_image_request, mock_local_image_ctx.id, 0);
1045
1046   // open the local image
1047   expect_open_local_image(mock_open_local_image_request, m_local_io_ctx,
1048                           mock_local_image_ctx.id, &mock_local_image_ctx, 0);
1049   expect_is_resync_requested(mock_journal, false, 0);
1050
1051   // sync the remote image to the local image
1052   MockImageSync mock_image_sync;
1053   expect_image_sync(mock_image_sync, 0);
1054
1055   MockCloseImageRequest mock_close_image_request;
1056   expect_close_image(mock_close_image_request, mock_remote_image_ctx, 0);
1057
1058   C_SaferCond ctx;
1059   MockInstanceWatcher mock_instance_watcher;
1060   MockBootstrapRequest *request = create_request(
1061     &mock_instance_watcher, mock_journaler, "",
1062     mock_remote_image_ctx.id, "global image id", "local mirror uuid",
1063     "remote mirror uuid", &ctx);
1064   request->send();
1065   ASSERT_EQ(0, ctx.wait());
1066 }
1067
1068 } // namespace image_replayer
1069 } // namespace mirror
1070 } // namespace rbd