]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/mirror/snapshot/test_mock_CreatePrimaryRequest.cc
update ceph source to reef 18.2.1
[ceph.git] / ceph / src / test / librbd / mirror / snapshot / test_mock_CreatePrimaryRequest.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 "include/stringify.h"
5 #include "test/librbd/test_mock_fixture.h"
6 #include "test/librbd/test_support.h"
7 #include "test/librbd/mock/MockImageCtx.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/mirror/snapshot/CreatePrimaryRequest.h"
12 #include "librbd/mirror/snapshot/UnlinkPeerRequest.h"
13 #include "librbd/mirror/snapshot/Utils.h"
14
15 namespace librbd {
16
17 namespace {
18
19 struct MockTestImageCtx : public MockImageCtx {
20 explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
21 }
22 };
23
24 } // anonymous namespace
25
26 namespace mirror {
27 namespace snapshot {
28 namespace util {
29
30 namespace {
31
32 struct Mock {
33 static Mock* s_instance;
34
35 Mock() {
36 s_instance = this;
37 }
38
39 MOCK_METHOD4(can_create_primary_snapshot,
40 bool(librbd::MockTestImageCtx *, bool, bool, uint64_t *));
41 };
42
43 Mock *Mock::s_instance = nullptr;
44
45 } // anonymous namespace
46
47 template<> bool can_create_primary_snapshot(librbd::MockTestImageCtx *image_ctx,
48 bool demoted, bool force,
49 bool* requires_orphan,
50 uint64_t *rollback_snap_id) {
51 return Mock::s_instance->can_create_primary_snapshot(image_ctx, demoted,
52 force, rollback_snap_id);
53 }
54
55 } // namespace util
56
57 template <>
58 struct UnlinkPeerRequest<MockTestImageCtx> {
59 uint64_t snap_id = CEPH_NOSNAP;
60 std::string mirror_peer_uuid;
61 bool allow_remove;
62 Context* on_finish = nullptr;
63 static UnlinkPeerRequest* s_instance;
64 static UnlinkPeerRequest *create(MockTestImageCtx *image_ctx,
65 uint64_t snap_id,
66 const std::string &mirror_peer_uuid,
67 bool allow_remove,
68 Context *on_finish) {
69 ceph_assert(s_instance != nullptr);
70 s_instance->snap_id = snap_id;
71 s_instance->mirror_peer_uuid = mirror_peer_uuid;
72 s_instance->allow_remove = allow_remove;
73 s_instance->on_finish = on_finish;
74 return s_instance;
75 }
76
77 MOCK_METHOD0(send, void());
78
79 UnlinkPeerRequest() {
80 s_instance = this;
81 }
82 };
83
84 UnlinkPeerRequest<MockTestImageCtx>* UnlinkPeerRequest<MockTestImageCtx>::s_instance = nullptr;
85
86 } // namespace snapshot
87 } // namespace mirror
88 } // namespace librbd
89
90 // template definitions
91 #include "librbd/mirror/snapshot/CreatePrimaryRequest.cc"
92 template class librbd::mirror::snapshot::CreatePrimaryRequest<librbd::MockTestImageCtx>;
93
94 namespace librbd {
95 namespace mirror {
96 namespace snapshot {
97
98 using ::testing::_;
99 using ::testing::DoAll;
100 using ::testing::InSequence;
101 using ::testing::Invoke;
102 using ::testing::Return;
103 using ::testing::StrEq;
104 using ::testing::WithArg;
105
106 class TestMockMirrorSnapshotCreatePrimaryRequest : public TestMockFixture {
107 public:
108 typedef CreatePrimaryRequest<MockTestImageCtx> MockCreatePrimaryRequest;
109 typedef UnlinkPeerRequest<MockTestImageCtx> MockUnlinkPeerRequest;
110 typedef util::Mock MockUtils;
111
112 uint64_t m_snap_seq = 0;
113
114 void snap_create(MockTestImageCtx &mock_image_ctx,
115 const cls::rbd::SnapshotNamespace &ns,
116 const std::string& snap_name) {
117 ASSERT_TRUE(mock_image_ctx.snap_info.insert(
118 {m_snap_seq++,
119 SnapInfo{snap_name, ns, 0, {}, 0, 0, {}}}).second);
120 }
121
122 void expect_clone_md_ctx(MockTestImageCtx &mock_image_ctx) {
123 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx), clone())
124 .WillOnce(Invoke([&mock_image_ctx]() {
125 get_mock_io_ctx(mock_image_ctx.md_ctx).get();
126 return &get_mock_io_ctx(mock_image_ctx.md_ctx);
127 }));
128 }
129
130 void expect_can_create_primary_snapshot(MockUtils &mock_utils, bool demoted,
131 bool force, bool result) {
132 EXPECT_CALL(mock_utils,
133 can_create_primary_snapshot(_, demoted, force, nullptr))
134 .WillOnce(Return(result));
135 }
136
137 void expect_get_mirror_peers(MockTestImageCtx &mock_image_ctx,
138 const std::vector<cls::rbd::MirrorPeer> &peers,
139 int r) {
140 using ceph::encode;
141 bufferlist bl;
142 encode(peers, bl);
143
144 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
145 exec(RBD_MIRRORING, _, StrEq("rbd"), StrEq("mirror_peer_list"),
146 _, _, _, _))
147 .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
148 Return(r)));
149 }
150
151 void expect_create_snapshot(MockTestImageCtx &mock_image_ctx, int r) {
152 EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _, _, _))
153 .WillOnce(DoAll(
154 Invoke([this, &mock_image_ctx, r](
155 const cls::rbd::SnapshotNamespace &ns,
156 const std::string& snap_name,
157 uint64_t flags,
158 ProgressContext &prog_ctx,
159 Context *on_finish) {
160 if (r != 0) {
161 return;
162 }
163 auto mirror_ns =
164 std::get<cls::rbd::MirrorSnapshotNamespace>(ns);
165 mirror_ns.complete = true;
166 snap_create(mock_image_ctx, mirror_ns, snap_name);
167 }),
168 WithArg<4>(CompleteContext(
169 r, mock_image_ctx.image_ctx->op_work_queue))
170 ));
171 }
172
173 void expect_refresh_image(MockTestImageCtx &mock_image_ctx, int r) {
174 EXPECT_CALL(*mock_image_ctx.state, refresh(_))
175 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
176 }
177
178 void expect_unlink_peer(MockTestImageCtx &mock_image_ctx,
179 MockUnlinkPeerRequest &mock_unlink_peer_request,
180 uint64_t snap_id, const std::string &peer_uuid,
181 bool is_linked, bool complete, bool allow_remove,
182 int r) {
183 EXPECT_CALL(mock_unlink_peer_request, send())
184 .WillOnce(Invoke([&mock_image_ctx, &mock_unlink_peer_request,
185 snap_id, peer_uuid, is_linked, complete, allow_remove, r]() {
186 ASSERT_EQ(mock_unlink_peer_request.mirror_peer_uuid,
187 peer_uuid);
188 ASSERT_EQ(mock_unlink_peer_request.snap_id, snap_id);
189 ASSERT_EQ(mock_unlink_peer_request.allow_remove, allow_remove);
190 if (r == 0) {
191 auto it = mock_image_ctx.snap_info.find(snap_id);
192 ASSERT_NE(it, mock_image_ctx.snap_info.end());
193 auto info =
194 std::get_if<cls::rbd::MirrorSnapshotNamespace>(
195 &it->second.snap_namespace);
196 ASSERT_NE(nullptr, info);
197 ASSERT_EQ(complete, info->complete);
198 ASSERT_EQ(is_linked, info->mirror_peer_uuids.erase(
199 peer_uuid));
200 if (info->mirror_peer_uuids.empty()) {
201 mock_image_ctx.snap_info.erase(it);
202 }
203 }
204 mock_image_ctx.image_ctx->op_work_queue->queue(
205 mock_unlink_peer_request.on_finish, r);
206 }));
207 }
208 };
209
210 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, Success) {
211 REQUIRE_FORMAT_V2();
212
213 librbd::ImageCtx *ictx;
214 ASSERT_EQ(0, open_image(m_image_name, &ictx));
215
216 MockTestImageCtx mock_image_ctx(*ictx);
217
218 InSequence seq;
219
220 expect_clone_md_ctx(mock_image_ctx);
221 MockUtils mock_utils;
222 expect_can_create_primary_snapshot(mock_utils, false, false, true);
223 expect_get_mirror_peers(mock_image_ctx,
224 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
225 "mirror", "mirror uuid"}}, 0);
226 expect_create_snapshot(mock_image_ctx, 0);
227 expect_refresh_image(mock_image_ctx, 0);
228
229 C_SaferCond ctx;
230 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
231 0U, 0U, nullptr, &ctx);
232 req->send();
233 ASSERT_EQ(0, ctx.wait());
234 }
235
236 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessPrimary) {
237 REQUIRE_FORMAT_V2();
238
239 librbd::ImageCtx *ictx;
240 ASSERT_EQ(0, open_image(m_image_name, &ictx));
241
242 MockTestImageCtx mock_image_ctx(*ictx);
243 cls::rbd::MirrorSnapshotNamespace ns{
244 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
245 ns.complete = true;
246 snap_create(mock_image_ctx, ns, "mirror_snap");
247
248 InSequence seq;
249
250 expect_clone_md_ctx(mock_image_ctx);
251 MockUtils mock_utils;
252 expect_can_create_primary_snapshot(mock_utils, false, false, true);
253 expect_get_mirror_peers(mock_image_ctx,
254 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
255 "mirror", "mirror uuid"}}, 0);
256 expect_create_snapshot(mock_image_ctx, 0);
257 expect_refresh_image(mock_image_ctx, 0);
258
259 C_SaferCond ctx;
260 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
261 0U, 0U, nullptr, &ctx);
262 req->send();
263 ASSERT_EQ(0, ctx.wait());
264 }
265
266 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessPrimaryDemoted) {
267 REQUIRE_FORMAT_V2();
268
269 librbd::ImageCtx *ictx;
270 ASSERT_EQ(0, open_image(m_image_name, &ictx));
271
272 MockTestImageCtx mock_image_ctx(*ictx);
273 cls::rbd::MirrorSnapshotNamespace ns{
274 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {"uuid"}, "", CEPH_NOSNAP};
275 ns.complete = true;
276 snap_create(mock_image_ctx, ns, "mirror_snap");
277
278 InSequence seq;
279
280 expect_clone_md_ctx(mock_image_ctx);
281 MockUtils mock_utils;
282 expect_can_create_primary_snapshot(mock_utils, false, false, true);
283 expect_get_mirror_peers(mock_image_ctx,
284 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
285 "mirror", "mirror uuid"}}, 0);
286 expect_create_snapshot(mock_image_ctx, 0);
287 expect_refresh_image(mock_image_ctx, 0);
288
289 C_SaferCond ctx;
290 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
291 0U, 0U, nullptr, &ctx);
292 req->send();
293 ASSERT_EQ(0, ctx.wait());
294 }
295
296 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessNonPrimaryDemoted) {
297 REQUIRE_FORMAT_V2();
298
299 librbd::ImageCtx *ictx;
300 ASSERT_EQ(0, open_image(m_image_name, &ictx));
301
302 MockTestImageCtx mock_image_ctx(*ictx);
303 cls::rbd::MirrorSnapshotNamespace ns{
304 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, {"uuid"},
305 "mirror uuid", 123};
306 ns.complete = true;
307 snap_create(mock_image_ctx, ns, "mirror_snap");
308
309 InSequence seq;
310
311 expect_clone_md_ctx(mock_image_ctx);
312 MockUtils mock_utils;
313 expect_can_create_primary_snapshot(mock_utils, false, false, true);
314 expect_get_mirror_peers(mock_image_ctx,
315 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
316 "mirror", "mirror uuid"}}, 0);
317 expect_create_snapshot(mock_image_ctx, 0);
318 expect_refresh_image(mock_image_ctx, 0);
319
320 C_SaferCond ctx;
321 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
322 0U, 0U, nullptr, &ctx);
323 req->send();
324 ASSERT_EQ(0, ctx.wait());
325 }
326
327 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessPrimaryBelowMaxSnapshots) {
328 REQUIRE_FORMAT_V2();
329
330 librbd::ImageCtx *ictx;
331 ASSERT_EQ(0, open_image(m_image_name, &ictx));
332 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
333
334 MockTestImageCtx mock_image_ctx(*ictx);
335 for (int i = 0; i < 2; i++) {
336 cls::rbd::MirrorSnapshotNamespace ns{
337 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
338 ns.complete = true;
339 snap_create(mock_image_ctx, ns, "mirror_snap");
340 }
341
342 InSequence seq;
343
344 expect_clone_md_ctx(mock_image_ctx);
345 MockUtils mock_utils;
346 expect_can_create_primary_snapshot(mock_utils, false, false, true);
347 expect_get_mirror_peers(mock_image_ctx,
348 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
349 "mirror", "mirror uuid"}}, 0);
350 expect_create_snapshot(mock_image_ctx, 0);
351 expect_refresh_image(mock_image_ctx, 0);
352
353 C_SaferCond ctx;
354 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
355 0U, 0U, nullptr, &ctx);
356 req->send();
357 ASSERT_EQ(0, ctx.wait());
358 }
359
360 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessPrimaryBelowMaxSnapshotsReset) {
361 REQUIRE_FORMAT_V2();
362
363 librbd::ImageCtx *ictx;
364 ASSERT_EQ(0, open_image(m_image_name, &ictx));
365 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
366
367 MockTestImageCtx mock_image_ctx(*ictx);
368 for (int i = 0; i < 6; i++) {
369 cls::rbd::MirrorSnapshotNamespace ns{
370 (i == 3 ? cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED :
371 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY),
372 {"uuid"}, "", CEPH_NOSNAP};
373 ns.complete = true;
374 snap_create(mock_image_ctx, ns, "mirror_snap");
375 }
376
377 InSequence seq;
378
379 expect_clone_md_ctx(mock_image_ctx);
380 MockUtils mock_utils;
381 expect_can_create_primary_snapshot(mock_utils, false, false, true);
382 expect_get_mirror_peers(mock_image_ctx,
383 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
384 "mirror", "mirror uuid"}}, 0);
385 expect_create_snapshot(mock_image_ctx, 0);
386 expect_refresh_image(mock_image_ctx, 0);
387
388 C_SaferCond ctx;
389 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
390 0U, 0U, nullptr, &ctx);
391 req->send();
392 ASSERT_EQ(0, ctx.wait());
393 }
394
395 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, CanNotError) {
396 REQUIRE_FORMAT_V2();
397
398 librbd::ImageCtx *ictx;
399 ASSERT_EQ(0, open_image(m_image_name, &ictx));
400
401 MockTestImageCtx mock_image_ctx(*ictx);
402
403 InSequence seq;
404
405 expect_clone_md_ctx(mock_image_ctx);
406 MockUtils mock_utils;
407 expect_can_create_primary_snapshot(mock_utils, false, false, false);
408
409 C_SaferCond ctx;
410 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
411 0U, 0U, nullptr, &ctx);
412 req->send();
413 ASSERT_EQ(-EINVAL, ctx.wait());
414 }
415
416 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, GetMirrorPeersError) {
417 REQUIRE_FORMAT_V2();
418
419 librbd::ImageCtx *ictx;
420 ASSERT_EQ(0, open_image(m_image_name, &ictx));
421
422 MockTestImageCtx mock_image_ctx(*ictx);
423
424 InSequence seq;
425
426 expect_clone_md_ctx(mock_image_ctx);
427 MockUtils mock_utils;
428 expect_can_create_primary_snapshot(mock_utils, false, false, true);
429 expect_get_mirror_peers(mock_image_ctx,
430 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
431 "mirror", "mirror uuid"}}, -EINVAL);
432
433 C_SaferCond ctx;
434 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
435 0U, 0U, nullptr, &ctx);
436 req->send();
437 ASSERT_EQ(-EINVAL, ctx.wait());
438 }
439
440 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, CreateSnapshotError) {
441 REQUIRE_FORMAT_V2();
442
443 librbd::ImageCtx *ictx;
444 ASSERT_EQ(0, open_image(m_image_name, &ictx));
445
446 MockTestImageCtx mock_image_ctx(*ictx);
447
448 InSequence seq;
449
450 expect_clone_md_ctx(mock_image_ctx);
451 MockUtils mock_utils;
452 expect_can_create_primary_snapshot(mock_utils, false, false, true);
453 expect_get_mirror_peers(mock_image_ctx,
454 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
455 "mirror", "mirror uuid"}}, 0);
456 expect_create_snapshot(mock_image_ctx, -EINVAL);
457
458 C_SaferCond ctx;
459 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
460 0U, 0U, nullptr, &ctx);
461 req->send();
462 ASSERT_EQ(-EINVAL, ctx.wait());
463 }
464
465 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPrimaryNoPeer) {
466 REQUIRE_FORMAT_V2();
467
468 librbd::ImageCtx *ictx;
469 ASSERT_EQ(0, open_image(m_image_name, &ictx));
470
471 MockTestImageCtx mock_image_ctx(*ictx);
472 cls::rbd::MirrorSnapshotNamespace ns{
473 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP};
474 ns.complete = true;
475 snap_create(mock_image_ctx, ns, "mirror_snap");
476
477 InSequence seq;
478
479 expect_clone_md_ctx(mock_image_ctx);
480 MockUtils mock_utils;
481 expect_can_create_primary_snapshot(mock_utils, false, false, true);
482 expect_get_mirror_peers(mock_image_ctx,
483 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
484 "mirror", "mirror uuid"}}, 0);
485 expect_create_snapshot(mock_image_ctx, 0);
486 expect_refresh_image(mock_image_ctx, 0);
487 MockUnlinkPeerRequest mock_unlink_peer_request;
488 auto it = mock_image_ctx.snap_info.rbegin();
489 auto snap_id = it->first;
490 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
491 false, true, true, 0);
492
493 C_SaferCond ctx;
494 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
495 0U, 0U, nullptr, &ctx);
496 req->send();
497 ASSERT_EQ(0, ctx.wait());
498 }
499
500 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPrimaryDemotedNoPeer) {
501 REQUIRE_FORMAT_V2();
502
503 librbd::ImageCtx *ictx;
504 ASSERT_EQ(0, open_image(m_image_name, &ictx));
505
506 MockTestImageCtx mock_image_ctx(*ictx);
507 cls::rbd::MirrorSnapshotNamespace ns{
508 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP};
509 ns.complete = true;
510 snap_create(mock_image_ctx, ns, "mirror_snap");
511
512 InSequence seq;
513
514 expect_clone_md_ctx(mock_image_ctx);
515 MockUtils mock_utils;
516 expect_can_create_primary_snapshot(mock_utils, false, false, true);
517 expect_get_mirror_peers(mock_image_ctx,
518 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
519 "mirror", "mirror uuid"}}, 0);
520 expect_create_snapshot(mock_image_ctx, 0);
521 expect_refresh_image(mock_image_ctx, 0);
522 MockUnlinkPeerRequest mock_unlink_peer_request;
523 auto it = mock_image_ctx.snap_info.rbegin();
524 auto snap_id = it->first;
525 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
526 false, true, true, 0);
527
528 C_SaferCond ctx;
529 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
530 0U, 0U, nullptr, &ctx);
531 req->send();
532 ASSERT_EQ(0, ctx.wait());
533 }
534
535 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkNonPrimaryDemotedNoPeer) {
536 REQUIRE_FORMAT_V2();
537
538 librbd::ImageCtx *ictx;
539 ASSERT_EQ(0, open_image(m_image_name, &ictx));
540
541 MockTestImageCtx mock_image_ctx(*ictx);
542 cls::rbd::MirrorSnapshotNamespace ns{
543 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY_DEMOTED, {},
544 "mirror uuid", 123};
545 ns.complete = true;
546 snap_create(mock_image_ctx, ns, "mirror_snap");
547
548 InSequence seq;
549
550 expect_clone_md_ctx(mock_image_ctx);
551 MockUtils mock_utils;
552 expect_can_create_primary_snapshot(mock_utils, false, false, true);
553 expect_get_mirror_peers(mock_image_ctx,
554 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
555 "mirror", "mirror uuid"}}, 0);
556 expect_create_snapshot(mock_image_ctx, 0);
557 expect_refresh_image(mock_image_ctx, 0);
558 MockUnlinkPeerRequest mock_unlink_peer_request;
559 auto it = mock_image_ctx.snap_info.rbegin();
560 auto snap_id = it->first;
561 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
562 false, true, true, 0);
563
564 C_SaferCond ctx;
565 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
566 0U, 0U, nullptr, &ctx);
567 req->send();
568 ASSERT_EQ(0, ctx.wait());
569 }
570
571 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkOrphanNoPeer) {
572 REQUIRE_FORMAT_V2();
573
574 librbd::ImageCtx *ictx;
575 ASSERT_EQ(0, open_image(m_image_name, &ictx));
576
577 MockTestImageCtx mock_image_ctx(*ictx);
578 cls::rbd::MirrorSnapshotNamespace ns{
579 cls::rbd::MIRROR_SNAPSHOT_STATE_NON_PRIMARY, {}, "", CEPH_NOSNAP};
580 ns.complete = true;
581 snap_create(mock_image_ctx, ns, "mirror_snap");
582
583 InSequence seq;
584
585 expect_clone_md_ctx(mock_image_ctx);
586 MockUtils mock_utils;
587 expect_can_create_primary_snapshot(mock_utils, false, false, true);
588 expect_get_mirror_peers(mock_image_ctx,
589 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
590 "mirror", "mirror uuid"}}, 0);
591 expect_create_snapshot(mock_image_ctx, 0);
592 expect_refresh_image(mock_image_ctx, 0);
593 MockUnlinkPeerRequest mock_unlink_peer_request;
594 auto it = mock_image_ctx.snap_info.rbegin();
595 auto snap_id = it->first;
596 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
597 false, true, true, 0);
598
599 C_SaferCond ctx;
600 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
601 0U, 0U, nullptr, &ctx);
602 req->send();
603 ASSERT_EQ(0, ctx.wait());
604 }
605
606 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPrimaryIncomplete) {
607 REQUIRE_FORMAT_V2();
608
609 librbd::ImageCtx *ictx;
610 ASSERT_EQ(0, open_image(m_image_name, &ictx));
611
612 MockTestImageCtx mock_image_ctx(*ictx);
613 cls::rbd::MirrorSnapshotNamespace ns{
614 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
615 ns.complete = false;
616 snap_create(mock_image_ctx, ns, "mirror_snap");
617
618 InSequence seq;
619
620 expect_clone_md_ctx(mock_image_ctx);
621 MockUtils mock_utils;
622 expect_can_create_primary_snapshot(mock_utils, false, false, true);
623 expect_get_mirror_peers(mock_image_ctx,
624 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
625 "mirror", "mirror uuid"}}, 0);
626 expect_create_snapshot(mock_image_ctx, 0);
627 expect_refresh_image(mock_image_ctx, 0);
628 MockUnlinkPeerRequest mock_unlink_peer_request;
629 auto it = mock_image_ctx.snap_info.rbegin();
630 auto snap_id = it->first;
631 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
632 true, false, true, 0);
633
634 C_SaferCond ctx;
635 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
636 0U, 0U, nullptr, &ctx);
637 req->send();
638 ASSERT_EQ(0, ctx.wait());
639 }
640
641 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPrimaryMaxSnapshots) {
642 REQUIRE_FORMAT_V2();
643
644 librbd::ImageCtx *ictx;
645 ASSERT_EQ(0, open_image(m_image_name, &ictx));
646 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
647
648 MockTestImageCtx mock_image_ctx(*ictx);
649 for (int i = 0; i < 3; i++) {
650 cls::rbd::MirrorSnapshotNamespace ns{
651 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
652 ns.complete = true;
653 snap_create(mock_image_ctx, ns, "mirror_snap");
654 }
655
656 InSequence seq;
657
658 expect_clone_md_ctx(mock_image_ctx);
659 MockUtils mock_utils;
660 expect_can_create_primary_snapshot(mock_utils, false, false, true);
661 expect_get_mirror_peers(mock_image_ctx,
662 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
663 "mirror", "mirror uuid"}}, 0);
664 expect_create_snapshot(mock_image_ctx, 0);
665 expect_refresh_image(mock_image_ctx, 0);
666 MockUnlinkPeerRequest mock_unlink_peer_request;
667 auto it = mock_image_ctx.snap_info.rbegin();
668 auto snap_id = it->first;
669 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
670 true, true, true, 0);
671
672 C_SaferCond ctx;
673 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
674 0U, 0U, nullptr, &ctx);
675 req->send();
676 ASSERT_EQ(0, ctx.wait());
677 }
678
679 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPrimaryMaxSnapshotsReset) {
680 REQUIRE_FORMAT_V2();
681
682 librbd::ImageCtx *ictx;
683 ASSERT_EQ(0, open_image(m_image_name, &ictx));
684 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
685
686 MockTestImageCtx mock_image_ctx(*ictx);
687 for (int i = 0; i < 7; i++) {
688 cls::rbd::MirrorSnapshotNamespace ns{
689 (i == 3 ? cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED :
690 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY),
691 {"uuid"}, "", CEPH_NOSNAP};
692 ns.complete = true;
693 snap_create(mock_image_ctx, ns, "mirror_snap");
694 }
695
696 InSequence seq;
697
698 expect_clone_md_ctx(mock_image_ctx);
699 MockUtils mock_utils;
700 expect_can_create_primary_snapshot(mock_utils, false, false, true);
701 expect_get_mirror_peers(mock_image_ctx,
702 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
703 "mirror", "mirror uuid"}}, 0);
704 expect_create_snapshot(mock_image_ctx, 0);
705 expect_refresh_image(mock_image_ctx, 0);
706 MockUnlinkPeerRequest mock_unlink_peer_request;
707 auto it = mock_image_ctx.snap_info.rbegin();
708 auto snap_id = it->first;
709 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
710 true, true, true, 0);
711
712 C_SaferCond ctx;
713 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
714 0U, 0U, nullptr, &ctx);
715 req->send();
716 ASSERT_EQ(0, ctx.wait());
717 }
718
719 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkMultiplePeers) {
720 REQUIRE_FORMAT_V2();
721
722 librbd::ImageCtx *ictx;
723 ASSERT_EQ(0, open_image(m_image_name, &ictx));
724 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
725
726 MockTestImageCtx mock_image_ctx(*ictx);
727 for (int i = 0; i < 3; i++) {
728 cls::rbd::MirrorSnapshotNamespace ns{
729 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid1", "uuid2"}, "",
730 CEPH_NOSNAP};
731 ns.complete = true;
732 snap_create(mock_image_ctx, ns, "mirror_snap");
733 }
734
735 InSequence seq;
736
737 expect_clone_md_ctx(mock_image_ctx);
738 MockUtils mock_utils;
739 expect_can_create_primary_snapshot(mock_utils, false, false, true);
740 expect_get_mirror_peers(mock_image_ctx,
741 {{"uuid1", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
742 "mirror", "mirror uuid"},
743 {"uuid2", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
744 "mirror", "mirror uuid"}}, 0);
745 expect_create_snapshot(mock_image_ctx, 0);
746 expect_refresh_image(mock_image_ctx, 0);
747 MockUnlinkPeerRequest mock_unlink_peer_request;
748 auto it = mock_image_ctx.snap_info.rbegin();
749 auto snap_id = it->first;
750 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid1",
751 true, true, true, 0);
752 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid2",
753 true, true, true, 0);
754
755 C_SaferCond ctx;
756 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
757 0U, 0U, nullptr, &ctx);
758 req->send();
759 ASSERT_EQ(0, ctx.wait());
760 }
761
762 TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkMultipleSnapshots) {
763 REQUIRE_FORMAT_V2();
764
765 librbd::ImageCtx *ictx;
766 ASSERT_EQ(0, open_image(m_image_name, &ictx));
767
768 MockTestImageCtx mock_image_ctx(*ictx);
769 cls::rbd::MirrorSnapshotNamespace ns1{
770 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP};
771 ns1.complete = true;
772 snap_create(mock_image_ctx, ns1, "mirror_snap");
773 cls::rbd::MirrorSnapshotNamespace ns2{
774 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY_DEMOTED, {}, "", CEPH_NOSNAP};
775 ns2.complete = true;
776 snap_create(mock_image_ctx, ns2, "mirror_snap");
777
778 InSequence seq;
779
780 expect_clone_md_ctx(mock_image_ctx);
781 MockUtils mock_utils;
782 expect_can_create_primary_snapshot(mock_utils, false, false, true);
783 expect_get_mirror_peers(mock_image_ctx,
784 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
785 "mirror", "mirror uuid"}}, 0);
786 expect_create_snapshot(mock_image_ctx, 0);
787 expect_refresh_image(mock_image_ctx, 0);
788 MockUnlinkPeerRequest mock_unlink_peer_request;
789 auto it = mock_image_ctx.snap_info.begin();
790 auto snap_id = it->first;
791 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
792 false, true, true, 0);
793 snap_id = (++it)->first;
794 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
795 false, true, true, 0);
796
797 C_SaferCond ctx;
798 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
799 0U, 0U, nullptr, &ctx);
800 req->send();
801 ASSERT_EQ(0, ctx.wait());
802 }
803
804 } // namespace snapshot
805 } // namespace mirror
806 } // namespace librbd
807