]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/librbd/test_mock_Watcher.cc
update source to Ceph Pacific 16.2.2
[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"
9f95a23c 10#include "common/ceph_mutex.h"
7c673cae 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
f67539c2 25 MockWatcher(librados::IoCtx& ioctx, asio::ContextWQ *work_queue,
91327a77
AA
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::_;
9f95a23c 41using ::testing::DoAll;
7c673cae
FG
42using ::testing::DoDefault;
43using ::testing::Invoke;
44using ::testing::InSequence;
45using ::testing::Return;
46using ::testing::SaveArg;
47using ::testing::WithArg;
91327a77 48using ::testing::WithArgs;
7c673cae 49
91327a77 50class TestMockWatcher : public TestMockFixture {
7c673cae 51public:
9f95a23c 52 TestMockWatcher() = default;
7c673cae
FG
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();
9f95a23c 79 mock_image_ctx.image_ctx->op_work_queue->queue(new LambdaContext([mock_rados_client, action, c](int r) {
91327a77
AA
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();
9f95a23c 100 mock_image_ctx.image_ctx->op_work_queue->queue(new LambdaContext([mock_rados_client, action, c](int r) {
91327a77
AA
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() {
9f95a23c 115 std::lock_guard locker{m_lock};
7c673cae 116 ++m_watch_count;
9f95a23c 117 m_cond.notify_all();
7c673cae
FG
118 }
119
120 bool wait_for_watch(MockImageCtx &mock_image_ctx, size_t count) {
9f95a23c 121 std::unique_lock locker{m_lock};
7c673cae 122 while (m_watch_count < count) {
9f95a23c 123 if (m_cond.wait_for(locker, 10s) == std::cv_status::timeout) {
7c673cae
FG
124 return false;
125 }
126 }
91327a77 127 m_watch_count -= count;
7c673cae
FG
128 return true;
129 }
130
9f95a23c
TL
131 ceph::mutex m_lock = ceph::make_mutex("TestMockWatcher::m_lock");
132 ceph::condition_variable m_cond;
7c673cae
FG
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
11fdf7f2 210 ceph_assert(m_watch_ctx != nullptr);
7c673cae
FG
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
11fdf7f2 240 ceph_assert(m_watch_ctx != nullptr);
7c673cae
FG
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
11fdf7f2 271 ceph_assert(m_watch_ctx != nullptr);
7c673cae
FG
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
f67539c2 282TEST_F(TestMockWatcher, ReregisterWatchBlocklist) {
91327a77
AA
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);
f67539c2 294 expect_aio_watch(mock_image_ctx, -EBLOCKLISTED);
91327a77 295
91327a77
AA
296 C_SaferCond register_ctx;
297 mock_image_watcher.register_watch(&register_ctx);
298 ASSERT_TRUE(wait_for_watch(mock_image_ctx, 1));
299 ASSERT_EQ(0, register_ctx.wait());
300
301 ceph_assert(m_watch_ctx != nullptr);
f67539c2 302 m_watch_ctx->handle_error(0, -EBLOCKLISTED);
91327a77
AA
303
304 // wait for recovery unwatch/watch
305 ASSERT_TRUE(wait_for_watch(mock_image_ctx, 2));
f67539c2 306 ASSERT_TRUE(mock_image_watcher.is_blocklisted());
91327a77
AA
307
308 C_SaferCond unregister_ctx;
309 mock_image_watcher.unregister_watch(&unregister_ctx);
310 ASSERT_EQ(0, unregister_ctx.wait());
91327a77
AA
311}
312
313TEST_F(TestMockWatcher, ReregisterUnwatchPendingUnregister) {
7c673cae
FG
314 librbd::ImageCtx *ictx;
315 ASSERT_EQ(0, open_image(m_image_name, &ictx));
316
317 MockImageCtx mock_image_ctx(*ictx);
91327a77 318 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
319
320 expect_op_work_queue(mock_image_ctx);
321
322 InSequence seq;
323 expect_aio_watch(mock_image_ctx, 0);
324
325 // inject an unregister
326 C_SaferCond unregister_ctx;
f67539c2 327 expect_aio_unwatch(mock_image_ctx, -EBLOCKLISTED,
91327a77 328 [&mock_image_watcher, &unregister_ctx]() {
7c673cae
FG
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
11fdf7f2 336 ceph_assert(m_watch_ctx != nullptr);
f67539c2 337 m_watch_ctx->handle_error(0, -EBLOCKLISTED);
7c673cae
FG
338
339 ASSERT_EQ(0, unregister_ctx.wait());
340}
341
91327a77 342TEST_F(TestMockWatcher, ReregisterWatchPendingUnregister) {
7c673cae
FG
343 librbd::ImageCtx *ictx;
344 ASSERT_EQ(0, open_image(m_image_name, &ictx));
345
346 MockImageCtx mock_image_ctx(*ictx);
91327a77 347 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
11fdf7f2 366 ceph_assert(m_watch_ctx != nullptr);
7c673cae
FG
367 m_watch_ctx->handle_error(0, -ESHUTDOWN);
368
369 ASSERT_EQ(0, unregister_ctx.wait());
370}
371
91327a77 372TEST_F(TestMockWatcher, ReregisterPendingUnregister) {
7c673cae
FG
373 librbd::ImageCtx *ictx;
374 ASSERT_EQ(0, open_image(m_image_name, &ictx));
375
376 MockImageCtx mock_image_ctx(*ictx);
91327a77 377 MockWatcher mock_image_watcher(m_ioctx, ictx->op_work_queue, m_oid);
7c673cae
FG
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
11fdf7f2 398 ceph_assert(m_watch_ctx != nullptr);
7c673cae
FG
399 m_watch_ctx->handle_error(0, -ESHUTDOWN);
400
401 ASSERT_EQ(0, unregister_ctx.wait());
402}
403
404} // namespace librbd