X-Git-Url: https://gerrit.opnfv.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fceph%2Fsrc%2Ftest%2Flibrbd%2Fexclusive_lock%2Ftest_mock_PreReleaseRequest.cc;fp=src%2Fceph%2Fsrc%2Ftest%2Flibrbd%2Fexclusive_lock%2Ftest_mock_PreReleaseRequest.cc;h=44aa012568d12d935408ad6398146e2e806cb153;hb=812ff6ca9fcd3e629e49d4328905f33eee8ca3f5;hp=0000000000000000000000000000000000000000;hpb=15280273faafb77777eab341909a3f495cf248d9;p=stor4nfv.git diff --git a/src/ceph/src/test/librbd/exclusive_lock/test_mock_PreReleaseRequest.cc b/src/ceph/src/test/librbd/exclusive_lock/test_mock_PreReleaseRequest.cc new file mode 100644 index 0000000..44aa012 --- /dev/null +++ b/src/ceph/src/test/librbd/exclusive_lock/test_mock_PreReleaseRequest.cc @@ -0,0 +1,301 @@ +// -*- 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 "test/librbd/mock/MockJournal.h" +#include "test/librbd/mock/MockObjectMap.h" +#include "test/librados_test_stub/MockTestMemIoCtxImpl.h" +#include "common/AsyncOpTracker.h" +#include "librbd/exclusive_lock/PreReleaseRequest.h" +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include + +// template definitions +#include "librbd/exclusive_lock/PreReleaseRequest.cc" +template class librbd::exclusive_lock::PreReleaseRequest; + +namespace librbd { + +namespace exclusive_lock { + +namespace { + +struct MockContext : public Context { + MOCK_METHOD1(complete, void(int)); + MOCK_METHOD1(finish, void(int)); +}; + +} // anonymous namespace + +using ::testing::_; +using ::testing::InSequence; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::StrEq; +using ::testing::WithArg; + +static const std::string TEST_COOKIE("auto 123"); + +class TestMockExclusiveLockPreReleaseRequest : public TestMockFixture { +public: + typedef PreReleaseRequest MockPreReleaseRequest; + + void expect_complete_context(MockContext &mock_context, int r) { + EXPECT_CALL(mock_context, complete(r)); + } + + void expect_test_features(MockImageCtx &mock_image_ctx, uint64_t features, + bool enabled) { + EXPECT_CALL(mock_image_ctx, test_features(features)) + .WillOnce(Return(enabled)); + } + + void expect_set_require_lock(MockImageCtx &mock_image_ctx, + librbd::io::Direction direction, bool enabled) { + EXPECT_CALL(*mock_image_ctx.io_work_queue, set_require_lock(direction, + enabled)); + } + + void expect_block_writes(MockImageCtx &mock_image_ctx, int r) { + expect_test_features(mock_image_ctx, RBD_FEATURE_JOURNALING, + ((mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0)); + if (mock_image_ctx.clone_copy_on_read || + (mock_image_ctx.features & RBD_FEATURE_JOURNALING) != 0) { + expect_set_require_lock(mock_image_ctx, librbd::io::DIRECTION_BOTH, true); + } else { + expect_set_require_lock(mock_image_ctx, librbd::io::DIRECTION_WRITE, + true); + } + EXPECT_CALL(*mock_image_ctx.io_work_queue, block_writes(_)) + .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_unblock_writes(MockImageCtx &mock_image_ctx) { + EXPECT_CALL(*mock_image_ctx.io_work_queue, unblock_writes()); + } + + void expect_cancel_op_requests(MockImageCtx &mock_image_ctx, int r) { + EXPECT_CALL(mock_image_ctx, cancel_async_requests(_)) + .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_close_journal(MockImageCtx &mock_image_ctx, + MockJournal &mock_journal, int r) { + EXPECT_CALL(mock_journal, close(_)) + .WillOnce(CompleteContext(r, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_close_object_map(MockImageCtx &mock_image_ctx, + MockObjectMap &mock_object_map) { + EXPECT_CALL(mock_object_map, close(_)) + .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_invalidate_cache(MockImageCtx &mock_image_ctx, bool purge, + int r) { + if (mock_image_ctx.object_cacher != nullptr) { + EXPECT_CALL(mock_image_ctx, invalidate_cache(purge, _)) + .WillOnce(WithArg<1>(CompleteContext(r, static_cast(NULL)))); + } + } + + void expect_is_cache_empty(MockImageCtx &mock_image_ctx, bool empty) { + if (mock_image_ctx.object_cacher != nullptr) { + EXPECT_CALL(mock_image_ctx, is_cache_empty()) + .WillOnce(Return(empty)); + } + } + + void expect_flush_notifies(MockImageCtx &mock_image_ctx) { + EXPECT_CALL(*mock_image_ctx.image_watcher, flush(_)) + .WillOnce(CompleteContext(0, mock_image_ctx.image_ctx->op_work_queue)); + } + + void expect_prepare_lock(MockImageCtx &mock_image_ctx) { + EXPECT_CALL(*mock_image_ctx.state, prepare_lock(_)) + .WillOnce(Invoke([](Context *on_ready) { + on_ready->complete(0); + })); + } + + void expect_handle_prepare_lock_complete(MockImageCtx &mock_image_ctx) { + EXPECT_CALL(*mock_image_ctx.state, handle_prepare_lock_complete()); + } + + AsyncOpTracker m_async_op_tracker; +}; + +TEST_F(TestMockExclusiveLockPreReleaseRequest, Success) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + + expect_prepare_lock(mock_image_ctx); + expect_cancel_op_requests(mock_image_ctx, 0); + expect_block_writes(mock_image_ctx, 0); + expect_invalidate_cache(mock_image_ctx, false, 0); + expect_flush_notifies(mock_image_ctx); + + MockJournal *mock_journal = new MockJournal(); + mock_image_ctx.journal = mock_journal; + expect_close_journal(mock_image_ctx, *mock_journal, -EINVAL); + + MockObjectMap *mock_object_map = new MockObjectMap(); + mock_image_ctx.object_map = mock_object_map; + expect_close_object_map(mock_image_ctx, *mock_object_map); + + expect_handle_prepare_lock_complete(mock_image_ctx); + + C_SaferCond ctx; + MockPreReleaseRequest *req = MockPreReleaseRequest::create( + mock_image_ctx, false, m_async_op_tracker, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessJournalDisabled) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + + expect_block_writes(mock_image_ctx, 0); + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_prepare_lock(mock_image_ctx); + expect_cancel_op_requests(mock_image_ctx, 0); + expect_invalidate_cache(mock_image_ctx, false, 0); + expect_flush_notifies(mock_image_ctx); + + MockObjectMap *mock_object_map = new MockObjectMap(); + mock_image_ctx.object_map = mock_object_map; + expect_close_object_map(mock_image_ctx, *mock_object_map); + + expect_handle_prepare_lock_complete(mock_image_ctx); + + C_SaferCond ctx; + MockPreReleaseRequest *req = MockPreReleaseRequest::create( + mock_image_ctx, false, m_async_op_tracker, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockExclusiveLockPreReleaseRequest, SuccessObjectMapDisabled) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + + expect_block_writes(mock_image_ctx, 0); + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_cancel_op_requests(mock_image_ctx, 0); + expect_invalidate_cache(mock_image_ctx, false, 0); + expect_flush_notifies(mock_image_ctx); + + C_SaferCond release_ctx; + C_SaferCond ctx; + MockPreReleaseRequest *req = MockPreReleaseRequest::create( + mock_image_ctx, true, m_async_op_tracker, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockExclusiveLockPreReleaseRequest, Blacklisted) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_prepare_lock(mock_image_ctx); + expect_cancel_op_requests(mock_image_ctx, 0); + expect_block_writes(mock_image_ctx, -EBLACKLISTED); + expect_invalidate_cache(mock_image_ctx, false, -EBLACKLISTED); + expect_is_cache_empty(mock_image_ctx, false); + expect_invalidate_cache(mock_image_ctx, true, -EBLACKLISTED); + expect_is_cache_empty(mock_image_ctx, true); + expect_flush_notifies(mock_image_ctx); + + MockJournal *mock_journal = new MockJournal(); + mock_image_ctx.journal = mock_journal; + expect_close_journal(mock_image_ctx, *mock_journal, -EBLACKLISTED); + + MockObjectMap *mock_object_map = new MockObjectMap(); + mock_image_ctx.object_map = mock_object_map; + expect_close_object_map(mock_image_ctx, *mock_object_map); + + expect_handle_prepare_lock_complete(mock_image_ctx); + + C_SaferCond ctx; + MockPreReleaseRequest *req = MockPreReleaseRequest::create( + mock_image_ctx, false, m_async_op_tracker, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +TEST_F(TestMockExclusiveLockPreReleaseRequest, BlockWritesError) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_cancel_op_requests(mock_image_ctx, 0); + expect_block_writes(mock_image_ctx, -EINVAL); + expect_unblock_writes(mock_image_ctx); + + C_SaferCond ctx; + MockPreReleaseRequest *req = MockPreReleaseRequest::create( + mock_image_ctx, true, m_async_op_tracker, &ctx); + req->send(); + ASSERT_EQ(-EINVAL, ctx.wait()); +} + +TEST_F(TestMockExclusiveLockPreReleaseRequest, UnlockError) { + REQUIRE_FEATURE(RBD_FEATURE_EXCLUSIVE_LOCK); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + + MockImageCtx mock_image_ctx(*ictx); + + expect_op_work_queue(mock_image_ctx); + + InSequence seq; + expect_cancel_op_requests(mock_image_ctx, 0); + expect_block_writes(mock_image_ctx, 0); + expect_invalidate_cache(mock_image_ctx, false, 0); + expect_flush_notifies(mock_image_ctx); + + C_SaferCond ctx; + MockPreReleaseRequest *req = MockPreReleaseRequest::create( + mock_image_ctx, true, m_async_op_tracker, &ctx); + req->send(); + ASSERT_EQ(0, ctx.wait()); +} + +} // namespace exclusive_lock +} // namespace librbd