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/internal.h"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/operation/SnapshotCreateRequest.h"
12 #include "gmock/gmock.h"
13 #include "gtest/gtest.h"
15 // template definitions
16 #include "librbd/operation/SnapshotCreateRequest.cc"
22 using ::testing::DoAll
;
23 using ::testing::DoDefault
;
24 using ::testing::Return
;
25 using ::testing::SetArgPointee
;
26 using ::testing::StrEq
;
27 using ::testing::WithArg
;
29 class TestMockOperationSnapshotCreateRequest
: public TestMockFixture
{
31 typedef SnapshotCreateRequest
<MockImageCtx
> MockSnapshotCreateRequest
;
33 void expect_block_writes(MockImageCtx
&mock_image_ctx
) {
34 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, block_writes(_
))
35 .WillOnce(CompleteContext(0, mock_image_ctx
.image_ctx
->op_work_queue
));
38 void expect_verify_lock_ownership(MockImageCtx
&mock_image_ctx
) {
39 if (mock_image_ctx
.exclusive_lock
!= nullptr) {
40 EXPECT_CALL(*mock_image_ctx
.exclusive_lock
, is_lock_owner())
41 .WillRepeatedly(Return(true));
45 void expect_allocate_snap_id(MockImageCtx
&mock_image_ctx
, int r
) {
46 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
47 selfmanaged_snap_create(_
));
48 if (r
< 0 && r
!= -ESTALE
) {
49 expect
.WillOnce(Return(r
));
51 expect
.Times(r
< 0 ? 2 : 1).WillRepeatedly(DoDefault());
55 void expect_release_snap_id(MockImageCtx
&mock_image_ctx
, int r
) {
56 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
57 selfmanaged_snap_remove(_
));
59 expect
.WillOnce(Return(r
));
61 expect
.WillOnce(DoDefault());
65 void expect_snap_create(MockImageCtx
&mock_image_ctx
, int r
) {
66 auto &expect
= EXPECT_CALL(get_mock_io_ctx(mock_image_ctx
.md_ctx
),
67 exec(mock_image_ctx
.header_oid
, _
, StrEq("rbd"),
68 StrEq(mock_image_ctx
.old_format
? "snap_add" :
72 expect
.WillOnce(Return(r
)).WillOnce(DoDefault());
74 expect
.WillOnce(Return(r
));
76 expect
.WillOnce(DoDefault());
80 void expect_object_map_snap_create(MockImageCtx
&mock_image_ctx
) {
81 if (mock_image_ctx
.object_map
!= nullptr) {
82 EXPECT_CALL(*mock_image_ctx
.object_map
, snapshot_add(_
, _
))
83 .WillOnce(WithArg
<1>(CompleteContext(
84 0, mock_image_ctx
.image_ctx
->op_work_queue
)));
88 void expect_update_snap_context(MockImageCtx
&mock_image_ctx
) {
89 // state machine checks to ensure a refresh hasn't already added the snap
90 EXPECT_CALL(mock_image_ctx
, get_snap_info(_
))
91 .WillOnce(Return(static_cast<const librbd::SnapInfo
*>(NULL
)));
92 EXPECT_CALL(mock_image_ctx
, add_snap(_
, "snap1", _
, _
, _
, _
, _
, _
));
95 void expect_unblock_writes(MockImageCtx
&mock_image_ctx
) {
96 EXPECT_CALL(*mock_image_ctx
.io_work_queue
, unblock_writes())
102 TEST_F(TestMockOperationSnapshotCreateRequest
, Success
) {
105 librbd::ImageCtx
*ictx
;
106 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
108 MockImageCtx
mock_image_ctx(*ictx
);
110 MockExclusiveLock mock_exclusive_lock
;
111 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
112 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
115 MockObjectMap mock_object_map
;
116 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
117 mock_image_ctx
.object_map
= &mock_object_map
;
120 expect_verify_lock_ownership(mock_image_ctx
);
121 expect_op_work_queue(mock_image_ctx
);
123 ::testing::InSequence seq
;
124 expect_block_writes(mock_image_ctx
);
125 expect_allocate_snap_id(mock_image_ctx
, 0);
126 expect_snap_create(mock_image_ctx
, 0);
127 if (!mock_image_ctx
.old_format
) {
128 expect_update_snap_context(mock_image_ctx
);
129 expect_object_map_snap_create(mock_image_ctx
);
131 expect_unblock_writes(mock_image_ctx
);
133 C_SaferCond cond_ctx
;
134 MockSnapshotCreateRequest
*req
= new MockSnapshotCreateRequest(
135 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(),
138 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
141 ASSERT_EQ(0, cond_ctx
.wait());
144 TEST_F(TestMockOperationSnapshotCreateRequest
, AllocateSnapIdError
) {
145 librbd::ImageCtx
*ictx
;
146 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
148 MockImageCtx
mock_image_ctx(*ictx
);
150 MockExclusiveLock mock_exclusive_lock
;
151 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
152 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
155 expect_verify_lock_ownership(mock_image_ctx
);
156 expect_op_work_queue(mock_image_ctx
);
158 ::testing::InSequence seq
;
159 expect_block_writes(mock_image_ctx
);
160 expect_allocate_snap_id(mock_image_ctx
, -EINVAL
);
161 expect_unblock_writes(mock_image_ctx
);
163 C_SaferCond cond_ctx
;
164 MockSnapshotCreateRequest
*req
= new MockSnapshotCreateRequest(
165 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(),
168 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
171 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
174 TEST_F(TestMockOperationSnapshotCreateRequest
, CreateSnapStale
) {
175 librbd::ImageCtx
*ictx
;
176 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
178 MockImageCtx
mock_image_ctx(*ictx
);
180 MockExclusiveLock mock_exclusive_lock
;
181 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
182 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
185 MockObjectMap mock_object_map
;
186 if (ictx
->test_features(RBD_FEATURE_OBJECT_MAP
)) {
187 mock_image_ctx
.object_map
= &mock_object_map
;
190 expect_verify_lock_ownership(mock_image_ctx
);
191 expect_op_work_queue(mock_image_ctx
);
193 expect_block_writes(mock_image_ctx
);
194 expect_allocate_snap_id(mock_image_ctx
, -ESTALE
);
195 expect_snap_create(mock_image_ctx
, -ESTALE
);
196 if (!mock_image_ctx
.old_format
) {
197 expect_update_snap_context(mock_image_ctx
);
198 expect_object_map_snap_create(mock_image_ctx
);
200 expect_unblock_writes(mock_image_ctx
);
202 C_SaferCond cond_ctx
;
203 MockSnapshotCreateRequest
*req
= new MockSnapshotCreateRequest(
204 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(),
207 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
210 ASSERT_EQ(0, cond_ctx
.wait());
213 TEST_F(TestMockOperationSnapshotCreateRequest
, CreateSnapError
) {
214 librbd::ImageCtx
*ictx
;
215 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
217 MockImageCtx
mock_image_ctx(*ictx
);
219 MockExclusiveLock mock_exclusive_lock
;
220 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
221 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
224 expect_verify_lock_ownership(mock_image_ctx
);
225 expect_op_work_queue(mock_image_ctx
);
227 expect_block_writes(mock_image_ctx
);
228 expect_allocate_snap_id(mock_image_ctx
, 0);
229 expect_snap_create(mock_image_ctx
, -EINVAL
);
230 expect_release_snap_id(mock_image_ctx
, 0);
231 expect_unblock_writes(mock_image_ctx
);
233 C_SaferCond cond_ctx
;
234 MockSnapshotCreateRequest
*req
= new MockSnapshotCreateRequest(
235 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(),
238 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
241 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
244 TEST_F(TestMockOperationSnapshotCreateRequest
, ReleaseSnapIdError
) {
245 librbd::ImageCtx
*ictx
;
246 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
248 MockImageCtx
mock_image_ctx(*ictx
);
250 MockExclusiveLock mock_exclusive_lock
;
251 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
252 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
255 expect_verify_lock_ownership(mock_image_ctx
);
256 expect_op_work_queue(mock_image_ctx
);
258 expect_block_writes(mock_image_ctx
);
259 expect_allocate_snap_id(mock_image_ctx
, 0);
260 expect_snap_create(mock_image_ctx
, -EINVAL
);
261 expect_release_snap_id(mock_image_ctx
, -ESTALE
);
262 expect_unblock_writes(mock_image_ctx
);
264 C_SaferCond cond_ctx
;
265 MockSnapshotCreateRequest
*req
= new MockSnapshotCreateRequest(
266 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(),
269 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
272 ASSERT_EQ(-EINVAL
, cond_ctx
.wait());
275 TEST_F(TestMockOperationSnapshotCreateRequest
, SkipObjectMap
) {
276 REQUIRE_FEATURE(RBD_FEATURE_OBJECT_MAP
);
278 librbd::ImageCtx
*ictx
;
279 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
281 MockImageCtx
mock_image_ctx(*ictx
);
283 MockExclusiveLock mock_exclusive_lock
;
284 if (ictx
->test_features(RBD_FEATURE_EXCLUSIVE_LOCK
)) {
285 mock_image_ctx
.exclusive_lock
= &mock_exclusive_lock
;
288 MockObjectMap mock_object_map
;
289 mock_image_ctx
.object_map
= &mock_object_map
;
291 expect_verify_lock_ownership(mock_image_ctx
);
292 expect_op_work_queue(mock_image_ctx
);
294 ::testing::InSequence seq
;
295 expect_block_writes(mock_image_ctx
);
296 expect_allocate_snap_id(mock_image_ctx
, 0);
297 expect_snap_create(mock_image_ctx
, 0);
298 expect_update_snap_context(mock_image_ctx
);
299 expect_unblock_writes(mock_image_ctx
);
301 C_SaferCond cond_ctx
;
302 MockSnapshotCreateRequest
*req
= new MockSnapshotCreateRequest(
303 mock_image_ctx
, &cond_ctx
, cls::rbd::UserSnapshotNamespace(),
306 RWLock::RLocker
owner_locker(mock_image_ctx
.owner_lock
);
309 ASSERT_EQ(0, cond_ctx
.wait());
312 } // namespace operation
313 } // namespace librbd