From e6918187568dbd01842d8d1d2c808ce16a894239 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:54:28 +0200 Subject: Adding upstream version 18.2.2. Signed-off-by: Daniel Baumann --- src/test/librbd/crypto/test_mock_LoadRequest.cc | 382 ++++++++++++++++++++++++ 1 file changed, 382 insertions(+) create mode 100644 src/test/librbd/crypto/test_mock_LoadRequest.cc (limited to 'src/test/librbd/crypto/test_mock_LoadRequest.cc') diff --git a/src/test/librbd/crypto/test_mock_LoadRequest.cc b/src/test/librbd/crypto/test_mock_LoadRequest.cc new file mode 100644 index 000000000..849710d82 --- /dev/null +++ b/src/test/librbd/crypto/test_mock_LoadRequest.cc @@ -0,0 +1,382 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab + +#include "librbd/crypto/CryptoObjectDispatch.h" +#include "librbd/crypto/Utils.h" +#include "test/librbd/test_mock_fixture.h" +#include "test/librbd/test_support.h" +#include "test/librbd/mock/MockImageCtx.h" +#include "test/librbd/mock/crypto/MockCryptoInterface.h" +#include "test/librbd/mock/crypto/MockEncryptionFormat.h" +#include "test/librbd/mock/io/MockObjectDispatch.h" + +namespace librbd { + +namespace { + +struct MockTestImageCtx : public MockImageCtx { + MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) { + } + + MockTestImageCtx *parent = nullptr; +}; + +} // anonymous namespace + +namespace util { + +inline ImageCtx *get_image_ctx(MockTestImageCtx *image_ctx) { + return image_ctx->image_ctx; +} + +} // namespace util + +namespace crypto { +namespace util { + +template <> +void set_crypto(MockTestImageCtx *image_ctx, + std::unique_ptr encryption_format) { + image_ctx->encryption_format = std::move(encryption_format); +} + +} // namespace util +} // namespace crypto +} // namespace librbd + +#include "librbd/crypto/LoadRequest.cc" + +namespace librbd { +namespace crypto { + +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::WithArgs; + +struct TestMockCryptoLoadRequest : public TestMockFixture { + typedef LoadRequest MockLoadRequest; + + MockTestImageCtx* mock_image_ctx; + MockTestImageCtx* mock_parent_image_ctx; + C_SaferCond finished_cond; + Context *on_finish = &finished_cond; + MockEncryptionFormat* mock_encryption_format; + MockEncryptionFormat* cloned_encryption_format; + Context* load_context; + MockLoadRequest* mock_load_request; + + void SetUp() override { + TestMockFixture::SetUp(); + + librbd::ImageCtx *ictx; + ASSERT_EQ(0, open_image(m_image_name, &ictx)); + mock_image_ctx = new MockTestImageCtx(*ictx); + mock_parent_image_ctx = new MockTestImageCtx(*ictx); + mock_image_ctx->parent = mock_parent_image_ctx; + mock_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + mock_load_request = MockLoadRequest::create( + mock_image_ctx, std::move(formats), on_finish); + } + + void TearDown() override { + delete mock_image_ctx; + delete mock_parent_image_ctx; + TestMockFixture::TearDown(); + } + + void expect_test_journal_feature(MockTestImageCtx* ictx, + bool has_journal = false) { + EXPECT_CALL(*ictx, test_features( + RBD_FEATURE_JOURNALING)).WillOnce(Return(has_journal)); + } + + void expect_encryption_load(MockEncryptionFormat* encryption_format, + MockTestImageCtx* ictx, + std::string detected_format = "SOMEFORMAT") { + EXPECT_CALL(*encryption_format, load( + ictx, _, _)).WillOnce( + WithArgs<1, 2>(Invoke([this, detected_format]( + std::string* detected_format_name, Context* ctx) { + if (!detected_format.empty()) { + *detected_format_name = detected_format; + } + load_context = ctx; + }))); + } + + void expect_encryption_format_clone(MockEncryptionFormat* encryption_format) { + cloned_encryption_format = new MockEncryptionFormat(); + EXPECT_CALL(*encryption_format, clone()).WillOnce( + Invoke([this]() { + return std::unique_ptr( + cloned_encryption_format); + })); + } + + void expect_image_flush(int r = 0) { + EXPECT_CALL(*mock_image_ctx->io_image_dispatcher, send(_)).WillOnce( + Invoke([r](io::ImageDispatchSpec* spec) { + ASSERT_TRUE(boost::get( + &spec->request) != nullptr); + spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE; + spec->aio_comp->set_request_count(1); + spec->aio_comp->add_request(); + spec->aio_comp->complete_request(r); + })); + } + + void expect_invalidate_cache(int r = 0) { + EXPECT_CALL(*mock_image_ctx->io_image_dispatcher, + invalidate_cache(_)).WillOnce( + Invoke([r](Context* ctx) { + ctx->complete(r); + })); + } +}; + +TEST_F(TestMockCryptoLoadRequest, NoFormats) { + delete mock_load_request; + std::vector> formats; + mock_load_request = MockLoadRequest::create( + mock_image_ctx, std::move(formats), on_finish); + mock_load_request->send(); + ASSERT_EQ(-EINVAL, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, CryptoAlreadyLoaded) { + mock_image_ctx->encryption_format.reset(new MockEncryptionFormat()); + mock_load_request->send(); + ASSERT_EQ(-EEXIST, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, JournalEnabled) { + expect_test_journal_feature(mock_image_ctx, true); + mock_load_request->send(); + ASSERT_EQ(-ENOTSUP, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, JournalEnabledOnParent) { + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx, true); + mock_load_request->send(); + ASSERT_EQ(-ENOTSUP, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, LoadFail) { + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + load_context->complete(-EINVAL); + ASSERT_EQ(-EINVAL, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, Success) { + delete mock_load_request; + mock_image_ctx->parent = nullptr; + mock_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + mock_load_request = MockLoadRequest::create( + mock_image_ctx, std::move(formats), on_finish); + expect_test_journal_feature(mock_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_invalidate_cache(); + load_context->complete(0); + ASSERT_EQ(0, finished_cond.wait()); + ASSERT_EQ(mock_encryption_format, mock_image_ctx->encryption_format.get()); +} + +TEST_F(TestMockCryptoLoadRequest, FlushFail) { + delete mock_load_request; + mock_image_ctx->parent = nullptr; + mock_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + mock_load_request = MockLoadRequest::create( + mock_image_ctx, std::move(formats), on_finish); + expect_test_journal_feature(mock_image_ctx); + expect_image_flush(-EIO); + mock_load_request->send(); + ASSERT_EQ(-EIO, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, InvalidateCacheFail) { + delete mock_load_request; + mock_image_ctx->parent = nullptr; + mock_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + mock_load_request = MockLoadRequest::create( + mock_image_ctx, std::move(formats), on_finish); + expect_test_journal_feature(mock_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_invalidate_cache(-EIO); + load_context->complete(0); + ASSERT_EQ(-EIO, finished_cond.wait()); +} + +TEST_F(TestMockCryptoLoadRequest, LoadClonedEncryptedParent) { + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_encryption_format_clone(mock_encryption_format); + expect_encryption_load(cloned_encryption_format, mock_parent_image_ctx); + load_context->complete(0); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_invalidate_cache(); + load_context->complete(0); + ASSERT_EQ(0, finished_cond.wait()); + ASSERT_EQ(mock_encryption_format, mock_image_ctx->encryption_format.get()); + ASSERT_EQ(cloned_encryption_format, + mock_parent_image_ctx->encryption_format.get()); +} + +TEST_F(TestMockCryptoLoadRequest, LoadClonedParentFail) { + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_encryption_format_clone(mock_encryption_format); + expect_encryption_load(cloned_encryption_format, mock_parent_image_ctx); + load_context->complete(0); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + load_context->complete(-EIO); + ASSERT_EQ(-EIO, finished_cond.wait()); + ASSERT_EQ(nullptr, mock_image_ctx->encryption_format.get()); + ASSERT_EQ(nullptr, mock_parent_image_ctx->encryption_format.get()); +} + + +TEST_F(TestMockCryptoLoadRequest, LoadClonedPlaintextParent) { + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_encryption_format_clone(mock_encryption_format); + expect_encryption_load( + cloned_encryption_format, mock_parent_image_ctx, + LoadRequest::UNKNOWN_FORMAT); + load_context->complete(0); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_invalidate_cache(); + load_context->complete(-EINVAL); + ASSERT_EQ(0, finished_cond.wait()); + ASSERT_EQ(mock_encryption_format, mock_image_ctx->encryption_format.get()); + ASSERT_EQ(nullptr, mock_parent_image_ctx->encryption_format.get()); +} + +TEST_F(TestMockCryptoLoadRequest, LoadClonedParentDetectionError) { + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_encryption_format_clone(mock_encryption_format); + expect_encryption_load( + cloned_encryption_format, mock_parent_image_ctx, ""); + load_context->complete(0); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + load_context->complete(-EINVAL); + ASSERT_EQ(-EINVAL, finished_cond.wait()); + ASSERT_EQ(nullptr, mock_image_ctx->encryption_format.get()); + ASSERT_EQ(nullptr, mock_parent_image_ctx->encryption_format.get()); +} + +TEST_F(TestMockCryptoLoadRequest, LoadParentFail) { + delete mock_load_request; + mock_encryption_format = new MockEncryptionFormat(); + auto mock_parent_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + formats.emplace_back(mock_parent_encryption_format); + mock_load_request = MockLoadRequest::create( + mock_image_ctx, + std::move(formats), + on_finish); + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_encryption_load(mock_parent_encryption_format, mock_parent_image_ctx); + load_context->complete(0); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + load_context->complete(-EINVAL); + ASSERT_EQ(-EINVAL, finished_cond.wait()); + ASSERT_EQ(nullptr, mock_image_ctx->encryption_format.get()); + ASSERT_EQ(nullptr, mock_parent_image_ctx->encryption_format.get()); +} + +TEST_F(TestMockCryptoLoadRequest, EncryptedParent) { + delete mock_load_request; + mock_encryption_format = new MockEncryptionFormat(); + auto mock_parent_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + formats.emplace_back(mock_parent_encryption_format); + mock_load_request = MockLoadRequest::create( + mock_image_ctx, + std::move(formats), + on_finish); + expect_test_journal_feature(mock_image_ctx); + expect_test_journal_feature(mock_parent_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_encryption_load(mock_parent_encryption_format, mock_parent_image_ctx); + load_context->complete(0); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + expect_invalidate_cache(); + load_context->complete(0); + ASSERT_EQ(0, finished_cond.wait()); + ASSERT_EQ(mock_encryption_format, mock_image_ctx->encryption_format.get()); + ASSERT_EQ(mock_parent_encryption_format, + mock_parent_image_ctx->encryption_format.get()); +} + +TEST_F(TestMockCryptoLoadRequest, TooManyFormats) { + delete mock_load_request; + mock_encryption_format = new MockEncryptionFormat(); + auto mock_parent_encryption_format = new MockEncryptionFormat(); + std::vector> formats; + formats.emplace_back(mock_encryption_format); + formats.emplace_back(mock_parent_encryption_format); + mock_image_ctx->parent = nullptr; + mock_load_request = MockLoadRequest::create( + mock_image_ctx, + std::move(formats), + on_finish); + expect_test_journal_feature(mock_image_ctx); + expect_image_flush(); + expect_encryption_load(mock_encryption_format, mock_image_ctx); + mock_load_request->send(); + ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0)); + load_context->complete(0); + ASSERT_EQ(-EINVAL, finished_cond.wait()); + ASSERT_EQ(nullptr, mock_image_ctx->encryption_format.get()); +} + +} // namespace crypto +} // namespace librbd -- cgit v1.2.3