]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/operation/test_mock_SnapshotRollbackRequest.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / test / librbd / operation / test_mock_SnapshotRollbackRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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/io/MockObjectDispatch.h"
8 #include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9 #include "include/stringify.h"
10 #include "common/bit_vector.hpp"
11 #include "librbd/ImageState.h"
12 #include "librbd/internal.h"
13 #include "librbd/operation/SnapshotRollbackRequest.h"
14 #include "gmock/gmock.h"
15 #include "gtest/gtest.h"
16
17 namespace librbd {
18
19 namespace {
20
21 struct MockOperationImageCtx : public MockImageCtx {
22 MockOperationImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
23 }
24 };
25
26 } // anonymous namespace
27
28 namespace operation {
29
30 template <>
31 struct ResizeRequest<MockOperationImageCtx> {
32 static ResizeRequest *s_instance;
33 Context *on_finish = nullptr;
34
35 static ResizeRequest* create(MockOperationImageCtx &image_ctx, Context *on_finish,
36 uint64_t new_size, bool allow_shrink,
37 ProgressContext &prog_ctx, uint64_t journal_op_tid,
38 bool disable_journal) {
39 ceph_assert(s_instance != nullptr);
40 ceph_assert(journal_op_tid == 0);
41 ceph_assert(disable_journal);
42 s_instance->on_finish = on_finish;
43 return s_instance;
44 }
45
46 ResizeRequest() {
47 s_instance = this;
48 }
49
50 MOCK_METHOD0(send, void());
51 };
52
53 ResizeRequest<MockOperationImageCtx> *ResizeRequest<MockOperationImageCtx>::s_instance = nullptr;
54
55 } // namespace operation
56
57 template <>
58 struct AsyncRequest<MockOperationImageCtx> : public AsyncRequest<MockImageCtx> {
59 MockOperationImageCtx &m_image_ctx;
60
61 AsyncRequest(MockOperationImageCtx &image_ctx, Context *on_finish)
62 : AsyncRequest<MockImageCtx>(image_ctx, on_finish), m_image_ctx(image_ctx) {
63 }
64 };
65
66 } // namespace librbd
67
68 // template definitions
69 #include "librbd/AsyncRequest.cc"
70 #include "librbd/AsyncObjectThrottle.cc"
71 #include "librbd/operation/Request.cc"
72 #include "librbd/operation/SnapshotRollbackRequest.cc"
73
74 namespace librbd {
75 namespace operation {
76
77 using ::testing::_;
78 using ::testing::InSequence;
79 using ::testing::Return;
80 using ::testing::WithArg;
81
82 class TestMockOperationSnapshotRollbackRequest : public TestMockFixture {
83 public:
84 typedef SnapshotRollbackRequest<MockOperationImageCtx> MockSnapshotRollbackRequest;
85 typedef ResizeRequest<MockOperationImageCtx> MockResizeRequest;
86
87 void expect_block_writes(MockOperationImageCtx &mock_image_ctx, int r) {
88 EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_))
89 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
90 }
91
92 void expect_unblock_writes(MockOperationImageCtx &mock_image_ctx) {
93 EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes())
94 .Times(1);
95 }
96
97 void expect_get_image_size(MockOperationImageCtx &mock_image_ctx,
98 uint64_t size) {
99 EXPECT_CALL(mock_image_ctx, get_image_size(CEPH_NOSNAP))
100 .WillOnce(Return(size));
101 }
102
103 void expect_resize(MockOperationImageCtx &mock_image_ctx,
104 MockResizeRequest &mock_resize_request, int r) {
105 expect_get_image_size(mock_image_ctx, 123);
106 EXPECT_CALL(mock_resize_request, send())
107 .WillOnce(FinishRequest(&mock_resize_request, r,
108 &mock_image_ctx));
109 }
110
111 void expect_get_flags(MockOperationImageCtx &mock_image_ctx,
112 uint64_t snap_id, int r) {
113 EXPECT_CALL(mock_image_ctx, get_flags(snap_id, _))
114 .WillOnce(Return(r));
115 }
116
117 void expect_object_may_exist(MockOperationImageCtx &mock_image_ctx,
118 uint64_t object_no, bool exists) {
119 if (mock_image_ctx.object_map != nullptr) {
120 EXPECT_CALL(*mock_image_ctx.object_map, object_may_exist(object_no))
121 .WillOnce(Return(exists));
122 }
123 }
124
125 void expect_get_snap_object_map(MockOperationImageCtx &mock_image_ctx,
126 MockObjectMap *mock_object_map, uint64_t snap_id) {
127 if (mock_image_ctx.object_map != nullptr) {
128 EXPECT_CALL(mock_image_ctx, create_object_map(snap_id))
129 .WillOnce(Return(mock_object_map));
130 EXPECT_CALL(*mock_object_map, open(_))
131 .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
132 }
133 }
134
135 void expect_rollback_object_map(MockOperationImageCtx &mock_image_ctx,
136 MockObjectMap &mock_object_map) {
137 if (mock_image_ctx.object_map != nullptr) {
138 EXPECT_CALL(mock_object_map, rollback(_, _))
139 .WillOnce(WithArg<1>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
140 }
141 }
142
143 void expect_get_object_name(MockOperationImageCtx &mock_image_ctx,
144 uint64_t object_num) {
145 EXPECT_CALL(mock_image_ctx, get_object_name(object_num))
146 .WillOnce(Return("object-name-" + stringify(object_num)));
147 }
148
149 void expect_get_current_size(MockOperationImageCtx &mock_image_ctx, uint64_t size) {
150 EXPECT_CALL(mock_image_ctx, get_current_size())
151 .WillOnce(Return(size));
152 }
153
154 void expect_rollback_snap_id(MockOperationImageCtx &mock_image_ctx,
155 const std::string &oid, int r) {
156 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx),
157 selfmanaged_snap_rollback(oid, _))
158 .WillOnce(Return(r));
159 }
160
161 void expect_rollback(MockOperationImageCtx &mock_image_ctx, int r) {
162 expect_get_current_size(mock_image_ctx, 1);
163 expect_object_may_exist(mock_image_ctx, 0, true);
164 expect_get_object_name(mock_image_ctx, 0);
165 expect_rollback_snap_id(mock_image_ctx, "object-name-0", r);
166 }
167
168 void expect_create_object_map(MockOperationImageCtx &mock_image_ctx,
169 MockObjectMap *mock_object_map) {
170 EXPECT_CALL(mock_image_ctx, create_object_map(_))
171 .WillOnce(Return(mock_object_map));
172 }
173
174 void expect_open_object_map(MockOperationImageCtx &mock_image_ctx,
175 MockObjectMap &mock_object_map) {
176 EXPECT_CALL(mock_object_map, open(_))
177 .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue));
178 }
179
180 void expect_refresh_object_map(MockOperationImageCtx &mock_image_ctx,
181 MockObjectMap &mock_object_map) {
182 if (mock_image_ctx.object_map != nullptr) {
183 expect_create_object_map(mock_image_ctx, &mock_object_map);
184 expect_open_object_map(mock_image_ctx, mock_object_map);
185 }
186 }
187
188 void expect_invalidate_cache(MockOperationImageCtx &mock_image_ctx,
189 int r) {
190 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, invalidate_cache(_))
191 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
192 }
193
194 int when_snap_rollback(MockOperationImageCtx &mock_image_ctx,
195 const std::string &snap_name,
196 uint64_t snap_id, uint64_t snap_size) {
197 C_SaferCond cond_ctx;
198 librbd::NoOpProgressContext prog_ctx;
199 MockSnapshotRollbackRequest *req = new MockSnapshotRollbackRequest(
200 mock_image_ctx, &cond_ctx, cls::rbd::UserSnapshotNamespace(), snap_name,
201 snap_id, snap_size, prog_ctx);
202 {
203 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
204 req->send();
205 }
206 return cond_ctx.wait();
207 }
208 };
209
210 TEST_F(TestMockOperationSnapshotRollbackRequest, Success) {
211 librbd::ImageCtx *ictx;
212 ASSERT_EQ(0, open_image(m_image_name, &ictx));
213
214 MockOperationImageCtx mock_image_ctx(*ictx);
215 MockExclusiveLock mock_exclusive_lock;
216 MockJournal mock_journal;
217 MockObjectMap mock_object_map;
218 MockObjectMap mock_snap_object_map;
219 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
220 mock_object_map);
221 expect_op_work_queue(mock_image_ctx);
222
223 InSequence seq;
224 MockResizeRequest mock_resize_request;
225 expect_append_op_event(mock_image_ctx, false, 0);
226 expect_block_writes(mock_image_ctx, 0);
227 expect_resize(mock_image_ctx, mock_resize_request, 0);
228 expect_get_flags(mock_image_ctx, 123, 0);
229 expect_get_snap_object_map(mock_image_ctx, &mock_snap_object_map, 123);
230 expect_rollback_object_map(mock_image_ctx, mock_object_map);
231 expect_rollback(mock_image_ctx, 0);
232 expect_refresh_object_map(mock_image_ctx, mock_object_map);
233 expect_invalidate_cache(mock_image_ctx, 0);
234 expect_commit_op_event(mock_image_ctx, 0);
235 expect_unblock_writes(mock_image_ctx);
236 ASSERT_EQ(0, when_snap_rollback(mock_image_ctx, "snap", 123, 0));
237 }
238
239 TEST_F(TestMockOperationSnapshotRollbackRequest, BlockWritesError) {
240 librbd::ImageCtx *ictx;
241 ASSERT_EQ(0, open_image(m_image_name, &ictx));
242
243 MockOperationImageCtx mock_image_ctx(*ictx);
244 MockExclusiveLock mock_exclusive_lock;
245 MockJournal mock_journal;
246 MockObjectMap mock_object_map;
247 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
248 mock_object_map);
249 expect_op_work_queue(mock_image_ctx);
250
251 InSequence seq;
252 expect_append_op_event(mock_image_ctx, false, 0);
253 expect_block_writes(mock_image_ctx, -EINVAL);
254 expect_commit_op_event(mock_image_ctx, -EINVAL);
255 expect_unblock_writes(mock_image_ctx);
256 ASSERT_EQ(-EINVAL, when_snap_rollback(mock_image_ctx, "snap", 123, 0));
257 }
258
259 TEST_F(TestMockOperationSnapshotRollbackRequest, SkipResize) {
260 librbd::ImageCtx *ictx;
261 ASSERT_EQ(0, open_image(m_image_name, &ictx));
262
263 MockOperationImageCtx mock_image_ctx(*ictx);
264 MockExclusiveLock mock_exclusive_lock;
265 MockJournal mock_journal;
266 MockObjectMap mock_object_map;
267 MockObjectMap mock_snap_object_map;
268 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
269 mock_object_map);
270 expect_op_work_queue(mock_image_ctx);
271
272 InSequence seq;
273 expect_append_op_event(mock_image_ctx, false, 0);
274 expect_block_writes(mock_image_ctx, 0);
275 expect_get_image_size(mock_image_ctx, 345);
276 expect_get_flags(mock_image_ctx, 123, 0);
277 expect_get_snap_object_map(mock_image_ctx, &mock_snap_object_map, 123);
278 expect_rollback_object_map(mock_image_ctx, mock_object_map);
279 expect_rollback(mock_image_ctx, 0);
280 expect_refresh_object_map(mock_image_ctx, mock_object_map);
281 expect_invalidate_cache(mock_image_ctx, 0);
282 expect_commit_op_event(mock_image_ctx, 0);
283 expect_unblock_writes(mock_image_ctx);
284 ASSERT_EQ(0, when_snap_rollback(mock_image_ctx, "snap", 123, 345));
285 }
286
287 TEST_F(TestMockOperationSnapshotRollbackRequest, ResizeError) {
288 librbd::ImageCtx *ictx;
289 ASSERT_EQ(0, open_image(m_image_name, &ictx));
290
291 MockOperationImageCtx mock_image_ctx(*ictx);
292 MockExclusiveLock mock_exclusive_lock;
293 MockJournal mock_journal;
294 MockObjectMap mock_object_map;
295 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
296 mock_object_map);
297 expect_op_work_queue(mock_image_ctx);
298
299 InSequence seq;
300 MockResizeRequest mock_resize_request;
301 expect_append_op_event(mock_image_ctx, false, 0);
302 expect_block_writes(mock_image_ctx, 0);
303 expect_resize(mock_image_ctx, mock_resize_request, -EINVAL);
304 expect_commit_op_event(mock_image_ctx, -EINVAL);
305 expect_unblock_writes(mock_image_ctx);
306 ASSERT_EQ(-EINVAL, when_snap_rollback(mock_image_ctx, "snap", 123, 0));
307 }
308
309 TEST_F(TestMockOperationSnapshotRollbackRequest, RollbackObjectsError) {
310 librbd::ImageCtx *ictx;
311 ASSERT_EQ(0, open_image(m_image_name, &ictx));
312
313 MockOperationImageCtx mock_image_ctx(*ictx);
314 MockExclusiveLock mock_exclusive_lock;
315 MockJournal mock_journal;
316 MockObjectMap mock_object_map;
317 MockObjectMap mock_snap_object_map;
318 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
319 mock_object_map);
320 expect_op_work_queue(mock_image_ctx);
321
322 InSequence seq;
323 MockResizeRequest mock_resize_request;
324 expect_append_op_event(mock_image_ctx, false, 0);
325 expect_block_writes(mock_image_ctx, 0);
326 expect_resize(mock_image_ctx, mock_resize_request, 0);
327 expect_get_flags(mock_image_ctx, 123, 0);
328 expect_get_snap_object_map(mock_image_ctx, &mock_snap_object_map, 123);
329 expect_rollback_object_map(mock_image_ctx, mock_object_map);
330 expect_rollback(mock_image_ctx, -EINVAL);
331 expect_commit_op_event(mock_image_ctx, -EINVAL);
332 expect_unblock_writes(mock_image_ctx);
333 ASSERT_EQ(-EINVAL, when_snap_rollback(mock_image_ctx, "snap", 123, 0));
334 }
335
336 TEST_F(TestMockOperationSnapshotRollbackRequest, InvalidateCacheError) {
337 librbd::ImageCtx *ictx;
338 ASSERT_EQ(0, open_image(m_image_name, &ictx));
339 REQUIRE(ictx->cache);
340
341 MockOperationImageCtx mock_image_ctx(*ictx);
342 MockExclusiveLock mock_exclusive_lock;
343 MockJournal mock_journal;
344 MockObjectMap mock_object_map;
345 MockObjectMap mock_snap_object_map;
346 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
347 mock_object_map);
348 expect_op_work_queue(mock_image_ctx);
349
350 InSequence seq;
351 MockResizeRequest mock_resize_request;
352 expect_append_op_event(mock_image_ctx, false, 0);
353 expect_block_writes(mock_image_ctx, 0);
354 expect_resize(mock_image_ctx, mock_resize_request, 0);
355 expect_get_flags(mock_image_ctx, 123, 0);
356 expect_get_snap_object_map(mock_image_ctx, &mock_snap_object_map, 123);
357 expect_rollback_object_map(mock_image_ctx, mock_object_map);
358 expect_rollback(mock_image_ctx, 0);
359 expect_refresh_object_map(mock_image_ctx, mock_object_map);
360 expect_invalidate_cache(mock_image_ctx, -EINVAL);
361 expect_commit_op_event(mock_image_ctx, -EINVAL);
362 expect_unblock_writes(mock_image_ctx);
363 ASSERT_EQ(-EINVAL, when_snap_rollback(mock_image_ctx, "snap", 123, 0));
364 }
365
366 } // namespace operation
367 } // namespace librbd