summaryrefslogtreecommitdiffstats
path: root/src/test/librbd/crypto/test_mock_FormatRequest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/librbd/crypto/test_mock_FormatRequest.cc')
-rw-r--r--src/test/librbd/crypto/test_mock_FormatRequest.cc195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/test/librbd/crypto/test_mock_FormatRequest.cc b/src/test/librbd/crypto/test_mock_FormatRequest.cc
new file mode 100644
index 000000000..2008deb68
--- /dev/null
+++ b/src/test/librbd/crypto/test_mock_FormatRequest.cc
@@ -0,0 +1,195 @@
+// -*- 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/crypto/MockCryptoInterface.h"
+#include "test/librbd/mock/crypto/MockEncryptionFormat.h"
+#include "librbd/crypto/Utils.h"
+
+namespace librbd {
+namespace util {
+
+inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
+ return image_ctx->image_ctx;
+}
+
+} // namespace util
+} // namespace librbd
+
+#include "librbd/crypto/FormatRequest.cc"
+
+namespace librbd {
+namespace crypto {
+
+namespace util {
+
+template <> void set_crypto(
+ MockImageCtx *image_ctx, ceph::ref_t<CryptoInterface> crypto) {
+ image_ctx->crypto = crypto.get();
+}
+
+} // namespace util
+
+using ::testing::_;
+using ::testing::Invoke;
+using ::testing::Return;
+using ::testing::WithArg;
+
+template <>
+struct ShutDownCryptoRequest<MockImageCtx> {
+ Context *on_finish = nullptr;
+ static ShutDownCryptoRequest *s_instance;
+ static ShutDownCryptoRequest *create(
+ MockImageCtx* image_ctx, Context *on_finish) {
+ ceph_assert(s_instance != nullptr);
+ s_instance->on_finish = on_finish;
+ return s_instance;
+ }
+
+ MOCK_METHOD0(send, void());
+
+ ShutDownCryptoRequest() {
+ s_instance = this;
+ }
+};
+
+ShutDownCryptoRequest<MockImageCtx> *ShutDownCryptoRequest<
+ MockImageCtx>::s_instance = nullptr;
+
+struct TestMockCryptoFormatRequest : public TestMockFixture {
+ typedef FormatRequest<librbd::MockImageCtx> MockFormatRequest;
+ typedef ShutDownCryptoRequest<MockImageCtx> MockShutDownCryptoRequest;
+
+ MockImageCtx* mock_image_ctx;
+ C_SaferCond finished_cond;
+ Context *on_finish = &finished_cond;
+ MockEncryptionFormat* mock_encryption_format;
+ Context* format_context;
+ MockCryptoInterface* crypto;
+ MockCryptoInterface* old_crypto;
+ MockFormatRequest* mock_format_request;
+ std::string key = std::string(64, '0');
+
+ void SetUp() override {
+ TestMockFixture::SetUp();
+
+ librbd::ImageCtx *ictx;
+ ASSERT_EQ(0, open_image(m_image_name, &ictx));
+ mock_image_ctx = new MockImageCtx(*ictx);
+ mock_encryption_format = new MockEncryptionFormat();
+ crypto = new MockCryptoInterface();
+ old_crypto = new MockCryptoInterface();
+ mock_image_ctx->crypto = old_crypto;
+ mock_format_request = MockFormatRequest::create(
+ mock_image_ctx,
+ std::unique_ptr<MockEncryptionFormat>(mock_encryption_format),
+ on_finish);
+ }
+
+ void TearDown() override {
+ crypto->put();
+ old_crypto->put();
+ delete mock_image_ctx;
+ TestMockFixture::TearDown();
+ }
+
+ void expect_test_journal_feature(bool has_journal=false) {
+ EXPECT_CALL(*mock_image_ctx, test_features(
+ RBD_FEATURE_JOURNALING)).WillOnce(Return(has_journal));
+ }
+
+ void expect_encryption_format() {
+ EXPECT_CALL(*mock_encryption_format, format(
+ mock_image_ctx, _)).WillOnce(
+ WithArg<1>(Invoke([this](Context* ctx) {
+ format_context = ctx;
+ })));
+ }
+
+ void expect_image_flush(int r) {
+ 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);
+ }));
+ }
+};
+
+TEST_F(TestMockCryptoFormatRequest, JournalEnabled) {
+ expect_test_journal_feature(true);
+ mock_format_request->send();
+ ASSERT_EQ(-ENOTSUP, finished_cond.wait());
+ ASSERT_EQ(old_crypto, mock_image_ctx->crypto);
+}
+
+TEST_F(TestMockCryptoFormatRequest, FailShutDownCrypto) {
+ expect_test_journal_feature(false);
+ MockShutDownCryptoRequest mock_shutdown_crypto_request;
+ EXPECT_CALL(mock_shutdown_crypto_request, send());
+ mock_format_request->send();
+ ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0));
+ mock_shutdown_crypto_request.on_finish->complete(-EIO);
+ ASSERT_EQ(-EIO, finished_cond.wait());
+ ASSERT_EQ(old_crypto, mock_image_ctx->crypto);
+}
+
+TEST_F(TestMockCryptoFormatRequest, FormatFail) {
+ mock_image_ctx->crypto = nullptr;
+ expect_test_journal_feature(false);
+ expect_encryption_format();
+ mock_format_request->send();
+ ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0));
+ format_context->complete(-EIO);
+ ASSERT_EQ(-EIO, finished_cond.wait());
+ ASSERT_EQ(nullptr, mock_image_ctx->crypto);
+}
+
+TEST_F(TestMockCryptoFormatRequest, Success) {
+ mock_image_ctx->crypto = nullptr;
+ expect_test_journal_feature(false);
+ expect_encryption_format();
+ mock_format_request->send();
+ ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0));
+ expect_image_flush(0);
+ EXPECT_CALL(*mock_encryption_format, get_crypto()).WillOnce(Return(crypto));
+ format_context->complete(0);
+ ASSERT_EQ(0, finished_cond.wait());
+ ASSERT_EQ(crypto, mock_image_ctx->crypto);
+}
+
+TEST_F(TestMockCryptoFormatRequest, FailFlush) {
+ mock_image_ctx->crypto = nullptr;
+ expect_test_journal_feature(false);
+ expect_encryption_format();
+ mock_format_request->send();
+ ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0));
+ expect_image_flush(-EIO);
+ format_context->complete(0);
+ ASSERT_EQ(-EIO, finished_cond.wait());
+ ASSERT_EQ(nullptr, mock_image_ctx->crypto);
+}
+
+TEST_F(TestMockCryptoFormatRequest, CryptoAlreadyLoaded) {
+ expect_test_journal_feature(false);
+ MockShutDownCryptoRequest mock_shutdown_crypto_request;
+ EXPECT_CALL(mock_shutdown_crypto_request, send());
+ mock_format_request->send();
+ ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0));
+ expect_encryption_format();
+ mock_shutdown_crypto_request.on_finish->complete(0);
+ ASSERT_EQ(ETIMEDOUT, finished_cond.wait_for(0));
+ expect_image_flush(0);
+ EXPECT_CALL(*mock_encryption_format, get_crypto()).WillOnce(Return(crypto));
+ format_context->complete(0);
+ ASSERT_EQ(0, finished_cond.wait());
+ ASSERT_EQ(crypto, mock_image_ctx->crypto);
+}
+
+} // namespace crypto
+} // namespace librbd