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