]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/mirror/test_mock_DisableRequest.cc
update sources to 12.2.10
[ceph.git] / 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, 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