Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / 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     if (!mock_image_ctx.image_ctx->cache) {
118       return;
119     }
120     EXPECT_CALL(mock_image_ctx, flush_cache(_))
121                   .WillOnce(CompleteContext(r, static_cast<ContextWQ*>(NULL)));
122     expect_op_work_queue(mock_image_ctx);
123   }
124
125   void expect_invalidate_cache(MockImageCtx &mock_image_ctx, int r) {
126     if (!mock_image_ctx.image_ctx->cache) {
127       return;
128     }
129     EXPECT_CALL(mock_image_ctx, invalidate_cache(false, _))
130                    .WillOnce(WithArg<1>(CompleteContext(r, static_cast<ContextWQ*>(NULL))));
131     expect_op_work_queue(mock_image_ctx);
132   }
133
134   void expect_resize_object_map(MockImageCtx &mock_image_ctx,
135                                 uint64_t new_size) {
136     EXPECT_CALL(*mock_image_ctx.object_map, aio_resize(new_size, _, _))
137                   .WillOnce(WithArg<2>(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)));
138   }
139
140   int when_resize(MockImageCtx &mock_image_ctx, uint64_t new_size,
141                   bool allow_shrink, uint64_t journal_op_tid,
142                   bool disable_journal) {
143     C_SaferCond cond_ctx;
144     librbd::NoOpProgressContext prog_ctx;
145     MockResizeRequest *req = new MockResizeRequest(
146       mock_image_ctx, &cond_ctx, new_size, allow_shrink, prog_ctx,
147       journal_op_tid, disable_journal);
148     {
149       RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
150       req->send();
151     }
152     return cond_ctx.wait();
153   }
154 };
155
156 TEST_F(TestMockOperationResizeRequest, NoOpSuccess) {
157   librbd::ImageCtx *ictx;
158   ASSERT_EQ(0, open_image(m_image_name, &ictx));
159
160   MockImageCtx mock_image_ctx(*ictx);
161   MockExclusiveLock mock_exclusive_lock;
162   MockJournal mock_journal;
163   MockObjectMap mock_object_map;
164   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
165                       mock_object_map);
166
167   InSequence seq;
168   expect_block_writes(mock_image_ctx, 0);
169   expect_append_op_event(mock_image_ctx, true, 0);
170   expect_unblock_writes(mock_image_ctx);
171   expect_commit_op_event(mock_image_ctx, 0);
172   ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, false));
173 }
174
175 TEST_F(TestMockOperationResizeRequest, GrowSuccess) {
176   librbd::ImageCtx *ictx;
177   ASSERT_EQ(0, open_image(m_image_name, &ictx));
178
179   MockImageCtx mock_image_ctx(*ictx);
180   MockExclusiveLock mock_exclusive_lock;
181   MockJournal mock_journal;
182   MockObjectMap mock_object_map;
183   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
184                       mock_object_map);
185
186   InSequence seq;
187   expect_block_writes(mock_image_ctx, 0);
188   expect_append_op_event(mock_image_ctx, true, 0);
189   expect_unblock_writes(mock_image_ctx);
190   expect_grow_object_map(mock_image_ctx);
191   expect_block_writes(mock_image_ctx, 0);
192   expect_update_header(mock_image_ctx, 0);
193   expect_unblock_writes(mock_image_ctx);
194   expect_commit_op_event(mock_image_ctx, 0);
195   ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
196 }
197
198 TEST_F(TestMockOperationResizeRequest, ShrinkSuccess) {
199   librbd::ImageCtx *ictx;
200   ASSERT_EQ(0, open_image(m_image_name, &ictx));
201
202   MockImageCtx mock_image_ctx(*ictx);
203   MockExclusiveLock mock_exclusive_lock;
204   MockJournal mock_journal;
205   MockObjectMap mock_object_map;
206   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
207                       mock_object_map);
208
209   InSequence seq;
210   expect_block_writes(mock_image_ctx, 0);
211   expect_append_op_event(mock_image_ctx, true, 0);
212   expect_unblock_writes(mock_image_ctx);
213
214   MockTrimRequest mock_trim_request;
215   expect_flush_cache(mock_image_ctx, 0);
216   expect_invalidate_cache(mock_image_ctx, 0);
217   expect_trim(mock_image_ctx, mock_trim_request, 0);
218   expect_block_writes(mock_image_ctx, 0);
219   expect_update_header(mock_image_ctx, 0);
220   expect_shrink_object_map(mock_image_ctx);
221   expect_unblock_writes(mock_image_ctx);
222   expect_commit_op_event(mock_image_ctx, 0);
223   ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
224 }
225
226 TEST_F(TestMockOperationResizeRequest, ShrinkError) {
227   librbd::ImageCtx *ictx;
228   ASSERT_EQ(0, open_image(m_image_name, &ictx));
229
230   MockImageCtx mock_image_ctx(*ictx);
231   MockExclusiveLock mock_exclusive_lock;
232   MockJournal mock_journal;
233   MockObjectMap mock_object_map;
234   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
235                       mock_object_map);
236
237   InSequence seq;
238   expect_block_writes(mock_image_ctx, -EINVAL);
239   expect_unblock_writes(mock_image_ctx);
240   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, false, 0, false));
241 }
242
243 TEST_F(TestMockOperationResizeRequest, PreBlockWritesError) {
244   librbd::ImageCtx *ictx;
245   ASSERT_EQ(0, open_image(m_image_name, &ictx));
246
247   MockImageCtx mock_image_ctx(*ictx);
248   MockExclusiveLock mock_exclusive_lock;
249   MockJournal mock_journal;
250   MockObjectMap mock_object_map;
251   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
252                       mock_object_map);
253
254   InSequence seq;
255   expect_block_writes(mock_image_ctx, -EINVAL);
256   expect_unblock_writes(mock_image_ctx);
257   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
258 }
259
260 TEST_F(TestMockOperationResizeRequest, TrimError) {
261   librbd::ImageCtx *ictx;
262   ASSERT_EQ(0, open_image(m_image_name, &ictx));
263
264   MockImageCtx mock_image_ctx(*ictx);
265   MockExclusiveLock mock_exclusive_lock;
266   MockJournal mock_journal;
267   MockObjectMap mock_object_map;
268   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
269                       mock_object_map);
270
271   InSequence seq;
272   expect_block_writes(mock_image_ctx, 0);
273   expect_append_op_event(mock_image_ctx, true, 0);
274   expect_unblock_writes(mock_image_ctx);
275
276   MockTrimRequest mock_trim_request;
277   expect_flush_cache(mock_image_ctx, 0);
278   expect_invalidate_cache(mock_image_ctx, -EBUSY);
279   expect_trim(mock_image_ctx, mock_trim_request, -EINVAL);
280   expect_commit_op_event(mock_image_ctx, -EINVAL);
281   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
282 }
283
284 TEST_F(TestMockOperationResizeRequest, FlushCacheError) {
285   librbd::ImageCtx *ictx;
286   ASSERT_EQ(0, open_image(m_image_name, &ictx));
287   REQUIRE(ictx->cache);
288
289   MockImageCtx mock_image_ctx(*ictx);
290   MockExclusiveLock mock_exclusive_lock;
291   MockJournal mock_journal;
292   MockObjectMap mock_object_map;
293   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
294                       mock_object_map);
295
296   InSequence seq;
297   expect_block_writes(mock_image_ctx, 0);
298   expect_append_op_event(mock_image_ctx, true, 0);
299   expect_unblock_writes(mock_image_ctx);
300
301   MockTrimRequest mock_trim_request;
302   expect_flush_cache(mock_image_ctx, -EINVAL);
303   expect_commit_op_event(mock_image_ctx, -EINVAL);
304   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
305 }
306
307 TEST_F(TestMockOperationResizeRequest, InvalidateCacheError) {
308   librbd::ImageCtx *ictx;
309   ASSERT_EQ(0, open_image(m_image_name, &ictx));
310   REQUIRE(ictx->cache);
311
312   MockImageCtx mock_image_ctx(*ictx);
313   MockExclusiveLock mock_exclusive_lock;
314   MockJournal mock_journal;
315   MockObjectMap mock_object_map;
316   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
317                       mock_object_map);
318
319   InSequence seq;
320   expect_block_writes(mock_image_ctx, 0);
321   expect_append_op_event(mock_image_ctx, true, 0);
322   expect_unblock_writes(mock_image_ctx);
323
324   MockTrimRequest mock_trim_request;
325   expect_flush_cache(mock_image_ctx, 0);
326   expect_invalidate_cache(mock_image_ctx, -EINVAL);
327   expect_commit_op_event(mock_image_ctx, -EINVAL);
328   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size / 2, true, 0, false));
329 }
330
331 TEST_F(TestMockOperationResizeRequest, PostBlockWritesError) {
332   librbd::ImageCtx *ictx;
333   ASSERT_EQ(0, open_image(m_image_name, &ictx));
334
335   MockImageCtx mock_image_ctx(*ictx);
336   MockExclusiveLock mock_exclusive_lock;
337   MockJournal mock_journal;
338   MockObjectMap mock_object_map;
339   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
340                       mock_object_map);
341
342   InSequence seq;
343   expect_block_writes(mock_image_ctx, 0);
344   expect_append_op_event(mock_image_ctx, true, 0);
345   expect_unblock_writes(mock_image_ctx);
346   expect_grow_object_map(mock_image_ctx);
347   expect_block_writes(mock_image_ctx, -EINVAL);
348   expect_unblock_writes(mock_image_ctx);
349   expect_commit_op_event(mock_image_ctx, -EINVAL);
350   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
351 }
352
353 TEST_F(TestMockOperationResizeRequest, UpdateHeaderError) {
354   librbd::ImageCtx *ictx;
355   ASSERT_EQ(0, open_image(m_image_name, &ictx));
356
357   MockImageCtx mock_image_ctx(*ictx);
358   MockExclusiveLock mock_exclusive_lock;
359   MockJournal mock_journal;
360   MockObjectMap mock_object_map;
361   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
362                       mock_object_map);
363
364   InSequence seq;
365   expect_block_writes(mock_image_ctx, 0);
366   expect_append_op_event(mock_image_ctx, true, 0);
367   expect_unblock_writes(mock_image_ctx);
368   expect_grow_object_map(mock_image_ctx);
369   expect_block_writes(mock_image_ctx, 0);
370   expect_update_header(mock_image_ctx, -EINVAL);
371   expect_unblock_writes(mock_image_ctx);
372   expect_commit_op_event(mock_image_ctx, -EINVAL);
373   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size * 2, true, 0, false));
374 }
375
376 TEST_F(TestMockOperationResizeRequest, JournalAppendError) {
377   REQUIRE_FEATURE(RBD_FEATURE_JOURNALING);
378
379   librbd::ImageCtx *ictx;
380   ASSERT_EQ(0, open_image(m_image_name, &ictx));
381
382   MockImageCtx mock_image_ctx(*ictx);
383   MockExclusiveLock mock_exclusive_lock;
384   MockJournal mock_journal;
385   MockObjectMap mock_object_map;
386   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
387                       mock_object_map);
388
389   InSequence seq;
390   expect_block_writes(mock_image_ctx, 0);
391   expect_append_op_event(mock_image_ctx, true, -EINVAL);
392   expect_unblock_writes(mock_image_ctx);
393   ASSERT_EQ(-EINVAL, when_resize(mock_image_ctx, ictx->size, true, 0, false));
394 }
395
396 TEST_F(TestMockOperationResizeRequest, JournalDisabled) {
397   librbd::ImageCtx *ictx;
398   ASSERT_EQ(0, open_image(m_image_name, &ictx));
399
400   MockImageCtx mock_image_ctx(*ictx);
401   MockExclusiveLock mock_exclusive_lock;
402   MockJournal mock_journal;
403   MockObjectMap mock_object_map;
404   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
405                       mock_object_map);
406
407   InSequence seq;
408   expect_block_writes(mock_image_ctx, 0);
409   expect_unblock_writes(mock_image_ctx);
410   ASSERT_EQ(0, when_resize(mock_image_ctx, ictx->size, true, 0, true));
411 }
412
413 } // namespace operation
414 } // namespace librbd