]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/deep_copy/test_mock_SnapshotCopyRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / deep_copy / test_mock_SnapshotCopyRequest.cc
CommitLineData
11fdf7f2
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 "test/librbd/test_mock_fixture.h"
5#include "include/rbd/librbd.hpp"
f67539c2 6#include "librbd/AsioEngine.h"
11fdf7f2
TL
7#include "librbd/ImageCtx.h"
8#include "librbd/ImageState.h"
9#include "librbd/Operations.h"
10#include "librbd/deep_copy/SetHeadRequest.h"
11#include "librbd/deep_copy/SnapshotCopyRequest.h"
12#include "librbd/deep_copy/SnapshotCreateRequest.h"
13#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
14#include "test/librbd/mock/MockImageCtx.h"
15#include "test/librbd/test_support.h"
16
17namespace librbd {
18
19namespace {
20
21struct MockTestImageCtx : public librbd::MockImageCtx {
22 explicit MockTestImageCtx(librbd::ImageCtx &image_ctx)
23 : librbd::MockImageCtx(image_ctx) {
24 }
25};
26
27} // anonymous namespace
28
29namespace deep_copy {
30
31template <>
32class SetHeadRequest<librbd::MockTestImageCtx> {
33public:
34 static SetHeadRequest* s_instance;
35 Context *on_finish;
36
37 static SetHeadRequest* create(librbd::MockTestImageCtx *image_ctx,
38 uint64_t size,
39 const cls::rbd::ParentImageSpec &parent_spec,
40 uint64_t parent_overlap, Context *on_finish) {
41 ceph_assert(s_instance != nullptr);
42 s_instance->on_finish = on_finish;
43 return s_instance;
44 }
45
46 SetHeadRequest() {
47 s_instance = this;
48 }
49
50 MOCK_METHOD0(send, void());
51};
52
53template <>
54struct SnapshotCreateRequest<librbd::MockTestImageCtx> {
55 static SnapshotCreateRequest* s_instance;
56 static SnapshotCreateRequest* create(librbd::MockTestImageCtx* image_ctx,
57 const std::string &snap_name,
58 const cls::rbd::SnapshotNamespace &snap_namespace,
59 uint64_t size,
60 const cls::rbd::ParentImageSpec &parent_spec,
61 uint64_t parent_overlap,
62 Context *on_finish) {
63 ceph_assert(s_instance != nullptr);
64 s_instance->on_finish = on_finish;
65 return s_instance;
66 }
67
68 Context *on_finish = nullptr;
69
70 SnapshotCreateRequest() {
71 s_instance = this;
72 }
73
74 MOCK_METHOD0(send, void());
75};
76
77SetHeadRequest<librbd::MockTestImageCtx>* SetHeadRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
78SnapshotCreateRequest<librbd::MockTestImageCtx>* SnapshotCreateRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
79
80} // namespace deep_copy
81} // namespace librbd
82
83// template definitions
84#include "librbd/deep_copy/SnapshotCopyRequest.cc"
85template class librbd::deep_copy::SnapshotCopyRequest<librbd::MockTestImageCtx>;
86
87namespace librbd {
88namespace deep_copy {
89
90using ::testing::_;
91using ::testing::DoAll;
92using ::testing::DoDefault;
93using ::testing::InSequence;
94using ::testing::Invoke;
95using ::testing::InvokeWithoutArgs;
96using ::testing::Return;
97using ::testing::ReturnNew;
98using ::testing::SetArgPointee;
99using ::testing::StrEq;
100using ::testing::WithArg;
101
102class TestMockDeepCopySnapshotCopyRequest : public TestMockFixture {
103public:
104 typedef SetHeadRequest<librbd::MockTestImageCtx> MockSetHeadRequest;
105 typedef SnapshotCopyRequest<librbd::MockTestImageCtx> MockSnapshotCopyRequest;
106 typedef SnapshotCreateRequest<librbd::MockTestImageCtx> MockSnapshotCreateRequest;
107
108 librbd::ImageCtx *m_src_image_ctx;
109 librbd::ImageCtx *m_dst_image_ctx;
f67539c2
TL
110
111 std::shared_ptr<librbd::AsioEngine> m_asio_engine;
112 asio::ContextWQ *m_work_queue;
11fdf7f2
TL
113
114 librbd::SnapSeqs m_snap_seqs;
115
116 void SetUp() override {
117 TestMockFixture::SetUp();
118
119 ASSERT_EQ(0, open_image(m_image_name, &m_src_image_ctx));
120
121 librbd::RBD rbd;
122 std::string dst_image_name = get_temp_image_name();
123 ASSERT_EQ(0, create_image_pp(rbd, m_ioctx, dst_image_name, m_image_size));
124 ASSERT_EQ(0, open_image(dst_image_name, &m_dst_image_ctx));
125
f67539c2
TL
126 m_asio_engine = std::make_shared<librbd::AsioEngine>(
127 m_src_image_ctx->md_ctx);
128 m_work_queue = m_asio_engine->get_work_queue();
11fdf7f2
TL
129 }
130
131 void prepare_exclusive_lock(librbd::MockImageCtx &mock_image_ctx,
132 librbd::MockExclusiveLock &mock_exclusive_lock) {
133 if ((mock_image_ctx.features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
134 return;
135 }
136 mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
137 }
138
139 void expect_test_features(librbd::MockImageCtx &mock_image_ctx) {
140 EXPECT_CALL(mock_image_ctx, test_features(_, _))
141 .WillRepeatedly(WithArg<0>(Invoke([&mock_image_ctx](uint64_t features) {
142 return (mock_image_ctx.features & features) != 0;
143 })));
144 EXPECT_CALL(mock_image_ctx, test_features(_))
145 .WillRepeatedly(WithArg<0>(Invoke([&mock_image_ctx](uint64_t features) {
146 return (mock_image_ctx.features & features) != 0;
147 })));
148 }
149
150 void expect_start_op(librbd::MockExclusiveLock &mock_exclusive_lock) {
151 if ((m_src_image_ctx->features & RBD_FEATURE_EXCLUSIVE_LOCK) == 0) {
152 return;
153 }
9f95a23c 154 EXPECT_CALL(mock_exclusive_lock, start_op(_)).WillOnce(Return(new LambdaContext([](int){})));
11fdf7f2
TL
155 }
156
157 void expect_get_snap_namespace(librbd::MockTestImageCtx &mock_image_ctx,
158 uint64_t snap_id) {
159 EXPECT_CALL(mock_image_ctx, get_snap_namespace(snap_id, _))
9f95a23c
TL
160 .WillOnce(Invoke([&mock_image_ctx](uint64_t snap_id,
161 cls::rbd::SnapshotNamespace* snap_ns) {
162 auto it = mock_image_ctx.snap_info.find(snap_id);
163 *snap_ns = it->second.snap_namespace;
164 return 0;
165 }));
11fdf7f2
TL
166 }
167
168 void expect_snap_create(librbd::MockTestImageCtx &mock_image_ctx,
169 MockSnapshotCreateRequest &mock_snapshot_create_request,
170 const std::string &snap_name, uint64_t snap_id, int r) {
171 EXPECT_CALL(mock_snapshot_create_request, send())
172 .WillOnce(DoAll(Invoke([&mock_image_ctx, snap_id, snap_name]() {
173 inject_snap(mock_image_ctx, snap_id, snap_name);
174 }),
175 Invoke([this, &mock_snapshot_create_request, r]() {
176 m_work_queue->queue(mock_snapshot_create_request.on_finish, r);
177 })));
178 }
179
180 void expect_snap_remove(librbd::MockTestImageCtx &mock_image_ctx,
181 const std::string &snap_name, int r) {
182 EXPECT_CALL(*mock_image_ctx.operations, execute_snap_remove(_, StrEq(snap_name), _))
183 .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) {
184 m_work_queue->queue(ctx, r);
185 })));
186 }
187
188 void expect_snap_protect(librbd::MockTestImageCtx &mock_image_ctx,
189 const std::string &snap_name, int r) {
190 EXPECT_CALL(*mock_image_ctx.operations, execute_snap_protect(_, StrEq(snap_name), _))
191 .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) {
192 m_work_queue->queue(ctx, r);
193 })));
194 }
195
196 void expect_snap_unprotect(librbd::MockTestImageCtx &mock_image_ctx,
197 const std::string &snap_name, int r) {
198 EXPECT_CALL(*mock_image_ctx.operations, execute_snap_unprotect(_, StrEq(snap_name), _))
199 .WillOnce(WithArg<2>(Invoke([this, r](Context *ctx) {
200 m_work_queue->queue(ctx, r);
201 })));
202 }
203
204 void expect_snap_is_protected(librbd::MockTestImageCtx &mock_image_ctx,
205 uint64_t snap_id, bool is_protected, int r) {
206 EXPECT_CALL(mock_image_ctx, is_snap_protected(snap_id, _))
207 .WillOnce(DoAll(SetArgPointee<1>(is_protected),
208 Return(r)));
209 }
210
211 void expect_snap_is_unprotected(librbd::MockTestImageCtx &mock_image_ctx,
212 uint64_t snap_id, bool is_unprotected, int r) {
213 EXPECT_CALL(mock_image_ctx, is_snap_unprotected(snap_id, _))
214 .WillOnce(DoAll(SetArgPointee<1>(is_unprotected),
215 Return(r)));
216 }
217
218 void expect_set_head(MockSetHeadRequest &mock_set_head_request, int r) {
219 EXPECT_CALL(mock_set_head_request, send())
220 .WillOnce(Invoke([&mock_set_head_request, r]() {
221 mock_set_head_request.on_finish->complete(r);
222 }));
223 }
224
225 static void inject_snap(librbd::MockTestImageCtx &mock_image_ctx,
226 uint64_t snap_id, const std::string &snap_name) {
227 mock_image_ctx.snap_ids[{cls::rbd::UserSnapshotNamespace(),
228 snap_name}] = snap_id;
229 }
230
231 MockSnapshotCopyRequest *create_request(
232 librbd::MockTestImageCtx &mock_src_image_ctx,
9f95a23c
TL
233 librbd::MockTestImageCtx &mock_dst_image_ctx,
234 librados::snap_t src_snap_id_start,
235 librados::snap_t src_snap_id_end,
236 librados::snap_t dst_snap_id_start,
237 Context *on_finish) {
11fdf7f2 238 return new MockSnapshotCopyRequest(&mock_src_image_ctx, &mock_dst_image_ctx,
9f95a23c
TL
239 src_snap_id_start, src_snap_id_end,
240 dst_snap_id_start, false, m_work_queue,
11fdf7f2
TL
241 &m_snap_seqs, on_finish);
242 }
243
9f95a23c
TL
244 int create_snap(librbd::ImageCtx *image_ctx,
245 const cls::rbd::SnapshotNamespace& snap_ns,
246 const std::string &snap_name, bool protect) {
f67539c2
TL
247 NoOpProgressContext prog_ctx;
248 int r = image_ctx->operations->snap_create(snap_ns, snap_name.c_str(), 0,
249 prog_ctx);
11fdf7f2
TL
250 if (r < 0) {
251 return r;
252 }
253
254 if (protect) {
1e59de90 255 EXPECT_TRUE(std::holds_alternative<cls::rbd::UserSnapshotNamespace>(snap_ns));
9f95a23c 256 r = image_ctx->operations->snap_protect(snap_ns, snap_name.c_str());
11fdf7f2
TL
257 if (r < 0) {
258 return r;
259 }
260 }
261
262 r = image_ctx->state->refresh();
263 if (r < 0) {
264 return r;
265 }
266 return 0;
267 }
268
9f95a23c
TL
269 int create_snap(librbd::ImageCtx *image_ctx, const std::string &snap_name,
270 bool protect = false) {
271 return create_snap(image_ctx, cls::rbd::UserSnapshotNamespace{}, snap_name,
272 protect);
273 }
274
11fdf7f2
TL
275 void validate_snap_seqs(const librbd::SnapSeqs &snap_seqs) {
276 ASSERT_EQ(snap_seqs, m_snap_seqs);
277 }
278};
279
280TEST_F(TestMockDeepCopySnapshotCopyRequest, Empty) {
281 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
282 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
283 MockSetHeadRequest mock_set_head_request;
284
285 librbd::MockExclusiveLock mock_exclusive_lock;
286 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
287
288 expect_test_features(mock_dst_image_ctx);
289
290 InSequence seq;
291 expect_set_head(mock_set_head_request, 0);
292
293 C_SaferCond ctx;
294 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
295 mock_dst_image_ctx, 0,
296 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
297 request->send();
298 ASSERT_EQ(0, ctx.wait());
299
300 validate_snap_seqs({});
301}
302
303TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreate) {
304 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1"));
305 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap2"));
306
307 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
308 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
309 uint64_t src_snap_id2 = m_src_image_ctx->snap_ids[
310 {cls::rbd::UserSnapshotNamespace(), "snap2"}];
311
312 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
313 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
314 MockSnapshotCreateRequest mock_snapshot_create_request;
315 MockSetHeadRequest mock_set_head_request;
316
317 librbd::MockExclusiveLock mock_exclusive_lock;
318 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
319
320 expect_test_features(mock_dst_image_ctx);
321
322 InSequence seq;
323 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
324 expect_start_op(mock_exclusive_lock);
325 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1", 12, 0);
326 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id2);
327 expect_start_op(mock_exclusive_lock);
328 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap2", 14, 0);
329 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
330 expect_snap_is_protected(mock_src_image_ctx, src_snap_id2, false, 0);
331 expect_set_head(mock_set_head_request, 0);
332
333 C_SaferCond ctx;
334 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
335 mock_dst_image_ctx, 0,
336 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
337 request->send();
338 ASSERT_EQ(0, ctx.wait());
339
340 validate_snap_seqs({{src_snap_id1, 12}, {src_snap_id2, 14}});
341}
342
343TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreateError) {
344 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1"));
345
346 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
347 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
348 MockSnapshotCreateRequest mock_snapshot_create_request;
349
350 librbd::MockExclusiveLock mock_exclusive_lock;
351 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
352
353 uint64_t src_snap_id1 = mock_src_image_ctx.snap_ids[
354 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
355
356 expect_test_features(mock_dst_image_ctx);
357
358 InSequence seq;
359 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
360 expect_start_op(mock_exclusive_lock);
361 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1",
362 12, -EINVAL);
363
364 C_SaferCond ctx;
365 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
366 mock_dst_image_ctx, 0,
367 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
368 request->send();
369 ASSERT_EQ(-EINVAL, ctx.wait());
370}
371
372TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreateCancel) {
373 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1"));
374
375 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
376 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
377 MockSnapshotCreateRequest mock_snapshot_create_request;
378
379 librbd::MockExclusiveLock mock_exclusive_lock;
380 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
381
382 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
383 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
384 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
385
386 C_SaferCond ctx;
387 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
388 mock_dst_image_ctx, 0,
389 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
390 expect_test_features(mock_dst_image_ctx);
391
392 InSequence seq;
393 expect_start_op(mock_exclusive_lock);
394 EXPECT_CALL(mock_snapshot_create_request, send())
395 .WillOnce(DoAll(InvokeWithoutArgs([request]() {
396 request->cancel();
397 }),
398 Invoke([this, &mock_snapshot_create_request]() {
399 m_work_queue->queue(mock_snapshot_create_request.on_finish, 0);
400 })));
401
402 request->send();
403 ASSERT_EQ(-ECANCELED, ctx.wait());
404}
405
406TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapRemoveAndCreate) {
407 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1"));
408 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1"));
409
410 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
411 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
412 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
413 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
414
415 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
416 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
417 MockSnapshotCreateRequest mock_snapshot_create_request;
418 MockSetHeadRequest mock_set_head_request;
419
420 librbd::MockExclusiveLock mock_exclusive_lock;
421 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
422
423 expect_test_features(mock_dst_image_ctx);
424
425 InSequence seq;
426 expect_snap_is_unprotected(mock_dst_image_ctx,
427 m_dst_image_ctx->snap_ids[
428 {cls::rbd::UserSnapshotNamespace(), "snap1"}],
429 true, 0);
430 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
431 expect_start_op(mock_exclusive_lock);
432 expect_snap_remove(mock_dst_image_ctx, "snap1", 0);
433 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
434 expect_start_op(mock_exclusive_lock);
435 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1", 12, 0);
436 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
437 expect_set_head(mock_set_head_request, 0);
438
439 C_SaferCond ctx;
440 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
441 mock_dst_image_ctx, 0,
442 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
443 request->send();
444 ASSERT_EQ(0, ctx.wait());
445
446 validate_snap_seqs({{src_snap_id1, 12}});
447}
448
449TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapRemoveError) {
450 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1"));
451
452 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
453 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
454
455 librbd::MockExclusiveLock mock_exclusive_lock;
456 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
457
458 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
459 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
460
461 expect_test_features(mock_dst_image_ctx);
462
463 InSequence seq;
464 expect_snap_is_unprotected(mock_dst_image_ctx,
465 m_dst_image_ctx->snap_ids[
466 {cls::rbd::UserSnapshotNamespace(), "snap1"}],
467 true, 0);
468 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
469 expect_start_op(mock_exclusive_lock);
470 expect_snap_remove(mock_dst_image_ctx, "snap1", -EINVAL);
471
472 C_SaferCond ctx;
473 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
474 mock_dst_image_ctx, 0,
475 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
476 request->send();
477 ASSERT_EQ(-EINVAL, ctx.wait());
478}
479
480TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotect) {
481 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
482
483 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
484 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
485
486 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
487 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
488 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
489 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
490 m_snap_seqs[src_snap_id1] = dst_snap_id1;
491
492 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
493 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
494 MockSetHeadRequest mock_set_head_request;
495
496 librbd::MockExclusiveLock mock_exclusive_lock;
497 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
498
499 expect_test_features(mock_dst_image_ctx);
500
501 InSequence seq;
502 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id1, false, 0);
503 expect_snap_is_unprotected(mock_src_image_ctx, src_snap_id1, true, 0);
504 expect_start_op(mock_exclusive_lock);
505 expect_snap_unprotect(mock_dst_image_ctx, "snap1", 0);
506 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
507 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
508 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
509 expect_set_head(mock_set_head_request, 0);
510
511 C_SaferCond ctx;
512 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
513 mock_dst_image_ctx, 0,
514 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
515 request->send();
516 ASSERT_EQ(0, ctx.wait());
517
518 validate_snap_seqs({{src_snap_id1, dst_snap_id1}});
519}
520
521TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotectError) {
522 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
523
524 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
525 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
526
527 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
528 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
529 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
530 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
531 m_snap_seqs[src_snap_id1] = dst_snap_id1;
532
533 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
534 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
535
536 librbd::MockExclusiveLock mock_exclusive_lock;
537 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
538
539 expect_test_features(mock_dst_image_ctx);
540
541 InSequence seq;
542 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id1, false, 0);
543 expect_snap_is_unprotected(mock_src_image_ctx, src_snap_id1, true, 0);
544 expect_start_op(mock_exclusive_lock);
545 expect_snap_unprotect(mock_dst_image_ctx, "snap1", -EBUSY);
546
547 C_SaferCond ctx;
548 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
549 mock_dst_image_ctx, 0,
550 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
551 request->send();
552 ASSERT_EQ(-EBUSY, ctx.wait());
553}
554
555TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotectCancel) {
556 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
557
558 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
559 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
560
561 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
562 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
563 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
564 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
565 m_snap_seqs[src_snap_id1] = dst_snap_id1;
566
567 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
568 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
569
570 librbd::MockExclusiveLock mock_exclusive_lock;
571 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
572
573 C_SaferCond ctx;
574 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
575 mock_dst_image_ctx, 0,
576 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
577 expect_test_features(mock_dst_image_ctx);
578
579 InSequence seq;
580 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id1, false, 0);
581 expect_snap_is_unprotected(mock_src_image_ctx, src_snap_id1, true, 0);
582 expect_start_op(mock_exclusive_lock);
583 EXPECT_CALL(*mock_dst_image_ctx.operations,
584 execute_snap_unprotect(_, StrEq("snap1"), _))
585 .WillOnce(DoAll(InvokeWithoutArgs([request]() {
586 request->cancel();
587 }),
588 WithArg<2>(Invoke([this](Context *ctx) {
589 m_work_queue->queue(ctx, 0);
590 }))));
591
592 request->send();
593 ASSERT_EQ(-ECANCELED, ctx.wait());
594}
595
596TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapUnprotectRemove) {
597 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
598
599 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
600 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
601
602 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
603 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
604 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
605 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
606
607 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
608 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
609 MockSnapshotCreateRequest mock_snapshot_create_request;
610 MockSetHeadRequest mock_set_head_request;
611
612 librbd::MockExclusiveLock mock_exclusive_lock;
613 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
614
615 expect_test_features(mock_dst_image_ctx);
616
617 InSequence seq;
618 expect_snap_is_unprotected(mock_dst_image_ctx,
619 m_dst_image_ctx->snap_ids[
620 {cls::rbd::UserSnapshotNamespace(), "snap1"}],
621 false, 0);
622 expect_start_op(mock_exclusive_lock);
623 expect_snap_unprotect(mock_dst_image_ctx, "snap1", 0);
624 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
625 expect_start_op(mock_exclusive_lock);
626 expect_snap_remove(mock_dst_image_ctx, "snap1", 0);
627 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
628 expect_start_op(mock_exclusive_lock);
629 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1",
630 12, 0);
631 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
632 expect_set_head(mock_set_head_request, 0);
633
634 C_SaferCond ctx;
635 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
636 mock_dst_image_ctx, 0,
637 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
638 request->send();
639 ASSERT_EQ(0, ctx.wait());
640
641 validate_snap_seqs({{src_snap_id1, 12}});
642}
643
644TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapCreateProtect) {
645 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
646
647 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
648
649 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
650 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
651
652 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
653 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
654 MockSnapshotCreateRequest mock_snapshot_create_request;
655 MockSetHeadRequest mock_set_head_request;
656
657 librbd::MockExclusiveLock mock_exclusive_lock;
658 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
659
660 expect_test_features(mock_dst_image_ctx);
661
662 InSequence seq;
663 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
664 expect_start_op(mock_exclusive_lock);
665 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1",
666 12, 0);
667 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, true, 0);
668 expect_snap_is_protected(mock_dst_image_ctx, 12, false, 0);
669 expect_start_op(mock_exclusive_lock);
670 expect_snap_protect(mock_dst_image_ctx, "snap1", 0);
671 expect_set_head(mock_set_head_request, 0);
672
673 C_SaferCond ctx;
674 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
675 mock_dst_image_ctx, 0,
676 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
677 request->send();
678 ASSERT_EQ(0, ctx.wait());
679
680 validate_snap_seqs({{src_snap_id1, 12}});
681}
682
683TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapProtect) {
684 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
685
686 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
687 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
688
689 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
690 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
691 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
692 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
693 m_snap_seqs[src_snap_id1] = dst_snap_id1;
694
695 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
696 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
697 MockSetHeadRequest mock_set_head_request;
698
699 librbd::MockExclusiveLock mock_exclusive_lock;
700 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
701
702 expect_test_features(mock_dst_image_ctx);
703
704 InSequence seq;
705 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id1, true, 0);
706 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
707 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
708 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, true, 0);
709 expect_snap_is_protected(mock_dst_image_ctx, dst_snap_id1, false, 0);
710 expect_start_op(mock_exclusive_lock);
711 expect_snap_protect(mock_dst_image_ctx, "snap1", 0);
712 expect_set_head(mock_set_head_request, 0);
713
714 C_SaferCond ctx;
715 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
716 mock_dst_image_ctx, 0,
717 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
718 request->send();
719 ASSERT_EQ(0, ctx.wait());
720
721 validate_snap_seqs({{src_snap_id1, dst_snap_id1}});
722}
723
724TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapProtectError) {
725 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
726
727 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
728 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
729
730 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
731 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
732 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
733 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
734 m_snap_seqs[src_snap_id1] = dst_snap_id1;
735
736 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
737 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
738
739 librbd::MockExclusiveLock mock_exclusive_lock;
740 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
741
742 expect_test_features(mock_dst_image_ctx);
743
744 InSequence seq;
745 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id1, true, 0);
746 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
747 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
748 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, true, 0);
749 expect_snap_is_protected(mock_dst_image_ctx, dst_snap_id1, false, 0);
750 expect_start_op(mock_exclusive_lock);
751 expect_snap_protect(mock_dst_image_ctx, "snap1", -EINVAL);
752
753 C_SaferCond ctx;
754 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
755 mock_dst_image_ctx, 0,
756 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
757 request->send();
758 ASSERT_EQ(-EINVAL, ctx.wait());
759}
760
761TEST_F(TestMockDeepCopySnapshotCopyRequest, SnapProtectCancel) {
762 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
763
764 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
765 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", true));
766
767 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
768 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
769 uint64_t dst_snap_id1 = m_dst_image_ctx->snap_ids[
770 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
771 m_snap_seqs[src_snap_id1] = dst_snap_id1;
772
773 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
774 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
775
776 librbd::MockExclusiveLock mock_exclusive_lock;
777 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
778
779 C_SaferCond ctx;
780 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
781 mock_dst_image_ctx, 0,
782 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
783 expect_test_features(mock_dst_image_ctx);
784
785 InSequence seq;
786 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id1, true, 0);
787 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id1);
788 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
789 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, true, 0);
790 expect_snap_is_protected(mock_dst_image_ctx, dst_snap_id1, false, 0);
791 expect_start_op(mock_exclusive_lock);
792 EXPECT_CALL(*mock_dst_image_ctx.operations,
793 execute_snap_protect(_, StrEq("snap1"), _))
794 .WillOnce(DoAll(InvokeWithoutArgs([request]() {
795 request->cancel();
796 }),
797 WithArg<2>(Invoke([this](Context *ctx) {
798 m_work_queue->queue(ctx, 0);
799 }))));
800
801 request->send();
802 ASSERT_EQ(-ECANCELED, ctx.wait());
803}
804
805TEST_F(TestMockDeepCopySnapshotCopyRequest, SetHeadError) {
806 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
807 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
808 MockSetHeadRequest mock_set_head_request;
809
810 librbd::MockExclusiveLock mock_exclusive_lock;
811 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
812
813 expect_test_features(mock_dst_image_ctx);
814
815 InSequence seq;
816 expect_set_head(mock_set_head_request, -EINVAL);
817
818 C_SaferCond ctx;
819 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
820 mock_dst_image_ctx, 0,
821 CEPH_NOSNAP, 0, &ctx);
11fdf7f2
TL
822 request->send();
823 ASSERT_EQ(-EINVAL, ctx.wait());
824}
825
826TEST_F(TestMockDeepCopySnapshotCopyRequest, NoSetHead) {
827 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
828
829 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", true));
830
831 uint64_t src_snap_id1 = m_src_image_ctx->snap_ids[
832 {cls::rbd::UserSnapshotNamespace(), "snap1"}];
833
834 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
835 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
836 MockSnapshotCreateRequest mock_snapshot_create_request;
837
838 librbd::MockExclusiveLock mock_exclusive_lock;
839 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
840
841 expect_test_features(mock_dst_image_ctx);
842
843 InSequence seq;
844 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id1);
845 expect_start_op(mock_exclusive_lock);
846 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap1",
847 12, 0);
848 expect_snap_is_protected(mock_src_image_ctx, src_snap_id1, false, 0);
849
850 C_SaferCond ctx;
851 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
9f95a23c
TL
852 mock_dst_image_ctx,0,
853 src_snap_id1, 0, &ctx);
11fdf7f2
TL
854 request->send();
855 ASSERT_EQ(0, ctx.wait());
856
857 validate_snap_seqs({{src_snap_id1, 12}});
858}
859
9f95a23c
TL
860TEST_F(TestMockDeepCopySnapshotCopyRequest, StartEndLimit) {
861 REQUIRE_FEATURE(RBD_FEATURE_LAYERING);
862
863 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap1", false));
864 ASSERT_EQ(0, create_snap(m_src_image_ctx, "snap2", false));
865 ASSERT_EQ(0, create_snap(m_src_image_ctx,
866 {cls::rbd::MirrorSnapshotNamespace{
867 cls::rbd::MIRROR_SNAPSHOT_STATE_PRIMARY,
868 {"peer uuid1"}, "", CEPH_NOSNAP}},
869 "snap3", false));
870 auto src_snap_id1 = m_src_image_ctx->snaps[2];
871 auto src_snap_id2 = m_src_image_ctx->snaps[1];
872 auto src_snap_id3 = m_src_image_ctx->snaps[0];
873
874 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap0", true));
875 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap1", false));
876 ASSERT_EQ(0, create_snap(m_dst_image_ctx, "snap3", false));
877 auto dst_snap_id1 = m_dst_image_ctx->snaps[1];
878 auto dst_snap_id3 = m_dst_image_ctx->snaps[0];
879
880 librbd::MockTestImageCtx mock_src_image_ctx(*m_src_image_ctx);
881 librbd::MockTestImageCtx mock_dst_image_ctx(*m_dst_image_ctx);
882 MockSnapshotCreateRequest mock_snapshot_create_request;
883
884 librbd::MockExclusiveLock mock_exclusive_lock;
885 prepare_exclusive_lock(mock_dst_image_ctx, mock_exclusive_lock);
886
887 expect_test_features(mock_dst_image_ctx);
888
889 InSequence seq;
890 expect_snap_is_unprotected(mock_dst_image_ctx, dst_snap_id3,
891 true, 0);
892
893 expect_get_snap_namespace(mock_dst_image_ctx, dst_snap_id3);
894 expect_start_op(mock_exclusive_lock);
895 expect_snap_remove(mock_dst_image_ctx, "snap3", 0);
896
897 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id2);
898 expect_start_op(mock_exclusive_lock);
899 expect_snap_create(mock_dst_image_ctx, mock_snapshot_create_request, "snap2",
900 12, 0);
901 expect_get_snap_namespace(mock_src_image_ctx, src_snap_id3);
902
903 expect_snap_is_protected(mock_src_image_ctx, src_snap_id2, false, 0);
904 expect_snap_is_protected(mock_src_image_ctx, src_snap_id3, false, 0);
905
906 MockSetHeadRequest mock_set_head_request;
907 expect_set_head(mock_set_head_request, 0);
908
909 C_SaferCond ctx;
910 MockSnapshotCopyRequest *request = create_request(mock_src_image_ctx,
911 mock_dst_image_ctx,
912 src_snap_id1,
913 src_snap_id3,
914 dst_snap_id1, &ctx);
915 request->send();
916 ASSERT_EQ(0, ctx.wait());
917
918 validate_snap_seqs({{src_snap_id2, 12}, {src_snap_id3, CEPH_NOSNAP}});
919}
920
11fdf7f2
TL
921} // namespace deep_copy
922} // namespace librbd