]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/operation/test_mock_ResizeRequest.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / test / librbd / operation / test_mock_ResizeRequest.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 "common/bit_vector.hpp"
9 #include "librbd/internal.h"
10 #include "librbd/ObjectMap.h"
11 #include "librbd/operation/ResizeRequest.h"
12 #include "librbd/operation/TrimRequest.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15
16 namespace librbd {
17 namespace operation {
18
19 template <>
20 class TrimRequest<MockImageCtx> {
21 public:
22 static TrimRequest *s_instance;
23 static TrimRequest *create(MockImageCtx &image_ctx, Context *on_finish,
24 uint64_t original_size, uint64_t new_size,
25 ProgressContext &prog_ctx) {
26 assert(s_instance != nullptr);
27 s_instance->on_finish = on_finish;
28 return s_instance;
29 }
30
31 Context *on_finish = nullptr;
32
33 TrimRequest() {
34 s_instance = this;
35 }
36
37 MOCK_METHOD0(send, void());
38 };
39
40 TrimRequest<MockImageCtx> *TrimRequest<MockImageCtx>::s_instance = nullptr;
41
42 } // namespace operation
43 } // namespace librbd
44
45 // template definitions
46 #include "librbd/operation/ResizeRequest.cc"
47 #include "librbd/operation/TrimRequest.cc"
48
49 namespace librbd {
50 namespace operation {
51
52 using ::testing::_;
53 using ::testing::DoAll;
54 using ::testing::InSequence;
55 using ::testing::Return;
56 using ::testing::StrEq;
57 using ::testing::WithArg;
58
59 class TestMockOperationResizeRequest : public TestMockFixture {
60 public:
61 typedef ResizeRequest<MockImageCtx> MockResizeRequest;
62 typedef TrimRequest<MockImageCtx> MockTrimRequest;
63
64 void expect_block_writes(MockImageCtx &mock_image_ctx, int r) {
65 EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_))
66 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
67 }
68
69 void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
70 EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes())
71 .Times(1);
72 }
73
74 void expect_is_lock_owner(MockImageCtx &mock_image_ctx) {
75 if (mock_image_ctx.exclusive_lock != nullptr) {
76 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
77 .WillOnce(Return(true));
78 }
79 }
80
81 void expect_grow_object_map(MockImageCtx &mock_image_ctx) {
82 if (mock_image_ctx.object_map != nullptr) {
83 expect_is_lock_owner(mock_image_ctx);
84 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
85 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
86 }
87 }
88
89 void expect_shrink_object_map(MockImageCtx &mock_image_ctx) {
90 if (mock_image_ctx.object_map != nullptr) {
91 expect_is_lock_owner(mock_image_ctx);
92 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
93 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
94 }
95 }
96
97 void expect_update_header(MockImageCtx &mock_image_ctx, int r) {
98 if (mock_image_ctx.old_format) {
99 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
100 write(mock_image_ctx.header_oid, _, _, _, _))
101 .WillOnce(Return(r));
102 } else {
103 expect_is_lock_owner(mock_image_ctx);
104 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
105 exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_size"), _, _, _))
106 .WillOnce(Return(r));
107 }
108 }
109
110 void expect_trim(MockImageCtx &mock_image_ctx,
111 MockTrimRequest &mock_trim_request, int r) {
112 EXPECT_CALL(mock_trim_request, send())
113 .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx));
114 }
115
116 void expect_flush_cache(MockImageCtx &mock_image_ctx, int r) {
117 EXPECT_CALL(mock_image_ctx, flush_cache(_))
118 .WillOnce(CompleteContext(r, static_cast<ContextWQ*>(NULL)));
119 expect_op_work_queue(mock_image_ctx);
120 }
121
122 void expect_invalidate_cache(MockImageCtx &mock_image_ctx, int r) {
123 EXPECT_CALL(mock_image_ctx, invalidate_cache(false, _))
124 .WillOnce(WithArg<1>(CompleteContext(r, static_cast<ContextWQ*>(NULL))));
125 expect_op_work_queue(mock_image_ctx);
126 }
127
128 void expect_resize_object_map(MockImageCtx &mock_image_ctx,
129 uint64_t new_size) {
130 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(new_size, _, _))
131 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
132 }
133
134 int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size,
135 bool allow_shrink, uint64_t journal_op_tid,
136 bool disable_journal) {
137 C_SaferCond cond_ctx;
138 librbd::NoOpProgressContext prog_ctx;
139 MockResizeRequest *req = new MockResizeRequest(
140 mock_image_ctx, &cond_ctx, new_size, allow_shrink, prog_ctx,
141 journal_op_tid, disable_journal);
142 {
143 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
144 req->send();
145 }
146 return cond_ctx.wait();
147 }
148 };
149
150 TEST_F(TestMockOperationResizeRequest, NoOpSuccess) {
151 librbd::ImageCtx *ictx;
152 ASSERT_EQ(0, open_image(m_image_name, &ictx));
153
154 MockImageCtx mock_image_ctx(*ictx);
155 MockExclusiveLock mock_exclusive_lock;
156 MockJournal mock_journal;
157 MockObjectMap mock_object_map;
158 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
159 mock_object_map);
160
161 InSequence seq;
162 expect_block_writes(mock_image_ctx, 0);
163 expect_append_op_event(mock_image_ctx, true, 0);
164 expect_unblock_writes(mock_image_ctx);
165 expect_commit_op_event(mock_image_ctx, 0);
166 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, false));
167 }
168
169 TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
170 librbd::ImageCtx *ictx;
171 ASSERT_EQ(0, open_image(m_image_name, &ictx));
172
173 MockImageCtx mock_image_ctx(*ictx);
174 MockExclusiveLock mock_exclusive_lock;
175 MockJournal mock_journal;
176 MockObjectMap mock_object_map;
177 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
178 mock_object_map);
179
180 InSequence seq;
181 expect_block_writes(mock_image_ctx, 0);
182 expect_append_op_event(mock_image_ctx, true, 0);
183 expect_unblock_writes(mock_image_ctx);
184 expect_grow_object_map(mock_image_ctx);
185 expect_block_writes(mock_image_ctx, 0);
186 expect_update_header(mock_image_ctx, 0);
187 expect_unblock_writes(mock_image_ctx);
188 expect_commit_op_event(mock_image_ctx, 0);
189 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
190 }
191
192 TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
193 librbd::ImageCtx *ictx;
194 ASSERT_EQ(0, open_image(m_image_name, &ictx));
195
196 MockImageCtx mock_image_ctx(*ictx);
197 MockExclusiveLock mock_exclusive_lock;
198 MockJournal mock_journal;
199 MockObjectMap mock_object_map;
200 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
201 mock_object_map);
202
203 InSequence seq;
204 expect_block_writes(mock_image_ctx, 0);
205 expect_append_op_event(mock_image_ctx, true, 0);
206 expect_unblock_writes(mock_image_ctx);
207
208 MockTrimRequest mock_trim_request;
209 expect_flush_cache(mock_image_ctx, 0);
210 expect_invalidate_cache(mock_image_ctx, 0);
211 expect_trim(mock_image_ctx, mock_trim_request, 0);
212 expect_block_writes(mock_image_ctx, 0);
213 expect_update_header(mock_image_ctx, 0);
214 expect_shrink_object_map(mock_image_ctx);
215 expect_unblock_writes(mock_image_ctx);
216 expect_commit_op_event(mock_image_ctx, 0);
217 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
218 }
219
220 TEST_F(TestMockOperationResizeRequest, ShrinkError) {
221 librbd::ImageCtx *ictx;
222 ASSERT_EQ(0, open_image(m_image_name, &ictx));
223
224 MockImageCtx mock_image_ctx(*ictx);
225 MockExclusiveLock mock_exclusive_lock;
226 MockJournal mock_journal;
227 MockObjectMap mock_object_map;
228 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
229 mock_object_map);
230
231 InSequence seq;
232 expect_block_writes(mock_image_ctx, -EINVAL);
233 expect_unblock_writes(mock_image_ctx);
234 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, false, 0, false));
235 }
236
237 TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
238 librbd::ImageCtx *ictx;
239 ASSERT_EQ(0, open_image(m_image_name, &ictx));
240
241 MockImageCtx mock_image_ctx(*ictx);
242 MockExclusiveLock mock_exclusive_lock;
243 MockJournal mock_journal;
244 MockObjectMap mock_object_map;
245 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
246 mock_object_map);
247
248 InSequence seq;
249 expect_block_writes(mock_image_ctx, -EINVAL);
250 expect_unblock_writes(mock_image_ctx);
251 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
252 }
253
254 TEST_F(TestMockOperationResizeRequest, TrimError) {
255 librbd::ImageCtx *ictx;
256 ASSERT_EQ(0, open_image(m_image_name, &ictx));
257
258 MockImageCtx mock_image_ctx(*ictx);
259 MockExclusiveLock mock_exclusive_lock;
260 MockJournal mock_journal;
261 MockObjectMap mock_object_map;
262 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
263 mock_object_map);
264
265 InSequence seq;
266 expect_block_writes(mock_image_ctx, 0);
267 expect_append_op_event(mock_image_ctx, true, 0);
268 expect_unblock_writes(mock_image_ctx);
269
270 MockTrimRequest mock_trim_request;
271 expect_flush_cache(mock_image_ctx, 0);
272 expect_invalidate_cache(mock_image_ctx, -EBUSY);
273 expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
274 expect_commit_op_event(mock_image_ctx, -EINVAL);
275 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
276 }
277
278 TEST_F(TestMockOperationResizeRequest, FlushCacheError) {
279 librbd::ImageCtx *ictx;
280 ASSERT_EQ(0, open_image(m_image_name, &ictx));
281
282 MockImageCtx 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
289 InSequence seq;
290 expect_block_writes(mock_image_ctx, 0);
291 expect_append_op_event(mock_image_ctx, true, 0);
292 expect_unblock_writes(mock_image_ctx);
293
294 MockTrimRequest mock_trim_request;
295 expect_flush_cache(mock_image_ctx, -EINVAL);
296 expect_commit_op_event(mock_image_ctx, -EINVAL);
297 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
298 }
299
300 TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
301 librbd::ImageCtx *ictx;
302 ASSERT_EQ(0, open_image(m_image_name, &ictx));
303
304 MockImageCtx mock_image_ctx(*ictx);
305 MockExclusiveLock mock_exclusive_lock;
306 MockJournal mock_journal;
307 MockObjectMap mock_object_map;
308 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
309 mock_object_map);
310
311 InSequence seq;
312 expect_block_writes(mock_image_ctx, 0);
313 expect_append_op_event(mock_image_ctx, true, 0);
314 expect_unblock_writes(mock_image_ctx);
315
316 MockTrimRequest mock_trim_request;
317 expect_flush_cache(mock_image_ctx, 0);
318 expect_invalidate_cache(mock_image_ctx, -EINVAL);
319 expect_commit_op_event(mock_image_ctx, -EINVAL);
320 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
321 }
322
323 TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) {
324 librbd::ImageCtx *ictx;
325 ASSERT_EQ(0, open_image(m_image_name, &ictx));
326
327 MockImageCtx mock_image_ctx(*ictx);
328 MockExclusiveLock mock_exclusive_lock;
329 MockJournal mock_journal;
330 MockObjectMap mock_object_map;
331 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
332 mock_object_map);
333
334 InSequence seq;
335 expect_block_writes(mock_image_ctx, 0);
336 expect_append_op_event(mock_image_ctx, true, 0);
337 expect_unblock_writes(mock_image_ctx);
338 expect_grow_object_map(mock_image_ctx);
339 expect_block_writes(mock_image_ctx, -EINVAL);
340 expect_unblock_writes(mock_image_ctx);
341 expect_commit_op_event(mock_image_ctx, -EINVAL);
342 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
343 }
344
345 TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
346 librbd::ImageCtx *ictx;
347 ASSERT_EQ(0, open_image(m_image_name, &ictx));
348
349 MockImageCtx mock_image_ctx(*ictx);
350 MockExclusiveLock mock_exclusive_lock;
351 MockJournal mock_journal;
352 MockObjectMap mock_object_map;
353 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
354 mock_object_map);
355
356 InSequence seq;
357 expect_block_writes(mock_image_ctx, 0);
358 expect_append_op_event(mock_image_ctx, true, 0);
359 expect_unblock_writes(mock_image_ctx);
360 expect_grow_object_map(mock_image_ctx);
361 expect_block_writes(mock_image_ctx, 0);
362 expect_update_header(mock_image_ctx, -EINVAL);
363 expect_unblock_writes(mock_image_ctx);
364 expect_commit_op_event(mock_image_ctx, -EINVAL);
365 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
366 }
367
368 TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
369 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
370
371 librbd::ImageCtx *ictx;
372 ASSERT_EQ(0, open_image(m_image_name, &ictx));
373
374 MockImageCtx mock_image_ctx(*ictx);
375 MockExclusiveLock mock_exclusive_lock;
376 MockJournal mock_journal;
377 MockObjectMap mock_object_map;
378 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
379 mock_object_map);
380
381 InSequence seq;
382 expect_block_writes(mock_image_ctx, 0);
383 expect_append_op_event(mock_image_ctx, true, -EINVAL);
384 expect_unblock_writes(mock_image_ctx);
385 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
386 }
387
388 TEST_F(TestMockOperationResizeRequest, JournalDisabled) {
389 librbd::ImageCtx *ictx;
390 ASSERT_EQ(0, open_image(m_image_name, &ictx));
391
392 MockImageCtx mock_image_ctx(*ictx);
393 MockExclusiveLock mock_exclusive_lock;
394 MockJournal mock_journal;
395 MockObjectMap mock_object_map;
396 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
397 mock_object_map);
398
399 InSequence seq;
400 expect_block_writes(mock_image_ctx, 0);
401 expect_unblock_writes(mock_image_ctx);
402 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, true));
403 }
404
405 } // namespace operation
406 } // namespace librbd