Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / mirror / test_mock_DisableRequest.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/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockImageCtx.h"
7 #include "test/librbd/mock/MockOperations.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "test/librados_test_stub/MockTestMemRadosClient.h"
10 #include "common/Mutex.h"
11 #include "librbd/MirroringWatcher.h"
12 #include "librbd/journal/PromoteRequest.h"
13 #include "librbd/mirror/DisableRequest.h"
14
15 namespace librbd {
16
17 namespace {
18
19 struct MockTestImageCtx : public MockImageCtx {
20   MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
21   }
22 };
23
24 } // anonymous namespace
25
26 template <>
27 struct Journal<librbd::MockTestImageCtx> {
28   static Journal *s_instance;
29   static void is_tag_owner(librbd::MockTestImageCtx *, bool *is_primary,
30                            Context *on_finish) {
31     assert(s_instance != nullptr);
32     s_instance->is_tag_owner(is_primary, on_finish);
33   }
34
35   Journal() {
36     s_instance = this;
37   }
38
39   MOCK_METHOD2(is_tag_owner, void(bool*, Context*));
40 };
41
42 Journal<librbd::MockTestImageCtx> *Journal<librbd::MockTestImageCtx>::s_instance = nullptr;
43
44 template <>
45 struct MirroringWatcher<librbd::MockTestImageCtx> {
46   static MirroringWatcher *s_instance;
47   static void notify_image_updated(librados::IoCtx &io_ctx,
48                                    cls::rbd::MirrorImageState mirror_image_state,
49                                    const std::string &image_id,
50                                    const std::string &global_image_id,
51                                    Context *on_finish) {
52     assert(s_instance != nullptr);
53     s_instance->notify_image_updated(mirror_image_state, image_id,
54                                      global_image_id, on_finish);
55   }
56
57   MirroringWatcher() {
58     s_instance = this;
59   }
60
61   MOCK_METHOD4(notify_image_updated, void(cls::rbd::MirrorImageState,
62                                           const std::string &,
63                                           const std::string &,
64                                           Context *));
65 };
66
67 MirroringWatcher<librbd::MockTestImageCtx> *MirroringWatcher<librbd::MockTestImageCtx>::s_instance = nullptr;
68
69 namespace journal {
70
71 template <>
72 struct PromoteRequest<librbd::MockTestImageCtx> {
73   Context *on_finish = nullptr;
74   static PromoteRequest *s_instance;
75   static PromoteRequest *create(librbd::MockTestImageCtx *, bool force,
76                                 Context *on_finish) {
77     assert(s_instance != nullptr);
78     s_instance->on_finish = on_finish;
79     return s_instance;
80   }
81
82   PromoteRequest() {
83     s_instance = this;
84   }
85
86   MOCK_METHOD0(send, void());
87 };
88
89 PromoteRequest<librbd::MockTestImageCtx> *PromoteRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
90
91 } // namespace journal
92
93 } // namespace librbd
94
95 // template definitions
96 #include "librbd/mirror/DisableRequest.cc"
97 template class librbd::mirror::DisableRequest<librbd::MockTestImageCtx>;
98
99 namespace librbd {
100 namespace mirror {
101
102 using ::testing::_;
103 using ::testing::DoAll;
104 using ::testing::InSequence;
105 using ::testing::Return;
106 using ::testing::SetArgPointee;
107 using ::testing::StrEq;
108 using ::testing::WithArg;
109
110 class TestMockMirrorDisableRequest : public TestMockFixture {
111 public:
112   typedef DisableRequest<MockTestImageCtx> MockDisableRequest;
113   typedef Journal<MockTestImageCtx> MockJournal;
114   typedef MirroringWatcher<MockTestImageCtx> MockMirroringWatcher;
115   typedef journal::PromoteRequest<MockTestImageCtx> MockPromoteRequest;
116
117   void expect_get_mirror_image(MockTestImageCtx &mock_image_ctx,
118                                const cls::rbd::MirrorImage &mirror_image,
119                                int r) {
120     bufferlist bl;
121     ::encode(mirror_image, bl);
122
123     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
124                 exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_get"),
125                      _, _, _))
126       .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
127                       Return(r)));
128   }
129
130   void expect_is_tag_owner(MockTestImageCtx &mock_image_ctx,
131                            MockJournal &mock_journal,
132                            bool is_primary, int r) {
133     EXPECT_CALL(mock_journal, is_tag_owner(_, _))
134       .WillOnce(DoAll(SetArgPointee<0>(is_primary),
135                       WithArg<1>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue))));
136   }
137
138   void expect_set_mirror_image(MockTestImageCtx &mock_image_ctx, int r) {
139     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
140                 exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_set"),
141                      _, _, _))
142       .WillOnce(Return(r));
143   }
144
145   void expect_remove_mirror_image(MockTestImageCtx &mock_image_ctx, int r) {
146     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
147                 exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_image_remove"),
148                      _, _, _))
149       .WillOnce(Return(r));
150   }
151
152   void expect_notify_image_updated(MockTestImageCtx &mock_image_ctx,
153                                    MockMirroringWatcher &mock_mirroring_watcher,
154                                    cls::rbd::MirrorImageState state,
155                                    const std::string &global_id, int r) {
156     EXPECT_CALL(mock_mirroring_watcher,
157                 notify_image_updated(state, mock_image_ctx.id, global_id, _))
158       .WillOnce(WithArg<3>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
159   }
160
161   void expect_journal_client_list(MockTestImageCtx &mock_image_ctx,
162                                   const std::set<cls::journal::Client> &clients,
163                                   int r) {
164     bufferlist bl;
165     ::encode(clients, bl);
166
167     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
168                 exec(::journal::Journaler::header_oid(mock_image_ctx.id),
169                      _, StrEq("journal"), StrEq("client_list"), _, _, _))
170       .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
171                       Return(r)));
172   }
173
174   void expect_journal_client_unregister(MockTestImageCtx &mock_image_ctx,
175                                         const std::string &client_id,
176                                         int r) {
177     bufferlist bl;
178     ::encode(client_id, bl);
179
180     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
181                 exec(::journal::Journaler::header_oid(mock_image_ctx.id),
182                      _, StrEq("journal"), StrEq("client_unregister"),
183                      ContentsEqual(bl), _, _))
184       .WillOnce(Return(r));
185   }
186
187   void expect_journal_promote(MockTestImageCtx &mock_image_ctx,
188                               MockPromoteRequest &mock_promote_request, int r) {
189     EXPECT_CALL(mock_promote_request, send())
190       .WillOnce(FinishRequest(&mock_promote_request, r, &mock_image_ctx));
191   }
192
193   void expect_snap_remove(MockTestImageCtx &mock_image_ctx,
194                           const std::string &snap_name, int r) {
195     EXPECT_CALL(*mock_image_ctx.operations, execute_snap_remove(_, StrEq(snap_name), _))
196       .WillOnce(WithArg<2>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
197   }
198
199   template <typename T>
200   bufferlist encode(const T &t) {
201     bufferlist bl;
202     ::encode(t, bl);
203     return bl;
204   }
205
206 };
207
208 TEST_F(TestMockMirrorDisableRequest, Success) {
209   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
210
211   librbd::ImageCtx *ictx;
212   ASSERT_EQ(0, open_image(m_image_name, &ictx));
213
214   MockTestImageCtx mock_image_ctx(*ictx);
215   MockJournal mock_journal;
216   MockMirroringWatcher mock_mirroring_watcher;
217
218   expect_op_work_queue(mock_image_ctx);
219   expect_snap_remove(mock_image_ctx, "snap 1", 0);
220   expect_snap_remove(mock_image_ctx, "snap 2", 0);
221
222   InSequence seq;
223   expect_get_mirror_image(mock_image_ctx,
224                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
225                           0);
226   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
227   expect_set_mirror_image(mock_image_ctx, 0);
228   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
229                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
230                               "global id", -ESHUTDOWN);
231   expect_journal_client_list(
232     mock_image_ctx, {
233       {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
234       {"peer 1", encode(journal::ClientData{journal::MirrorPeerClientMeta{}})},
235       {"peer 2", encode(journal::ClientData{journal::MirrorPeerClientMeta{
236         "remote image id", {{cls::rbd::UserSnapshotNamespace(), "snap 1", boost::optional<uint64_t>(0)},
237                             {cls::rbd::UserSnapshotNamespace(), "snap 2", boost::optional<uint64_t>(0)}}}
238       })}
239     }, 0);
240   expect_journal_client_unregister(mock_image_ctx, "peer 1", 0);
241   expect_journal_client_unregister(mock_image_ctx, "peer 2", 0);
242   expect_journal_client_list(mock_image_ctx, {}, 0);
243   expect_remove_mirror_image(mock_image_ctx, 0);
244   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
245                               cls::rbd::MIRROR_IMAGE_STATE_DISABLED,
246                               "global id", -ETIMEDOUT);
247
248   C_SaferCond ctx;
249   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
250   req->send();
251   ASSERT_EQ(0, ctx.wait());
252 }
253
254 TEST_F(TestMockMirrorDisableRequest, SuccessNoRemove) {
255   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
256
257   librbd::ImageCtx *ictx;
258   ASSERT_EQ(0, open_image(m_image_name, &ictx));
259
260   MockTestImageCtx mock_image_ctx(*ictx);
261   MockJournal mock_journal;
262   MockMirroringWatcher mock_mirroring_watcher;
263
264   expect_op_work_queue(mock_image_ctx);
265
266   InSequence seq;
267   expect_get_mirror_image(mock_image_ctx,
268                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
269                           0);
270   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
271   expect_set_mirror_image(mock_image_ctx, 0);
272   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
273                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
274                               "global id", 0);
275   expect_journal_client_list(mock_image_ctx, {}, 0);
276
277   C_SaferCond ctx;
278   auto req = new MockDisableRequest(&mock_image_ctx, false, false, &ctx);
279   req->send();
280   ASSERT_EQ(0, ctx.wait());
281 }
282
283 TEST_F(TestMockMirrorDisableRequest, SuccessNonPrimary) {
284   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
285
286   librbd::ImageCtx *ictx;
287   ASSERT_EQ(0, open_image(m_image_name, &ictx));
288
289   MockTestImageCtx mock_image_ctx(*ictx);
290   MockJournal mock_journal;
291   MockMirroringWatcher mock_mirroring_watcher;
292   MockPromoteRequest mock_promote_request;
293
294   expect_op_work_queue(mock_image_ctx);
295
296   InSequence seq;
297   expect_get_mirror_image(mock_image_ctx,
298                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
299                           0);
300   expect_is_tag_owner(mock_image_ctx, mock_journal, false, 0);
301   expect_set_mirror_image(mock_image_ctx, 0);
302   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
303                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
304                               "global id", 0);
305   expect_journal_promote(mock_image_ctx, mock_promote_request, 0);
306   expect_journal_client_list(mock_image_ctx, {}, 0);
307   expect_remove_mirror_image(mock_image_ctx, 0);
308   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
309                               cls::rbd::MIRROR_IMAGE_STATE_DISABLED,
310                               "global id", 0);
311
312   C_SaferCond ctx;
313   auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
314   req->send();
315   ASSERT_EQ(0, ctx.wait());
316 }
317
318 TEST_F(TestMockMirrorDisableRequest, NonPrimaryError) {
319   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
320
321   librbd::ImageCtx *ictx;
322   ASSERT_EQ(0, open_image(m_image_name, &ictx));
323
324   MockTestImageCtx mock_image_ctx(*ictx);
325   MockJournal mock_journal;
326   MockMirroringWatcher mock_mirroring_watcher;
327
328   expect_op_work_queue(mock_image_ctx);
329
330   InSequence seq;
331   expect_get_mirror_image(mock_image_ctx,
332                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
333                           0);
334   expect_is_tag_owner(mock_image_ctx, mock_journal, false, 0);
335
336   C_SaferCond ctx;
337   auto req = new MockDisableRequest(&mock_image_ctx, false, false, &ctx);
338   req->send();
339   ASSERT_EQ(-EINVAL, ctx.wait());
340 }
341
342 TEST_F(TestMockMirrorDisableRequest, MirrorImageGetError) {
343   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
344
345   librbd::ImageCtx *ictx;
346   ASSERT_EQ(0, open_image(m_image_name, &ictx));
347
348   MockTestImageCtx mock_image_ctx(*ictx);
349   MockJournal mock_journal;
350
351   expect_op_work_queue(mock_image_ctx);
352
353   InSequence seq;
354   expect_get_mirror_image(mock_image_ctx, {}, -EBADMSG);
355
356   C_SaferCond ctx;
357   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
358   req->send();
359   ASSERT_EQ(-EBADMSG, ctx.wait());
360 }
361
362 TEST_F(TestMockMirrorDisableRequest, IsTagOwnerError) {
363   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
364
365   librbd::ImageCtx *ictx;
366   ASSERT_EQ(0, open_image(m_image_name, &ictx));
367
368   MockTestImageCtx mock_image_ctx(*ictx);
369   MockJournal mock_journal;
370
371   expect_op_work_queue(mock_image_ctx);
372
373   InSequence seq;
374   expect_get_mirror_image(mock_image_ctx,
375                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
376                           0);
377   expect_is_tag_owner(mock_image_ctx, mock_journal, true, -EBADMSG);
378
379   C_SaferCond ctx;
380   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
381   req->send();
382   ASSERT_EQ(-EBADMSG, ctx.wait());
383 }
384
385 TEST_F(TestMockMirrorDisableRequest, MirrorImageSetError) {
386   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
387
388   librbd::ImageCtx *ictx;
389   ASSERT_EQ(0, open_image(m_image_name, &ictx));
390
391   MockTestImageCtx mock_image_ctx(*ictx);
392   MockJournal mock_journal;
393
394   expect_op_work_queue(mock_image_ctx);
395
396   InSequence seq;
397   expect_get_mirror_image(mock_image_ctx,
398                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
399                           0);
400   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
401   expect_set_mirror_image(mock_image_ctx, -ENOENT);
402
403   C_SaferCond ctx;
404   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
405   req->send();
406   ASSERT_EQ(-ENOENT, ctx.wait());
407 }
408
409 TEST_F(TestMockMirrorDisableRequest, JournalPromoteError) {
410   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
411
412   librbd::ImageCtx *ictx;
413   ASSERT_EQ(0, open_image(m_image_name, &ictx));
414
415   MockTestImageCtx mock_image_ctx(*ictx);
416   MockJournal mock_journal;
417   MockMirroringWatcher mock_mirroring_watcher;
418   MockPromoteRequest mock_promote_request;
419
420   expect_op_work_queue(mock_image_ctx);
421
422   InSequence seq;
423   expect_get_mirror_image(mock_image_ctx,
424                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
425                           0);
426   expect_is_tag_owner(mock_image_ctx, mock_journal, false, 0);
427   expect_set_mirror_image(mock_image_ctx, 0);
428   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
429                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
430                               "global id", 0);
431   expect_journal_promote(mock_image_ctx, mock_promote_request, -EPERM);
432
433   C_SaferCond ctx;
434   auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
435   req->send();
436   ASSERT_EQ(-EPERM, ctx.wait());
437 }
438
439 TEST_F(TestMockMirrorDisableRequest, JournalClientListError) {
440   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
441
442   librbd::ImageCtx *ictx;
443   ASSERT_EQ(0, open_image(m_image_name, &ictx));
444
445   MockTestImageCtx mock_image_ctx(*ictx);
446   MockJournal mock_journal;
447   MockMirroringWatcher mock_mirroring_watcher;
448
449   expect_op_work_queue(mock_image_ctx);
450
451   InSequence seq;
452   expect_get_mirror_image(mock_image_ctx,
453                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
454                           0);
455   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
456   expect_set_mirror_image(mock_image_ctx, 0);
457   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
458                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
459                               "global id", 0);
460   expect_journal_client_list(mock_image_ctx, {}, -EBADMSG);
461
462   C_SaferCond ctx;
463   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
464   req->send();
465   ASSERT_EQ(-EBADMSG, ctx.wait());
466 }
467
468 TEST_F(TestMockMirrorDisableRequest, SnapRemoveError) {
469   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
470
471   librbd::ImageCtx *ictx;
472   ASSERT_EQ(0, open_image(m_image_name, &ictx));
473
474   MockTestImageCtx mock_image_ctx(*ictx);
475   MockJournal mock_journal;
476   MockMirroringWatcher mock_mirroring_watcher;
477
478   expect_op_work_queue(mock_image_ctx);
479   expect_snap_remove(mock_image_ctx, "snap 1", 0);
480   expect_snap_remove(mock_image_ctx, "snap 2", -EPERM);
481
482   InSequence seq;
483   expect_get_mirror_image(mock_image_ctx,
484                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
485                           0);
486   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
487   expect_set_mirror_image(mock_image_ctx, 0);
488   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
489                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
490                               "global id", 0);
491   expect_journal_client_list(
492     mock_image_ctx, {
493       {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
494       {"peer 1", encode(journal::ClientData{journal::MirrorPeerClientMeta{}})},
495       {"peer 2", encode(journal::ClientData{journal::MirrorPeerClientMeta{
496         "remote image id", {{cls::rbd::UserSnapshotNamespace(), "snap 1", boost::optional<uint64_t>(0)},
497                             {cls::rbd::UserSnapshotNamespace(), "snap 2", boost::optional<uint64_t>(0)}}}
498       })}
499     }, 0);
500   expect_journal_client_unregister(mock_image_ctx, "peer 1", 0);
501
502   C_SaferCond ctx;
503   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
504   req->send();
505   ASSERT_EQ(-EPERM, ctx.wait());
506 }
507
508 TEST_F(TestMockMirrorDisableRequest, JournalClientUnregisterError) {
509   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
510
511   librbd::ImageCtx *ictx;
512   ASSERT_EQ(0, open_image(m_image_name, &ictx));
513
514   MockTestImageCtx mock_image_ctx(*ictx);
515   MockJournal mock_journal;
516   MockMirroringWatcher mock_mirroring_watcher;
517
518   expect_op_work_queue(mock_image_ctx);
519   expect_snap_remove(mock_image_ctx, "snap 1", 0);
520   expect_snap_remove(mock_image_ctx, "snap 2", 0);
521
522   InSequence seq;
523   expect_get_mirror_image(mock_image_ctx,
524                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
525                           0);
526   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
527   expect_set_mirror_image(mock_image_ctx, 0);
528   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
529                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
530                               "global id", 0);
531   expect_journal_client_list(
532     mock_image_ctx, {
533       {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
534       {"peer 1", encode(journal::ClientData{journal::MirrorPeerClientMeta{}})},
535       {"peer 2", encode(journal::ClientData{journal::MirrorPeerClientMeta{
536         "remote image id", {{cls::rbd::UserSnapshotNamespace(), "snap 1", boost::optional<uint64_t>(0)},
537                             {cls::rbd::UserSnapshotNamespace(), "snap 2", boost::optional<uint64_t>(0)}}}
538       })}
539     }, 0);
540   expect_journal_client_unregister(mock_image_ctx, "peer 1", -EINVAL);
541   expect_journal_client_unregister(mock_image_ctx, "peer 2", 0);
542
543   C_SaferCond ctx;
544   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
545   req->send();
546   ASSERT_EQ(-EINVAL, ctx.wait());
547 }
548
549 TEST_F(TestMockMirrorDisableRequest, MirrorImageRemoveError) {
550   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
551
552   librbd::ImageCtx *ictx;
553   ASSERT_EQ(0, open_image(m_image_name, &ictx));
554
555   MockTestImageCtx mock_image_ctx(*ictx);
556   MockJournal mock_journal;
557   MockMirroringWatcher mock_mirroring_watcher;
558
559   expect_op_work_queue(mock_image_ctx);
560
561   InSequence seq;
562   expect_get_mirror_image(mock_image_ctx,
563                           {"global id", cls::rbd::MIRROR_IMAGE_STATE_ENABLED},
564                           0);
565   expect_is_tag_owner(mock_image_ctx, mock_journal, true, 0);
566   expect_set_mirror_image(mock_image_ctx, 0);
567   expect_notify_image_updated(mock_image_ctx, mock_mirroring_watcher,
568                               cls::rbd::MIRROR_IMAGE_STATE_DISABLING,
569                               "global id", 0);
570   expect_journal_client_list(mock_image_ctx, {}, 0);
571   expect_remove_mirror_image(mock_image_ctx, -EINVAL);
572
573   C_SaferCond ctx;
574   auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
575   req->send();
576   ASSERT_EQ(-EINVAL, ctx.wait());
577 }
578
579 } // namespace mirror
580 } // namespace librbd
581