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.data_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.data_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