diff options
Diffstat (limited to 'src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc')
-rw-r--r-- | src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc b/src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc new file mode 100644 index 000000000..05e56f520 --- /dev/null +++ b/src/test/librbd/cache/test_mock_ParentCacheObjectDispatch.cc @@ -0,0 +1,427 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "test/librbd/test_mock_fixture.h" +#include "test/librbd/test_support.h" +#include "test/librbd/mock/MockImageCtx.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "include/Context.h" +#include "tools/immutable_object_cache/CacheClient.h" +#include "test/immutable_object_cache/MockCacheDaemon.h" +#include "librbd/cache/ParentCacheObjectDispatch.h" +#include "librbd/plugin/Api.h" +#include "test/librbd/test_mock_fixture.h" +#include "test/librbd/mock/MockImageCtx.h" + +using namespace ceph::immutable_obj_cache; + +namespace librbd { + +namespace { + +struct MockParentImageCacheImageCtx : public MockImageCtx { + MockParentImageCacheImageCtx(ImageCtx& image_ctx) + : MockImageCtx(image_ctx) { + } + ~MockParentImageCacheImageCtx() {} +}; + +} // anonymous namespace + +namespace cache { + +template<> +struct TypeTraits<MockParentImageCacheImageCtx> { + typedef ceph::immutable_obj_cache::MockCacheClient CacheClient; +}; + +} // namespace cache + +namespace plugin { + +template <> +struct Api<MockParentImageCacheImageCtx> { + MOCK_METHOD6(read_parent, void(MockParentImageCacheImageCtx*, uint64_t, + librbd::io::ReadExtents*, librados::snap_t, + const ZTracer::Trace &, Context*)); +}; + +} // namespace plugin +} // namespace librbd + +#include "librbd/cache/ParentCacheObjectDispatch.cc" +template class librbd::cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx>; + +namespace librbd { + +using ::testing::_; +using ::testing::DoAll; +using ::testing::Invoke; +using ::testing::InSequence; +using ::testing::Return; +using ::testing::WithArg; +using ::testing::WithArgs; + +class TestMockParentCacheObjectDispatch : public TestMockFixture { +public : + typedef cache::ParentCacheObjectDispatch<librbd::MockParentImageCacheImageCtx> MockParentImageCache; + typedef plugin::Api<MockParentImageCacheImageCtx> MockPluginApi; + + // ====== mock cache client ==== + void expect_cache_run(MockParentImageCache& mparent_image_cache, bool ret_val) { + auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), run()); + + expect.WillOnce((Invoke([]() { + }))); + } + + void expect_cache_session_state(MockParentImageCache& mparent_image_cache, bool ret_val) { + auto & expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), is_session_work()); + + expect.WillOnce((Invoke([ret_val]() { + return ret_val; + }))); + } + + void expect_cache_connect(MockParentImageCache& mparent_image_cache, int ret_val) { + auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect()); + + expect.WillOnce((Invoke([ret_val]() { + return ret_val; + }))); + } + + void expect_cache_async_connect(MockParentImageCache& mparent_image_cache, int ret_val, + Context* on_finish) { + auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), connect(_)); + + expect.WillOnce(WithArg<0>(Invoke([on_finish, ret_val](Context* ctx) { + ctx->complete(ret_val); + on_finish->complete(ret_val); + }))); + } + + void expect_cache_lookup_object(MockParentImageCache& mparent_image_cache, + const std::string &cache_path) { + EXPECT_CALL(*(mparent_image_cache.get_cache_client()), + lookup_object(_, _, _, _, _, _)) + .WillOnce(WithArg<5>(Invoke([cache_path](CacheGenContextURef on_finish) { + ObjectCacheReadReplyData ack(RBDSC_READ_REPLY, 0, cache_path); + on_finish.release()->complete(&ack); + }))); + } + + void expect_read_parent(MockPluginApi &mock_plugin_api, uint64_t object_no, + io::ReadExtents* extents, librados::snap_t snap_id, + int r) { + EXPECT_CALL(mock_plugin_api, + read_parent(_, object_no, extents, snap_id, _, _)) + .WillOnce(WithArg<5>(CompleteContext(r, static_cast<asio::ContextWQ*>(nullptr)))); + } + + void expect_cache_close(MockParentImageCache& mparent_image_cache, int ret_val) { + auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), close()); + + expect.WillOnce((Invoke([]() { + }))); + } + + void expect_cache_stop(MockParentImageCache& mparent_image_cache, int ret_val) { + auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), stop()); + + expect.WillOnce((Invoke([]() { + }))); + } + + void expect_cache_register(MockParentImageCache& mparent_image_cache, Context* mock_handle_register, int ret_val) { + auto& expect = EXPECT_CALL(*(mparent_image_cache.get_cache_client()), register_client(_)); + + expect.WillOnce(WithArg<0>(Invoke([mock_handle_register, ret_val](Context* ctx) { + if(ret_val == 0) { + mock_handle_register->complete(true); + } else { + mock_handle_register->complete(false); + } + ctx->complete(true); + return ret_val; + }))); + } + + void expect_io_object_dispatcher_register_state(MockParentImageCache& mparent_image_cache, + int ret_val) { + auto& expect = EXPECT_CALL((*(mparent_image_cache.get_image_ctx()->io_object_dispatcher)), + register_dispatch(_)); + + expect.WillOnce(WithArg<0>(Invoke([&mparent_image_cache] + (io::ObjectDispatchInterface* object_dispatch) { + ASSERT_EQ(object_dispatch, &mparent_image_cache); + }))); + } +}; + +TEST_F(TestMockParentCacheObjectDispatch, test_initialization_success) { + librbd::ImageCtx* ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + MockParentImageCacheImageCtx mock_image_ctx(*ictx); + mock_image_ctx.child = &mock_image_ctx; + + MockPluginApi mock_plugin_api; + auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx, + mock_plugin_api); + + expect_cache_run(*mock_parent_image_cache, 0); + C_SaferCond cond; + Context* handle_connect = new LambdaContext([&cond](int ret) { + ASSERT_EQ(ret, 0); + cond.complete(0); + }); + expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect); + Context* ctx = new LambdaContext([](bool reg) { + ASSERT_EQ(reg, true); + }); + expect_cache_register(*mock_parent_image_cache, ctx, 0); + expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0); + expect_cache_close(*mock_parent_image_cache, 0); + expect_cache_stop(*mock_parent_image_cache, 0); + + mock_parent_image_cache->init(); + cond.wait(); + + ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(), + io::OBJECT_DISPATCH_LAYER_PARENT_CACHE); + expect_cache_session_state(*mock_parent_image_cache, true); + ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true); + + mock_parent_image_cache->get_cache_client()->close(); + mock_parent_image_cache->get_cache_client()->stop(); + + delete mock_parent_image_cache; +} + +TEST_F(TestMockParentCacheObjectDispatch, test_initialization_fail_at_connect) { + librbd::ImageCtx* ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + MockParentImageCacheImageCtx mock_image_ctx(*ictx); + mock_image_ctx.child = &mock_image_ctx; + + MockPluginApi mock_plugin_api; + auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx, + mock_plugin_api); + + expect_cache_run(*mock_parent_image_cache, 0); + C_SaferCond cond; + Context* handle_connect = new LambdaContext([&cond](int ret) { + ASSERT_EQ(ret, -1); + cond.complete(0); + }); + expect_cache_async_connect(*mock_parent_image_cache, -1, handle_connect); + expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0); + expect_cache_session_state(*mock_parent_image_cache, false); + expect_cache_close(*mock_parent_image_cache, 0); + expect_cache_stop(*mock_parent_image_cache, 0); + + mock_parent_image_cache->init(); + + // initialization fails. + ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(), + io::OBJECT_DISPATCH_LAYER_PARENT_CACHE); + ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), false); + + mock_parent_image_cache->get_cache_client()->close(); + mock_parent_image_cache->get_cache_client()->stop(); + + delete mock_parent_image_cache; + +} + +TEST_F(TestMockParentCacheObjectDispatch, test_initialization_fail_at_register) { + librbd::ImageCtx* ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + MockParentImageCacheImageCtx mock_image_ctx(*ictx); + mock_image_ctx.child = &mock_image_ctx; + + MockPluginApi mock_plugin_api; + auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx, + mock_plugin_api); + + expect_cache_run(*mock_parent_image_cache, 0); + C_SaferCond cond; + Context* handle_connect = new LambdaContext([&cond](int ret) { + ASSERT_EQ(ret, 0); + cond.complete(0); + }); + expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect); + Context* ctx = new LambdaContext([](bool reg) { + ASSERT_EQ(reg, false); + }); + expect_cache_register(*mock_parent_image_cache, ctx, -1); + expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0); + expect_cache_close(*mock_parent_image_cache, 0); + expect_cache_stop(*mock_parent_image_cache, 0); + + mock_parent_image_cache->init(); + cond.wait(); + + ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(), + io::OBJECT_DISPATCH_LAYER_PARENT_CACHE); + expect_cache_session_state(*mock_parent_image_cache, true); + ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true); + + mock_parent_image_cache->get_cache_client()->close(); + mock_parent_image_cache->get_cache_client()->stop(); + + delete mock_parent_image_cache; +} + +TEST_F(TestMockParentCacheObjectDispatch, test_disble_interface) { + librbd::ImageCtx* ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + MockParentImageCacheImageCtx mock_image_ctx(*ictx); + mock_image_ctx.child = &mock_image_ctx; + + MockPluginApi mock_plugin_api; + auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx, + mock_plugin_api); + + std::string temp_oid("12345"); + ceph::bufferlist temp_bl; + IOContext io_context = mock_image_ctx.get_data_io_context(); + io::DispatchResult* temp_dispatch_result = nullptr; + io::Extents temp_buffer_extents; + int* temp_op_flags = nullptr; + uint64_t* temp_journal_tid = nullptr; + Context** temp_on_finish = nullptr; + Context* temp_on_dispatched = nullptr; + ZTracer::Trace* temp_trace = nullptr; + io::LightweightBufferExtents buffer_extents; + + ASSERT_EQ(mock_parent_image_cache->discard(0, 0, 0, io_context, 0, + *temp_trace, temp_op_flags, temp_journal_tid, temp_dispatch_result, + temp_on_finish, temp_on_dispatched), false); + ASSERT_EQ(mock_parent_image_cache->write(0, 0, std::move(temp_bl), + io_context, 0, 0, std::nullopt, *temp_trace, temp_op_flags, + temp_journal_tid, temp_dispatch_result, temp_on_finish, + temp_on_dispatched), false); + ASSERT_EQ(mock_parent_image_cache->write_same(0, 0, 0, std::move(buffer_extents), + std::move(temp_bl), io_context, 0, *temp_trace, temp_op_flags, + temp_journal_tid, temp_dispatch_result, temp_on_finish, temp_on_dispatched), false ); + ASSERT_EQ(mock_parent_image_cache->compare_and_write(0, 0, std::move(temp_bl), std::move(temp_bl), + io_context, 0, *temp_trace, temp_journal_tid, temp_op_flags, + temp_journal_tid, temp_dispatch_result, temp_on_finish, + temp_on_dispatched), false); + ASSERT_EQ(mock_parent_image_cache->flush(io::FLUSH_SOURCE_USER, *temp_trace, temp_journal_tid, + temp_dispatch_result, temp_on_finish, temp_on_dispatched), false); + ASSERT_EQ(mock_parent_image_cache->invalidate_cache(nullptr), false); + ASSERT_EQ(mock_parent_image_cache->reset_existence_cache(nullptr), false); + + delete mock_parent_image_cache; + +} + +TEST_F(TestMockParentCacheObjectDispatch, test_read) { + librbd::ImageCtx* ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + MockParentImageCacheImageCtx mock_image_ctx(*ictx); + mock_image_ctx.child = &mock_image_ctx; + + MockPluginApi mock_plugin_api; + auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx, + mock_plugin_api); + + expect_cache_run(*mock_parent_image_cache, 0); + C_SaferCond conn_cond; + Context* handle_connect = new LambdaContext([&conn_cond](int ret) { + ASSERT_EQ(ret, 0); + conn_cond.complete(0); + }); + expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect); + Context* ctx = new LambdaContext([](bool reg) { + ASSERT_EQ(reg, true); + }); + expect_cache_register(*mock_parent_image_cache, ctx, 0); + expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0); + expect_cache_close(*mock_parent_image_cache, 0); + expect_cache_stop(*mock_parent_image_cache, 0); + + mock_parent_image_cache->init(); + conn_cond.wait(); + + ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(), + io::OBJECT_DISPATCH_LAYER_PARENT_CACHE); + expect_cache_session_state(*mock_parent_image_cache, true); + ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), true); + + auto& expect = EXPECT_CALL(*(mock_parent_image_cache->get_cache_client()), is_session_work()); + expect.WillOnce(Return(true)); + + expect_cache_lookup_object(*mock_parent_image_cache, "/dev/null"); + + C_SaferCond on_dispatched; + io::DispatchResult dispatch_result; + io::ReadExtents extents = {{0, 4096}, {8192, 4096}}; + mock_parent_image_cache->read( + 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr, + nullptr, &dispatch_result, nullptr, &on_dispatched); + ASSERT_EQ(0, on_dispatched.wait()); + + mock_parent_image_cache->get_cache_client()->close(); + mock_parent_image_cache->get_cache_client()->stop(); + delete mock_parent_image_cache; +} + +TEST_F(TestMockParentCacheObjectDispatch, test_read_dne) { + librbd::ImageCtx* ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + MockParentImageCacheImageCtx mock_image_ctx(*ictx); + mock_image_ctx.child = &mock_image_ctx; + + MockPluginApi mock_plugin_api; + auto mock_parent_image_cache = MockParentImageCache::create(&mock_image_ctx, + mock_plugin_api); + + expect_cache_run(*mock_parent_image_cache, 0); + C_SaferCond conn_cond; + Context* handle_connect = new LambdaContext([&conn_cond](int ret) { + ASSERT_EQ(ret, 0); + conn_cond.complete(0); + }); + expect_cache_async_connect(*mock_parent_image_cache, 0, handle_connect); + Context* ctx = new LambdaContext([](bool reg) { + ASSERT_EQ(reg, true); + }); + expect_cache_register(*mock_parent_image_cache, ctx, 0); + expect_io_object_dispatcher_register_state(*mock_parent_image_cache, 0); + expect_cache_close(*mock_parent_image_cache, 0); + expect_cache_stop(*mock_parent_image_cache, 0); + + mock_parent_image_cache->init(); + conn_cond.wait(); + + ASSERT_EQ(mock_parent_image_cache->get_dispatch_layer(), + io::OBJECT_DISPATCH_LAYER_PARENT_CACHE); + expect_cache_session_state(*mock_parent_image_cache, true); + ASSERT_EQ(mock_parent_image_cache->get_cache_client()->is_session_work(), + true); + + EXPECT_CALL(*(mock_parent_image_cache->get_cache_client()), is_session_work()) + .WillOnce(Return(true)); + + expect_cache_lookup_object(*mock_parent_image_cache, ""); + + io::ReadExtents extents = {{0, 4096}}; + expect_read_parent(mock_plugin_api, 0, &extents, CEPH_NOSNAP, 0); + + C_SaferCond on_dispatched; + io::DispatchResult dispatch_result; + mock_parent_image_cache->read( + 0, &extents, mock_image_ctx.get_data_io_context(), 0, 0, {}, nullptr, + nullptr, &dispatch_result, nullptr, &on_dispatched); + ASSERT_EQ(0, on_dispatched.wait()); + + mock_parent_image_cache->get_cache_client()->close(); + mock_parent_image_cache->get_cache_client()->stop(); + delete mock_parent_image_cache; +} + +} // namespace librbd |