1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 #include "test/librbd/test_mock_fixture.h"
5 #include "test/librbd/test_support.h"
6 #include "test/librbd/mock/MockImageCtx.h"
7 #include "test/librbd/mock/crypto/MockCryptoInterface.h"
8 #include "test/librbd/mock/crypto/MockEncryptionFormat.h"
14 struct MockTestImageCtx
: public MockImageCtx
{
15 MockTestImageCtx(ImageCtx
&image_ctx
) : MockImageCtx(image_ctx
) {
19 } // anonymous namespace
23 inline ImageCtx
*get_image_ctx(MockImageCtx
*image_ctx
) {
24 return image_ctx
->image_ctx
;
30 #include "librbd/crypto/luks/FlattenRequest.cc"
37 using ::testing::Invoke
;
38 using ::testing::Return
;
40 struct TestMockCryptoLuksFlattenRequest
: public TestMockFixture
{
41 typedef FlattenRequest
<MockTestImageCtx
> MockFlattenRequest
;
43 const size_t OBJECT_SIZE
= 4 * 1024 * 1024;
44 const uint64_t DATA_OFFSET
= MockCryptoInterface::DATA_OFFSET
;
45 const char* passphrase_cstr
= "password";
46 std::string passphrase
= passphrase_cstr
;
48 MockTestImageCtx
* mock_image_ctx
;
49 MockFlattenRequest
* mock_flatten_request
;
50 MockEncryptionFormat
* mock_encryption_format
;
51 MockCryptoInterface mock_crypto
;
52 C_SaferCond finished_cond
;
53 Context
*on_finish
= &finished_cond
;
54 Context
* image_read_request
;
55 io::AioCompletion
* aio_comp
;
56 ceph::bufferlist header_bl
;
58 void SetUp() override
{
59 TestMockFixture::SetUp();
61 librbd::ImageCtx
*ictx
;
62 ASSERT_EQ(0, open_image(m_image_name
, &ictx
));
63 mock_image_ctx
= new MockTestImageCtx(*ictx
);
64 mock_encryption_format
= new MockEncryptionFormat();
65 mock_image_ctx
->encryption_format
.reset(mock_encryption_format
);
66 mock_flatten_request
= MockFlattenRequest::create(
67 mock_image_ctx
, on_finish
);
70 void TearDown() override
{
71 delete mock_image_ctx
;
72 TestMockFixture::TearDown();
75 void generate_header(const char* type
, const char* alg
, size_t key_size
,
76 const char* cipher_mode
, uint32_t sector_size
,
77 bool magic_switched
) {
78 Header
header(mock_image_ctx
->cct
);
80 ASSERT_EQ(0, header
.init());
81 ASSERT_EQ(0, header
.format(type
, alg
, nullptr, key_size
, cipher_mode
,
82 sector_size
, OBJECT_SIZE
, true));
83 ASSERT_EQ(0, header
.add_keyslot(passphrase_cstr
, strlen(passphrase_cstr
)));
84 ASSERT_LT(0, header
.read(&header_bl
));
86 ASSERT_EQ(0, Magic::replace_magic(mock_image_ctx
->cct
, header_bl
));
90 void expect_get_crypto() {
91 EXPECT_CALL(*mock_encryption_format
, get_crypto()).WillOnce(
92 Return(&mock_crypto
));
95 void expect_image_read(uint64_t offset
, uint64_t length
) {
96 EXPECT_CALL(*mock_image_ctx
->io_image_dispatcher
, send(_
))
97 .WillOnce(Invoke([this, offset
,
98 length
](io::ImageDispatchSpec
* spec
) {
99 auto* read
= boost::get
<io::ImageDispatchSpec::Read
>(
101 ASSERT_TRUE(read
!= nullptr);
103 ASSERT_EQ(1, spec
->image_extents
.size());
104 ASSERT_EQ(offset
, spec
->image_extents
[0].first
);
105 ASSERT_EQ(length
, spec
->image_extents
[0].second
);
107 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
108 auto aio_comp
= spec
->aio_comp
;
109 aio_comp
->set_request_count(1);
110 aio_comp
->read_result
= std::move(read
->read_result
);
111 aio_comp
->read_result
.set_image_extents(spec
->image_extents
);
112 auto ctx
= new io::ReadResult::C_ImageReadRequest(
113 aio_comp
, 0, spec
->image_extents
);
114 if (header_bl
.length() < offset
+ length
) {
115 header_bl
.append_zero(offset
+ length
- header_bl
.length());
117 ctx
->bl
.substr_of(header_bl
, offset
, length
);
118 image_read_request
= ctx
;
122 void expect_image_write() {
123 EXPECT_CALL(*mock_image_ctx
->io_image_dispatcher
, send(_
))
124 .WillOnce(Invoke([this](io::ImageDispatchSpec
* spec
) {
125 auto* write
= boost::get
<io::ImageDispatchSpec::Write
>(
127 ASSERT_TRUE(write
!= nullptr);
129 ASSERT_EQ(1, spec
->image_extents
.size());
130 ASSERT_EQ(0, spec
->image_extents
[0].first
);
131 ASSERT_GT(spec
->image_extents
[0].second
, 0);
133 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
134 aio_comp
= spec
->aio_comp
;
136 // patch header_bl with write
138 bl
.substr_of(header_bl
, write
->bl
.length(),
139 header_bl
.length() - write
->bl
.length());
140 header_bl
= write
->bl
;
141 header_bl
.claim_append(bl
);
145 void expect_image_flush(int r
) {
146 EXPECT_CALL(*mock_image_ctx
->io_image_dispatcher
, send(_
)).WillOnce(
147 Invoke([r
](io::ImageDispatchSpec
* spec
) {
148 ASSERT_TRUE(boost::get
<io::ImageDispatchSpec::Flush
>(
149 &spec
->request
) != nullptr);
150 spec
->dispatch_result
= io::DISPATCH_RESULT_COMPLETE
;
151 spec
->aio_comp
->set_request_count(1);
152 spec
->aio_comp
->add_request();
153 spec
->aio_comp
->complete_request(r
);
157 void complete_aio(int r
) {
161 aio_comp
->set_request_count(1);
162 aio_comp
->add_request();
163 aio_comp
->complete_request(r
);
167 void verify_header(const char* expected_format
) {
168 Header
header(mock_image_ctx
->cct
);
170 ASSERT_EQ(0, header
.init());
171 ASSERT_EQ(0, header
.write(header_bl
));
172 ASSERT_EQ(0, header
.load(expected_format
));
176 TEST_F(TestMockCryptoLuksFlattenRequest
, LUKS1
) {
177 generate_header(CRYPT_LUKS1
, "aes", 32, "xts-plain64", 512, true);
179 expect_image_read(0, DATA_OFFSET
);
180 mock_flatten_request
->send();
181 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
182 expect_image_write();
183 image_read_request
->complete(DATA_OFFSET
);
184 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
185 expect_image_flush(0);
187 ASSERT_EQ(0, finished_cond
.wait());
188 ASSERT_NO_FATAL_FAILURE(verify_header(CRYPT_LUKS1
));
189 ASSERT_EQ(mock_encryption_format
, mock_image_ctx
->encryption_format
.get());
192 TEST_F(TestMockCryptoLuksFlattenRequest
, LUKS2
) {
193 generate_header(CRYPT_LUKS2
, "aes", 32, "xts-plain64", 4096, true);
195 expect_image_read(0, DATA_OFFSET
);
196 mock_flatten_request
->send();
197 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
198 expect_image_write();
199 image_read_request
->complete(DATA_OFFSET
);
200 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
201 expect_image_flush(0);
203 ASSERT_EQ(0, finished_cond
.wait());
204 ASSERT_NO_FATAL_FAILURE(verify_header(CRYPT_LUKS2
));
205 ASSERT_EQ(mock_encryption_format
, mock_image_ctx
->encryption_format
.get());
208 TEST_F(TestMockCryptoLuksFlattenRequest
, FailedRead
) {
209 generate_header(CRYPT_LUKS2
, "aes", 32, "xts-plain64", 4096, true);
211 expect_image_read(0, DATA_OFFSET
);
212 mock_flatten_request
->send();
213 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
214 image_read_request
->complete(-EIO
);
215 ASSERT_EQ(-EIO
, finished_cond
.wait());
216 ASSERT_EQ(mock_encryption_format
, mock_image_ctx
->encryption_format
.get());
219 TEST_F(TestMockCryptoLuksFlattenRequest
, AlreadyFlattened
) {
220 generate_header(CRYPT_LUKS2
, "aes", 32, "xts-plain64", 4096, false);
222 expect_image_read(0, DATA_OFFSET
);
223 mock_flatten_request
->send();
224 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
225 expect_image_write();
226 image_read_request
->complete(DATA_OFFSET
);
227 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
228 expect_image_flush(0);
230 ASSERT_EQ(0, finished_cond
.wait());
231 ASSERT_NO_FATAL_FAILURE(verify_header(CRYPT_LUKS2
));
232 ASSERT_EQ(mock_encryption_format
, mock_image_ctx
->encryption_format
.get());
235 TEST_F(TestMockCryptoLuksFlattenRequest
, FailedWrite
) {
236 generate_header(CRYPT_LUKS2
, "aes", 32, "xts-plain64", 4096, true);
238 expect_image_read(0, DATA_OFFSET
);
239 mock_flatten_request
->send();
240 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
241 expect_image_write();
242 image_read_request
->complete(DATA_OFFSET
);
243 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
245 ASSERT_EQ(-EIO
, finished_cond
.wait());
246 ASSERT_EQ(mock_encryption_format
, mock_image_ctx
->encryption_format
.get());
249 TEST_F(TestMockCryptoLuksFlattenRequest
, FailedFlush
) {
250 generate_header(CRYPT_LUKS2
, "aes", 32, "xts-plain64", 4096, true);
252 expect_image_read(0, DATA_OFFSET
);
253 mock_flatten_request
->send();
254 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
255 expect_image_write();
256 image_read_request
->complete(DATA_OFFSET
);
257 ASSERT_EQ(ETIMEDOUT
, finished_cond
.wait_for(0));
258 expect_image_flush(-EIO
);
260 ASSERT_EQ(-EIO
, finished_cond
.wait());
261 ASSERT_EQ(mock_encryption_format
, mock_image_ctx
->encryption_format
.get());
265 } // namespace crypto
266 } // namespace librbd