1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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/librados_test_stub/MockTestMemIoCtxImpl.h"
8 #include "common/bit_vector.hpp"
9 #include "librbd/ImageState.h"
10 #include "librbd/internal.h"
11 #include "librbd/Operations.h"
12 #include "librbd/image/DetachChildRequest.h"
13 #include "librbd/operation/SnapshotRemoveRequest.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
17 // template definitions
18 #include "librbd/operation/SnapshotRemoveRequest.cc"
24 class DetachChildRequest
<MockImageCtx
> {
26 static DetachChildRequest
*s_instance
;
27 static DetachChildRequest
*create(MockImageCtx
&image_ctx
,
29 ceph_assert(s_instance
!= nullptr);
30 s_instance
->on_finish
= on_finish
;
34 Context
*on_finish
= nullptr;
36 DetachChildRequest() {
40 MOCK_METHOD0(send
, void());
43 DetachChildRequest
<MockImageCtx
> *DetachChildRequest
<MockImageCtx
>::s_instance
;
50 using ::testing::DoAll
;
51 using ::testing::DoDefault
;
52 using ::testing::Invoke
;
53 using ::testing::Return
;
54 using ::testing::SetArgPointee
;
55 using ::testing::StrEq
;
56 using ::testing::WithArg
;
58 class TestMockOperationSnapshotRemoveRequest
: public TestMockFixture
{
60 typedef SnapshotRemoveRequest
<MockImageCtx
> MockSnapshotRemoveRequest
;
61 typedef image::DetachChildRequest
<MockImageCtx
> MockDetachChildRequest
;
63 int create_snapshot(const char *snap_name
) {
64 librbd::ImageCtx
*ictx
;
65 int r
= open_image(m_image_name
, &ictx
);
70 r
= snap_create(*ictx
, snap_name
);
75 r
= snap_protect(*ictx
, snap_name
);
83 void expect_snapshot_trash_add(MockImageCtx
&mock_image_ctx
, int r
) {
84 if (mock_image_ctx
.old_format
) {
88 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
89 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
90 StrEq("snapshot_trash_add"),
93 expect
.WillOnce(Return(r
));
95 expect
.WillOnce(DoDefault());
99 void expect_snapshot_get(MockImageCtx
&mock_image_ctx
,
100 const cls::rbd::SnapshotInfo
& snap_info
, int r
) {
101 if (mock_image_ctx
.old_format
) {
106 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
107 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
108 StrEq("snapshot_get"), _
, _
, _
))
109 .WillOnce(WithArg
<5>(Invoke([snap_info
, r
](bufferlist
* bl
) {
110 encode(snap_info
, *bl
);
115 void expect_children_list(MockImageCtx
&mock_image_ctx
,
116 const cls::rbd::ChildImageSpecs
& child_images
, int r
) {
117 if (mock_image_ctx
.old_format
) {
122 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
123 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
124 StrEq("children_list"), _
, _
, _
))
125 .WillOnce(WithArg
<5>(Invoke([child_images
, r
](bufferlist
* bl
) {
126 encode(child_images
, *bl
);
131 void expect_detach_stale_child(MockImageCtx
&mock_image_ctx
, int r
) {
132 auto& parent_spec
= mock_image_ctx
.parent_md
.spec
;
135 encode(parent_spec
.snap_id
, bl
);
136 encode(cls::rbd::ChildImageSpec
{mock_image_ctx
.md_ctx
.get_id(), "",
137 mock_image_ctx
.id
}, bl
);
138 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
139 exec(util::header_name(parent_spec
.image_id
),
140 _
, StrEq("rbd"), StrEq("child_detach"), ContentsEqual(bl
),
142 .WillOnce(Return(r
));
145 void expect_object_map_snap_remove(MockImageCtx
&mock_image_ctx
, int r
) {
146 if (mock_image_ctx
.object_map
!= nullptr) {
147 EXPECT_CALL(*mock_image_ctx
.object_map
, snapshot_remove(_
, _
))
148 .WillOnce(WithArg
<1>(CompleteContext(
149 r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
153 void expect_get_parent_spec(MockImageCtx
&mock_image_ctx
, int r
) {
154 if (mock_image_ctx
.old_format
) {
158 auto &expect
= EXPECT_CALL(mock_image_ctx
, get_parent_spec(_
, _
));
160 expect
.WillOnce(Return(r
));
162 auto &parent_spec
= mock_image_ctx
.snap_info
.rbegin()->second
.parent
.spec
;
163 expect
.WillOnce(DoAll(SetArgPointee
<1>(parent_spec
),
168 void expect_detach_child(MockImageCtx
&mock_image_ctx
,
169 MockDetachChildRequest
& mock_request
, int r
) {
170 EXPECT_CALL(mock_request
, send())
171 .WillOnce(FinishRequest(&mock_request
, r
, &mock_image_ctx
));
174 void expect_snap_remove(MockImageCtx
&mock_image_ctx
, int r
) {
175 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
176 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
177 StrEq(mock_image_ctx
.old_format
? "snap_remove" :
181 expect
.WillOnce(Return(r
));
183 expect
.WillOnce(DoDefault());
187 void expect_rm_snap(MockImageCtx
&mock_image_ctx
) {
188 EXPECT_CALL(mock_image_ctx
, rm_snap(_
, _
, _
)).Times(1);
191 void expect_release_snap_id(MockImageCtx
&mock_image_ctx
) {
192 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
193 selfmanaged_snap_remove(_
))
194 .WillOnce(DoDefault());
199 TEST_F(TestMockOperationSnapshotRemoveRequest
, Success
) {
200 librbd::ImageCtx
*ictx
;
201 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
202 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
203 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
205 MockImageCtx
mock_image_ctx(*ictx
);
207 MockExclusiveLock mock_exclusive_lock
;
208 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
209 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
212 MockObjectMap mock_object_map
;
213 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
214 mock_image_ctx
.object_map
= &mock_object_map
;
217 expect_op_work_queue(mock_image_ctx
);
219 ::testing::InSequence seq
;
220 expect_snapshot_trash_add(mock_image_ctx
, 0);
222 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
223 expect_snapshot_get(mock_image_ctx
,
224 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
225 "snap1", 123, {}, 0}, 0);
227 expect_get_parent_spec(mock_image_ctx
, 0);
228 expect_object_map_snap_remove(mock_image_ctx
, 0);
229 expect_release_snap_id(mock_image_ctx
);
230 expect_snap_remove(mock_image_ctx
, 0);
231 expect_rm_snap(mock_image_ctx
);
233 C_SaferCond cond_ctx
;
234 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
235 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
238 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
241 ASSERT_EQ(0, cond_ctx
.wait());
244 TEST_F(TestMockOperationSnapshotRemoveRequest
, SuccessCloneParent
) {
245 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
247 librbd::ImageCtx
*ictx
;
248 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
249 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
250 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
252 MockImageCtx
mock_image_ctx(*ictx
);
254 MockExclusiveLock mock_exclusive_lock
;
255 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
256 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
259 MockObjectMap mock_object_map
;
260 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
261 mock_image_ctx
.object_map
= &mock_object_map
;
264 expect_op_work_queue(mock_image_ctx
);
266 ::testing::InSequence seq
;
267 expect_snapshot_trash_add(mock_image_ctx
, 0);
269 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
270 expect_snapshot_get(mock_image_ctx
,
271 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
272 "snap1", 123, {}, 1}, 0);
274 const cls::rbd::ChildImageSpecs child_images
;
275 expect_children_list(mock_image_ctx
, child_images
, 0);
276 expect_get_parent_spec(mock_image_ctx
, 0);
278 C_SaferCond cond_ctx
;
279 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
280 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
283 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
286 ASSERT_EQ(0, cond_ctx
.wait());
289 TEST_F(TestMockOperationSnapshotRemoveRequest
, SuccessTrash
) {
290 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
292 librbd::ImageCtx
*ictx
;
293 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
294 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
295 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
297 MockImageCtx
mock_image_ctx(*ictx
);
299 MockExclusiveLock mock_exclusive_lock
;
300 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
301 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
304 MockObjectMap mock_object_map
;
305 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
306 mock_image_ctx
.object_map
= &mock_object_map
;
309 expect_op_work_queue(mock_image_ctx
);
311 ::testing::InSequence seq
;
312 expect_snapshot_trash_add(mock_image_ctx
, 0);
314 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
315 expect_snapshot_get(mock_image_ctx
,
317 {cls::rbd::TrashSnapshotNamespace
{
318 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER
, "snap1"}},
319 "snap1", 123, {}, 0}, 0);
321 expect_get_parent_spec(mock_image_ctx
, 0);
322 expect_object_map_snap_remove(mock_image_ctx
, 0);
323 expect_release_snap_id(mock_image_ctx
);
324 expect_snap_remove(mock_image_ctx
, 0);
325 expect_rm_snap(mock_image_ctx
);
327 C_SaferCond cond_ctx
;
328 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
329 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
332 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
335 ASSERT_EQ(0, cond_ctx
.wait());
338 TEST_F(TestMockOperationSnapshotRemoveRequest
, FlattenedCloneRemovesChild
) {
339 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
340 REQUIRE(!is_feature_enabled(RBD_FEATURE_DEEP_FLATTEN
))
342 ASSERT_EQ(0, create_snapshot("snap1"));
346 ASSERT_TRUE(::get_features(&features
));
347 std::string clone_name
= get_temp_image_name();
348 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
349 clone_name
.c_str(), features
, &order
, 0, 0));
351 librbd::ImageCtx
*ictx
;
352 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
353 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
355 librbd::NoOpProgressContext prog_ctx
;
356 ASSERT_EQ(0, flatten(*ictx
, prog_ctx
));
357 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
359 MockImageCtx
mock_image_ctx(*ictx
);
361 MockExclusiveLock mock_exclusive_lock
;
362 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
363 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
366 MockObjectMap mock_object_map
;
367 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
368 mock_image_ctx
.object_map
= &mock_object_map
;
371 expect_op_work_queue(mock_image_ctx
);
373 ::testing::InSequence seq
;
374 expect_snapshot_trash_add(mock_image_ctx
, 0);
376 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
377 expect_snapshot_get(mock_image_ctx
,
378 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
379 "snap1", 123, {}, 0}, 0);
381 expect_get_parent_spec(mock_image_ctx
, 0);
383 MockDetachChildRequest mock_detach_child_request
;
384 expect_detach_child(mock_image_ctx
, mock_detach_child_request
, -ENOENT
);
386 expect_object_map_snap_remove(mock_image_ctx
, 0);
388 expect_release_snap_id(mock_image_ctx
);
389 expect_snap_remove(mock_image_ctx
, 0);
390 expect_rm_snap(mock_image_ctx
);
392 C_SaferCond cond_ctx
;
393 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
394 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
397 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
400 ASSERT_EQ(0, cond_ctx
.wait());
403 TEST_F(TestMockOperationSnapshotRemoveRequest
, TrashCloneParent
) {
404 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
406 librbd::ImageCtx
*ictx
;
407 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
408 ASSERT_EQ(0, ictx
->operations
->snap_create(
409 {cls::rbd::TrashSnapshotNamespace
{}}, "snap1"));
410 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
412 MockImageCtx
mock_image_ctx(*ictx
);
414 MockExclusiveLock mock_exclusive_lock
;
415 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
416 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
419 MockObjectMap mock_object_map
;
420 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
421 mock_image_ctx
.object_map
= &mock_object_map
;
424 expect_op_work_queue(mock_image_ctx
);
426 ::testing::InSequence seq
;
428 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
429 expect_snapshot_get(mock_image_ctx
,
430 {snap_id
, {cls::rbd::TrashSnapshotNamespace
{}},
431 "snap1", 123, {}, 1}, 0);
432 const cls::rbd::ChildImageSpecs child_images
;
433 expect_children_list(mock_image_ctx
, child_images
, 0);
434 expect_get_parent_spec(mock_image_ctx
, 0);
436 C_SaferCond cond_ctx
;
437 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
438 mock_image_ctx
, &cond_ctx
, cls::rbd::TrashSnapshotNamespace
{}, "snap1",
441 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
444 ASSERT_EQ(-EBUSY
, cond_ctx
.wait());
447 TEST_F(TestMockOperationSnapshotRemoveRequest
, SnapshotTrashAddNotSupported
) {
450 librbd::ImageCtx
*ictx
;
451 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
452 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
453 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
455 MockImageCtx
mock_image_ctx(*ictx
);
457 MockExclusiveLock mock_exclusive_lock
;
458 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
459 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
462 MockObjectMap mock_object_map
;
463 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
464 mock_image_ctx
.object_map
= &mock_object_map
;
467 expect_op_work_queue(mock_image_ctx
);
469 ::testing::InSequence seq
;
470 expect_snapshot_trash_add(mock_image_ctx
, -EOPNOTSUPP
);
472 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
473 expect_get_parent_spec(mock_image_ctx
, 0);
474 expect_object_map_snap_remove(mock_image_ctx
, 0);
475 expect_release_snap_id(mock_image_ctx
);
476 expect_snap_remove(mock_image_ctx
, 0);
477 expect_rm_snap(mock_image_ctx
);
479 C_SaferCond cond_ctx
;
480 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
481 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
484 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
487 ASSERT_EQ(0, cond_ctx
.wait());
490 TEST_F(TestMockOperationSnapshotRemoveRequest
, SnapshotTrashAddError
) {
493 librbd::ImageCtx
*ictx
;
494 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
495 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
496 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
498 MockImageCtx
mock_image_ctx(*ictx
);
499 expect_op_work_queue(mock_image_ctx
);
501 ::testing::InSequence seq
;
502 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
503 expect_snapshot_trash_add(mock_image_ctx
, -EINVAL
);
505 C_SaferCond cond_ctx
;
506 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
507 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
510 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
513 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
516 TEST_F(TestMockOperationSnapshotRemoveRequest
, SnapshotGetError
) {
519 librbd::ImageCtx
*ictx
;
520 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
521 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
522 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
524 MockImageCtx
mock_image_ctx(*ictx
);
525 expect_op_work_queue(mock_image_ctx
);
527 ::testing::InSequence seq
;
528 expect_snapshot_trash_add(mock_image_ctx
, 0);
530 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
531 expect_snapshot_get(mock_image_ctx
,
532 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
533 "snap1", 123, {}, 0}, -EOPNOTSUPP
);
535 C_SaferCond cond_ctx
;
536 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
537 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
540 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
543 ASSERT_EQ(-EOPNOTSUPP
, cond_ctx
.wait());
546 TEST_F(TestMockOperationSnapshotRemoveRequest
, ObjectMapSnapRemoveError
) {
547 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
549 librbd::ImageCtx
*ictx
;
550 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
551 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
552 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
554 MockImageCtx
mock_image_ctx(*ictx
);
555 MockObjectMap mock_object_map
;
556 mock_image_ctx
.object_map
= &mock_object_map
;
558 expect_op_work_queue(mock_image_ctx
);
560 ::testing::InSequence seq
;
561 expect_snapshot_trash_add(mock_image_ctx
, 0);
563 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
564 expect_snapshot_get(mock_image_ctx
,
565 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
566 "snap1", 123, {}, 0}, 0);
568 expect_get_parent_spec(mock_image_ctx
, 0);
570 expect_object_map_snap_remove(mock_image_ctx
, -EINVAL
);
572 C_SaferCond cond_ctx
;
573 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
574 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
577 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
580 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
583 TEST_F(TestMockOperationSnapshotRemoveRequest
, RemoveChildParentError
) {
584 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
586 librbd::ImageCtx
*ictx
;
587 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
588 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
589 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
591 MockImageCtx
mock_image_ctx(*ictx
);
593 MockObjectMap mock_object_map
;
594 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
595 mock_image_ctx
.object_map
= &mock_object_map
;
598 expect_op_work_queue(mock_image_ctx
);
600 ::testing::InSequence seq
;
601 expect_snapshot_trash_add(mock_image_ctx
, 0);
603 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
604 expect_snapshot_get(mock_image_ctx
,
605 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
606 "snap1", 123, {}, 0}, 0);
608 expect_get_parent_spec(mock_image_ctx
, -ENOENT
);
610 C_SaferCond cond_ctx
;
611 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
612 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
615 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
618 ASSERT_EQ(-ENOENT
, cond_ctx
.wait());
621 TEST_F(TestMockOperationSnapshotRemoveRequest
, RemoveChildError
) {
622 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
624 ASSERT_EQ(0, create_snapshot("snap1"));
628 ASSERT_TRUE(::get_features(&features
));
629 std::string clone_name
= get_temp_image_name();
630 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
631 clone_name
.c_str(), features
, &order
, 0, 0));
633 librbd::ImageCtx
*ictx
;
634 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
635 if (ictx
->test_features(RBD_FEATURE_DEEP_FLATTEN
)) {
636 std::cout
<< "SKIPPING" << std::endl
;
640 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
642 librbd::NoOpProgressContext prog_ctx
;
643 ASSERT_EQ(0, flatten(*ictx
, prog_ctx
));
644 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
646 MockImageCtx
mock_image_ctx(*ictx
);
648 MockObjectMap mock_object_map
;
649 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
650 mock_image_ctx
.object_map
= &mock_object_map
;
653 expect_op_work_queue(mock_image_ctx
);
655 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
656 expect_get_parent_spec(mock_image_ctx
, 0);
658 MockDetachChildRequest mock_detach_child_request
;
659 expect_detach_child(mock_image_ctx
, mock_detach_child_request
, -EINVAL
);
661 C_SaferCond cond_ctx
;
662 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
663 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
666 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
669 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
672 TEST_F(TestMockOperationSnapshotRemoveRequest
, RemoveSnapError
) {
673 librbd::ImageCtx
*ictx
;
674 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
675 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
676 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
678 MockImageCtx
mock_image_ctx(*ictx
);
680 MockExclusiveLock mock_exclusive_lock
;
681 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
682 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
685 MockObjectMap mock_object_map
;
686 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
687 mock_image_ctx
.object_map
= &mock_object_map
;
690 expect_op_work_queue(mock_image_ctx
);
692 ::testing::InSequence seq
;
693 expect_snapshot_trash_add(mock_image_ctx
, 0);
695 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
696 expect_snapshot_get(mock_image_ctx
,
697 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
698 "snap1", 123, {}, 0}, 0);
700 expect_get_parent_spec(mock_image_ctx
, 0);
701 expect_object_map_snap_remove(mock_image_ctx
, 0);
702 expect_release_snap_id(mock_image_ctx
);
703 expect_snap_remove(mock_image_ctx
, -ENOENT
);
705 C_SaferCond cond_ctx
;
706 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
707 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
710 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
713 ASSERT_EQ(-ENOENT
, cond_ctx
.wait());
716 TEST_F(TestMockOperationSnapshotRemoveRequest
, MissingSnap
) {
717 librbd::ImageCtx
*ictx
;
718 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
720 MockImageCtx
mock_image_ctx(*ictx
);
722 MockExclusiveLock mock_exclusive_lock
;
723 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
724 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
727 MockObjectMap mock_object_map
;
728 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
729 mock_image_ctx
.object_map
= &mock_object_map
;
732 expect_op_work_queue(mock_image_ctx
);
734 ::testing::InSequence seq
;
735 uint64_t snap_id
= 456;
737 C_SaferCond cond_ctx
;
738 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
739 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
742 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
745 ASSERT_EQ(-ENOENT
, cond_ctx
.wait());
748 TEST_F(TestMockOperationSnapshotRemoveRequest
, ListChildrenError
) {
749 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
751 librbd::ImageCtx
*ictx
;
752 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
753 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
754 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
756 MockImageCtx
mock_image_ctx(*ictx
);
758 MockExclusiveLock mock_exclusive_lock
;
759 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
760 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
763 MockObjectMap mock_object_map
;
764 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
765 mock_image_ctx
.object_map
= &mock_object_map
;
768 expect_op_work_queue(mock_image_ctx
);
770 ::testing::InSequence seq
;
771 expect_snapshot_trash_add(mock_image_ctx
, 0);
773 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
774 expect_snapshot_get(mock_image_ctx
,
775 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
776 "snap1", 123, {}, 1}, 0);
777 const cls::rbd::ChildImageSpecs child_images
;
778 expect_children_list(mock_image_ctx
, child_images
, -EINVAL
);
780 C_SaferCond cond_ctx
;
781 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
782 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
785 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
788 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
791 TEST_F(TestMockOperationSnapshotRemoveRequest
, DetachStaleChildError
) {
792 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
794 ASSERT_EQ(0, create_snapshot("snap1"));
798 ASSERT_TRUE(::get_features(&features
));
799 std::string clone_name
= get_temp_image_name();
800 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
801 clone_name
.c_str(), features
, &order
, 0, 0));
803 librbd::ImageCtx
*ictx
;
804 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
805 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
806 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
808 MockImageCtx
mock_image_ctx(*ictx
);
809 expect_op_work_queue(mock_image_ctx
);
811 ::testing::InSequence seq
;
812 expect_snapshot_trash_add(mock_image_ctx
, 0);
814 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
815 expect_snapshot_get(mock_image_ctx
,
816 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
817 "snap1", 123, {}, 1}, 0);
818 const cls::rbd::ChildImageSpecs child_images
;
819 expect_children_list(mock_image_ctx
, child_images
, -EINVAL
);
821 C_SaferCond cond_ctx
;
822 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
823 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
826 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
829 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
832 } // namespace operation
833 } // namespace librbd