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/mirror/snapshot/RemoveImageStateRequest.h"
14 #include "librbd/operation/SnapshotRemoveRequest.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
22 class DetachChildRequest
<MockImageCtx
> {
24 static DetachChildRequest
*s_instance
;
25 static DetachChildRequest
*create(MockImageCtx
&image_ctx
,
27 ceph_assert(s_instance
!= nullptr);
28 s_instance
->on_finish
= on_finish
;
32 Context
*on_finish
= nullptr;
34 DetachChildRequest() {
38 MOCK_METHOD0(send
, void());
41 DetachChildRequest
<MockImageCtx
> *DetachChildRequest
<MockImageCtx
>::s_instance
;
49 class RemoveImageStateRequest
<MockImageCtx
> {
51 static RemoveImageStateRequest
*s_instance
;
52 Context
*on_finish
= nullptr;
54 static RemoveImageStateRequest
*create(MockImageCtx
*image_ctx
,
57 ceph_assert(s_instance
!= nullptr);
58 s_instance
->on_finish
= on_finish
;
62 RemoveImageStateRequest() {
66 MOCK_METHOD0(send
, void());
69 RemoveImageStateRequest
<MockImageCtx
> *RemoveImageStateRequest
<MockImageCtx
>::s_instance
;
71 } // namespace snapshot
75 // template definitions
76 #include "librbd/operation/SnapshotRemoveRequest.cc"
82 using ::testing::DoAll
;
83 using ::testing::DoDefault
;
84 using ::testing::Invoke
;
85 using ::testing::Return
;
86 using ::testing::SetArgPointee
;
87 using ::testing::StrEq
;
88 using ::testing::WithArg
;
90 class TestMockOperationSnapshotRemoveRequest
: public TestMockFixture
{
92 typedef SnapshotRemoveRequest
<MockImageCtx
> MockSnapshotRemoveRequest
;
93 typedef image::DetachChildRequest
<MockImageCtx
> MockDetachChildRequest
;
94 typedef mirror::snapshot::RemoveImageStateRequest
<MockImageCtx
> MockRemoveImageStateRequest
;
96 int create_snapshot(const char *snap_name
) {
97 librbd::ImageCtx
*ictx
;
98 int r
= open_image(m_image_name
, &ictx
);
103 r
= snap_create(*ictx
, snap_name
);
108 r
= snap_protect(*ictx
, snap_name
);
116 void expect_snapshot_trash_add(MockImageCtx
&mock_image_ctx
, int r
) {
117 if (mock_image_ctx
.old_format
) {
121 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
122 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
123 StrEq("snapshot_trash_add"),
126 expect
.WillOnce(Return(r
));
128 expect
.WillOnce(DoDefault());
132 void expect_snapshot_get(MockImageCtx
&mock_image_ctx
,
133 const cls::rbd::SnapshotInfo
& snap_info
, int r
) {
134 if (mock_image_ctx
.old_format
) {
139 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
140 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
141 StrEq("snapshot_get"), _
, _
, _
, _
))
142 .WillOnce(WithArg
<5>(Invoke([snap_info
, r
](bufferlist
* bl
) {
143 encode(snap_info
, *bl
);
148 void expect_children_list(MockImageCtx
&mock_image_ctx
,
149 const cls::rbd::ChildImageSpecs
& child_images
, int r
) {
150 if (mock_image_ctx
.old_format
) {
155 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
156 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
157 StrEq("children_list"), _
, _
, _
, _
))
158 .WillOnce(WithArg
<5>(Invoke([child_images
, r
](bufferlist
* bl
) {
159 encode(child_images
, *bl
);
164 void expect_detach_stale_child(MockImageCtx
&mock_image_ctx
, int r
) {
165 auto& parent_spec
= mock_image_ctx
.parent_md
.spec
;
168 encode(parent_spec
.snap_id
, bl
);
169 encode(cls::rbd::ChildImageSpec
{mock_image_ctx
.md_ctx
.get_id(), "",
170 mock_image_ctx
.id
}, bl
);
171 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
172 exec(util::header_name(parent_spec
.image_id
),
173 _
, StrEq("rbd"), StrEq("child_detach"), ContentsEqual(bl
),
175 .WillOnce(Return(r
));
178 void expect_object_map_snap_remove(MockImageCtx
&mock_image_ctx
, int r
) {
179 if (mock_image_ctx
.object_map
!= nullptr) {
180 EXPECT_CALL(*mock_image_ctx
.object_map
, snapshot_remove(_
, _
))
181 .WillOnce(WithArg
<1>(CompleteContext(
182 r
, mock_image_ctx
.image_ctx
->op_work_queue
)));
186 void expect_remove_image_state(
187 MockImageCtx
&mock_image_ctx
,
188 MockRemoveImageStateRequest
&mock_remove_image_state_request
, int r
) {
189 EXPECT_CALL(mock_remove_image_state_request
, send())
190 .WillOnce(FinishRequest(&mock_remove_image_state_request
, r
,
194 void expect_get_parent_spec(MockImageCtx
&mock_image_ctx
, int r
) {
195 if (mock_image_ctx
.old_format
) {
199 auto &expect
= EXPECT_CALL(mock_image_ctx
, get_parent_spec(_
, _
));
201 expect
.WillOnce(Return(r
));
203 auto &parent_spec
= mock_image_ctx
.snap_info
.rbegin()->second
.parent
.spec
;
204 expect
.WillOnce(DoAll(SetArgPointee
<1>(parent_spec
),
209 void expect_detach_child(MockImageCtx
&mock_image_ctx
,
210 MockDetachChildRequest
& mock_request
, int r
) {
211 EXPECT_CALL(mock_request
, send())
212 .WillOnce(FinishRequest(&mock_request
, r
, &mock_image_ctx
));
215 void expect_snap_remove(MockImageCtx
&mock_image_ctx
, int r
) {
216 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
217 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
218 StrEq(mock_image_ctx
.old_format
? "snap_remove" :
222 expect
.WillOnce(Return(r
));
224 expect
.WillOnce(DoDefault());
228 void expect_rm_snap(MockImageCtx
&mock_image_ctx
) {
229 EXPECT_CALL(mock_image_ctx
, rm_snap(_
, _
, _
)).Times(1);
232 void expect_release_snap_id(MockImageCtx
&mock_image_ctx
) {
233 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.data_ctx
),
234 selfmanaged_snap_remove(_
))
235 .WillOnce(DoDefault());
240 TEST_F(TestMockOperationSnapshotRemoveRequest
, Success
) {
241 librbd::ImageCtx
*ictx
;
242 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
243 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
244 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
246 MockImageCtx
mock_image_ctx(*ictx
);
248 MockExclusiveLock mock_exclusive_lock
;
249 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
250 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
253 MockObjectMap mock_object_map
;
254 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
255 mock_image_ctx
.object_map
= &mock_object_map
;
258 expect_op_work_queue(mock_image_ctx
);
260 ::testing::InSequence seq
;
261 expect_snapshot_trash_add(mock_image_ctx
, 0);
263 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
264 expect_snapshot_get(mock_image_ctx
,
265 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
266 "snap1", 123, {}, 0}, 0);
268 expect_get_parent_spec(mock_image_ctx
, 0);
269 expect_object_map_snap_remove(mock_image_ctx
, 0);
270 expect_release_snap_id(mock_image_ctx
);
271 expect_snap_remove(mock_image_ctx
, 0);
272 expect_rm_snap(mock_image_ctx
);
274 C_SaferCond cond_ctx
;
275 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
276 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
279 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
282 ASSERT_EQ(0, cond_ctx
.wait());
285 TEST_F(TestMockOperationSnapshotRemoveRequest
, SuccessCloneParent
) {
286 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
288 librbd::ImageCtx
*ictx
;
289 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
290 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
291 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
293 MockImageCtx
mock_image_ctx(*ictx
);
295 MockExclusiveLock mock_exclusive_lock
;
296 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
297 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
300 MockObjectMap mock_object_map
;
301 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
302 mock_image_ctx
.object_map
= &mock_object_map
;
305 expect_op_work_queue(mock_image_ctx
);
307 ::testing::InSequence seq
;
308 expect_snapshot_trash_add(mock_image_ctx
, 0);
310 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
311 expect_snapshot_get(mock_image_ctx
,
312 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
313 "snap1", 123, {}, 1}, 0);
315 const cls::rbd::ChildImageSpecs child_images
;
316 expect_children_list(mock_image_ctx
, child_images
, 0);
317 expect_get_parent_spec(mock_image_ctx
, 0);
319 C_SaferCond cond_ctx
;
320 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
321 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
324 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
327 ASSERT_EQ(0, cond_ctx
.wait());
330 TEST_F(TestMockOperationSnapshotRemoveRequest
, SuccessTrash
) {
331 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
333 librbd::ImageCtx
*ictx
;
334 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
335 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
336 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
338 MockImageCtx
mock_image_ctx(*ictx
);
340 MockExclusiveLock mock_exclusive_lock
;
341 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
342 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
345 MockObjectMap mock_object_map
;
346 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
347 mock_image_ctx
.object_map
= &mock_object_map
;
350 expect_op_work_queue(mock_image_ctx
);
352 ::testing::InSequence seq
;
353 expect_snapshot_trash_add(mock_image_ctx
, 0);
355 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
356 expect_snapshot_get(mock_image_ctx
,
358 {cls::rbd::TrashSnapshotNamespace
{
359 cls::rbd::SNAPSHOT_NAMESPACE_TYPE_USER
, "snap1"}},
360 "snap1", 123, {}, 0}, 0);
362 expect_get_parent_spec(mock_image_ctx
, 0);
363 expect_object_map_snap_remove(mock_image_ctx
, 0);
364 expect_release_snap_id(mock_image_ctx
);
365 expect_snap_remove(mock_image_ctx
, 0);
366 expect_rm_snap(mock_image_ctx
);
368 C_SaferCond cond_ctx
;
369 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
370 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
373 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
376 ASSERT_EQ(0, cond_ctx
.wait());
379 TEST_F(TestMockOperationSnapshotRemoveRequest
, FlattenedCloneRemovesChild
) {
380 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
381 REQUIRE(!is_feature_enabled(RBD_FEATURE_DEEP_FLATTEN
))
383 ASSERT_EQ(0, create_snapshot("snap1"));
387 ASSERT_TRUE(::get_features(&features
));
388 std::string clone_name
= get_temp_image_name();
389 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
390 clone_name
.c_str(), features
, &order
, 0, 0));
392 librbd::ImageCtx
*ictx
;
393 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
394 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
396 librbd::NoOpProgressContext prog_ctx
;
397 ASSERT_EQ(0, flatten(*ictx
, prog_ctx
));
398 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
400 MockImageCtx
mock_image_ctx(*ictx
);
402 MockExclusiveLock mock_exclusive_lock
;
403 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
404 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
407 MockObjectMap mock_object_map
;
408 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
409 mock_image_ctx
.object_map
= &mock_object_map
;
412 expect_op_work_queue(mock_image_ctx
);
414 ::testing::InSequence seq
;
415 expect_snapshot_trash_add(mock_image_ctx
, 0);
417 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
418 expect_snapshot_get(mock_image_ctx
,
419 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
420 "snap1", 123, {}, 0}, 0);
422 expect_get_parent_spec(mock_image_ctx
, 0);
424 MockDetachChildRequest mock_detach_child_request
;
425 expect_detach_child(mock_image_ctx
, mock_detach_child_request
, -ENOENT
);
427 expect_object_map_snap_remove(mock_image_ctx
, 0);
429 expect_release_snap_id(mock_image_ctx
);
430 expect_snap_remove(mock_image_ctx
, 0);
431 expect_rm_snap(mock_image_ctx
);
433 C_SaferCond cond_ctx
;
434 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
435 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
438 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
441 ASSERT_EQ(0, cond_ctx
.wait());
444 TEST_F(TestMockOperationSnapshotRemoveRequest
, TrashCloneParent
) {
445 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
447 librbd::ImageCtx
*ictx
;
448 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
449 NoOpProgressContext prog_ctx
;
450 ASSERT_EQ(0, ictx
->operations
->snap_create(
451 {cls::rbd::TrashSnapshotNamespace
{}}, "snap1", 0, prog_ctx
));
452 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
454 MockImageCtx
mock_image_ctx(*ictx
);
456 MockExclusiveLock mock_exclusive_lock
;
457 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
458 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
461 MockObjectMap mock_object_map
;
462 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
463 mock_image_ctx
.object_map
= &mock_object_map
;
466 expect_op_work_queue(mock_image_ctx
);
468 ::testing::InSequence seq
;
470 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
471 expect_snapshot_get(mock_image_ctx
,
472 {snap_id
, {cls::rbd::TrashSnapshotNamespace
{}},
473 "snap1", 123, {}, 1}, 0);
474 const cls::rbd::ChildImageSpecs child_images
;
475 expect_children_list(mock_image_ctx
, child_images
, 0);
476 expect_get_parent_spec(mock_image_ctx
, 0);
478 C_SaferCond cond_ctx
;
479 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
480 mock_image_ctx
, &cond_ctx
, cls::rbd::TrashSnapshotNamespace
{}, "snap1",
483 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
486 ASSERT_EQ(-EBUSY
, cond_ctx
.wait());
489 TEST_F(TestMockOperationSnapshotRemoveRequest
, MirrorSnapshot
) {
492 librbd::ImageCtx
*ictx
;
493 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
494 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
495 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
497 MockImageCtx
mock_image_ctx(*ictx
);
499 MockExclusiveLock mock_exclusive_lock
;
500 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
501 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
504 MockObjectMap mock_object_map
;
505 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
506 mock_image_ctx
.object_map
= &mock_object_map
;
509 expect_op_work_queue(mock_image_ctx
);
511 ::testing::InSequence seq
;
512 expect_snapshot_trash_add(mock_image_ctx
, 0);
514 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
515 expect_snapshot_get(mock_image_ctx
,
516 {snap_id
, {cls::rbd::MirrorSnapshotNamespace
{}},
517 "mirror", 123, {}, 0}, 0);
519 expect_get_parent_spec(mock_image_ctx
, 0);
520 expect_object_map_snap_remove(mock_image_ctx
, 0);
521 MockRemoveImageStateRequest mock_remove_image_state_request
;
522 expect_remove_image_state(mock_image_ctx
, mock_remove_image_state_request
, 0);
523 expect_release_snap_id(mock_image_ctx
);
524 expect_snap_remove(mock_image_ctx
, 0);
525 expect_rm_snap(mock_image_ctx
);
527 C_SaferCond cond_ctx
;
528 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
529 mock_image_ctx
, &cond_ctx
, cls::rbd::MirrorSnapshotNamespace(),
532 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
535 ASSERT_EQ(0, cond_ctx
.wait());
538 TEST_F(TestMockOperationSnapshotRemoveRequest
, SnapshotTrashAddNotSupported
) {
541 librbd::ImageCtx
*ictx
;
542 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
543 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
544 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
546 MockImageCtx
mock_image_ctx(*ictx
);
548 MockExclusiveLock mock_exclusive_lock
;
549 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
550 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
553 MockObjectMap mock_object_map
;
554 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
555 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
, -EOPNOTSUPP
);
563 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
564 expect_get_parent_spec(mock_image_ctx
, 0);
565 expect_object_map_snap_remove(mock_image_ctx
, 0);
566 expect_release_snap_id(mock_image_ctx
);
567 expect_snap_remove(mock_image_ctx
, 0);
568 expect_rm_snap(mock_image_ctx
);
570 C_SaferCond cond_ctx
;
571 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
572 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
575 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
578 ASSERT_EQ(0, cond_ctx
.wait());
581 TEST_F(TestMockOperationSnapshotRemoveRequest
, SnapshotTrashAddError
) {
584 librbd::ImageCtx
*ictx
;
585 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
586 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
587 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
589 MockImageCtx
mock_image_ctx(*ictx
);
590 expect_op_work_queue(mock_image_ctx
);
592 ::testing::InSequence seq
;
593 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
594 expect_snapshot_trash_add(mock_image_ctx
, -EINVAL
);
596 C_SaferCond cond_ctx
;
597 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
598 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
601 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
604 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
607 TEST_F(TestMockOperationSnapshotRemoveRequest
, SnapshotGetError
) {
610 librbd::ImageCtx
*ictx
;
611 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
612 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
613 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
615 MockImageCtx
mock_image_ctx(*ictx
);
616 expect_op_work_queue(mock_image_ctx
);
618 ::testing::InSequence seq
;
619 expect_snapshot_trash_add(mock_image_ctx
, 0);
621 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
622 expect_snapshot_get(mock_image_ctx
,
623 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
624 "snap1", 123, {}, 0}, -EOPNOTSUPP
);
626 C_SaferCond cond_ctx
;
627 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
628 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
631 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
634 ASSERT_EQ(-EOPNOTSUPP
, cond_ctx
.wait());
637 TEST_F(TestMockOperationSnapshotRemoveRequest
, ObjectMapSnapRemoveError
) {
638 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
640 librbd::ImageCtx
*ictx
;
641 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
642 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
643 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
645 MockImageCtx
mock_image_ctx(*ictx
);
646 MockObjectMap mock_object_map
;
647 mock_image_ctx
.object_map
= &mock_object_map
;
649 expect_op_work_queue(mock_image_ctx
);
651 ::testing::InSequence seq
;
652 expect_snapshot_trash_add(mock_image_ctx
, 0);
654 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
655 expect_snapshot_get(mock_image_ctx
,
656 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
657 "snap1", 123, {}, 0}, 0);
659 expect_get_parent_spec(mock_image_ctx
, 0);
661 expect_object_map_snap_remove(mock_image_ctx
, -EINVAL
);
663 C_SaferCond cond_ctx
;
664 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
665 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
668 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
671 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
674 TEST_F(TestMockOperationSnapshotRemoveRequest
, RemoveChildParentError
) {
675 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
677 librbd::ImageCtx
*ictx
;
678 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
679 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
680 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
682 MockImageCtx
mock_image_ctx(*ictx
);
684 MockObjectMap mock_object_map
;
685 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
686 mock_image_ctx
.object_map
= &mock_object_map
;
689 expect_op_work_queue(mock_image_ctx
);
691 ::testing::InSequence seq
;
692 expect_snapshot_trash_add(mock_image_ctx
, 0);
694 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
695 expect_snapshot_get(mock_image_ctx
,
696 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
697 "snap1", 123, {}, 0}, 0);
699 expect_get_parent_spec(mock_image_ctx
, -ENOENT
);
701 C_SaferCond cond_ctx
;
702 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
703 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
706 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
709 ASSERT_EQ(-ENOENT
, cond_ctx
.wait());
712 TEST_F(TestMockOperationSnapshotRemoveRequest
, RemoveChildError
) {
713 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
715 ASSERT_EQ(0, create_snapshot("snap1"));
719 ASSERT_TRUE(::get_features(&features
));
720 std::string clone_name
= get_temp_image_name();
721 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
722 clone_name
.c_str(), features
, &order
, 0, 0));
724 librbd::ImageCtx
*ictx
;
725 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
726 if (ictx
->test_features(RBD_FEATURE_DEEP_FLATTEN
)) {
727 GTEST_SKIP() << "Skipping due to enabled deep-flatten";
730 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
732 librbd::NoOpProgressContext prog_ctx
;
733 ASSERT_EQ(0, flatten(*ictx
, prog_ctx
));
734 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
736 MockImageCtx
mock_image_ctx(*ictx
);
738 MockObjectMap mock_object_map
;
739 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
740 mock_image_ctx
.object_map
= &mock_object_map
;
743 expect_op_work_queue(mock_image_ctx
);
745 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
746 expect_get_parent_spec(mock_image_ctx
, 0);
748 MockDetachChildRequest mock_detach_child_request
;
749 expect_detach_child(mock_image_ctx
, mock_detach_child_request
, -EINVAL
);
751 C_SaferCond cond_ctx
;
752 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
753 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
756 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
759 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
762 TEST_F(TestMockOperationSnapshotRemoveRequest
, RemoveSnapError
) {
763 librbd::ImageCtx
*ictx
;
764 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
765 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
766 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
768 MockImageCtx
mock_image_ctx(*ictx
);
770 MockExclusiveLock mock_exclusive_lock
;
771 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
772 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
775 MockObjectMap mock_object_map
;
776 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
777 mock_image_ctx
.object_map
= &mock_object_map
;
780 expect_op_work_queue(mock_image_ctx
);
782 ::testing::InSequence seq
;
783 expect_snapshot_trash_add(mock_image_ctx
, 0);
785 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
786 expect_snapshot_get(mock_image_ctx
,
787 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
788 "snap1", 123, {}, 0}, 0);
790 expect_get_parent_spec(mock_image_ctx
, 0);
791 expect_object_map_snap_remove(mock_image_ctx
, 0);
792 expect_release_snap_id(mock_image_ctx
);
793 expect_snap_remove(mock_image_ctx
, -ENOENT
);
795 C_SaferCond cond_ctx
;
796 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
797 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
800 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
803 ASSERT_EQ(-ENOENT
, cond_ctx
.wait());
806 TEST_F(TestMockOperationSnapshotRemoveRequest
, MissingSnap
) {
807 librbd::ImageCtx
*ictx
;
808 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
810 MockImageCtx
mock_image_ctx(*ictx
);
812 MockExclusiveLock mock_exclusive_lock
;
813 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
814 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
817 MockObjectMap mock_object_map
;
818 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
819 mock_image_ctx
.object_map
= &mock_object_map
;
822 expect_op_work_queue(mock_image_ctx
);
824 ::testing::InSequence seq
;
825 uint64_t snap_id
= 456;
827 C_SaferCond cond_ctx
;
828 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
829 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
832 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
835 ASSERT_EQ(-ENOENT
, cond_ctx
.wait());
838 TEST_F(TestMockOperationSnapshotRemoveRequest
, ListChildrenError
) {
839 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
841 librbd::ImageCtx
*ictx
;
842 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
843 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
844 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
846 MockImageCtx
mock_image_ctx(*ictx
);
848 MockExclusiveLock mock_exclusive_lock
;
849 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
850 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
853 MockObjectMap mock_object_map
;
854 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
855 mock_image_ctx
.object_map
= &mock_object_map
;
858 expect_op_work_queue(mock_image_ctx
);
860 ::testing::InSequence seq
;
861 expect_snapshot_trash_add(mock_image_ctx
, 0);
863 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
864 expect_snapshot_get(mock_image_ctx
,
865 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
866 "snap1", 123, {}, 1}, 0);
867 const cls::rbd::ChildImageSpecs child_images
;
868 expect_children_list(mock_image_ctx
, child_images
, -EINVAL
);
870 C_SaferCond cond_ctx
;
871 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
872 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
875 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
878 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
881 TEST_F(TestMockOperationSnapshotRemoveRequest
, DetachStaleChildError
) {
882 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
884 ASSERT_EQ(0, create_snapshot("snap1"));
888 ASSERT_TRUE(::get_features(&features
));
889 std::string clone_name
= get_temp_image_name();
890 ASSERT_EQ(0, librbd::clone(m_ioctx
, m_image_name
.c_str(), "snap1", m_ioctx
,
891 clone_name
.c_str(), features
, &order
, 0, 0));
893 librbd::ImageCtx
*ictx
;
894 ASSERT_EQ(0, open_image(clone_name
, &ictx
));
895 ASSERT_EQ(0, snap_create(*ictx
, "snap1"));
896 ASSERT_EQ(0, ictx
->state
->refresh_if_required());
898 MockImageCtx
mock_image_ctx(*ictx
);
899 expect_op_work_queue(mock_image_ctx
);
901 ::testing::InSequence seq
;
902 expect_snapshot_trash_add(mock_image_ctx
, 0);
904 uint64_t snap_id
= ictx
->snap_info
.rbegin()->first
;
905 expect_snapshot_get(mock_image_ctx
,
906 {snap_id
, {cls::rbd::UserSnapshotNamespace
{}},
907 "snap1", 123, {}, 1}, 0);
908 const cls::rbd::ChildImageSpecs child_images
;
909 expect_children_list(mock_image_ctx
, child_images
, -EINVAL
);
911 C_SaferCond cond_ctx
;
912 MockSnapshotRemoveRequest
*req
= new MockSnapshotRemoveRequest(
913 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(), "snap1",
916 std::shared_lock owner_locker
{mock_image_ctx
.owner_lock
};
919 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
922 } // namespace operation
923 } // namespace librbd