]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/test_mock_ObjectWatcher.cc
update sources to 12.2.7
[ceph.git] / 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