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/librbd/mock/MockContextWQ.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "librbd/ImageState.h"
10 #include "librbd/Operations.h"
11 #include "librbd/image/AttachChildRequest.h"
12 #include "librbd/image/RefreshRequest.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
19 struct MockTestImageCtx
: public MockImageCtx
{
20 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
24 } // anonymous namespace
29 struct RefreshRequest
<MockTestImageCtx
> {
30 Context
* on_finish
= nullptr;
31 static RefreshRequest
* s_instance
;
32 static RefreshRequest
* create(MockTestImageCtx
&image_ctx
,
33 bool acquiring_lock
, bool skip_open_parent
,
35 ceph_assert(s_instance
!= nullptr);
36 s_instance
->on_finish
= on_finish
;
40 MOCK_METHOD0(send
, void());
47 RefreshRequest
<MockTestImageCtx
>* RefreshRequest
<MockTestImageCtx
>::s_instance
= nullptr;
53 // template definitions
54 #include "librbd/image/AttachChildRequest.cc"
60 using ::testing::InSequence
;
61 using ::testing::Invoke
;
62 using ::testing::Return
;
63 using ::testing::StrEq
;
64 using ::testing::WithArg
;
66 class TestMockImageAttachChildRequest
: public TestMockFixture
{
68 typedef AttachChildRequest
<MockTestImageCtx
> MockAttachChildRequest
;
69 typedef RefreshRequest
<MockTestImageCtx
> MockRefreshRequest
;
71 void SetUp() override
{
72 TestMockFixture::SetUp();
74 ASSERT_EQ(0, open_image(m_image_name
, &image_ctx
));
75 ASSERT_EQ(0, image_ctx
->operations
->snap_create(
76 cls::rbd::UserSnapshotNamespace
{}, "snap"));
77 if (is_feature_enabled(RBD_FEATURE_LAYERING
)) {
78 ASSERT_EQ(0, image_ctx
->operations
->snap_protect(
79 cls::rbd::UserSnapshotNamespace
{}, "snap"));
81 uint64_t snap_id
= image_ctx
->snap_ids
[
82 {cls::rbd::UserSnapshotNamespace
{}, "snap"}];
83 ASSERT_NE(CEPH_NOSNAP
, snap_id
);
86 image_ctx
->state
->snap_set(snap_id
, &ctx
);
87 ASSERT_EQ(0, ctx
.wait());
91 void expect_add_child(MockImageCtx
&mock_image_ctx
, int r
) {
92 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
93 exec(RBD_CHILDREN
, _
, StrEq("rbd"), StrEq("add_child"), _
, _
, _
))
97 void expect_refresh(MockRefreshRequest
& mock_refresh_request
, int r
) {
98 EXPECT_CALL(mock_refresh_request
, send())
99 .WillOnce(Invoke([this, &mock_refresh_request
, r
]() {
100 image_ctx
->op_work_queue
->queue(mock_refresh_request
.on_finish
, r
);
104 void expect_is_snap_protected(MockImageCtx
&mock_image_ctx
, bool is_protected
,
106 EXPECT_CALL(mock_image_ctx
, is_snap_protected(_
, _
))
107 .WillOnce(WithArg
<1>(Invoke([is_protected
, r
](bool* is_prot
) {
108 *is_prot
= is_protected
;
113 void expect_op_features_set(MockImageCtx
&mock_image_ctx
, int r
) {
115 encode(static_cast<uint64_t>(RBD_OPERATION_FEATURE_CLONE_CHILD
), bl
);
116 encode(static_cast<uint64_t>(RBD_OPERATION_FEATURE_CLONE_CHILD
), bl
);
118 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
119 exec(util::header_name(mock_image_ctx
.id
), _
, StrEq("rbd"),
120 StrEq("op_features_set"), ContentsEqual(bl
), _
, _
))
121 .WillOnce(Return(r
));
124 void expect_child_attach(MockImageCtx
&mock_image_ctx
, int r
) {
126 encode(mock_image_ctx
.snap_id
, bl
);
127 encode(cls::rbd::ChildImageSpec
{m_ioctx
.get_id(), "", mock_image_ctx
.id
},
130 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
131 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
132 StrEq("child_attach"), ContentsEqual(bl
), _
, _
))
133 .WillOnce(Return(r
));
136 librbd::ImageCtx
*image_ctx
;
139 TEST_F(TestMockImageAttachChildRequest
, SuccessV1
) {
140 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
142 MockTestImageCtx
mock_image_ctx(*image_ctx
);
146 expect_add_child(mock_image_ctx
, 0);
148 MockRefreshRequest mock_refresh_request
;
149 expect_refresh(mock_refresh_request
, 0);
150 expect_is_snap_protected(mock_image_ctx
, true, 0);
153 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
154 image_ctx
->snap_id
, nullptr, 0, 1,
157 ASSERT_EQ(0, ctx
.wait());
160 TEST_F(TestMockImageAttachChildRequest
, SuccessV2
) {
161 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
163 MockTestImageCtx
mock_image_ctx(*image_ctx
);
167 expect_op_features_set(mock_image_ctx
, 0);
168 expect_child_attach(mock_image_ctx
, 0);
171 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
172 image_ctx
->snap_id
, nullptr, 0, 2,
175 ASSERT_EQ(0, ctx
.wait());
178 TEST_F(TestMockImageAttachChildRequest
, AddChildError
) {
179 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
181 MockTestImageCtx
mock_image_ctx(*image_ctx
);
185 expect_add_child(mock_image_ctx
, -EINVAL
);
188 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
189 image_ctx
->snap_id
, nullptr, 0, 1,
192 ASSERT_EQ(-EINVAL
, ctx
.wait());
195 TEST_F(TestMockImageAttachChildRequest
, RefreshError
) {
196 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
198 MockTestImageCtx
mock_image_ctx(*image_ctx
);
202 expect_add_child(mock_image_ctx
, 0);
204 MockRefreshRequest mock_refresh_request
;
205 expect_refresh(mock_refresh_request
, -EINVAL
);
208 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
209 image_ctx
->snap_id
, nullptr, 0, 1,
212 ASSERT_EQ(-EINVAL
, ctx
.wait());
215 TEST_F(TestMockImageAttachChildRequest
, ValidateProtectedFailed
) {
216 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
218 MockTestImageCtx
mock_image_ctx(*image_ctx
);
222 expect_add_child(mock_image_ctx
, 0);
224 MockRefreshRequest mock_refresh_request
;
225 expect_refresh(mock_refresh_request
, 0);
226 expect_is_snap_protected(mock_image_ctx
, false, 0);
229 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
230 image_ctx
->snap_id
, nullptr, 0, 1,
233 ASSERT_EQ(-EINVAL
, ctx
.wait());
236 TEST_F(TestMockImageAttachChildRequest
, SetCloneError
) {
237 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
239 MockTestImageCtx
mock_image_ctx(*image_ctx
);
243 expect_op_features_set(mock_image_ctx
, -EINVAL
);
246 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
247 image_ctx
->snap_id
, nullptr, 0, 2,
250 ASSERT_EQ(-EINVAL
, ctx
.wait());
253 TEST_F(TestMockImageAttachChildRequest
, AttachChildError
) {
254 REQUIRE_FEATURE(RBD_FEATURE_LAYERING
);
256 MockTestImageCtx
mock_image_ctx(*image_ctx
);
260 expect_op_features_set(mock_image_ctx
, 0);
261 expect_child_attach(mock_image_ctx
, -EINVAL
);
264 auto req
= MockAttachChildRequest::create(&mock_image_ctx
, &mock_image_ctx
,
265 image_ctx
->snap_id
, nullptr, 0, 2,
268 ASSERT_EQ(-EINVAL
, ctx
.wait());
272 } // namespace librbd