]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_mock_Watcher.cc
update sources to 12.2.10
[ceph.git] / ceph / src / test / librbd / test_mock_Watcher.cc
CommitLineData
7c673cae
FG
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"
91327a77
AA
12#include "librbd/Watcher.h"
13#include "librbd/watcher/RewatchRequest.h"
7c673cae
FG
14#include "gmock/gmock.h"
15#include "gtest/gtest.h"
16#include <list>
17
18namespace librbd {
19
20namespace {
21
91327a77 22struct MockWatcher : public Watcher {
7c673cae
FG
23 std::string oid;
24
91327a77
AA
25 MockWatcher(librados::IoCtx& ioctx, ContextWQ *work_queue,
26 const std::string& oid)
27 : Watcher(ioctx, work_queue, oid) {
7c673cae
FG
28 }
29
30 virtual void handle_notify(uint64_t notify_id, uint64_t handle,
91327a77 31 uint64_t notifier_id, bufferlist &bl) {
7c673cae
FG
32 }
33};
34
35} // anonymous namespace
7c673cae
FG
36} // namespace librbd
37
7c673cae
FG
38namespace librbd {
39
40using ::testing::_;
41using ::testing::DoDefault;
42using ::testing::Invoke;
43using ::testing::InSequence;
44using ::testing::Return;
45using ::testing::SaveArg;
46using ::testing::WithArg;
91327a77 47using ::testing::WithArgs;
7c673cae 48
91327a77 49class TestMockWatcher : public TestMockFixture {
7c673cae 50public:
91327a77 51 TestMockWatcher() : m_lock("TestMockWatcher::m_lock") {
7c673cae
FG
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()>()) {
91327a77 65 librados::MockTestMemIoCtxImpl &mock_io_ctx(get_mock_io_ctx(m_ioctx));
7c673cae
FG
66 librados::MockTestMemRadosClient *mock_rados_client(
67 mock_io_ctx.get_mock_rados_client());
68
91327a77
AA
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)));
7c673cae
FG
88 }
89
90 void expect_aio_unwatch(MockImageCtx &mock_image_ctx, int r,
91 const std::function<void()> &action = std::function<void()>()) {
91327a77
AA
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)));
7c673cae
FG
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 }
91327a77 127 m_watch_count -= count;
7c673cae
FG
128 return true;
129 }
130
131 Mutex m_lock;
132 Cond m_cond;
133 size_t m_watch_count = 0;
134};
135
91327a77 136TEST_F(TestMockWatcher, Success) {
7c673cae
FG
137 librbd::ImageCtx *ictx;
138 ASSERT_EQ(0, open_image(m_image_name, &ictx));
139
140 MockImageCtx mock_image_ctx(*ictx);
91327a77 141 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
91327a77 156TEST_F(TestMockWatcher, RegisterError) {
7c673cae
FG
157 librbd::ImageCtx *ictx;
158 ASSERT_EQ(0, open_image(m_image_name, &ictx));
159
160 MockImageCtx mock_image_ctx(*ictx);
91327a77 161 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
91327a77 171TEST_F(TestMockWatcher, UnregisterError) {
7c673cae
FG
172 librbd::ImageCtx *ictx;
173 ASSERT_EQ(0, open_image(m_image_name, &ictx));
174
175 MockImageCtx mock_image_ctx(*ictx);
91327a77 176 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
91327a77 191TEST_F(TestMockWatcher, Reregister) {
7c673cae
FG
192 librbd::ImageCtx *ictx;
193 ASSERT_EQ(0, open_image(m_image_name, &ictx));
194
195 MockImageCtx mock_image_ctx(*ictx);
91327a77 196 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
91327a77 221TEST_F(TestMockWatcher, ReregisterUnwatchError) {
7c673cae
FG
222 librbd::ImageCtx *ictx;
223 ASSERT_EQ(0, open_image(m_image_name, &ictx));
224
225 MockImageCtx mock_image_ctx(*ictx);
91327a77 226 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
91327a77 251TEST_F(TestMockWatcher, ReregisterWatchError) {
7c673cae
FG
252 librbd::ImageCtx *ictx;
253 ASSERT_EQ(0, open_image(m_image_name, &ictx));
254
255 MockImageCtx mock_image_ctx(*ictx);
91327a77 256 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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);
91327a77 263 expect_aio_watch(mock_image_ctx, -EPERM);
7c673cae
FG
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
91327a77
AA
282TEST_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
325TEST_F(TestMockWatcher, ReregisterUnwatchPendingUnregister) {
7c673cae
FG
326 librbd::ImageCtx *ictx;
327 ASSERT_EQ(0, open_image(m_image_name, &ictx));
328
329 MockImageCtx mock_image_ctx(*ictx);
91327a77 330 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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;
91327a77
AA
339 expect_aio_unwatch(mock_image_ctx, -EBLACKLISTED,
340 [&mock_image_watcher, &unregister_ctx]() {
7c673cae
FG
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);
91327a77 349 m_watch_ctx->handle_error(0, -EBLACKLISTED);
7c673cae
FG
350
351 ASSERT_EQ(0, unregister_ctx.wait());
352}
353
91327a77 354TEST_F(TestMockWatcher, ReregisterWatchPendingUnregister) {
7c673cae
FG
355 librbd::ImageCtx *ictx;
356 ASSERT_EQ(0, open_image(m_image_name, &ictx));
357
358 MockImageCtx mock_image_ctx(*ictx);
91327a77 359 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
91327a77 384TEST_F(TestMockWatcher, ReregisterPendingUnregister) {
7c673cae
FG
385 librbd::ImageCtx *ictx;
386 ASSERT_EQ(0, open_image(m_image_name, &ictx));
387
388 MockImageCtx mock_image_ctx(*ictx);
91327a77 389 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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