Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / test / librbd / test_mock_ObjectWatcher.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 "test/librados_test_stub/MockTestMemRadosClient.h"
9 #include "common/Cond.h"
10 #include "common/Mutex.h"
11 #include "librados/AioCompletionImpl.h"
12 #include "librbd/ObjectWatcher.h"
13 #include "gmock/gmock.h"
14 #include "gtest/gtest.h"
15 #include <list>
16
17 namespace librbd {
18
19 namespace {
20
21 struct MockObjectWatcher : public ObjectWatcher<MockImageCtx> {
22   std::string oid;
23
24   MockObjectWatcher(MockImageCtx &mock_image_ctx, const std::string &oid)
25     : ObjectWatcher<MockImageCtx>(mock_image_ctx.md_ctx,
26                                   mock_image_ctx.op_work_queue),
27       oid(oid) {
28   }
29
30   virtual std::string get_oid() const override {
31     return oid;
32   }
33
34   virtual void handle_notify(uint64_t notify_id, uint64_t handle,
35                              bufferlist &bl) {
36   }
37 };
38
39 } // anonymous namespace
40
41 } // namespace librbd
42
43 // template definitions
44 #include "librbd/ObjectWatcher.cc"
45 template class librbd::ObjectWatcher<librbd::MockImageCtx>;
46
47 namespace librbd {
48
49 using ::testing::_;
50 using ::testing::DoDefault;
51 using ::testing::Invoke;
52 using ::testing::InSequence;
53 using ::testing::Return;
54 using ::testing::SaveArg;
55 using ::testing::WithArg;
56
57 class TestMockObjectWatcher : public TestMockFixture {
58 public:
59   TestMockObjectWatcher() : m_lock("TestMockObjectWatcher::m_lock") {
60   }
61
62   virtual void SetUp() {
63     TestMockFixture::SetUp();
64
65     m_oid = get_temp_image_name();
66
67     bufferlist bl;
68     ASSERT_EQ(0, m_ioctx.write_full(m_oid, bl));
69   }
70
71   void expect_aio_watch(MockImageCtx &mock_image_ctx, int r,
72                         const std::function<void()> &action = std::function<void()>()) {
73     librados::MockTestMemIoCtxImpl &mock_io_ctx(get_mock_io_ctx(
74       mock_image_ctx.md_ctx));
75     librados::MockTestMemRadosClient *mock_rados_client(
76       mock_io_ctx.get_mock_rados_client());
77
78     auto &expect = EXPECT_CALL(mock_io_ctx, aio_watch(m_oid, _, _, _));
79     if (r < 0) {
80       expect.WillOnce(DoAll(WithArg<1>(Invoke([this, mock_rados_client, r, action](librados::AioCompletionImpl *c) {
81                                 if (action) {
82                                   action();
83                                 }
84
85                                 c->get();
86                                 mock_rados_client->finish_aio_completion(c, r);
87                                 notify_watch();
88                               })),
89                             Return(0)));
90     } else {
91       expect.WillOnce(DoAll(SaveArg<3>(&m_watch_ctx),
92                             Invoke([this, &mock_io_ctx, action](const std::string& o,
93                                                                 librados::AioCompletionImpl *c,
94                                                                 uint64_t *handle,
95                                                                 librados::WatchCtx2 *ctx) {
96                                 if (action) {
97                                   action();
98                                 }
99
100                                 mock_io_ctx.do_aio_watch(o, c, handle, ctx);
101                                 notify_watch();
102                               }),
103                             Return(0)));
104     }
105   }
106
107   void expect_aio_unwatch(MockImageCtx &mock_image_ctx, int r,
108                           const std::function<void()> &action = std::function<void()>()) {
109     librados::MockTestMemIoCtxImpl &mock_io_ctx(get_mock_io_ctx(
110       mock_image_ctx.md_ctx));
111
112     auto &expect = EXPECT_CALL(mock_io_ctx, aio_unwatch(_, _));
113     if (r < 0) {
114       expect.WillOnce(DoAll(Invoke([this, &mock_io_ctx, r, action](uint64_t handle,
115                                                                    librados::AioCompletionImpl *c) {
116                                 if (action) {
117                                   action();
118                                 }
119
120                                 librados::AioCompletionImpl *dummy_c = new librados::AioCompletionImpl();
121                                 mock_io_ctx.do_aio_unwatch(handle, dummy_c);
122                                 ASSERT_EQ(0, dummy_c->wait_for_complete());
123                                 dummy_c->release();
124
125                                 c->get();
126                                 mock_io_ctx.get_mock_rados_client()->finish_aio_completion(c, r);
127                                 notify_watch();
128                               }),
129                             Return(0)));
130     } else {
131       expect.WillOnce(DoAll(Invoke([this, &mock_io_ctx, action](uint64_t handle,
132                                                                 librados::AioCompletionImpl *c) {
133                                 if (action) {
134                                   action();
135                                 }
136
137                                 mock_io_ctx.do_aio_unwatch(handle, c);
138                                 notify_watch();
139                               }),
140                             Return(0)));
141     }
142   }
143
144   std::string m_oid;
145   librados::WatchCtx2 *m_watch_ctx = nullptr;
146
147   void notify_watch() {
148     Mutex::Locker locker(m_lock);
149     ++m_watch_count;
150     m_cond.Signal();
151   }
152
153   bool wait_for_watch(MockImageCtx &mock_image_ctx, size_t count) {
154     Mutex::Locker locker(m_lock);
155     while (m_watch_count < count) {
156       if (m_cond.WaitInterval(m_lock, utime_t(10, 0)) != 0) {
157         return false;
158       }
159     }
160     return true;
161   }
162
163   Mutex m_lock;
164   Cond m_cond;
165   size_t m_watch_count = 0;
166 };
167
168 TEST_F(TestMockObjectWatcher, Success) {
169   librbd::ImageCtx *ictx;
170   ASSERT_EQ(0, open_image(m_image_name, &ictx));
171
172   MockImageCtx mock_image_ctx(*ictx);
173   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
174
175   InSequence seq;
176   expect_aio_watch(mock_image_ctx, 0);
177   expect_aio_unwatch(mock_image_ctx, 0);
178
179   C_SaferCond register_ctx;
180   mock_image_watcher.register_watch(&register_ctx);
181   ASSERT_EQ(0, register_ctx.wait());
182
183   C_SaferCond unregister_ctx;
184   mock_image_watcher.unregister_watch(&unregister_ctx);
185   ASSERT_EQ(0, unregister_ctx.wait());
186 }
187
188 TEST_F(TestMockObjectWatcher, RegisterError) {
189   librbd::ImageCtx *ictx;
190   ASSERT_EQ(0, open_image(m_image_name, &ictx));
191
192   MockImageCtx mock_image_ctx(*ictx);
193   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
194
195   InSequence seq;
196   expect_aio_watch(mock_image_ctx, -EINVAL);
197
198   C_SaferCond register_ctx;
199   mock_image_watcher.register_watch(&register_ctx);
200   ASSERT_EQ(-EINVAL, register_ctx.wait());
201 }
202
203 TEST_F(TestMockObjectWatcher, UnregisterError) {
204   librbd::ImageCtx *ictx;
205   ASSERT_EQ(0, open_image(m_image_name, &ictx));
206
207   MockImageCtx mock_image_ctx(*ictx);
208   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
209
210   InSequence seq;
211   expect_aio_watch(mock_image_ctx, 0);
212   expect_aio_unwatch(mock_image_ctx, -EINVAL);
213
214   C_SaferCond register_ctx;
215   mock_image_watcher.register_watch(&register_ctx);
216   ASSERT_EQ(0, register_ctx.wait());
217
218   C_SaferCond unregister_ctx;
219   mock_image_watcher.unregister_watch(&unregister_ctx);
220   ASSERT_EQ(-EINVAL, unregister_ctx.wait());
221 }
222
223 TEST_F(TestMockObjectWatcher, Reregister) {
224   librbd::ImageCtx *ictx;
225   ASSERT_EQ(0, open_image(m_image_name, &ictx));
226
227   MockImageCtx mock_image_ctx(*ictx);
228   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
229
230   expect_op_work_queue(mock_image_ctx);
231
232   InSequence seq;
233   expect_aio_watch(mock_image_ctx, 0);
234   expect_aio_unwatch(mock_image_ctx, 0);
235   expect_aio_watch(mock_image_ctx, 0);
236   expect_aio_unwatch(mock_image_ctx, 0);
237
238   C_SaferCond register_ctx;
239   mock_image_watcher.register_watch(&register_ctx);
240   ASSERT_EQ(0, register_ctx.wait());
241
242   assert(m_watch_ctx != nullptr);
243   m_watch_ctx->handle_error(0, -ESHUTDOWN);
244
245   // wait for recovery unwatch/watch
246   ASSERT_TRUE(wait_for_watch(mock_image_ctx, 3));
247
248   C_SaferCond unregister_ctx;
249   mock_image_watcher.unregister_watch(&unregister_ctx);
250   ASSERT_EQ(0, unregister_ctx.wait());
251 }
252
253 TEST_F(TestMockObjectWatcher, ReregisterUnwatchError) {
254   librbd::ImageCtx *ictx;
255   ASSERT_EQ(0, open_image(m_image_name, &ictx));
256
257   MockImageCtx mock_image_ctx(*ictx);
258   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
259
260   expect_op_work_queue(mock_image_ctx);
261
262   InSequence seq;
263   expect_aio_watch(mock_image_ctx, 0);
264   expect_aio_unwatch(mock_image_ctx, -EINVAL);
265   expect_aio_watch(mock_image_ctx, 0);
266   expect_aio_unwatch(mock_image_ctx, 0);
267
268   C_SaferCond register_ctx;
269   mock_image_watcher.register_watch(&register_ctx);
270   ASSERT_EQ(0, register_ctx.wait());
271
272   assert(m_watch_ctx != nullptr);
273   m_watch_ctx->handle_error(0, -ESHUTDOWN);
274
275   // wait for recovery unwatch/watch
276   ASSERT_TRUE(wait_for_watch(mock_image_ctx, 3));
277
278   C_SaferCond unregister_ctx;
279   mock_image_watcher.unregister_watch(&unregister_ctx);
280   ASSERT_EQ(0, unregister_ctx.wait());
281 }
282
283 TEST_F(TestMockObjectWatcher, ReregisterWatchError) {
284   librbd::ImageCtx *ictx;
285   ASSERT_EQ(0, open_image(m_image_name, &ictx));
286
287   MockImageCtx mock_image_ctx(*ictx);
288   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
289
290   expect_op_work_queue(mock_image_ctx);
291
292   InSequence seq;
293   expect_aio_watch(mock_image_ctx, 0);
294   expect_aio_unwatch(mock_image_ctx, 0);
295   expect_aio_watch(mock_image_ctx, -ESHUTDOWN);
296   expect_aio_watch(mock_image_ctx, 0);
297   expect_aio_unwatch(mock_image_ctx, 0);
298
299   C_SaferCond register_ctx;
300   mock_image_watcher.register_watch(&register_ctx);
301   ASSERT_EQ(0, register_ctx.wait());
302
303   assert(m_watch_ctx != nullptr);
304   m_watch_ctx->handle_error(0, -ESHUTDOWN);
305
306   // wait for recovery unwatch/watch
307   ASSERT_TRUE(wait_for_watch(mock_image_ctx, 4));
308
309   C_SaferCond unregister_ctx;
310   mock_image_watcher.unregister_watch(&unregister_ctx);
311   ASSERT_EQ(0, unregister_ctx.wait());
312 }
313
314 TEST_F(TestMockObjectWatcher, ReregisterUnwatchPendingUnregister) {
315   librbd::ImageCtx *ictx;
316   ASSERT_EQ(0, open_image(m_image_name, &ictx));
317
318   MockImageCtx mock_image_ctx(*ictx);
319   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
320
321   expect_op_work_queue(mock_image_ctx);
322
323   InSequence seq;
324   expect_aio_watch(mock_image_ctx, 0);
325
326   // inject an unregister
327   C_SaferCond unregister_ctx;
328   expect_aio_unwatch(mock_image_ctx, 0, [&mock_image_watcher, &unregister_ctx]() {
329       mock_image_watcher.unregister_watch(&unregister_ctx);
330     });
331
332   C_SaferCond register_ctx;
333   mock_image_watcher.register_watch(&register_ctx);
334   ASSERT_EQ(0, register_ctx.wait());
335
336   assert(m_watch_ctx != nullptr);
337   m_watch_ctx->handle_error(0, -ESHUTDOWN);
338
339   ASSERT_EQ(0, unregister_ctx.wait());
340 }
341
342 TEST_F(TestMockObjectWatcher, ReregisterWatchPendingUnregister) {
343   librbd::ImageCtx *ictx;
344   ASSERT_EQ(0, open_image(m_image_name, &ictx));
345
346   MockImageCtx mock_image_ctx(*ictx);
347   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
348
349   expect_op_work_queue(mock_image_ctx);
350
351   InSequence seq;
352   expect_aio_watch(mock_image_ctx, 0);
353   expect_aio_unwatch(mock_image_ctx, 0);
354
355   // inject an unregister
356   C_SaferCond unregister_ctx;
357   expect_aio_watch(mock_image_ctx, -ESHUTDOWN,
358                    [&mock_image_watcher, &unregister_ctx]() {
359       mock_image_watcher.unregister_watch(&unregister_ctx);
360     });
361
362   C_SaferCond register_ctx;
363   mock_image_watcher.register_watch(&register_ctx);
364   ASSERT_EQ(0, register_ctx.wait());
365
366   assert(m_watch_ctx != nullptr);
367   m_watch_ctx->handle_error(0, -ESHUTDOWN);
368
369   ASSERT_EQ(0, unregister_ctx.wait());
370 }
371
372 TEST_F(TestMockObjectWatcher, ReregisterPendingUnregister) {
373   librbd::ImageCtx *ictx;
374   ASSERT_EQ(0, open_image(m_image_name, &ictx));
375
376   MockImageCtx mock_image_ctx(*ictx);
377   MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
378
379   expect_op_work_queue(mock_image_ctx);
380
381   InSequence seq;
382   expect_aio_watch(mock_image_ctx, 0);
383   expect_aio_unwatch(mock_image_ctx, 0);
384
385   // inject an unregister
386   C_SaferCond unregister_ctx;
387   expect_aio_watch(mock_image_ctx, 0,
388                    [&mock_image_watcher, &unregister_ctx]() {
389       mock_image_watcher.unregister_watch(&unregister_ctx);
390     });
391
392   expect_aio_unwatch(mock_image_ctx, 0);
393
394   C_SaferCond register_ctx;
395   mock_image_watcher.register_watch(&register_ctx);
396   ASSERT_EQ(0, register_ctx.wait());
397
398   assert(m_watch_ctx != nullptr);
399   m_watch_ctx->handle_error(0, -ESHUTDOWN);
400
401   ASSERT_EQ(0, unregister_ctx.wait());
402 }
403
404 } // namespace librbd