summaryrefslogtreecommitdiffstats
path: root/src/test/librbd/crypto/test_mock_LoadRequest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:54:28 +0000
commite6918187568dbd01842d8d1d2c808ce16a894239 (patch)
tree64f88b554b444a49f656b6c656111a145cbbaa28 /src/test/librbd/crypto/test_mock_LoadRequest.cc
parentInitial commit. (diff)
downloadceph-upstream/18.2.2.tar.xz
ceph-upstream/18.2.2.zip
Adding upstream version 18.2.2.upstream/18.2.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/librbd/crypto/test_mock_LoadRequest.cc')
-rw-r--r--src/test/librbd/crypto/test_mock_LoadRequest.cc382
1 files changed, 382 insertions, 0 deletions
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<MockEncryptionFormat> 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<librbd::MockTestImageCtx> 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<std::unique_ptr<MockEncryptionFormat>> 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<MockEncryptionFormat>(
+ 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<io::ImageDispatchSpec::Flush>(
+ &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<std::unique_ptr<MockEncryptionFormat>> 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<std::unique_ptr<MockEncryptionFormat>> 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<std::unique_ptr<MockEncryptionFormat>> 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<std::unique_ptr<MockEncryptionFormat>> 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<MockImageCtx>::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<std::unique_ptr<MockEncryptionFormat>> 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<std::unique_ptr<MockEncryptionFormat>> 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<std::unique_ptr<MockEncryptionFormat>> 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