1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
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"
21 struct MockObjectWatcher : public ObjectWatcher<MockImageCtx> {
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),
30 virtual std::string get_oid() const override {
34 virtual void handle_notify(uint64_t notify_id, uint64_t handle,
39 } // anonymous namespace
43 // template definitions
44 #include "librbd/ObjectWatcher.cc"
45 template class librbd::ObjectWatcher<librbd::MockImageCtx>;
50 using ::testing::DoDefault;
51 using ::testing::Invoke;
52 using ::testing::InSequence;
53 using ::testing::Return;
54 using ::testing::SaveArg;
55 using ::testing::WithArg;
57 class TestMockObjectWatcher : public TestMockFixture {
59 TestMockObjectWatcher() : m_lock("TestMockObjectWatcher::m_lock") {
62 virtual void SetUp() {
63 TestMockFixture::SetUp();
65 m_oid = get_temp_image_name();
68 ASSERT_EQ(0, m_ioctx.write_full(m_oid, bl));
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());
78 auto &expect = EXPECT_CALL(mock_io_ctx, aio_watch(m_oid, _, _, _));
80 expect.WillOnce(DoAll(WithArg<1>(Invoke([this, mock_rados_client, r, action](librados::AioCompletionImpl *c) {
86 mock_rados_client->finish_aio_completion(c, r);
91 expect.WillOnce(DoAll(SaveArg<3>(&m_watch_ctx),
92 Invoke([this, &mock_io_ctx, action](const std::string& o,
93 librados::AioCompletionImpl *c,
95 librados::WatchCtx2 *ctx) {
100 mock_io_ctx.do_aio_watch(o, c, handle, ctx);
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));
112 auto &expect = EXPECT_CALL(mock_io_ctx, aio_unwatch(_, _));
114 expect.WillOnce(DoAll(Invoke([this, &mock_io_ctx, r, action](uint64_t handle,
115 librados::AioCompletionImpl *c) {
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());
126 mock_io_ctx.get_mock_rados_client()->finish_aio_completion(c, r);
131 expect.WillOnce(DoAll(Invoke([this, &mock_io_ctx, action](uint64_t handle,
132 librados::AioCompletionImpl *c) {
137 mock_io_ctx.do_aio_unwatch(handle, c);
145 librados::WatchCtx2 *m_watch_ctx = nullptr;
147 void notify_watch() {
148 Mutex::Locker locker(m_lock);
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) {
165 size_t m_watch_count = 0;
168 TEST_F(TestMockObjectWatcher, Success) {
169 librbd::ImageCtx *ictx;
170 ASSERT_EQ(0, open_image(m_image_name, &ictx));
172 MockImageCtx mock_image_ctx(*ictx);
173 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
176 expect_aio_watch(mock_image_ctx, 0);
177 expect_aio_unwatch(mock_image_ctx, 0);
179 C_SaferCond register_ctx;
180 mock_image_watcher.register_watch(®ister_ctx);
181 ASSERT_EQ(0, register_ctx.wait());
183 C_SaferCond unregister_ctx;
184 mock_image_watcher.unregister_watch(&unregister_ctx);
185 ASSERT_EQ(0, unregister_ctx.wait());
188 TEST_F(TestMockObjectWatcher, RegisterError) {
189 librbd::ImageCtx *ictx;
190 ASSERT_EQ(0, open_image(m_image_name, &ictx));
192 MockImageCtx mock_image_ctx(*ictx);
193 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
196 expect_aio_watch(mock_image_ctx, -EINVAL);
198 C_SaferCond register_ctx;
199 mock_image_watcher.register_watch(®ister_ctx);
200 ASSERT_EQ(-EINVAL, register_ctx.wait());
203 TEST_F(TestMockObjectWatcher, UnregisterError) {
204 librbd::ImageCtx *ictx;
205 ASSERT_EQ(0, open_image(m_image_name, &ictx));
207 MockImageCtx mock_image_ctx(*ictx);
208 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
211 expect_aio_watch(mock_image_ctx, 0);
212 expect_aio_unwatch(mock_image_ctx, -EINVAL);
214 C_SaferCond register_ctx;
215 mock_image_watcher.register_watch(®ister_ctx);
216 ASSERT_EQ(0, register_ctx.wait());
218 C_SaferCond unregister_ctx;
219 mock_image_watcher.unregister_watch(&unregister_ctx);
220 ASSERT_EQ(-EINVAL, unregister_ctx.wait());
223 TEST_F(TestMockObjectWatcher, Reregister) {
224 librbd::ImageCtx *ictx;
225 ASSERT_EQ(0, open_image(m_image_name, &ictx));
227 MockImageCtx mock_image_ctx(*ictx);
228 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
230 expect_op_work_queue(mock_image_ctx);
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);
238 C_SaferCond register_ctx;
239 mock_image_watcher.register_watch(®ister_ctx);
240 ASSERT_EQ(0, register_ctx.wait());
242 assert(m_watch_ctx != nullptr);
243 m_watch_ctx->handle_error(0, -ESHUTDOWN);
245 // wait for recovery unwatch/watch
246 ASSERT_TRUE(wait_for_watch(mock_image_ctx, 3));
248 C_SaferCond unregister_ctx;
249 mock_image_watcher.unregister_watch(&unregister_ctx);
250 ASSERT_EQ(0, unregister_ctx.wait());
253 TEST_F(TestMockObjectWatcher, ReregisterUnwatchError) {
254 librbd::ImageCtx *ictx;
255 ASSERT_EQ(0, open_image(m_image_name, &ictx));
257 MockImageCtx mock_image_ctx(*ictx);
258 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
260 expect_op_work_queue(mock_image_ctx);
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);
268 C_SaferCond register_ctx;
269 mock_image_watcher.register_watch(®ister_ctx);
270 ASSERT_EQ(0, register_ctx.wait());
272 assert(m_watch_ctx != nullptr);
273 m_watch_ctx->handle_error(0, -ESHUTDOWN);
275 // wait for recovery unwatch/watch
276 ASSERT_TRUE(wait_for_watch(mock_image_ctx, 3));
278 C_SaferCond unregister_ctx;
279 mock_image_watcher.unregister_watch(&unregister_ctx);
280 ASSERT_EQ(0, unregister_ctx.wait());
283 TEST_F(TestMockObjectWatcher, ReregisterWatchError) {
284 librbd::ImageCtx *ictx;
285 ASSERT_EQ(0, open_image(m_image_name, &ictx));
287 MockImageCtx mock_image_ctx(*ictx);
288 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
290 expect_op_work_queue(mock_image_ctx);
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);
299 C_SaferCond register_ctx;
300 mock_image_watcher.register_watch(®ister_ctx);
301 ASSERT_EQ(0, register_ctx.wait());
303 assert(m_watch_ctx != nullptr);
304 m_watch_ctx->handle_error(0, -ESHUTDOWN);
306 // wait for recovery unwatch/watch
307 ASSERT_TRUE(wait_for_watch(mock_image_ctx, 4));
309 C_SaferCond unregister_ctx;
310 mock_image_watcher.unregister_watch(&unregister_ctx);
311 ASSERT_EQ(0, unregister_ctx.wait());
314 TEST_F(TestMockObjectWatcher, ReregisterUnwatchPendingUnregister) {
315 librbd::ImageCtx *ictx;
316 ASSERT_EQ(0, open_image(m_image_name, &ictx));
318 MockImageCtx mock_image_ctx(*ictx);
319 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
321 expect_op_work_queue(mock_image_ctx);
324 expect_aio_watch(mock_image_ctx, 0);
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);
332 C_SaferCond register_ctx;
333 mock_image_watcher.register_watch(®ister_ctx);
334 ASSERT_EQ(0, register_ctx.wait());
336 assert(m_watch_ctx != nullptr);
337 m_watch_ctx->handle_error(0, -ESHUTDOWN);
339 ASSERT_EQ(0, unregister_ctx.wait());
342 TEST_F(TestMockObjectWatcher, ReregisterWatchPendingUnregister) {
343 librbd::ImageCtx *ictx;
344 ASSERT_EQ(0, open_image(m_image_name, &ictx));
346 MockImageCtx mock_image_ctx(*ictx);
347 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
349 expect_op_work_queue(mock_image_ctx);
352 expect_aio_watch(mock_image_ctx, 0);
353 expect_aio_unwatch(mock_image_ctx, 0);
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);
362 C_SaferCond register_ctx;
363 mock_image_watcher.register_watch(®ister_ctx);
364 ASSERT_EQ(0, register_ctx.wait());
366 assert(m_watch_ctx != nullptr);
367 m_watch_ctx->handle_error(0, -ESHUTDOWN);
369 ASSERT_EQ(0, unregister_ctx.wait());
372 TEST_F(TestMockObjectWatcher, ReregisterPendingUnregister) {
373 librbd::ImageCtx *ictx;
374 ASSERT_EQ(0, open_image(m_image_name, &ictx));
376 MockImageCtx mock_image_ctx(*ictx);
377 MockObjectWatcher mock_image_watcher(mock_image_ctx, m_oid);
379 expect_op_work_queue(mock_image_ctx);
382 expect_aio_watch(mock_image_ctx, 0);
383 expect_aio_unwatch(mock_image_ctx, 0);
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);
392 expect_aio_unwatch(mock_image_ctx, 0);
394 C_SaferCond register_ctx;
395 mock_image_watcher.register_watch(®ister_ctx);
396 ASSERT_EQ(0, register_ctx.wait());
398 assert(m_watch_ctx != nullptr);
399 m_watch_ctx->handle_error(0, -ESHUTDOWN);
401 ASSERT_EQ(0, unregister_ctx.wait());
404 } // namespace librbd