]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/mirror/test_mock_DisableRequest.cc
import 15.2.0 Octopus source
[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/MockImageState.h"
8 #include "test/librbd/mock/MockOperations.h"
9 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
10 #include "test/librados_test_stub/MockTestMemRadosClient.h"
11 #include "librbd/journal/PromoteRequest.h"
12 #include "librbd/mirror/DisableRequest.h"
13 #include "librbd/mirror/GetInfoRequest.h"
14 #include "librbd/mirror/ImageRemoveRequest.h"
15 #include "librbd/mirror/ImageStateUpdateRequest.h"
16 #include "librbd/mirror/snapshot/PromoteRequest.h"
17
18 namespace librbd {
19
20 namespace {
21
22 struct MockTestImageCtx : public MockImageCtx {
23 explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
24 }
25 };
26
27 } // anonymous namespace
28
29 namespace journal {
30
31 template <>
32 struct PromoteRequest<librbd::MockTestImageCtx> {
33 Context *on_finish = nullptr;
34 static PromoteRequest *s_instance;
35 static PromoteRequest *create(librbd::MockTestImageCtx *, bool force,
36 Context *on_finish) {
37 ceph_assert(s_instance != nullptr);
38 s_instance->on_finish = on_finish;
39 return s_instance;
40 }
41
42 PromoteRequest() {
43 s_instance = this;
44 }
45
46 MOCK_METHOD0(send, void());
47 };
48
49 PromoteRequest<librbd::MockTestImageCtx> *PromoteRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
50
51 } // namespace journal
52
53 namespace mirror {
54 template <>
55 struct GetInfoRequest<librbd::MockTestImageCtx> {
56 cls::rbd::MirrorImage *mirror_image;
57 PromotionState *promotion_state;
58 Context *on_finish = nullptr;
59 static GetInfoRequest *s_instance;
60 static GetInfoRequest *create(librbd::MockTestImageCtx &,
61 cls::rbd::MirrorImage *mirror_image,
62 PromotionState *promotion_state,
63 std::string* primary_mirror_uuid,
64 Context *on_finish) {
65 ceph_assert(s_instance != nullptr);
66 s_instance->mirror_image = mirror_image;
67 s_instance->promotion_state = promotion_state;
68 s_instance->on_finish = on_finish;
69 return s_instance;
70 }
71
72 GetInfoRequest() {
73 s_instance = this;
74 }
75
76 MOCK_METHOD0(send, void());
77 };
78
79 template <>
80 struct ImageRemoveRequest<librbd::MockTestImageCtx> {
81 static ImageRemoveRequest* s_instance;
82 Context* on_finish = nullptr;
83
84 static ImageRemoveRequest* create(
85 librados::IoCtx& io_ctx,
86 const std::string& global_image_id,
87 const std::string& image_id,
88 Context* on_finish) {
89 ceph_assert(s_instance != nullptr);
90 s_instance->on_finish = on_finish;
91 return s_instance;
92 }
93
94 MOCK_METHOD0(send, void());
95
96 ImageRemoveRequest() {
97 s_instance = this;
98 }
99 };
100
101 template <>
102 struct ImageStateUpdateRequest<librbd::MockTestImageCtx> {
103 static ImageStateUpdateRequest* s_instance;
104 Context* on_finish = nullptr;
105
106 static ImageStateUpdateRequest* create(
107 librados::IoCtx& io_ctx,
108 const std::string& image_id,
109 cls::rbd::MirrorImageState mirror_image_state,
110 const cls::rbd::MirrorImage& mirror_image,
111 Context* on_finish) {
112 ceph_assert(s_instance != nullptr);
113 s_instance->on_finish = on_finish;
114 return s_instance;
115 }
116
117 MOCK_METHOD0(send, void());
118
119 ImageStateUpdateRequest() {
120 s_instance = this;
121 }
122 };
123
124 GetInfoRequest<librbd::MockTestImageCtx> *GetInfoRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
125 ImageRemoveRequest<librbd::MockTestImageCtx> *ImageRemoveRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
126 ImageStateUpdateRequest<librbd::MockTestImageCtx> *ImageStateUpdateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
127
128 namespace snapshot {
129
130 template <>
131 struct PromoteRequest<librbd::MockTestImageCtx> {
132 Context *on_finish = nullptr;
133 static PromoteRequest *s_instance;
134 static PromoteRequest *create(librbd::MockTestImageCtx*,
135 const std::string& global_image_id,
136 Context *on_finish) {
137 ceph_assert(s_instance != nullptr);
138 s_instance->on_finish = on_finish;
139 return s_instance;
140 }
141
142 PromoteRequest() {
143 s_instance = this;
144 }
145
146 MOCK_METHOD0(send, void());
147 };
148
149 PromoteRequest<librbd::MockTestImageCtx> *PromoteRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
150
151 } // namespace snapshot
152 } // namespace mirror
153 } // namespace librbd
154
155 // template definitions
156 #include "librbd/mirror/DisableRequest.cc"
157 template class librbd::mirror::DisableRequest<librbd::MockTestImageCtx>;
158
159 ACTION_P(TestFeatures, image_ctx) {
160 return ((image_ctx->features & arg0) != 0);
161 }
162
163 namespace librbd {
164 namespace mirror {
165
166 using ::testing::_;
167 using ::testing::DoAll;
168 using ::testing::InSequence;
169 using ::testing::Invoke;
170 using ::testing::Return;
171 using ::testing::StrEq;
172 using ::testing::WithArg;
173
174 class TestMockMirrorDisableRequest : public TestMockFixture {
175 public:
176 typedef DisableRequest<MockTestImageCtx> MockDisableRequest;
177 typedef Journal<MockTestImageCtx> MockJournal;
178 typedef journal::PromoteRequest<MockTestImageCtx> MockJournalPromoteRequest;
179 typedef mirror::GetInfoRequest<MockTestImageCtx> MockGetInfoRequest;
180 typedef mirror::ImageRemoveRequest<MockTestImageCtx> MockImageRemoveRequest;
181 typedef mirror::ImageStateUpdateRequest<MockTestImageCtx> MockImageStateUpdateRequest;
182 typedef mirror::snapshot::PromoteRequest<MockTestImageCtx> MockSnapshotPromoteRequest;
183
184 void expect_get_mirror_info(MockTestImageCtx &mock_image_ctx,
185 MockGetInfoRequest &mock_get_info_request,
186 const cls::rbd::MirrorImage &mirror_image,
187 PromotionState promotion_state, int r) {
188
189 EXPECT_CALL(mock_get_info_request, send())
190 .WillOnce(
191 Invoke([this, &mock_image_ctx, &mock_get_info_request, mirror_image,
192 promotion_state, r]() {
193 if (r == 0) {
194 *mock_get_info_request.mirror_image = mirror_image;
195 *mock_get_info_request.promotion_state = promotion_state;
196 }
197 mock_image_ctx.op_work_queue->queue(
198 mock_get_info_request.on_finish, r);
199 }));
200 }
201
202 void expect_mirror_image_state_update(
203 MockTestImageCtx &mock_image_ctx,
204 MockImageStateUpdateRequest& mock_request, int r) {
205 EXPECT_CALL(mock_request, send())
206 .WillOnce(
207 Invoke([this, &mock_image_ctx, &mock_request, r]() {
208 mock_image_ctx.op_work_queue->queue(mock_request.on_finish, r);
209 }));
210 }
211
212 void expect_mirror_image_remove(
213 MockTestImageCtx &mock_image_ctx,
214 MockImageRemoveRequest& mock_request, int r) {
215 EXPECT_CALL(mock_request, send())
216 .WillOnce(
217 Invoke([this, &mock_image_ctx, &mock_request, r]() {
218 mock_image_ctx.op_work_queue->queue(mock_request.on_finish, r);
219 }));
220 }
221
222 void expect_journal_client_list(MockTestImageCtx &mock_image_ctx,
223 const std::set<cls::journal::Client> &clients,
224 int r) {
225 bufferlist bl;
226 using ceph::encode;
227 encode(clients, bl);
228
229 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
230 exec(::journal::Journaler::header_oid(mock_image_ctx.id),
231 _, StrEq("journal"), StrEq("client_list"), _, _, _))
232 .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
233 Return(r)));
234 }
235
236 void expect_journal_client_unregister(MockTestImageCtx &mock_image_ctx,
237 const std::string &client_id,
238 int r) {
239 bufferlist bl;
240 using ceph::encode;
241 encode(client_id, bl);
242
243 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
244 exec(::journal::Journaler::header_oid(mock_image_ctx.id),
245 _, StrEq("journal"), StrEq("client_unregister"),
246 ContentsEqual(bl), _, _))
247 .WillOnce(Return(r));
248 }
249
250 void expect_journal_promote(MockTestImageCtx &mock_image_ctx,
251 MockJournalPromoteRequest &mock_promote_request,
252 int r) {
253 EXPECT_CALL(mock_promote_request, send())
254 .WillOnce(FinishRequest(&mock_promote_request, r, &mock_image_ctx));
255 }
256
257 void expect_snapshot_promote(MockTestImageCtx &mock_image_ctx,
258 MockSnapshotPromoteRequest &mock_promote_request,
259 int r) {
260 EXPECT_CALL(mock_promote_request, send())
261 .WillOnce(FinishRequest(&mock_promote_request, r, &mock_image_ctx));
262 }
263
264 void expect_is_refresh_required(MockTestImageCtx &mock_image_ctx,
265 bool refresh_required) {
266 EXPECT_CALL(*mock_image_ctx.state, is_refresh_required())
267 .WillOnce(Return(refresh_required));
268 }
269
270 void expect_refresh_image(MockTestImageCtx &mock_image_ctx, int r) {
271 EXPECT_CALL(*mock_image_ctx.state, refresh(_))
272 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
273 }
274
275 void expect_snap_remove(MockTestImageCtx &mock_image_ctx,
276 const std::string &snap_name, int r) {
277 EXPECT_CALL(*mock_image_ctx.operations, snap_remove(_, StrEq(snap_name), _))
278 .WillOnce(WithArg<2>(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)));
279 }
280
281 template <typename T>
282 bufferlist encode(const T &t) {
283 using ceph::encode;
284 bufferlist bl;
285 encode(t, bl);
286 return bl;
287 }
288
289 };
290
291 TEST_F(TestMockMirrorDisableRequest, Success) {
292 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
293
294 librbd::ImageCtx *ictx;
295 ASSERT_EQ(0, open_image(m_image_name, &ictx));
296
297 MockTestImageCtx mock_image_ctx(*ictx);
298
299 expect_op_work_queue(mock_image_ctx);
300 expect_snap_remove(mock_image_ctx, "snap 1", 0);
301 expect_snap_remove(mock_image_ctx, "snap 2", 0);
302
303 InSequence seq;
304
305 MockGetInfoRequest mock_get_info_request;
306 expect_get_mirror_info(
307 mock_image_ctx, mock_get_info_request,
308 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
309 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
310 MockImageStateUpdateRequest mock_image_state_update_request;
311 expect_mirror_image_state_update(
312 mock_image_ctx, mock_image_state_update_request, 0);
313 expect_journal_client_list(
314 mock_image_ctx, {
315 {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
316 {"peer 1", encode(journal::ClientData{journal::MirrorPeerClientMeta{}})},
317 {"peer 2", encode(journal::ClientData{journal::MirrorPeerClientMeta{
318 "remote image id", {{cls::rbd::UserSnapshotNamespace(), "snap 1", boost::optional<uint64_t>(0)},
319 {cls::rbd::UserSnapshotNamespace(), "snap 2", boost::optional<uint64_t>(0)}}}
320 })}
321 }, 0);
322 expect_journal_client_unregister(mock_image_ctx, "peer 1", 0);
323 expect_journal_client_unregister(mock_image_ctx, "peer 2", 0);
324 expect_journal_client_list(mock_image_ctx, {}, 0);
325 MockImageRemoveRequest mock_image_remove_request;
326 expect_mirror_image_remove(
327 mock_image_ctx, mock_image_remove_request, 0);
328
329 C_SaferCond ctx;
330 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
331 req->send();
332 ASSERT_EQ(0, ctx.wait());
333 }
334
335 TEST_F(TestMockMirrorDisableRequest, SuccessNoRemove) {
336 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
337
338 librbd::ImageCtx *ictx;
339 ASSERT_EQ(0, open_image(m_image_name, &ictx));
340
341 MockTestImageCtx mock_image_ctx(*ictx);
342
343 expect_op_work_queue(mock_image_ctx);
344
345 InSequence seq;
346
347 MockGetInfoRequest mock_get_info_request;
348 expect_get_mirror_info(
349 mock_image_ctx, mock_get_info_request,
350 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
351 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
352 MockImageStateUpdateRequest mock_image_state_update_request;
353 expect_mirror_image_state_update(
354 mock_image_ctx, mock_image_state_update_request, 0);
355 expect_journal_client_list(mock_image_ctx, {}, 0);
356
357 C_SaferCond ctx;
358 auto req = new MockDisableRequest(&mock_image_ctx, false, false, &ctx);
359 req->send();
360 ASSERT_EQ(0, ctx.wait());
361 }
362
363 TEST_F(TestMockMirrorDisableRequest, SuccessNonPrimary) {
364 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
365
366 librbd::ImageCtx *ictx;
367 ASSERT_EQ(0, open_image(m_image_name, &ictx));
368
369 MockTestImageCtx mock_image_ctx(*ictx);
370 MockJournalPromoteRequest mock_promote_request;
371
372 expect_op_work_queue(mock_image_ctx);
373
374 InSequence seq;
375
376 MockGetInfoRequest mock_get_info_request;
377 expect_get_mirror_info(
378 mock_image_ctx, mock_get_info_request,
379 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
380 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0);
381 MockImageStateUpdateRequest mock_image_state_update_request;
382 expect_mirror_image_state_update(
383 mock_image_ctx, mock_image_state_update_request, 0);
384 expect_journal_promote(mock_image_ctx, mock_promote_request, 0);
385 expect_is_refresh_required(mock_image_ctx, false);
386 expect_journal_client_list(mock_image_ctx, {}, 0);
387 MockImageRemoveRequest mock_image_remove_request;
388 expect_mirror_image_remove(
389 mock_image_ctx, mock_image_remove_request, 0);
390
391 C_SaferCond ctx;
392 auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
393 req->send();
394 ASSERT_EQ(0, ctx.wait());
395 }
396
397 TEST_F(TestMockMirrorDisableRequest, NonPrimaryError) {
398 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
399
400 librbd::ImageCtx *ictx;
401 ASSERT_EQ(0, open_image(m_image_name, &ictx));
402
403 MockTestImageCtx mock_image_ctx(*ictx);
404
405 expect_op_work_queue(mock_image_ctx);
406
407 InSequence seq;
408
409 MockGetInfoRequest mock_get_info_request;
410 expect_get_mirror_info(
411 mock_image_ctx, mock_get_info_request,
412 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
413 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0);
414
415 C_SaferCond ctx;
416 auto req = new MockDisableRequest(&mock_image_ctx, false, false, &ctx);
417 req->send();
418 ASSERT_EQ(-EINVAL, ctx.wait());
419 }
420
421 TEST_F(TestMockMirrorDisableRequest, GetMirrorInfoError) {
422 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
423
424 librbd::ImageCtx *ictx;
425 ASSERT_EQ(0, open_image(m_image_name, &ictx));
426
427 MockTestImageCtx mock_image_ctx(*ictx);
428
429 expect_op_work_queue(mock_image_ctx);
430
431 InSequence seq;
432
433 MockGetInfoRequest mock_get_info_request;
434 expect_get_mirror_info(
435 mock_image_ctx, mock_get_info_request,
436 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
437 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, -EINVAL);
438
439 C_SaferCond ctx;
440 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
441 req->send();
442 ASSERT_EQ(-EINVAL, ctx.wait());
443 }
444
445 TEST_F(TestMockMirrorDisableRequest, MirrorImageSetError) {
446 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
447
448 librbd::ImageCtx *ictx;
449 ASSERT_EQ(0, open_image(m_image_name, &ictx));
450
451 MockTestImageCtx mock_image_ctx(*ictx);
452
453 expect_op_work_queue(mock_image_ctx);
454
455 InSequence seq;
456
457 MockGetInfoRequest mock_get_info_request;
458 expect_get_mirror_info(
459 mock_image_ctx, mock_get_info_request,
460 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
461 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
462 MockImageStateUpdateRequest mock_image_state_update_request;
463 expect_mirror_image_state_update(
464 mock_image_ctx, mock_image_state_update_request, -ENOENT);
465
466 C_SaferCond ctx;
467 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
468 req->send();
469 ASSERT_EQ(-ENOENT, ctx.wait());
470 }
471
472 TEST_F(TestMockMirrorDisableRequest, JournalPromoteError) {
473 librbd::ImageCtx *ictx;
474 ASSERT_EQ(0, open_image(m_image_name, &ictx));
475
476 MockTestImageCtx mock_image_ctx(*ictx);
477 MockJournalPromoteRequest mock_promote_request;
478
479 expect_op_work_queue(mock_image_ctx);
480
481 InSequence seq;
482
483 MockGetInfoRequest mock_get_info_request;
484 expect_get_mirror_info(
485 mock_image_ctx, mock_get_info_request,
486 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
487 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0);
488 MockImageStateUpdateRequest mock_image_state_update_request;
489 expect_mirror_image_state_update(
490 mock_image_ctx, mock_image_state_update_request, 0);
491 expect_journal_promote(mock_image_ctx, mock_promote_request, -EPERM);
492
493 C_SaferCond ctx;
494 auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
495 req->send();
496 ASSERT_EQ(-EPERM, ctx.wait());
497 }
498
499 TEST_F(TestMockMirrorDisableRequest, JournalClientListError) {
500 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
501
502 librbd::ImageCtx *ictx;
503 ASSERT_EQ(0, open_image(m_image_name, &ictx));
504
505 MockTestImageCtx mock_image_ctx(*ictx);
506
507 expect_op_work_queue(mock_image_ctx);
508
509 InSequence seq;
510
511 MockGetInfoRequest mock_get_info_request;
512 expect_get_mirror_info(
513 mock_image_ctx, mock_get_info_request,
514 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
515 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
516 MockImageStateUpdateRequest mock_image_state_update_request;
517 expect_mirror_image_state_update(
518 mock_image_ctx, mock_image_state_update_request, 0);
519 expect_journal_client_list(mock_image_ctx, {}, -EBADMSG);
520
521 C_SaferCond ctx;
522 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
523 req->send();
524 ASSERT_EQ(-EBADMSG, ctx.wait());
525 }
526
527 TEST_F(TestMockMirrorDisableRequest, SnapRemoveError) {
528 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
529
530 librbd::ImageCtx *ictx;
531 ASSERT_EQ(0, open_image(m_image_name, &ictx));
532
533 MockTestImageCtx mock_image_ctx(*ictx);
534
535 expect_op_work_queue(mock_image_ctx);
536 expect_snap_remove(mock_image_ctx, "snap 1", 0);
537 expect_snap_remove(mock_image_ctx, "snap 2", -EPERM);
538
539 InSequence seq;
540
541 MockGetInfoRequest mock_get_info_request;
542 expect_get_mirror_info(
543 mock_image_ctx, mock_get_info_request,
544 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
545 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
546 MockImageStateUpdateRequest mock_image_state_update_request;
547 expect_mirror_image_state_update(
548 mock_image_ctx, mock_image_state_update_request, 0);
549 expect_journal_client_list(
550 mock_image_ctx, {
551 {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
552 {"peer 1", encode(journal::ClientData{journal::MirrorPeerClientMeta{}})},
553 {"peer 2", encode(journal::ClientData{journal::MirrorPeerClientMeta{
554 "remote image id", {{cls::rbd::UserSnapshotNamespace(), "snap 1", boost::optional<uint64_t>(0)},
555 {cls::rbd::UserSnapshotNamespace(), "snap 2", boost::optional<uint64_t>(0)}}}
556 })}
557 }, 0);
558 expect_journal_client_unregister(mock_image_ctx, "peer 1", 0);
559
560 C_SaferCond ctx;
561 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
562 req->send();
563 ASSERT_EQ(-EPERM, ctx.wait());
564 }
565
566 TEST_F(TestMockMirrorDisableRequest, JournalClientUnregisterError) {
567 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
568
569 librbd::ImageCtx *ictx;
570 ASSERT_EQ(0, open_image(m_image_name, &ictx));
571
572 MockTestImageCtx mock_image_ctx(*ictx);
573
574 expect_op_work_queue(mock_image_ctx);
575 expect_snap_remove(mock_image_ctx, "snap 1", 0);
576 expect_snap_remove(mock_image_ctx, "snap 2", 0);
577
578 InSequence seq;
579
580 MockGetInfoRequest mock_get_info_request;
581 expect_get_mirror_info(
582 mock_image_ctx, mock_get_info_request,
583 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
584 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
585 MockImageStateUpdateRequest mock_image_state_update_request;
586 expect_mirror_image_state_update(
587 mock_image_ctx, mock_image_state_update_request, 0);
588 expect_journal_client_list(
589 mock_image_ctx, {
590 {"", encode(journal::ClientData{journal::ImageClientMeta{}})},
591 {"peer 1", encode(journal::ClientData{journal::MirrorPeerClientMeta{}})},
592 {"peer 2", encode(journal::ClientData{journal::MirrorPeerClientMeta{
593 "remote image id", {{cls::rbd::UserSnapshotNamespace(), "snap 1", boost::optional<uint64_t>(0)},
594 {cls::rbd::UserSnapshotNamespace(), "snap 2", boost::optional<uint64_t>(0)}}}
595 })}
596 }, 0);
597 expect_journal_client_unregister(mock_image_ctx, "peer 1", -EINVAL);
598 expect_journal_client_unregister(mock_image_ctx, "peer 2", 0);
599
600 C_SaferCond ctx;
601 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
602 req->send();
603 ASSERT_EQ(-EINVAL, ctx.wait());
604 }
605
606 TEST_F(TestMockMirrorDisableRequest, SnapshotPromoteError) {
607 librbd::ImageCtx *ictx;
608 ASSERT_EQ(0, open_image(m_image_name, &ictx));
609
610 MockTestImageCtx mock_image_ctx(*ictx);
611 MockSnapshotPromoteRequest mock_promote_request;
612
613 expect_op_work_queue(mock_image_ctx);
614
615 InSequence seq;
616
617 MockGetInfoRequest mock_get_info_request;
618 expect_get_mirror_info(
619 mock_image_ctx, mock_get_info_request,
620 {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "global id",
621 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0);
622 MockImageStateUpdateRequest mock_image_state_update_request;
623 expect_mirror_image_state_update(
624 mock_image_ctx, mock_image_state_update_request, 0);
625 expect_snapshot_promote(mock_image_ctx, mock_promote_request, -EPERM);
626
627 C_SaferCond ctx;
628 auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
629 req->send();
630 ASSERT_EQ(-EPERM, ctx.wait());
631 }
632
633 TEST_F(TestMockMirrorDisableRequest, RefreshError) {
634 librbd::ImageCtx *ictx;
635 ASSERT_EQ(0, open_image(m_image_name, &ictx));
636
637 MockTestImageCtx mock_image_ctx(*ictx);
638 MockSnapshotPromoteRequest mock_promote_request;
639
640 expect_op_work_queue(mock_image_ctx);
641
642 InSequence seq;
643
644 MockGetInfoRequest mock_get_info_request;
645 expect_get_mirror_info(
646 mock_image_ctx, mock_get_info_request,
647 {cls::rbd::MIRROR_IMAGE_MODE_SNAPSHOT, "global id",
648 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_NON_PRIMARY, 0);
649 MockImageStateUpdateRequest mock_image_state_update_request;
650 expect_mirror_image_state_update(
651 mock_image_ctx, mock_image_state_update_request, 0);
652 expect_snapshot_promote(mock_image_ctx, mock_promote_request, 0);
653 expect_is_refresh_required(mock_image_ctx, true);
654 expect_refresh_image(mock_image_ctx, -EPERM);
655
656 C_SaferCond ctx;
657 auto req = new MockDisableRequest(&mock_image_ctx, true, true, &ctx);
658 req->send();
659 ASSERT_EQ(-EPERM, ctx.wait());
660 }
661
662 TEST_F(TestMockMirrorDisableRequest, MirrorImageRemoveError) {
663 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
664
665 librbd::ImageCtx *ictx;
666 ASSERT_EQ(0, open_image(m_image_name, &ictx));
667
668 MockTestImageCtx mock_image_ctx(*ictx);
669
670 expect_op_work_queue(mock_image_ctx);
671
672 InSequence seq;
673
674 MockGetInfoRequest mock_get_info_request;
675 expect_get_mirror_info(
676 mock_image_ctx, mock_get_info_request,
677 {cls::rbd::MIRROR_IMAGE_MODE_JOURNAL, "global id",
678 cls::rbd::MIRROR_IMAGE_STATE_ENABLED}, PROMOTION_STATE_PRIMARY, 0);
679 MockImageStateUpdateRequest mock_image_state_update_request;
680 expect_mirror_image_state_update(
681 mock_image_ctx, mock_image_state_update_request, 0);
682 expect_journal_client_list(mock_image_ctx, {}, 0);
683 MockImageRemoveRequest mock_image_remove_request;
684 expect_mirror_image_remove(
685 mock_image_ctx, mock_image_remove_request, -EINVAL);
686
687 C_SaferCond ctx;
688 auto req = new MockDisableRequest(&mock_image_ctx, false, true, &ctx);
689 req->send();
690 ASSERT_EQ(-EINVAL, ctx.wait());
691 }
692
693 } // namespace mirror
694 } // namespace librbd