Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / io / test_mock_ImageRequestWQ.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/librbd/mock/exclusive_lock/MockPolicy.h"
8 #include "librbd/io/ImageRequestWQ.h"
9 #include "librbd/io/ImageRequest.h"
10
11 namespace librbd {
12 namespace {
13
14 struct MockTestImageCtx : public MockImageCtx {
15   MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
16   }
17 };
18
19 } // anonymous namespace
20
21 namespace io {
22
23 template <>
24 struct ImageRequest<librbd::MockTestImageCtx> {
25   static ImageRequest* s_instance;
26   AioCompletion *aio_comp;
27
28   static ImageRequest* create_write_request(librbd::MockTestImageCtx &image_ctx,
29                                             AioCompletion *aio_comp,
30                                             Extents &&image_extents,
31                                             bufferlist &&bl, int op_flags,
32                                             const ZTracer::Trace &parent_trace) {
33     assert(s_instance != nullptr);
34     s_instance->aio_comp = aio_comp;
35     return s_instance;
36   }
37   static void aio_write(librbd::MockTestImageCtx *ictx, AioCompletion *c,
38                         Extents &&image_extents, bufferlist &&bl, int op_flags,
39                         const ZTracer::Trace &parent_trace) {
40   }
41
42
43   MOCK_CONST_METHOD0(is_write_op, bool());
44   MOCK_CONST_METHOD0(start_op, void());
45   MOCK_CONST_METHOD0(send, void());
46   MOCK_CONST_METHOD1(fail, void(int));
47
48   ImageRequest() {
49     s_instance = this;
50   }
51 };
52
53 } // namespace io
54
55 namespace util {
56
57 inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) {
58   return image_ctx->image_ctx;
59 }
60
61 } // namespace util
62
63 } // namespace librbd
64
65 template <>
66 struct ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>> {
67   typedef librbd::io::ImageRequest<librbd::MockTestImageCtx> ImageRequest;
68   static PointerWQ* s_instance;
69
70   Mutex m_lock;
71
72   PointerWQ(const std::string &name, time_t, int, ThreadPool *)
73     : m_lock(name) {
74     s_instance = this;
75   }
76   virtual ~PointerWQ() {
77   }
78
79   MOCK_METHOD0(drain, void());
80   MOCK_METHOD0(empty, bool());
81   MOCK_METHOD0(signal, void());
82   MOCK_METHOD0(process_finish, void());
83
84   MOCK_METHOD0(front, ImageRequest*());
85   MOCK_METHOD1(requeue, void(ImageRequest*));
86
87   MOCK_METHOD0(dequeue, void*());
88   MOCK_METHOD1(queue, void(ImageRequest*));
89
90   void register_work_queue() {
91     // no-op
92   }
93   Mutex &get_pool_lock() {
94     return m_lock;
95   }
96
97   void* invoke_dequeue() {
98     Mutex::Locker locker(m_lock);
99     return _void_dequeue();
100   }
101   void invoke_process(ImageRequest *image_request) {
102     process(image_request);
103   }
104
105   virtual void *_void_dequeue() {
106     return dequeue();
107   }
108   virtual void process(ImageRequest *req) = 0;
109
110 };
111
112 ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>*
113   ThreadPool::PointerWQ<librbd::io::ImageRequest<librbd::MockTestImageCtx>>::s_instance = nullptr;
114 librbd::io::ImageRequest<librbd::MockTestImageCtx>*
115   librbd::io::ImageRequest<librbd::MockTestImageCtx>::s_instance = nullptr;
116
117 #include "librbd/io/ImageRequestWQ.cc"
118
119 namespace librbd {
120 namespace io {
121
122 using ::testing::_;
123 using ::testing::InSequence;
124 using ::testing::Invoke;
125 using ::testing::Return;
126 using ::testing::WithArg;
127
128 struct TestMockIoImageRequestWQ : public TestMockFixture {
129   typedef ImageRequestWQ<librbd::MockTestImageCtx> MockImageRequestWQ;
130   typedef ImageRequest<librbd::MockTestImageCtx> MockImageRequest;
131
132   void expect_is_write_op(MockImageRequest &image_request, bool write_op) {
133     EXPECT_CALL(image_request, is_write_op()).WillOnce(Return(write_op));
134   }
135
136   void expect_signal(MockImageRequestWQ &image_request_wq) {
137     EXPECT_CALL(image_request_wq, signal());
138   }
139
140   void expect_queue(MockImageRequestWQ &image_request_wq) {
141     EXPECT_CALL(image_request_wq, queue(_));
142   }
143
144   void expect_front(MockImageRequestWQ &image_request_wq,
145                     MockImageRequest *image_request) {
146     EXPECT_CALL(image_request_wq, front()).WillOnce(Return(image_request));
147   }
148
149   void expect_is_refresh_request(MockTestImageCtx &mock_image_ctx,
150                                  bool required) {
151     EXPECT_CALL(*mock_image_ctx.state, is_refresh_required()).WillOnce(
152       Return(required));
153   }
154
155   void expect_dequeue(MockImageRequestWQ &image_request_wq,
156                       MockImageRequest *image_request) {
157     EXPECT_CALL(image_request_wq, dequeue()).WillOnce(Return(image_request));
158   }
159
160   void expect_get_exclusive_lock_policy(MockTestImageCtx &mock_image_ctx,
161                                         librbd::exclusive_lock::MockPolicy &policy) {
162     EXPECT_CALL(mock_image_ctx,
163                 get_exclusive_lock_policy()).WillOnce(Return(&policy));
164   }
165
166   void expect_may_auto_request_lock(librbd::exclusive_lock::MockPolicy &policy,
167                                     bool value) {
168     EXPECT_CALL(policy, may_auto_request_lock()).WillOnce(Return(value));
169   }
170
171   void expect_acquire_lock(MockExclusiveLock &mock_exclusive_lock,
172                            Context **on_finish) {
173     EXPECT_CALL(mock_exclusive_lock, acquire_lock(_))
174       .WillOnce(Invoke([on_finish](Context *ctx) {
175                     *on_finish = ctx;
176                   }));
177   }
178
179   void expect_process_finish(MockImageRequestWQ &mock_image_request_wq) {
180     EXPECT_CALL(mock_image_request_wq, process_finish()).Times(1);
181   }
182
183   void expect_fail(MockImageRequest &mock_image_request, int r) {
184     EXPECT_CALL(mock_image_request, fail(r))
185       .WillOnce(Invoke([&mock_image_request](int r) {
186                     mock_image_request.aio_comp->get();
187                     mock_image_request.aio_comp->fail(r);
188                   }));
189   }
190
191   void expect_refresh(MockTestImageCtx &mock_image_ctx, Context **on_finish) {
192     EXPECT_CALL(*mock_image_ctx.state, refresh(_))
193       .WillOnce(Invoke([on_finish](Context *ctx) {
194                     *on_finish = ctx;
195                   }));
196   }
197 };
198
199 TEST_F(TestMockIoImageRequestWQ, AcquireLockError) {
200   REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK);
201
202   librbd::ImageCtx *ictx;
203   ASSERT_EQ(0, open_image(m_image_name, &ictx));
204
205   MockTestImageCtx mock_image_ctx(*ictx);
206   MockExclusiveLock mock_exclusive_lock;
207   mock_image_ctx.exclusive_lock = &mock_exclusive_lock;
208
209   InSequence seq;
210   MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
211   expect_signal(mock_image_request_wq);
212   mock_image_request_wq.set_require_lock(DIRECTION_WRITE, true);
213
214   auto mock_image_request = new MockImageRequest();
215   expect_is_write_op(*mock_image_request, true);
216   expect_queue(mock_image_request_wq);
217   auto *aio_comp = new librbd::io::AioCompletion();
218   mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
219
220   librbd::exclusive_lock::MockPolicy mock_exclusive_lock_policy;
221   expect_front(mock_image_request_wq, mock_image_request);
222   expect_is_refresh_request(mock_image_ctx, false);
223   expect_is_write_op(*mock_image_request, true);
224   expect_dequeue(mock_image_request_wq, mock_image_request);
225   expect_get_exclusive_lock_policy(mock_image_ctx, mock_exclusive_lock_policy);
226   expect_may_auto_request_lock(mock_exclusive_lock_policy, true);
227   Context *on_acquire = nullptr;
228   expect_acquire_lock(mock_exclusive_lock, &on_acquire);
229   ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
230   ASSERT_TRUE(on_acquire != nullptr);
231
232   expect_process_finish(mock_image_request_wq);
233   expect_fail(*mock_image_request, -EPERM);
234   expect_is_write_op(*mock_image_request, true);
235   expect_signal(mock_image_request_wq);
236   on_acquire->complete(-EPERM);
237
238   ASSERT_EQ(0, aio_comp->wait_for_complete());
239   ASSERT_EQ(-EPERM, aio_comp->get_return_value());
240   aio_comp->release();
241 }
242
243 TEST_F(TestMockIoImageRequestWQ, RefreshError) {
244   librbd::ImageCtx *ictx;
245   ASSERT_EQ(0, open_image(m_image_name, &ictx));
246
247   MockTestImageCtx mock_image_ctx(*ictx);
248
249   InSequence seq;
250   MockImageRequestWQ mock_image_request_wq(&mock_image_ctx, "io", 60, nullptr);
251
252   auto mock_image_request = new MockImageRequest();
253   expect_is_write_op(*mock_image_request, true);
254   expect_queue(mock_image_request_wq);
255   auto *aio_comp = new librbd::io::AioCompletion();
256   mock_image_request_wq.aio_write(aio_comp, 0, 0, {}, 0);
257
258   expect_front(mock_image_request_wq, mock_image_request);
259   expect_is_refresh_request(mock_image_ctx, true);
260   expect_is_write_op(*mock_image_request, true);
261   expect_dequeue(mock_image_request_wq, mock_image_request);
262   Context *on_refresh = nullptr;
263   expect_refresh(mock_image_ctx, &on_refresh);
264   ASSERT_TRUE(mock_image_request_wq.invoke_dequeue() == nullptr);
265   ASSERT_TRUE(on_refresh != nullptr);
266
267   expect_process_finish(mock_image_request_wq);
268   expect_fail(*mock_image_request, -EPERM);
269   expect_is_write_op(*mock_image_request, true);
270   expect_signal(mock_image_request_wq);
271   on_refresh->complete(-EPERM);
272
273   ASSERT_EQ(0, aio_comp->wait_for_complete());
274   ASSERT_EQ(-EPERM, aio_comp->get_return_value());
275   aio_comp->release();
276 }
277
278 } // namespace io
279 } // namespace librbd