]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/operation/test_mock_ResizeRequest.cc
dowstream patches: fix-up series file
[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"
12#include "librbd/operation/ResizeRequest.h"
13#include "librbd/operation/TrimRequest.h"
14#include "gmock/gmock.h"
15#include "gtest/gtest.h"
16
17namespace librbd {
11fdf7f2
TL
18
19namespace util {
20
21inline ImageCtx* get_image_ctx(MockImageCtx* image_ctx) {
22 return image_ctx->image_ctx;
23}
24
25} // namespace util
26
7c673cae
FG
27namespace operation {
28
29template <>
30class TrimRequest<MockImageCtx> {
31public:
32 static TrimRequest *s_instance;
33 static TrimRequest *create(MockImageCtx &image_ctx, Context *on_finish,
34 uint64_t original_size, uint64_t new_size,
35 ProgressContext &prog_ctx) {
11fdf7f2 36 ceph_assert(s_instance != nullptr);
7c673cae
FG
37 s_instance->on_finish = on_finish;
38 return s_instance;
39 }
40
41 Context *on_finish = nullptr;
42
43 TrimRequest() {
44 s_instance = this;
45 }
46
47 MOCK_METHOD0(send, void());
48};
49
50TrimRequest<MockImageCtx> *TrimRequest<MockImageCtx>::s_instance = nullptr;
51
52} // namespace operation
53} // namespace librbd
54
55// template definitions
56#include "librbd/operation/ResizeRequest.cc"
7c673cae
FG
57
58namespace librbd {
59namespace operation {
60
61using ::testing::_;
62using ::testing::DoAll;
11fdf7f2 63using ::testing::Invoke;
7c673cae
FG
64using ::testing::InSequence;
65using ::testing::Return;
66using ::testing::StrEq;
67using ::testing::WithArg;
68
69class TestMockOperationResizeRequest : public TestMockFixture {
70public:
71 typedef ResizeRequest<MockImageCtx> MockResizeRequest;
72 typedef TrimRequest<MockImageCtx> MockTrimRequest;
73
74 void expect_block_writes(MockImageCtx &mock_image_ctx, int r) {
f67539c2 75 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, block_writes(_))
7c673cae
FG
76 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
77 }
78
79 void expect_unblock_writes(MockImageCtx &mock_image_ctx) {
f67539c2 80 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, unblock_writes())
7c673cae
FG
81 .Times(1);
82 }
83
84 void expect_is_lock_owner(MockImageCtx &mock_image_ctx) {
85 if (mock_image_ctx.exclusive_lock != nullptr) {
86 EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
87 .WillOnce(Return(true));
88 }
89 }
90
91 void expect_grow_object_map(MockImageCtx &mock_image_ctx) {
92 if (mock_image_ctx.object_map != nullptr) {
93 expect_is_lock_owner(mock_image_ctx);
94 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
95 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
96 }
97 }
98
99 void expect_shrink_object_map(MockImageCtx &mock_image_ctx) {
100 if (mock_image_ctx.object_map != nullptr) {
101 expect_is_lock_owner(mock_image_ctx);
102 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(_, _, _))
103 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
104 }
105 }
106
107 void expect_update_header(MockImageCtx &mock_image_ctx, int r) {
108 if (mock_image_ctx.old_format) {
109 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
110 write(mock_image_ctx.header_oid, _, _, _, _))
111 .WillOnce(Return(r));
112 } else {
113 expect_is_lock_owner(mock_image_ctx);
114 EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.md_ctx),
f67539c2
TL
115 exec(mock_image_ctx.header_oid, _, StrEq("rbd"),
116 StrEq("set_size"), _, _, _, _))
7c673cae
FG
117 .WillOnce(Return(r));
118 }
119 }
120
121 void expect_trim(MockImageCtx &mock_image_ctx,
122 MockTrimRequest &mock_trim_request, int r) {
123 EXPECT_CALL(mock_trim_request, send())
124 .WillOnce(FinishRequest(&mock_trim_request, r, &mock_image_ctx));
125 }
126
f67539c2
TL
127 void expect_flush_cache(MockImageCtx &mock_image_ctx, int r) {
128 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, send(_))
129 .WillOnce(Invoke([&mock_image_ctx, r](io::ImageDispatchSpec* spec) {
130 ASSERT_TRUE(boost::get<io::ImageDispatchSpec::Flush>(
131 &spec->request) != nullptr);
132 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
133 auto aio_comp = spec->aio_comp;
9f95a23c 134 auto ctx = new LambdaContext([aio_comp](int r) {
f67539c2
TL
135 if (r < 0) {
136 aio_comp->fail(r);
137 } else {
138 aio_comp->set_request_count(1);
139 aio_comp->add_request();
140 aio_comp->complete_request(r);
141 }
11fdf7f2
TL
142 });
143 mock_image_ctx.image_ctx->op_work_queue->queue(ctx, r);
144 }));
7c673cae
FG
145 }
146
11fdf7f2
TL
147 void expect_invalidate_cache(MockImageCtx &mock_image_ctx,
148 int r) {
f67539c2 149 EXPECT_CALL(*mock_image_ctx.io_image_dispatcher, invalidate_cache(_))
11fdf7f2 150 .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue));
7c673cae
FG
151 expect_op_work_queue(mock_image_ctx);
152 }
153
154 void expect_resize_object_map(MockImageCtx &mock_image_ctx,
155 uint64_t new_size) {
156 EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(new_size, _, _))
157 .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
158 }
159
160 int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size,
161 bool allow_shrink, uint64_t journal_op_tid,
162 bool disable_journal) {
163 C_SaferCond cond_ctx;
164 librbd::NoOpProgressContext prog_ctx;
165 MockResizeRequest *req = new MockResizeRequest(
166 mock_image_ctx, &cond_ctx, new_size, allow_shrink, prog_ctx,
167 journal_op_tid, disable_journal);
168 {
9f95a23c 169 std::shared_lock owner_locker{mock_image_ctx.owner_lock};
7c673cae
FG
170 req->send();
171 }
172 return cond_ctx.wait();
173 }
174};
175
176TEST_F(TestMockOperationResizeRequest, NoOpSuccess) {
177 librbd::ImageCtx *ictx;
178 ASSERT_EQ(0, open_image(m_image_name, &ictx));
179
180 MockImageCtx mock_image_ctx(*ictx);
181 MockExclusiveLock mock_exclusive_lock;
182 MockJournal mock_journal;
183 MockObjectMap mock_object_map;
184 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
185 mock_object_map);
186
187 InSequence seq;
188 expect_block_writes(mock_image_ctx, 0);
189 expect_append_op_event(mock_image_ctx, true, 0);
190 expect_unblock_writes(mock_image_ctx);
191 expect_commit_op_event(mock_image_ctx, 0);
192 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, false));
193}
194
195TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
196 librbd::ImageCtx *ictx;
197 ASSERT_EQ(0, open_image(m_image_name, &ictx));
198
199 MockImageCtx mock_image_ctx(*ictx);
200 MockExclusiveLock mock_exclusive_lock;
201 MockJournal mock_journal;
202 MockObjectMap mock_object_map;
203 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
204 mock_object_map);
205
206 InSequence seq;
207 expect_block_writes(mock_image_ctx, 0);
208 expect_append_op_event(mock_image_ctx, true, 0);
7c673cae 209 expect_grow_object_map(mock_image_ctx);
7c673cae
FG
210 expect_update_header(mock_image_ctx, 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 * 2, true, 0, false));
214}
215
216TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
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);
230 expect_unblock_writes(mock_image_ctx);
231
232 MockTrimRequest mock_trim_request;
f67539c2 233 expect_flush_cache(mock_image_ctx, 0);
7c673cae
FG
234 expect_invalidate_cache(mock_image_ctx, 0);
235 expect_trim(mock_image_ctx, mock_trim_request, 0);
236 expect_block_writes(mock_image_ctx, 0);
237 expect_update_header(mock_image_ctx, 0);
238 expect_shrink_object_map(mock_image_ctx);
239 expect_unblock_writes(mock_image_ctx);
240 expect_commit_op_event(mock_image_ctx, 0);
241 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
242}
243
244TEST_F(TestMockOperationResizeRequest, ShrinkError) {
245 librbd::ImageCtx *ictx;
246 ASSERT_EQ(0, open_image(m_image_name, &ictx));
247
248 MockImageCtx mock_image_ctx(*ictx);
249 MockExclusiveLock mock_exclusive_lock;
250 MockJournal mock_journal;
251 MockObjectMap mock_object_map;
252 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
253 mock_object_map);
254
255 InSequence seq;
256 expect_block_writes(mock_image_ctx, -EINVAL);
257 expect_unblock_writes(mock_image_ctx);
258 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, false, 0, false));
259}
260
261TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
262 librbd::ImageCtx *ictx;
263 ASSERT_EQ(0, open_image(m_image_name, &ictx));
264
265 MockImageCtx mock_image_ctx(*ictx);
266 MockExclusiveLock mock_exclusive_lock;
267 MockJournal mock_journal;
268 MockObjectMap mock_object_map;
269 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
270 mock_object_map);
271
272 InSequence seq;
273 expect_block_writes(mock_image_ctx, -EINVAL);
274 expect_unblock_writes(mock_image_ctx);
275 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
276}
277
278TEST_F(TestMockOperationResizeRequest, TrimError) {
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;
f67539c2 295 expect_flush_cache(mock_image_ctx, 0);
7c673cae
FG
296 expect_invalidate_cache(mock_image_ctx, -EBUSY);
297 expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
298 expect_commit_op_event(mock_image_ctx, -EINVAL);
299 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
300}
301
302TEST_F(TestMockOperationResizeRequest, FlushCacheError) {
303 librbd::ImageCtx *ictx;
304 ASSERT_EQ(0, open_image(m_image_name, &ictx));
31f18b77 305 REQUIRE(ictx->cache);
7c673cae
FG
306
307 MockImageCtx mock_image_ctx(*ictx);
308 MockExclusiveLock mock_exclusive_lock;
309 MockJournal mock_journal;
310 MockObjectMap mock_object_map;
311 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
312 mock_object_map);
313
314 InSequence seq;
315 expect_block_writes(mock_image_ctx, 0);
316 expect_append_op_event(mock_image_ctx, true, 0);
317 expect_unblock_writes(mock_image_ctx);
318
319 MockTrimRequest mock_trim_request;
f67539c2 320 expect_flush_cache(mock_image_ctx, -EINVAL);
7c673cae
FG
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, InvalidateCacheError) {
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;
f67539c2 343 expect_flush_cache(mock_image_ctx, 0);
7c673cae
FG
344 expect_invalidate_cache(mock_image_ctx, -EINVAL);
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, PostBlockWritesError) {
350 librbd::ImageCtx *ictx;
351 ASSERT_EQ(0, open_image(m_image_name, &ictx));
352
353 MockImageCtx mock_image_ctx(*ictx);
354 MockExclusiveLock mock_exclusive_lock;
355 MockJournal mock_journal;
356 MockObjectMap mock_object_map;
357 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
358 mock_object_map);
359
360 InSequence seq;
361 expect_block_writes(mock_image_ctx, 0);
362 expect_append_op_event(mock_image_ctx, true, 0);
363 expect_unblock_writes(mock_image_ctx);
494da23a
TL
364
365 MockTrimRequest mock_trim_request;
f67539c2 366 expect_flush_cache(mock_image_ctx, 0);
494da23a
TL
367 expect_invalidate_cache(mock_image_ctx, 0);
368 expect_trim(mock_image_ctx, mock_trim_request, 0);
7c673cae
FG
369 expect_block_writes(mock_image_ctx, -EINVAL);
370 expect_unblock_writes(mock_image_ctx);
371 expect_commit_op_event(mock_image_ctx, -EINVAL);
494da23a
TL
372 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0,
373 false));
7c673cae
FG
374}
375
376TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
377 librbd::ImageCtx *ictx;
378 ASSERT_EQ(0, open_image(m_image_name, &ictx));
379
380 MockImageCtx mock_image_ctx(*ictx);
381 MockExclusiveLock mock_exclusive_lock;
382 MockJournal mock_journal;
383 MockObjectMap mock_object_map;
384 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
385 mock_object_map);
386
387 InSequence seq;
388 expect_block_writes(mock_image_ctx, 0);
389 expect_append_op_event(mock_image_ctx, true, 0);
7c673cae 390 expect_grow_object_map(mock_image_ctx);
7c673cae
FG
391 expect_update_header(mock_image_ctx, -EINVAL);
392 expect_unblock_writes(mock_image_ctx);
393 expect_commit_op_event(mock_image_ctx, -EINVAL);
394 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
395}
396
397TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
398 REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
399
400 librbd::ImageCtx *ictx;
401 ASSERT_EQ(0, open_image(m_image_name, &ictx));
402
403 MockImageCtx mock_image_ctx(*ictx);
404 MockExclusiveLock mock_exclusive_lock;
405 MockJournal mock_journal;
406 MockObjectMap mock_object_map;
407 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
408 mock_object_map);
409
410 InSequence seq;
411 expect_block_writes(mock_image_ctx, 0);
412 expect_append_op_event(mock_image_ctx, true, -EINVAL);
413 expect_unblock_writes(mock_image_ctx);
414 ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
415}
416
417TEST_F(TestMockOperationResizeRequest, JournalDisabled) {
418 librbd::ImageCtx *ictx;
419 ASSERT_EQ(0, open_image(m_image_name, &ictx));
420
421 MockImageCtx mock_image_ctx(*ictx);
422 MockExclusiveLock mock_exclusive_lock;
423 MockJournal mock_journal;
424 MockObjectMap mock_object_map;
425 initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
426 mock_object_map);
427
428 InSequence seq;
429 expect_block_writes(mock_image_ctx, 0);
430 expect_unblock_writes(mock_image_ctx);
431 ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, true));
432}
433
434} // namespace operation
435} // namespace librbd