]>
Commit | Line | Data |
---|---|---|
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 | ||
17 | namespace librbd { | |
18 | ||
19 | namespace { | |
20 | ||
21 | struct MockTestImageCtx : public librbd::MockImageCtx { | |
22 | explicit MockTestImageCtx(librbd::ImageCtx &image_ctx) | |
23 | : librbd::MockImageCtx(image_ctx) { | |
24 | } | |
25 | }; | |
26 | ||
27 | } // anonymous namespace | |
28 | ||
29 | namespace deep_copy { | |
30 | ||
31 | template <> | |
32 | class SetHeadRequest<librbd::MockTestImageCtx> { | |
33 | public: | |
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 | ||
53 | template <> | |
54 | struct 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 | ||
77 | SetHeadRequest<librbd::MockTestImageCtx>* SetHeadRequest<librbd::MockTestImageCtx>::s_instance = nullptr; | |
78 | SnapshotCreateRequest<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" | |
85 | template class librbd::deep_copy::SnapshotCopyRequest<librbd::MockTestImageCtx>; | |
86 | ||
87 | namespace librbd { | |
88 | namespace deep_copy { | |
89 | ||
90 | using ::testing::_; | |
91 | using ::testing::DoAll; | |
92 | using ::testing::DoDefault; | |
93 | using ::testing::InSequence; | |
94 | using ::testing::Invoke; | |
95 | using ::testing::InvokeWithoutArgs; | |
96 | using ::testing::Return; | |
97 | using ::testing::ReturnNew; | |
98 | using ::testing::SetArgPointee; | |
99 | using ::testing::StrEq; | |
100 | using ::testing::WithArg; | |
101 | ||
102 | class TestMockDeepCopySnapshotCopyRequest : public TestMockFixture { | |
103 | public: | |
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 | ||
280 | TEST_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 | ||
303 | TEST_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 | ||
343 | TEST_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 | ||
372 | TEST_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 | ||
406 | TEST_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 | ||
449 | TEST_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 | ||
480 | TEST_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 | ||
521 | TEST_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 | ||
555 | TEST_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 | ||
596 | TEST_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 | ||
644 | TEST_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 | ||
683 | TEST_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 | ||
724 | TEST_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 | ||
761 | TEST_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 | ||
805 | TEST_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 | ||
826 | TEST_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 |
860 | TEST_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 |