]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/mirror/snapshot/test_mock_UnlinkPeerRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / mirror / snapshot / test_mock_UnlinkPeerRequest.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 "librbd/mirror/snapshot/UnlinkPeerRequest.h"
11
12 namespace librbd {
13
14 namespace {
15
16 struct MockTestImageCtx : public MockImageCtx {
17 explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
18 }
19 };
20
21 } // anonymous namespace
22 } // namespace librbd
23
24 // template definitions
25 #include "librbd/mirror/snapshot/UnlinkPeerRequest.cc"
26 template class librbd::mirror::snapshot::UnlinkPeerRequest<librbd::MockTestImageCtx>;
27
28 namespace librbd {
29 namespace mirror {
30 namespace snapshot {
31
32 using ::testing::_;
33 using ::testing::DoAll;
34 using ::testing::InSequence;
35 using ::testing::Invoke;
36 using ::testing::Return;
37 using ::testing::StrEq;
38
39 class TestMockMirrorSnapshotUnlinkPeerRequest : public TestMockFixture {
40 public:
41 typedef UnlinkPeerRequest<MockTestImageCtx> MockUnlinkPeerRequest;
42
43 uint64_t m_snap_seq = 0;
44
45 uint64_t snap_create(MockTestImageCtx &mock_image_ctx,
46 const cls::rbd::SnapshotNamespace &ns,
47 const std::string& snap_name) {
48 EXPECT_TRUE(mock_image_ctx.snap_info.insert(
49 {++m_snap_seq,
50 SnapInfo{snap_name, ns, 0, {}, 0, 0, {}}}).second);
51 return m_snap_seq;
52 }
53
54 void expect_get_snap_info(MockTestImageCtx &mock_image_ctx,
55 librados::snap_t snap_id) {
56 EXPECT_CALL(mock_image_ctx, get_snap_info(snap_id))
57 .WillRepeatedly(Invoke([&mock_image_ctx](
58 librados::snap_t snap_id) -> librbd::SnapInfo * {
59 auto it = mock_image_ctx.snap_info.find(snap_id);
60 if (it == mock_image_ctx.snap_info.end()) {
61 return nullptr;
62 }
63 return &it->second;
64 }));
65 }
66
67 void expect_is_refresh_required(MockTestImageCtx &mock_image_ctx,
68 bool refresh_required) {
69 EXPECT_CALL(*mock_image_ctx.state, is_refresh_required())
70 .WillOnce(Return(refresh_required));
71 }
72
73 void expect_refresh_image(MockTestImageCtx &mock_image_ctx, int r) {
74 EXPECT_CALL(*mock_image_ctx.state, refresh(_))
75 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
76 }
77
78 void expect_unlink_peer(MockTestImageCtx &mock_image_ctx, uint64_t snap_id,
79 const std::string &peer_uuid, int r) {
80 using ceph::encode;
81 bufferlist bl;
82 encode(snapid_t{snap_id}, bl);
83 encode(peer_uuid, bl);
84
85 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
86 exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
87 StrEq("mirror_image_snapshot_unlink_peer"),
88 ContentsEqual(bl), _, _, _))
89 .WillOnce(Invoke([&mock_image_ctx, snap_id, peer_uuid, r](auto&&... args) -> int {
90 if (r == 0) {
91 auto it = mock_image_ctx.snap_info.find(snap_id);
92 EXPECT_NE(it, mock_image_ctx.snap_info.end());
93 auto info =
94 std::get_if<cls::rbd::MirrorSnapshotNamespace>(
95 &it->second.snap_namespace);
96 EXPECT_NE(nullptr, info);
97 EXPECT_NE(0, info->mirror_peer_uuids.erase(
98 peer_uuid));
99 }
100 return r;
101 }));
102 }
103
104 void expect_notify_update(MockTestImageCtx &mock_image_ctx, int r) {
105 EXPECT_CALL(mock_image_ctx, notify_update(_))
106 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
107 }
108
109 void expect_remove_snapshot(MockTestImageCtx &mock_image_ctx,
110 uint64_t snap_id, int r) {
111 EXPECT_CALL(*mock_image_ctx.operations, snap_remove(_, _, _))
112 .WillOnce(Invoke([&mock_image_ctx, snap_id, r](
113 const cls::rbd::SnapshotNamespace &snap_namespace,
114 const std::string &snap_name, Context *on_finish) {
115 if (r == 0) {
116 auto it = mock_image_ctx.snap_info.find(snap_id);
117 EXPECT_NE(it, mock_image_ctx.snap_info.end());
118 EXPECT_EQ(it->second.snap_namespace, snap_namespace);
119 EXPECT_EQ(it->second.name, snap_name);
120 mock_image_ctx.snap_info.erase(it);
121 }
122 mock_image_ctx.image_ctx->op_work_queue->queue(
123 on_finish, r);
124 }));
125 }
126 };
127
128 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, Success) {
129 REQUIRE_FORMAT_V2();
130
131 librbd::ImageCtx *ictx;
132 ASSERT_EQ(0, open_image(m_image_name, &ictx));
133
134 MockTestImageCtx mock_image_ctx(*ictx);
135 cls::rbd::MirrorSnapshotNamespace ns{
136 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer1_uuid", "peer2_uuid"},
137 "", CEPH_NOSNAP};
138 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
139
140 expect_get_snap_info(mock_image_ctx, snap_id);
141
142 InSequence seq;
143
144 expect_is_refresh_required(mock_image_ctx, true);
145 expect_refresh_image(mock_image_ctx, 0);
146 expect_unlink_peer(mock_image_ctx, snap_id, "peer1_uuid", 0);
147 expect_notify_update(mock_image_ctx, 0);
148 expect_refresh_image(mock_image_ctx, 0);
149
150 C_SaferCond ctx;
151 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer1_uuid",
152 true, &ctx);
153 req->send();
154 ASSERT_EQ(0, ctx.wait());
155 }
156
157 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RemoveSnapshot) {
158 REQUIRE_FORMAT_V2();
159
160 librbd::ImageCtx *ictx;
161 ASSERT_EQ(0, open_image(m_image_name, &ictx));
162
163 MockTestImageCtx mock_image_ctx(*ictx);
164 cls::rbd::MirrorSnapshotNamespace ns{
165 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer_uuid"},
166 "", CEPH_NOSNAP};
167 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
168 snap_create(mock_image_ctx, ns, "mirror_snap2");
169
170 expect_get_snap_info(mock_image_ctx, snap_id);
171
172 InSequence seq;
173
174 expect_is_refresh_required(mock_image_ctx, true);
175 expect_refresh_image(mock_image_ctx, 0);
176 expect_remove_snapshot(mock_image_ctx, snap_id, 0);
177
178 C_SaferCond ctx;
179 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
180 true, &ctx);
181 req->send();
182 ASSERT_EQ(0, ctx.wait());
183 }
184
185 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RemoveSnapshotNotAllowed) {
186 REQUIRE_FORMAT_V2();
187
188 librbd::ImageCtx *ictx;
189 ASSERT_EQ(0, open_image(m_image_name, &ictx));
190
191 MockTestImageCtx mock_image_ctx(*ictx);
192 cls::rbd::MirrorSnapshotNamespace ns{
193 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer_uuid"},
194 "", CEPH_NOSNAP};
195 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
196 snap_create(mock_image_ctx, ns, "mirror_snap2");
197
198 expect_get_snap_info(mock_image_ctx, snap_id);
199
200 InSequence seq;
201
202 expect_is_refresh_required(mock_image_ctx, true);
203 expect_refresh_image(mock_image_ctx, 0);
204 expect_unlink_peer(mock_image_ctx, snap_id, "peer_uuid", 0);
205 expect_notify_update(mock_image_ctx, 0);
206 expect_refresh_image(mock_image_ctx, 0);
207
208 C_SaferCond ctx;
209 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
210 false, &ctx);
211 req->send();
212 ASSERT_EQ(0, ctx.wait());
213 }
214
215 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, SnapshotRemoveEmptyPeers) {
216 REQUIRE_FORMAT_V2();
217
218 librbd::ImageCtx *ictx;
219 ASSERT_EQ(0, open_image(m_image_name, &ictx));
220
221 MockTestImageCtx mock_image_ctx(*ictx);
222 cls::rbd::MirrorSnapshotNamespace ns{
223 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {},
224 "", CEPH_NOSNAP};
225 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
226 ns.mirror_peer_uuids = {"peer_uuid"};
227 snap_create(mock_image_ctx, ns, "mirror_snap2");
228
229 expect_get_snap_info(mock_image_ctx, snap_id);
230
231 InSequence seq;
232
233 expect_is_refresh_required(mock_image_ctx, true);
234 expect_refresh_image(mock_image_ctx, 0);
235 expect_remove_snapshot(mock_image_ctx, snap_id, 0);
236
237 C_SaferCond ctx;
238 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
239 true, &ctx);
240 req->send();
241 ASSERT_EQ(0, ctx.wait());
242 }
243
244 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, SnapshotRemoveEmptyPeersNotAllowed) {
245 REQUIRE_FORMAT_V2();
246
247 librbd::ImageCtx *ictx;
248 ASSERT_EQ(0, open_image(m_image_name, &ictx));
249
250 MockTestImageCtx mock_image_ctx(*ictx);
251 cls::rbd::MirrorSnapshotNamespace ns{
252 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {},
253 "", CEPH_NOSNAP};
254 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
255 ns.mirror_peer_uuids = {"peer_uuid"};
256 snap_create(mock_image_ctx, ns, "mirror_snap2");
257
258 expect_get_snap_info(mock_image_ctx, snap_id);
259
260 InSequence seq;
261
262 expect_is_refresh_required(mock_image_ctx, true);
263 expect_refresh_image(mock_image_ctx, 0);
264
265 C_SaferCond ctx;
266 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
267 false, &ctx);
268 req->send();
269 ASSERT_EQ(0, ctx.wait());
270 }
271
272 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, SnapshotDNE) {
273 REQUIRE_FORMAT_V2();
274
275 librbd::ImageCtx *ictx;
276 ASSERT_EQ(0, open_image(m_image_name, &ictx));
277
278 MockTestImageCtx mock_image_ctx(*ictx);
279
280 expect_get_snap_info(mock_image_ctx, 123);
281
282 InSequence seq;
283
284 expect_is_refresh_required(mock_image_ctx, true);
285 expect_refresh_image(mock_image_ctx, 0);
286
287 C_SaferCond ctx;
288 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, 123, "peer_uuid",
289 true, &ctx);
290 req->send();
291 ASSERT_EQ(-ENOENT, ctx.wait());
292 }
293
294 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, PeerDNE) {
295 REQUIRE_FORMAT_V2();
296
297 librbd::ImageCtx *ictx;
298 ASSERT_EQ(0, open_image(m_image_name, &ictx));
299
300 MockTestImageCtx mock_image_ctx(*ictx);
301 cls::rbd::MirrorSnapshotNamespace ns{
302 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer_uuid"},
303 "", CEPH_NOSNAP};
304 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
305
306 expect_get_snap_info(mock_image_ctx, snap_id);
307
308 InSequence seq;
309
310 expect_is_refresh_required(mock_image_ctx, true);
311 expect_refresh_image(mock_image_ctx, 0);
312
313 C_SaferCond ctx;
314 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "unknown_peer",
315 true, &ctx);
316 req->send();
317 ASSERT_EQ(0, ctx.wait());
318 }
319
320 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, MultiPeerPeerDNE) {
321 REQUIRE_FORMAT_V2();
322
323 librbd::ImageCtx *ictx;
324 ASSERT_EQ(0, open_image(m_image_name, &ictx));
325
326 MockTestImageCtx mock_image_ctx(*ictx);
327 cls::rbd::MirrorSnapshotNamespace ns{
328 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer1_uuid", "peer2_uuid"},
329 "", CEPH_NOSNAP};
330 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
331
332 expect_get_snap_info(mock_image_ctx, snap_id);
333
334 InSequence seq;
335
336 expect_is_refresh_required(mock_image_ctx, true);
337 expect_refresh_image(mock_image_ctx, 0);
338
339 C_SaferCond ctx;
340 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "unknown_peer",
341 true, &ctx);
342 req->send();
343 ASSERT_EQ(0, ctx.wait());
344 }
345
346 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, InvalidSnapshot) {
347 REQUIRE_FORMAT_V2();
348
349 librbd::ImageCtx *ictx;
350 ASSERT_EQ(0, open_image(m_image_name, &ictx));
351
352 MockTestImageCtx mock_image_ctx(*ictx);
353 cls::rbd::UserSnapshotNamespace ns;
354 auto snap_id = snap_create(mock_image_ctx, ns, "user_snap");
355
356 expect_get_snap_info(mock_image_ctx, snap_id);
357
358 InSequence seq;
359
360 expect_is_refresh_required(mock_image_ctx, false);
361
362 C_SaferCond ctx;
363 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
364 true, &ctx);
365 req->send();
366 ASSERT_EQ(-EINVAL, ctx.wait());
367 }
368
369 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RefreshError) {
370 REQUIRE_FORMAT_V2();
371
372 librbd::ImageCtx *ictx;
373 ASSERT_EQ(0, open_image(m_image_name, &ictx));
374
375 MockTestImageCtx mock_image_ctx(*ictx);
376
377 InSequence seq;
378
379 expect_is_refresh_required(mock_image_ctx, true);
380 expect_refresh_image(mock_image_ctx, -EINVAL);
381
382 C_SaferCond ctx;
383 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, 123, "peer_uuid",
384 true, &ctx);
385 req->send();
386 ASSERT_EQ(-EINVAL, ctx.wait());
387 }
388
389 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, UnlinkError) {
390 REQUIRE_FORMAT_V2();
391
392 librbd::ImageCtx *ictx;
393 ASSERT_EQ(0, open_image(m_image_name, &ictx));
394
395 MockTestImageCtx mock_image_ctx(*ictx);
396 cls::rbd::MirrorSnapshotNamespace ns{
397 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer1_uuid", "peer2_uuid"},
398 "", CEPH_NOSNAP};
399 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
400
401 expect_get_snap_info(mock_image_ctx, snap_id);
402
403 InSequence seq;
404
405 expect_is_refresh_required(mock_image_ctx, false);
406 expect_unlink_peer(mock_image_ctx, snap_id, "peer1_uuid", -EINVAL);
407
408 C_SaferCond ctx;
409 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer1_uuid",
410 true, &ctx);
411 req->send();
412 ASSERT_EQ(-EINVAL, ctx.wait());
413 }
414
415 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, UnlinkErrorRestart) {
416 REQUIRE_FORMAT_V2();
417
418 librbd::ImageCtx *ictx;
419 ASSERT_EQ(0, open_image(m_image_name, &ictx));
420
421 MockTestImageCtx mock_image_ctx(*ictx);
422 cls::rbd::MirrorSnapshotNamespace ns{
423 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer_uuid"},
424 "", CEPH_NOSNAP};
425 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
426 snap_create(mock_image_ctx, ns, "mirror_snap2");
427
428 expect_get_snap_info(mock_image_ctx, snap_id);
429
430 InSequence seq;
431
432 expect_is_refresh_required(mock_image_ctx, true);
433 expect_refresh_image(mock_image_ctx, 0);
434 expect_unlink_peer(mock_image_ctx, snap_id, "peer_uuid", -ERESTART);
435 expect_refresh_image(mock_image_ctx, 0);
436 expect_remove_snapshot(mock_image_ctx, snap_id, 0);
437
438 C_SaferCond ctx;
439 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
440 false, &ctx);
441 req->send();
442 ASSERT_EQ(0, ctx.wait());
443 }
444
445 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, NotifyError) {
446 REQUIRE_FORMAT_V2();
447
448 librbd::ImageCtx *ictx;
449 ASSERT_EQ(0, open_image(m_image_name, &ictx));
450
451 MockTestImageCtx mock_image_ctx(*ictx);
452 cls::rbd::MirrorSnapshotNamespace ns{
453 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer1_uuid", "peer2_uuid"},
454 "", CEPH_NOSNAP};
455 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
456
457 expect_get_snap_info(mock_image_ctx, snap_id);
458
459 InSequence seq;
460
461 expect_is_refresh_required(mock_image_ctx, false);
462 expect_unlink_peer(mock_image_ctx, snap_id, "peer1_uuid", 0);
463 expect_notify_update(mock_image_ctx, -EINVAL);
464
465 C_SaferCond ctx;
466 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer1_uuid",
467 true, &ctx);
468 req->send();
469 ASSERT_EQ(-EINVAL, ctx.wait());
470 }
471
472 TEST_F(TestMockMirrorSnapshotUnlinkPeerRequest, RemoveSnapshotError) {
473 REQUIRE_FORMAT_V2();
474
475 librbd::ImageCtx *ictx;
476 ASSERT_EQ(0, open_image(m_image_name, &ictx));
477
478 MockTestImageCtx mock_image_ctx(*ictx);
479 cls::rbd::MirrorSnapshotNamespace ns{
480 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"peer_uuid"},
481 "", CEPH_NOSNAP};
482 auto snap_id = snap_create(mock_image_ctx, ns, "mirror_snap");
483 snap_create(mock_image_ctx, ns, "mirror_snap2");
484
485 expect_get_snap_info(mock_image_ctx, snap_id);
486
487 InSequence seq;
488
489 expect_is_refresh_required(mock_image_ctx, false);
490 expect_remove_snapshot(mock_image_ctx, snap_id, -EINVAL);
491
492 C_SaferCond ctx;
493 auto req = new MockUnlinkPeerRequest(&mock_image_ctx, snap_id, "peer_uuid",
494 true, &ctx);
495 req->send();
496 ASSERT_EQ(-EINVAL, ctx.wait());
497 }
498
499 } // namespace snapshot
500 } // namespace mirror
501 } // namespace librbd