]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/operation/test_mock_ResizeRequest.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / test / librbd / operation / test_mock_ResizeRequest.cc
CommitLineData
7c673cae
FG
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"
11fdf7f2 7#include "test/librbd/mock/io/MockObjectDispatch.h"
7c673cae
FG
8#include "test/librados_test_stub/MockTestMemIoCtxImpl.h"
9#include "common/bit_vector.hpp"
10#include "librbd/internal.h"
11#include "librbd/ObjectMap.h"
11fdf7f2 12#include "librbd/io/ImageDispatchSpec.h"
7c673cae
FG
13#include "librbd/operation/ResizeRequest.h"
14#include "librbd/operation/TrimRequest.h"
15#include "gmock/gmock.h"
16#include "gtest/gtest.h"
17
18namespace librbd {
11fdf7f2
TL
19
20namespace util {
21
22inline ImageCtx* get_image_ctx(MockImageCtx* image_ctx) {
23 return image_ctx->image_ctx;
24}
25
26} // namespace util
27
28namespace io {
29
30template <>
31struct ImageDispatchSpec<MockImageCtx> {
32 static ImageDispatchSpec* s_instance;
33 AioCompletion *aio_comp = nullptr;
34
35 static ImageDispatchSpec* create_flush_request(
36 MockImageCtx &image_ctx, AioCompletion *aio_comp,
37 FlushSource flush_source, const ZTracer::Trace &parent_trace) {
38 ceph_assert(s_instance != nullptr);
39 s_instance->aio_comp = aio_comp;
40 return s_instance;
41 }
42
43 MOCK_CONST_METHOD0(send, void());
44
45 ImageDispatchSpec() {
46 s_instance = this;
47 }
48};
49
50ImageDispatchSpec<MockImageCtx>* ImageDispatchSpec<MockImageCtx>::s_instance = nullptr;
51
52} // namespace io
53
7c673cae
FG
54namespace operation {
55
56template <>
57class TrimRequest<MockImageCtx> {
58public:
59 static TrimRequest *s_instance;
60 static TrimRequest *create(MockImageCtx &image_ctx, Context *on_finish,
61 uint64_t original_size, uint64_t new_size,
62 ProgressContext &prog_ctx) {
11fdf7f2 63 ceph_assert(s_instance != nullptr);
7c673cae
FG
64 s_instance->on_finish = on_finish;
65 return s_instance;
66 }
67
68 Context *on_finish = nullptr;
69
70 TrimRequest() {
71 s_instance = this;
72 }
73
74 MOCK_METHOD0(send, void());
75};
76
77TrimRequest<MockImageCtx> *TrimRequest<MockImageCtx>::s_instance = nullptr;
78
79} // namespace operation
80} // namespace librbd
81
82// template definitions
83#include "librbd/operation/ResizeRequest.cc"
7c673cae
FG
84
85namespace librbd {
86namespace operation {
87
88using ::testing::_;
89using ::testing::DoAll;
11fdf7f2 90using ::testing::Invoke;
7c673cae
FG
91using ::testing::InSequence;
92using ::testing::Return;
93using ::testing::StrEq;
94using ::testing::WithArg;
95
96class TestMockOperationResizeRequest : public TestMockFixture {
97public:
98 typedef ResizeRequest<MockImageCtx> MockResizeRequest;
99 typedef TrimRequest<MockImageCtx> MockTrimRequest;
11fdf7f2 100 typedef io::ImageDispatchSpec<MockImageCtx> MockIoImageDispatchSpec;
7c673cae
FG
101
102 void expect_block_writes(MockImageCtx &mock_image_ctx, int r) {
103 EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_))
104 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
105 }
106
107 void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
108 EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes())
109 .Times(1);
110 }
111
112 void expect_is_lock_owner(MockImageCtx &mock_image_ctx) {
113 if (mock_image_ctx.exclusive_lock != nullptr) {
114 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
115 .WillOnce(Return(true));
116 }
117 }
118
119 void expect_grow_object_map(MockImageCtx &mock_image_ctx) {
120 if (mock_image_ctx.object_map != nullptr) {
121 expect_is_lock_owner(mock_image_ctx);
122 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
123 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
124 }
125 }
126
127 void expect_shrink_object_map(MockImageCtx &mock_image_ctx) {
128 if (mock_image_ctx.object_map != nullptr) {
129 expect_is_lock_owner(mock_image_ctx);
130 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
131 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
132 }
133 }
134
135 void expect_update_header(MockImageCtx &mock_image_ctx, int r) {
136 if (mock_image_ctx.old_format) {
137 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
138 write(mock_image_ctx.header_oid, _, _, _, _))
139 .WillOnce(Return(r));
140 } else {
141 expect_is_lock_owner(mock_image_ctx);
142 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
143 exec(mock_image_ctx.header_oid, _, StrEq("rbd"), StrEq("set_size"), _, _, _))
144 .WillOnce(Return(r));
145 }
146 }
147
148 void expect_trim(MockImageCtx &mock_image_ctx,
149 MockTrimRequest &mock_trim_request, int r) {
150 EXPECT_CALL(mock_trim_request, send())
151 .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx));
152 }
153
11fdf7f2
TL
154 void expect_flush_cache(MockImageCtx &mock_image_ctx,
155 MockIoImageDispatchSpec& mock_io_image_dispatch_spec,
156 int r) {
157 EXPECT_CALL(mock_io_image_dispatch_spec, send())
158 .WillOnce(Invoke([&mock_image_ctx, &mock_io_image_dispatch_spec, r]() {
159 auto aio_comp = mock_io_image_dispatch_spec.s_instance->aio_comp;
160 auto ctx = new FunctionContext([aio_comp](int r) {
161 aio_comp->get();
162 aio_comp->fail(r);
163 });
164 mock_image_ctx.image_ctx->op_work_queue->queue(ctx, r);
165 }));
7c673cae
FG
166 }
167
11fdf7f2
TL
168 void expect_invalidate_cache(MockImageCtx &mock_image_ctx,
169 int r) {
170 EXPECT_CALL(*mock_image_ctx.io_object_dispatcher, invalidate_cache(_))
171 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
7c673cae
FG
172 expect_op_work_queue(mock_image_ctx);
173 }
174
175 void expect_resize_object_map(MockImageCtx &mock_image_ctx,
176 uint64_t new_size) {
177 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(new_size, _, _))
178 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
179 }
180
181 int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size,
182 bool allow_shrink, uint64_t journal_op_tid,
183 bool disable_journal) {
184 C_SaferCond cond_ctx;
185 librbd::NoOpProgressContext prog_ctx;
186 MockResizeRequest *req = new MockResizeRequest(
187 mock_image_ctx, &cond_ctx, new_size, allow_shrink, prog_ctx,
188 journal_op_tid, disable_journal);
189 {
190 RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
191 req->send();
192 }
193 return cond_ctx.wait();
194 }
195};
196
197TEST_F(TestMockOperationResizeRequest, NoOpSuccess) {
198 librbd::ImageCtx *ictx;
199 ASSERT_EQ(0, open_image(m_image_name, &ictx));
200
201 MockImageCtx mock_image_ctx(*ictx);
202 MockExclusiveLock mock_exclusive_lock;
203 MockJournal mock_journal;
204 MockObjectMap mock_object_map;
205 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
206 mock_object_map);
207
208 InSequence seq;
209 expect_block_writes(mock_image_ctx, 0);
210 expect_append_op_event(mock_image_ctx, true, 0);
211 expect_unblock_writes(mock_image_ctx);
212 expect_commit_op_event(mock_image_ctx, 0);
213 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, false));
214}
215
216TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
217 librbd::ImageCtx *ictx;
218 ASSERT_EQ(0, open_image(m_image_name, &ictx));
219
220 MockImageCtx mock_image_ctx(*ictx);
221 MockExclusiveLock mock_exclusive_lock;
222 MockJournal mock_journal;
223 MockObjectMap mock_object_map;
224 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
225 mock_object_map);
226
227 InSequence seq;
228 expect_block_writes(mock_image_ctx, 0);
229 expect_append_op_event(mock_image_ctx, true, 0);
7c673cae 230 expect_grow_object_map(mock_image_ctx);
7c673cae
FG
231 expect_update_header(mock_image_ctx, 0);
232 expect_unblock_writes(mock_image_ctx);
233 expect_commit_op_event(mock_image_ctx, 0);
234 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
235}
236
237TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
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, 0);
250 expect_append_op_event(mock_image_ctx, true, 0);
251 expect_unblock_writes(mock_image_ctx);
252
253 MockTrimRequest mock_trim_request;
11fdf7f2
TL
254 auto mock_io_image_dispatch_spec = new MockIoImageDispatchSpec();
255 expect_flush_cache(mock_image_ctx, *mock_io_image_dispatch_spec, 0);
7c673cae
FG
256 expect_invalidate_cache(mock_image_ctx, 0);
257 expect_trim(mock_image_ctx, mock_trim_request, 0);
258 expect_block_writes(mock_image_ctx, 0);
259 expect_update_header(mock_image_ctx, 0);
260 expect_shrink_object_map(mock_image_ctx);
261 expect_unblock_writes(mock_image_ctx);
262 expect_commit_op_event(mock_image_ctx, 0);
263 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
264}
265
266TEST_F(TestMockOperationResizeRequest, ShrinkError) {
267 librbd::ImageCtx *ictx;
268 ASSERT_EQ(0, open_image(m_image_name, &ictx));
269
270 MockImageCtx mock_image_ctx(*ictx);
271 MockExclusiveLock mock_exclusive_lock;
272 MockJournal mock_journal;
273 MockObjectMap mock_object_map;
274 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
275 mock_object_map);
276
277 InSequence seq;
278 expect_block_writes(mock_image_ctx, -EINVAL);
279 expect_unblock_writes(mock_image_ctx);
280 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, false, 0, false));
281}
282
283TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
284 librbd::ImageCtx *ictx;
285 ASSERT_EQ(0, open_image(m_image_name, &ictx));
286
287 MockImageCtx mock_image_ctx(*ictx);
288 MockExclusiveLock mock_exclusive_lock;
289 MockJournal mock_journal;
290 MockObjectMap mock_object_map;
291 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
292 mock_object_map);
293
294 InSequence seq;
295 expect_block_writes(mock_image_ctx, -EINVAL);
296 expect_unblock_writes(mock_image_ctx);
297 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
298}
299
300TEST_F(TestMockOperationResizeRequest, TrimError) {
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;
11fdf7f2
TL
317 auto mock_io_image_dispatch_spec = new MockIoImageDispatchSpec();
318 expect_flush_cache(mock_image_ctx, *mock_io_image_dispatch_spec, 0);
7c673cae
FG
319 expect_invalidate_cache(mock_image_ctx, -EBUSY);
320 expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
321 expect_commit_op_event(mock_image_ctx, -EINVAL);
322 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
323}
324
325TEST_F(TestMockOperationResizeRequest, FlushCacheError) {
326 librbd::ImageCtx *ictx;
327 ASSERT_EQ(0, open_image(m_image_name, &ictx));
31f18b77 328 REQUIRE(ictx->cache);
7c673cae
FG
329
330 MockImageCtx mock_image_ctx(*ictx);
331 MockExclusiveLock mock_exclusive_lock;
332 MockJournal mock_journal;
333 MockObjectMap mock_object_map;
334 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
335 mock_object_map);
336
337 InSequence seq;
338 expect_block_writes(mock_image_ctx, 0);
339 expect_append_op_event(mock_image_ctx, true, 0);
340 expect_unblock_writes(mock_image_ctx);
341
342 MockTrimRequest mock_trim_request;
11fdf7f2
TL
343 auto mock_io_image_dispatch_spec = new MockIoImageDispatchSpec();
344 expect_flush_cache(mock_image_ctx, *mock_io_image_dispatch_spec, -EINVAL);
7c673cae
FG
345 expect_commit_op_event(mock_image_ctx, -EINVAL);
346 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
347}
348
349TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
350 librbd::ImageCtx *ictx;
351 ASSERT_EQ(0, open_image(m_image_name, &ictx));
31f18b77 352 REQUIRE(ictx->cache);
7c673cae
FG
353
354 MockImageCtx mock_image_ctx(*ictx);
355 MockExclusiveLock mock_exclusive_lock;
356 MockJournal mock_journal;
357 MockObjectMap mock_object_map;
358 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
359 mock_object_map);
360
361 InSequence seq;
362 expect_block_writes(mock_image_ctx, 0);
363 expect_append_op_event(mock_image_ctx, true, 0);
364 expect_unblock_writes(mock_image_ctx);
365
366 MockTrimRequest mock_trim_request;
11fdf7f2
TL
367 auto mock_io_image_dispatch_spec = new MockIoImageDispatchSpec();
368 expect_flush_cache(mock_image_ctx, *mock_io_image_dispatch_spec, 0);
7c673cae
FG
369 expect_invalidate_cache(mock_image_ctx, -EINVAL);
370 expect_commit_op_event(mock_image_ctx, -EINVAL);
371 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
372}
373
374TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) {
375 librbd::ImageCtx *ictx;
376 ASSERT_EQ(0, open_image(m_image_name, &ictx));
377
378 MockImageCtx mock_image_ctx(*ictx);
379 MockExclusiveLock mock_exclusive_lock;
380 MockJournal mock_journal;
381 MockObjectMap mock_object_map;
382 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
383 mock_object_map);
384
385 InSequence seq;
386 expect_block_writes(mock_image_ctx, 0);
387 expect_append_op_event(mock_image_ctx, true, 0);
388 expect_unblock_writes(mock_image_ctx);
494da23a
TL
389
390 MockTrimRequest mock_trim_request;
391 auto mock_io_image_dispatch_spec = new MockIoImageDispatchSpec();
392 expect_flush_cache(mock_image_ctx, *mock_io_image_dispatch_spec, 0);
393 expect_invalidate_cache(mock_image_ctx, 0);
394 expect_trim(mock_image_ctx, mock_trim_request, 0);
7c673cae
FG
395 expect_block_writes(mock_image_ctx, -EINVAL);
396 expect_unblock_writes(mock_image_ctx);
397 expect_commit_op_event(mock_image_ctx, -EINVAL);
494da23a
TL
398 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0,
399 false));
7c673cae
FG
400}
401
402TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
403 librbd::ImageCtx *ictx;
404 ASSERT_EQ(0, open_image(m_image_name, &ictx));
405
406 MockImageCtx mock_image_ctx(*ictx);
407 MockExclusiveLock mock_exclusive_lock;
408 MockJournal mock_journal;
409 MockObjectMap mock_object_map;
410 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
411 mock_object_map);
412
413 InSequence seq;
414 expect_block_writes(mock_image_ctx, 0);
415 expect_append_op_event(mock_image_ctx, true, 0);
7c673cae 416 expect_grow_object_map(mock_image_ctx);
7c673cae
FG
417 expect_update_header(mock_image_ctx, -EINVAL);
418 expect_unblock_writes(mock_image_ctx);
419 expect_commit_op_event(mock_image_ctx, -EINVAL);
420 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
421}
422
423TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
424 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
425
426 librbd::ImageCtx *ictx;
427 ASSERT_EQ(0, open_image(m_image_name, &ictx));
428
429 MockImageCtx mock_image_ctx(*ictx);
430 MockExclusiveLock mock_exclusive_lock;
431 MockJournal mock_journal;
432 MockObjectMap mock_object_map;
433 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
434 mock_object_map);
435
436 InSequence seq;
437 expect_block_writes(mock_image_ctx, 0);
438 expect_append_op_event(mock_image_ctx, true, -EINVAL);
439 expect_unblock_writes(mock_image_ctx);
440 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
441}
442
443TEST_F(TestMockOperationResizeRequest, JournalDisabled) {
444 librbd::ImageCtx *ictx;
445 ASSERT_EQ(0, open_image(m_image_name, &ictx));
446
447 MockImageCtx mock_image_ctx(*ictx);
448 MockExclusiveLock mock_exclusive_lock;
449 MockJournal mock_journal;
450 MockObjectMap mock_object_map;
451 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
452 mock_object_map);
453
454 InSequence seq;
455 expect_block_writes(mock_image_ctx, 0);
456 expect_unblock_writes(mock_image_ctx);
457 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, true));
458}
459
460} // namespace operation
461} // namespace librbd