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