Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / operation / test_mock_TrimRequest.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/AsyncRequest.h"
10 #include "librbd/internal.h"
11 #include "librbd/ObjectMap.h"
12 #include "librbd/Utils.h"
13 #include "librbd/io/ObjectRequest.h"
14 #include "librbd/operation/TrimRequest.h"
15 #include "gmock/gmock.h"
16 #include "gtest/gtest.h"
17
18 namespace librbd {
19 namespace {
20
21 struct MockTestImageCtx : public MockImageCtx {
22   MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
23   }
24 };
25
26 } // anonymous namespace
27
28 template<>
29 struct AsyncRequest<librbd::MockTestImageCtx> {
30   librbd::MockTestImageCtx& m_image_ctx;
31   Context *on_finish;
32
33   AsyncRequest(librbd::MockTestImageCtx& image_ctx, Context* on_finish)
34     : m_image_ctx(image_ctx), on_finish(on_finish) {
35   }
36   virtual ~AsyncRequest() {
37   }
38
39   Context* create_callback_context() {
40     return util::create_context_callback(this);
41   }
42
43   Context* create_async_callback_context() {
44     return util::create_context_callback<AsyncRequest,
45                                          &AsyncRequest::async_complete>(this);
46   }
47
48   void complete(int r) {
49     if (should_complete(r)) {
50       async_complete(r);
51     }
52   }
53
54   void async_complete(int r) {
55     on_finish->complete(r);
56   }
57
58   bool is_canceled() const {
59     return false;
60   }
61
62   virtual void send() = 0;
63   virtual bool should_complete(int r) = 0;
64 };
65
66 namespace io {
67
68 template <>
69 struct ObjectRequest<librbd::MockTestImageCtx> : public ObjectRequestHandle {
70   static ObjectRequest* s_instance;
71   Context *on_finish = nullptr;
72
73   static ObjectRequest* create_truncate(librbd::MockTestImageCtx *ictx,
74                                         const std::string &oid,
75                                         uint64_t object_no,
76                                         uint64_t object_off,
77                                         const ::SnapContext &snapc,
78                                         const ZTracer::Trace &parent_trace,
79                                         Context *completion) {
80     assert(s_instance != nullptr);
81     s_instance->on_finish = completion;
82     s_instance->construct_truncate();
83     return s_instance;
84   }
85
86   static ObjectRequest* create_trim(librbd::MockTestImageCtx *ictx,
87                                     const std::string &oid,
88                                     uint64_t object_no,
89                                     const ::SnapContext &snapc,
90                                     bool post_object_map_update,
91                                     Context *completion) {
92     assert(s_instance != nullptr);
93     s_instance->on_finish = completion;
94     s_instance->construct_trim();
95     return s_instance;
96   }
97
98   ObjectRequest() {
99     s_instance = this;
100   }
101
102   MOCK_METHOD0(construct_truncate, void());
103   MOCK_METHOD0(construct_trim, void());
104   MOCK_METHOD0(send, void());
105   MOCK_METHOD1(complete, void(int));
106 };
107
108 ObjectRequest<librbd::MockTestImageCtx>* ObjectRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
109
110 } // namespace io
111 } // namespace librbd
112
113 // template definitions
114 #include "librbd/AsyncObjectThrottle.cc"
115 #include "librbd/operation/TrimRequest.cc"
116
117 namespace librbd {
118 namespace operation {
119
120 using ::testing::_;
121 using ::testing::DoAll;
122 using ::testing::InSequence;
123 using ::testing::Invoke;
124 using ::testing::Return;
125 using ::testing::StrEq;
126 using ::testing::WithArg;
127
128 class TestMockOperationTrimRequest : public TestMockFixture {
129 public:
130   typedef TrimRequest<MockTestImageCtx> MockTrimRequest;
131   typedef librbd::io::ObjectRequest<MockTestImageCtx> MockObjectRequest;
132
133   int create_snapshot(const char *snap_name) {
134     librbd::ImageCtx *ictx;
135     int r = open_image(m_image_name, &ictx);
136     if (r < 0) {
137       return r;
138     }
139
140     r = snap_create(*ictx, snap_name);
141     if (r < 0) {
142       return r;
143     }
144
145     r = snap_protect(*ictx, snap_name);
146     if (r < 0) {
147       return r;
148     }
149     close_image(ictx);
150     return 0;
151   }
152
153   void expect_is_lock_owner(MockTestImageCtx &mock_image_ctx) {
154     if (mock_image_ctx.exclusive_lock != nullptr) {
155       EXPECT_CALL(*mock_image_ctx.exclusive_lock, is_lock_owner())
156                     .WillRepeatedly(Return(true));
157     }
158   }
159
160   void expect_object_map_update(MockTestImageCtx &mock_image_ctx,
161                                 uint64_t start_object, uint64_t end_object,
162                                 uint8_t state, uint8_t current_state,
163                                 bool updated, int ret_val) {
164     if (mock_image_ctx.object_map != nullptr) {
165       EXPECT_CALL(*mock_image_ctx.object_map,
166                   aio_update(CEPH_NOSNAP, start_object, end_object, state,
167                              boost::optional<uint8_t>(current_state), _, _))
168         .WillOnce(WithArg<6>(Invoke([&mock_image_ctx, updated, ret_val](Context *ctx) {
169                                if (updated) {
170                                  mock_image_ctx.op_work_queue->queue(ctx, ret_val);
171                                }
172                                return updated;
173                              })));
174     }
175   }
176
177   void expect_get_parent_overlap(MockTestImageCtx &mock_image_ctx,
178                                  uint64_t overlap) {
179     EXPECT_CALL(mock_image_ctx, get_parent_overlap(CEPH_NOSNAP, _))
180       .WillOnce(WithArg<1>(Invoke([overlap](uint64_t *o) {
181                              *o = overlap;
182                              return 0;
183                            })));
184   }
185
186   void expect_object_may_exist(MockTestImageCtx &mock_image_ctx,
187                                uint64_t object_no, bool exists) {
188     if (mock_image_ctx.object_map != nullptr) {
189       EXPECT_CALL(*mock_image_ctx.object_map, object_may_exist(object_no))
190         .WillOnce(Return(exists));
191     }
192   }
193
194   void expect_get_object_name(MockTestImageCtx &mock_image_ctx,
195                               uint64_t object_no, const std::string& oid) {
196     EXPECT_CALL(mock_image_ctx, get_object_name(object_no))
197       .WillOnce(Return(oid));
198   }
199
200   void expect_aio_remove(MockTestImageCtx &mock_image_ctx,
201                          const std::string& oid, int ret_val) {
202     EXPECT_CALL(get_mock_io_ctx(mock_image_ctx.data_ctx), remove(oid, _))
203       .WillOnce(Return(ret_val));
204   }
205
206   void expect_object_trim(MockImageCtx &mock_image_ctx,
207                           MockObjectRequest &mock_object_request, int ret_val) {
208     EXPECT_CALL(mock_object_request, construct_trim());
209     EXPECT_CALL(mock_object_request, send())
210       .WillOnce(Invoke([&mock_image_ctx, &mock_object_request, ret_val]() {
211                          mock_image_ctx.op_work_queue->queue(mock_object_request.on_finish, ret_val);
212                        }));
213   }
214
215   void expect_object_truncate(MockImageCtx &mock_image_ctx,
216                               MockObjectRequest &mock_object_request,
217                               int ret_val) {
218     EXPECT_CALL(mock_object_request, construct_truncate());
219     EXPECT_CALL(mock_object_request, send())
220       .WillOnce(Invoke([&mock_image_ctx, &mock_object_request, ret_val]() {
221                          mock_image_ctx.op_work_queue->queue(mock_object_request.on_finish, ret_val);
222                        }));
223   }
224 };
225
226 TEST_F(TestMockOperationTrimRequest, SuccessRemove) {
227   librbd::ImageCtx *ictx;
228   ASSERT_EQ(0, open_image(m_image_name, &ictx));
229
230   MockTestImageCtx 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   expect_op_work_queue(mock_image_ctx);
237   expect_is_lock_owner(mock_image_ctx);
238
239   InSequence seq;
240   EXPECT_CALL(mock_image_ctx, get_stripe_period()).WillOnce(Return(ictx->get_object_size()));
241   EXPECT_CALL(mock_image_ctx, get_stripe_count()).WillOnce(Return(ictx->get_stripe_count()));
242
243   // pre
244   expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_PENDING, OBJECT_EXISTS,
245                            true, 0);
246
247   // copy-up
248   expect_get_parent_overlap(mock_image_ctx, 0);
249
250   // remove
251   expect_object_may_exist(mock_image_ctx, 0, true);
252   expect_get_object_name(mock_image_ctx, 0, "object0");
253   expect_aio_remove(mock_image_ctx, "object0", 0);
254
255    // post
256   expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_NONEXISTENT,
257                            OBJECT_PENDING, true, 0);
258
259   C_SaferCond cond_ctx;
260   librbd::NoOpProgressContext progress_ctx;
261   MockTrimRequest *req = new MockTrimRequest(
262     mock_image_ctx, &cond_ctx, m_image_size, 0, progress_ctx);
263   {
264     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
265     req->send();
266   }
267   ASSERT_EQ(0, cond_ctx.wait());
268 }
269
270 TEST_F(TestMockOperationTrimRequest, SuccessCopyUp) {
271   REQUIRE_FEATURE(RBD_FEATURE_LAYERING)
272   ASSERT_EQ(0, create_snapshot("snap1"));
273
274   int order = 22;
275   uint64_t features;
276   ASSERT_TRUE(::get_features(&features));
277   std::string clone_name = get_temp_image_name();
278   ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
279                              clone_name.c_str(), features, &order, 0, 0));
280
281   librbd::ImageCtx *ictx;
282   ASSERT_EQ(0, open_image(clone_name, &ictx));
283   ASSERT_EQ(0, snap_create(*ictx, "snap"));
284
285   MockTestImageCtx mock_image_ctx(*ictx);
286   MockExclusiveLock mock_exclusive_lock;
287   MockJournal mock_journal;
288   MockObjectMap mock_object_map;
289   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
290                       mock_object_map);
291   expect_op_work_queue(mock_image_ctx);
292   expect_is_lock_owner(mock_image_ctx);
293
294   InSequence seq;
295   EXPECT_CALL(mock_image_ctx, get_stripe_period()).WillOnce(Return(ictx->get_object_size()));
296   EXPECT_CALL(mock_image_ctx, get_stripe_count()).WillOnce(Return(ictx->get_stripe_count()));
297
298   // pre
299   expect_object_map_update(mock_image_ctx, 0, 2, OBJECT_PENDING, OBJECT_EXISTS,
300                            true, 0);
301
302   // copy-up
303   expect_get_parent_overlap(mock_image_ctx, ictx->get_object_size());
304   expect_get_object_name(mock_image_ctx, 0, "object0");
305
306   MockObjectRequest mock_object_request;
307   expect_object_trim(mock_image_ctx, mock_object_request, 0);
308
309   // remove
310   expect_object_may_exist(mock_image_ctx, 1, true);
311   expect_get_object_name(mock_image_ctx, 1, "object1");
312   expect_aio_remove(mock_image_ctx, "object1", 0);
313
314    // post
315   expect_object_map_update(mock_image_ctx, 0, 2, OBJECT_NONEXISTENT,
316                            OBJECT_PENDING, true, 0);
317
318   C_SaferCond cond_ctx;
319   librbd::NoOpProgressContext progress_ctx;
320   MockTrimRequest *req = new MockTrimRequest(
321     mock_image_ctx, &cond_ctx, 2 * ictx->get_object_size(), 0, progress_ctx);
322   {
323     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
324     req->send();
325   }
326   ASSERT_EQ(0, cond_ctx.wait());
327 }
328
329 TEST_F(TestMockOperationTrimRequest, SuccessBoundary) {
330   librbd::ImageCtx *ictx;
331   ASSERT_EQ(0, open_image(m_image_name, &ictx));
332
333   MockTestImageCtx mock_image_ctx(*ictx);
334   MockExclusiveLock mock_exclusive_lock;
335   MockJournal mock_journal;
336   MockObjectMap mock_object_map;
337   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
338                       mock_object_map);
339   expect_op_work_queue(mock_image_ctx);
340   expect_is_lock_owner(mock_image_ctx);
341
342   InSequence seq;
343   EXPECT_CALL(mock_image_ctx, get_stripe_period()).WillOnce(Return(ictx->get_object_size()));
344   EXPECT_CALL(mock_image_ctx, get_stripe_count()).WillOnce(Return(ictx->get_stripe_count()));
345
346   // boundary
347   MockObjectRequest mock_object_request;
348   expect_object_truncate(mock_image_ctx, mock_object_request, 0);
349
350   C_SaferCond cond_ctx;
351   librbd::NoOpProgressContext progress_ctx;
352   MockTrimRequest *req = new MockTrimRequest(
353     mock_image_ctx, &cond_ctx, ictx->get_object_size(), 1, progress_ctx);
354   {
355     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
356     req->send();
357   }
358   ASSERT_EQ(0, cond_ctx.wait());
359 }
360
361 TEST_F(TestMockOperationTrimRequest, SuccessNoOp) {
362   librbd::ImageCtx *ictx;
363   ASSERT_EQ(0, open_image(m_image_name, &ictx));
364
365   MockTestImageCtx mock_image_ctx(*ictx);
366   MockExclusiveLock mock_exclusive_lock;
367   MockJournal mock_journal;
368   MockObjectMap mock_object_map;
369   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
370                       mock_object_map);
371 }
372
373 TEST_F(TestMockOperationTrimRequest, RemoveError) {
374   librbd::ImageCtx *ictx;
375   ASSERT_EQ(0, open_image(m_image_name, &ictx));
376
377   MockTestImageCtx mock_image_ctx(*ictx);
378   MockExclusiveLock mock_exclusive_lock;
379   MockJournal mock_journal;
380   MockObjectMap mock_object_map;
381   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
382                       mock_object_map);
383   expect_op_work_queue(mock_image_ctx);
384   expect_is_lock_owner(mock_image_ctx);
385
386   InSequence seq;
387   EXPECT_CALL(mock_image_ctx, get_stripe_period()).WillOnce(Return(ictx->get_object_size()));
388   EXPECT_CALL(mock_image_ctx, get_stripe_count()).WillOnce(Return(ictx->get_stripe_count()));
389
390   // pre
391   expect_object_map_update(mock_image_ctx, 0, 1, OBJECT_PENDING, OBJECT_EXISTS,
392                            false, 0);
393
394   // copy-up
395   expect_get_parent_overlap(mock_image_ctx, 0);
396
397   // remove
398   expect_object_may_exist(mock_image_ctx, 0, true);
399   expect_get_object_name(mock_image_ctx, 0, "object0");
400   expect_aio_remove(mock_image_ctx, "object0", -EPERM);
401
402   C_SaferCond cond_ctx;
403   librbd::NoOpProgressContext progress_ctx;
404   MockTrimRequest *req = new MockTrimRequest(
405     mock_image_ctx, &cond_ctx, m_image_size, 0, progress_ctx);
406   {
407     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
408     req->send();
409   }
410   ASSERT_EQ(-EPERM, cond_ctx.wait());
411 }
412
413 TEST_F(TestMockOperationTrimRequest, CopyUpError) {
414   REQUIRE_FEATURE(RBD_FEATURE_LAYERING)
415   ASSERT_EQ(0, create_snapshot("snap1"));
416
417   int order = 22;
418   uint64_t features;
419   ASSERT_TRUE(::get_features(&features));
420   std::string clone_name = get_temp_image_name();
421   ASSERT_EQ(0, librbd::clone(m_ioctx, m_image_name.c_str(), "snap1", m_ioctx,
422                              clone_name.c_str(), features, &order, 0, 0));
423
424   librbd::ImageCtx *ictx;
425   ASSERT_EQ(0, open_image(clone_name, &ictx));
426   ASSERT_EQ(0, snap_create(*ictx, "snap"));
427
428   MockTestImageCtx mock_image_ctx(*ictx);
429   MockExclusiveLock mock_exclusive_lock;
430   MockJournal mock_journal;
431   MockObjectMap mock_object_map;
432   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
433                       mock_object_map);
434   expect_op_work_queue(mock_image_ctx);
435   expect_is_lock_owner(mock_image_ctx);
436
437   InSequence seq;
438   EXPECT_CALL(mock_image_ctx, get_stripe_period()).WillOnce(Return(ictx->get_object_size()));
439   EXPECT_CALL(mock_image_ctx, get_stripe_count()).WillOnce(Return(ictx->get_stripe_count()));
440
441   // pre
442   expect_object_map_update(mock_image_ctx, 0, 2, OBJECT_PENDING, OBJECT_EXISTS,
443                            false, 0);
444
445   // copy-up
446   expect_get_parent_overlap(mock_image_ctx, ictx->get_object_size());
447   expect_get_object_name(mock_image_ctx, 0, "object0");
448
449   MockObjectRequest mock_object_request;
450   expect_object_trim(mock_image_ctx, mock_object_request, -EINVAL);
451
452   C_SaferCond cond_ctx;
453   librbd::NoOpProgressContext progress_ctx;
454   MockTrimRequest *req = new MockTrimRequest(
455     mock_image_ctx, &cond_ctx, 2 * ictx->get_object_size(), 0, progress_ctx);
456   {
457     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
458     req->send();
459   }
460   ASSERT_EQ(-EINVAL, cond_ctx.wait());
461 }
462
463 TEST_F(TestMockOperationTrimRequest, BoundaryError) {
464   librbd::ImageCtx *ictx;
465   ASSERT_EQ(0, open_image(m_image_name, &ictx));
466
467   MockTestImageCtx mock_image_ctx(*ictx);
468   MockExclusiveLock mock_exclusive_lock;
469   MockJournal mock_journal;
470   MockObjectMap mock_object_map;
471   initialize_features(ictx, mock_image_ctx, mock_exclusive_lock, mock_journal,
472                       mock_object_map);
473   expect_op_work_queue(mock_image_ctx);
474   expect_is_lock_owner(mock_image_ctx);
475
476   InSequence seq;
477   EXPECT_CALL(mock_image_ctx, get_stripe_period()).WillOnce(Return(ictx->get_object_size()));
478   EXPECT_CALL(mock_image_ctx, get_stripe_count()).WillOnce(Return(ictx->get_stripe_count()));
479
480   // boundary
481   MockObjectRequest mock_object_request;
482   expect_object_truncate(mock_image_ctx, mock_object_request, -EINVAL);
483
484   C_SaferCond cond_ctx;
485   librbd::NoOpProgressContext progress_ctx;
486   MockTrimRequest *req = new MockTrimRequest(
487     mock_image_ctx, &cond_ctx, ictx->get_object_size(), 1, progress_ctx);
488   {
489     RWLock::RLocker owner_locker(mock_image_ctx.owner_lock);
490     req->send();
491   }
492   ASSERT_EQ(-EINVAL, cond_ctx.wait());
493 }
494
495 } // namespace operation
496 } // namespace librbd