]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/mirror/snapshot/test_mock_CreatePrimaryRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / mirror / snapshot / test_mock_CreatePrimaryRequest.cc
CommitLineData
9f95a23c
TL
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
15namespace librbd {
16
17namespace {
18
19struct MockTestImageCtx : public MockImageCtx {
20 explicit MockTestImageCtx(librbd::ImageCtx& image_ctx) : MockImageCtx(image_ctx) {
21 }
22};
23
24} // anonymous namespace
25
26namespace mirror {
27namespace snapshot {
28namespace util {
29
30namespace {
31
32struct 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
43Mock *Mock::s_instance = nullptr;
44
45} // anonymous namespace
46
47template<> 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
57template <>
58struct UnlinkPeerRequest<MockTestImageCtx> {
59 uint64_t snap_id = CEPH_NOSNAP;
60 std::string mirror_peer_uuid;
1e59de90 61 bool allow_remove;
9f95a23c
TL
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,
1e59de90 67 bool allow_remove,
9f95a23c
TL
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;
1e59de90 72 s_instance->allow_remove = allow_remove;
9f95a23c
TL
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
84UnlinkPeerRequest<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"
92template class librbd::mirror::snapshot::CreatePrimaryRequest<librbd::MockTestImageCtx>;
93
94namespace librbd {
95namespace mirror {
96namespace snapshot {
97
98using ::testing::_;
99using ::testing::DoAll;
100using ::testing::InSequence;
101using ::testing::Invoke;
102using ::testing::Return;
103using ::testing::StrEq;
104using ::testing::WithArg;
105
106class TestMockMirrorSnapshotCreatePrimaryRequest : public TestMockFixture {
107public:
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"),
f67539c2 146 _, _, _, _))
9f95a23c
TL
147 .WillOnce(DoAll(WithArg<5>(CopyInBufferlist(bl)),
148 Return(r)));
149 }
150
151 void expect_create_snapshot(MockTestImageCtx &mock_image_ctx, int r) {
f67539c2 152 EXPECT_CALL(*mock_image_ctx.operations, snap_create(_, _, _, _, _))
9f95a23c
TL
153 .WillOnce(DoAll(
154 Invoke([this, &mock_image_ctx, r](
155 const cls::rbd::SnapshotNamespace &ns,
156 const std::string& snap_name,
f67539c2
TL
157 uint64_t flags,
158 ProgressContext &prog_ctx,
9f95a23c
TL
159 Context *on_finish) {
160 if (r != 0) {
161 return;
162 }
1e59de90
TL
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);
9f95a23c 167 }),
f67539c2 168 WithArg<4>(CompleteContext(
9f95a23c
TL
169 r, mock_image_ctx.image_ctx->op_work_queue))
170 ));
171 }
172
1e59de90
TL
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
9f95a23c
TL
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,
1e59de90
TL
181 bool is_linked, bool complete, bool allow_remove,
182 int r) {
9f95a23c 183 EXPECT_CALL(mock_unlink_peer_request, send())
b3b6e05e 184 .WillOnce(Invoke([&mock_image_ctx, &mock_unlink_peer_request,
1e59de90 185 snap_id, peer_uuid, is_linked, complete, allow_remove, r]() {
9f95a23c
TL
186 ASSERT_EQ(mock_unlink_peer_request.mirror_peer_uuid,
187 peer_uuid);
188 ASSERT_EQ(mock_unlink_peer_request.snap_id, snap_id);
1e59de90 189 ASSERT_EQ(mock_unlink_peer_request.allow_remove, allow_remove);
9f95a23c
TL
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 =
1e59de90 194 std::get_if<cls::rbd::MirrorSnapshotNamespace>(
9f95a23c
TL
195 &it->second.snap_namespace);
196 ASSERT_NE(nullptr, info);
1e59de90 197 ASSERT_EQ(complete, info->complete);
b3b6e05e
TL
198 ASSERT_EQ(is_linked, info->mirror_peer_uuids.erase(
199 peer_uuid));
9f95a23c
TL
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
210TEST_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);
1e59de90 227 expect_refresh_image(mock_image_ctx, 0);
9f95a23c
TL
228
229 C_SaferCond ctx;
1911f103 230 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
f67539c2 231 0U, 0U, nullptr, &ctx);
9f95a23c
TL
232 req->send();
233 ASSERT_EQ(0, ctx.wait());
234}
235
236TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, CanNotError) {
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
244 InSequence seq;
245
246 expect_clone_md_ctx(mock_image_ctx);
247 MockUtils mock_utils;
248 expect_can_create_primary_snapshot(mock_utils, false, false, false);
249
250 C_SaferCond ctx;
1911f103 251 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
f67539c2 252 0U, 0U, nullptr, &ctx);
9f95a23c
TL
253 req->send();
254 ASSERT_EQ(-EINVAL, ctx.wait());
255}
256
257TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, GetMirrorPeersError) {
258 REQUIRE_FORMAT_V2();
259
260 librbd::ImageCtx *ictx;
261 ASSERT_EQ(0, open_image(m_image_name, &ictx));
262
263 MockTestImageCtx mock_image_ctx(*ictx);
264
265 InSequence seq;
266
267 expect_clone_md_ctx(mock_image_ctx);
268 MockUtils mock_utils;
269 expect_can_create_primary_snapshot(mock_utils, false, false, true);
270 expect_get_mirror_peers(mock_image_ctx,
271 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
272 "mirror", "mirror uuid"}}, -EINVAL);
273
274 C_SaferCond ctx;
1911f103 275 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
f67539c2 276 0U, 0U, nullptr, &ctx);
9f95a23c
TL
277 req->send();
278 ASSERT_EQ(-EINVAL, ctx.wait());
279}
280
281TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, CreateSnapshotError) {
282 REQUIRE_FORMAT_V2();
283
284 librbd::ImageCtx *ictx;
285 ASSERT_EQ(0, open_image(m_image_name, &ictx));
286
287 MockTestImageCtx mock_image_ctx(*ictx);
288
289 InSequence seq;
290
291 expect_clone_md_ctx(mock_image_ctx);
292 MockUtils mock_utils;
293 expect_can_create_primary_snapshot(mock_utils, false, false, true);
294 expect_get_mirror_peers(mock_image_ctx,
295 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
296 "mirror", "mirror uuid"}}, 0);
297 expect_create_snapshot(mock_image_ctx, -EINVAL);
298
299 C_SaferCond ctx;
1911f103 300 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
f67539c2 301 0U, 0U, nullptr, &ctx);
9f95a23c
TL
302 req->send();
303 ASSERT_EQ(-EINVAL, ctx.wait());
304}
305
1e59de90
TL
306TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkIncomplete) {
307 REQUIRE_FORMAT_V2();
308
309 librbd::ImageCtx *ictx;
310 ASSERT_EQ(0, open_image(m_image_name, &ictx));
311 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
312
313 MockTestImageCtx mock_image_ctx(*ictx);
314 cls::rbd::MirrorSnapshotNamespace ns{
315 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
316 ns.complete = false;
317 snap_create(mock_image_ctx, ns, "mirror_snap");
318
319 InSequence seq;
320
321 expect_clone_md_ctx(mock_image_ctx);
322 MockUtils mock_utils;
323 expect_can_create_primary_snapshot(mock_utils, false, false, true);
324 expect_get_mirror_peers(mock_image_ctx,
325 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
326 "mirror", "mirror uuid"}}, 0);
327 expect_create_snapshot(mock_image_ctx, 0);
328 expect_refresh_image(mock_image_ctx, 0);
329 MockUnlinkPeerRequest mock_unlink_peer_request;
330 auto it = mock_image_ctx.snap_info.rbegin();
331 auto snap_id = it->first;
332 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
333 true, false, true, 0);
334 C_SaferCond ctx;
335 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
336 0U, 0U, nullptr, &ctx);
337 req->send();
338 ASSERT_EQ(0, ctx.wait());
339}
340
9f95a23c
TL
341TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkPeer) {
342 REQUIRE_FORMAT_V2();
343
344 librbd::ImageCtx *ictx;
345 ASSERT_EQ(0, open_image(m_image_name, &ictx));
2a845540 346 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
9f95a23c
TL
347
348 MockTestImageCtx mock_image_ctx(*ictx);
349 for (int i = 0; i < 3; i++) {
350 cls::rbd::MirrorSnapshotNamespace ns{
351 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid"}, "", CEPH_NOSNAP};
1e59de90 352 ns.complete = true;
9f95a23c
TL
353 snap_create(mock_image_ctx, ns, "mirror_snap");
354 }
355
356 InSequence seq;
357
358 expect_clone_md_ctx(mock_image_ctx);
359 MockUtils mock_utils;
360 expect_can_create_primary_snapshot(mock_utils, false, false, true);
361 expect_get_mirror_peers(mock_image_ctx,
362 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
363 "mirror", "mirror uuid"}}, 0);
364 expect_create_snapshot(mock_image_ctx, 0);
1e59de90 365 expect_refresh_image(mock_image_ctx, 0);
9f95a23c
TL
366 MockUnlinkPeerRequest mock_unlink_peer_request;
367 auto it = mock_image_ctx.snap_info.rbegin();
f67539c2 368 auto snap_id = it->first;
9f95a23c 369 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
1e59de90 370 true, true, true, 0);
b3b6e05e
TL
371 C_SaferCond ctx;
372 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
373 0U, 0U, nullptr, &ctx);
374 req->send();
375 ASSERT_EQ(0, ctx.wait());
376}
377
378TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkNoPeer) {
379 REQUIRE_FORMAT_V2();
380
381 librbd::ImageCtx *ictx;
382 ASSERT_EQ(0, open_image(m_image_name, &ictx));
2a845540 383 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
b3b6e05e
TL
384
385 MockTestImageCtx mock_image_ctx(*ictx);
386 cls::rbd::MirrorSnapshotNamespace ns{
387 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {}, "", CEPH_NOSNAP};
1e59de90 388 ns.complete = true;
b3b6e05e
TL
389 snap_create(mock_image_ctx, ns, "mirror_snap");
390
391 InSequence seq;
392
393 expect_clone_md_ctx(mock_image_ctx);
394 MockUtils mock_utils;
395 expect_can_create_primary_snapshot(mock_utils, false, false, true);
396 expect_get_mirror_peers(mock_image_ctx,
397 {{"uuid", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
398 "mirror", "mirror uuid"}}, 0);
399 expect_create_snapshot(mock_image_ctx, 0);
1e59de90 400 expect_refresh_image(mock_image_ctx, 0);
b3b6e05e
TL
401 MockUnlinkPeerRequest mock_unlink_peer_request;
402 auto it = mock_image_ctx.snap_info.rbegin();
403 auto snap_id = it->first;
b3b6e05e 404 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid",
1e59de90 405 false, true, true, 0);
b3b6e05e
TL
406
407 C_SaferCond ctx;
408 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
409 0U, 0U, nullptr, &ctx);
410 req->send();
411 ASSERT_EQ(0, ctx.wait());
412}
413
414TEST_F(TestMockMirrorSnapshotCreatePrimaryRequest, SuccessUnlinkMultiplePeers) {
415 REQUIRE_FORMAT_V2();
416
417 librbd::ImageCtx *ictx;
418 ASSERT_EQ(0, open_image(m_image_name, &ictx));
2a845540 419 ictx->config.set_val("rbd_mirroring_max_mirroring_snapshots", "3");
b3b6e05e
TL
420
421 MockTestImageCtx mock_image_ctx(*ictx);
422 for (int i = 0; i < 3; i++) {
423 cls::rbd::MirrorSnapshotNamespace ns{
424 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY, {"uuid1", "uuid2"}, "",
425 CEPH_NOSNAP};
1e59de90 426 ns.complete = true;
b3b6e05e
TL
427 snap_create(mock_image_ctx, ns, "mirror_snap");
428 }
429
430 InSequence seq;
431
432 expect_clone_md_ctx(mock_image_ctx);
433 MockUtils mock_utils;
434 expect_can_create_primary_snapshot(mock_utils, false, false, true);
435 expect_get_mirror_peers(mock_image_ctx,
436 {{"uuid1", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
437 "mirror", "mirror uuid"},
438 {"uuid2", cls::rbd::MIRROR_PEER_DIRECTION_TX, "ceph",
439 "mirror", "mirror uuid"}}, 0);
440 expect_create_snapshot(mock_image_ctx, 0);
1e59de90 441 expect_refresh_image(mock_image_ctx, 0);
b3b6e05e
TL
442 MockUnlinkPeerRequest mock_unlink_peer_request;
443 auto it = mock_image_ctx.snap_info.rbegin();
444 auto snap_id = it->first;
445 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid1",
1e59de90 446 true, true, true, 0);
b3b6e05e 447 expect_unlink_peer(mock_image_ctx, mock_unlink_peer_request, snap_id, "uuid2",
1e59de90 448 true, true, true, 0);
9f95a23c 449 C_SaferCond ctx;
1911f103 450 auto req = new MockCreatePrimaryRequest(&mock_image_ctx, "gid", CEPH_NOSNAP,
f67539c2 451 0U, 0U, nullptr, &ctx);
9f95a23c
TL
452 req->send();
453 ASSERT_EQ(0, ctx.wait());
454}
455
456} // namespace snapshot
457} // namespace mirror
458} // namespace librbd
459