]> git.proxmox.com Git - ceph.git/blob - ceph/src/test/librbd/crypto/luks/test_mock_FlattenRequest.cc
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / test / librbd / crypto / luks / test_mock_FlattenRequest.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
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"
9
10 namespace librbd {
11
12 namespace {
13
14 struct MockTestImageCtx : public MockImageCtx {
15 MockTestImageCtx(ImageCtx &image_ctx) : MockImageCtx(image_ctx) {
16 }
17 };
18
19 } // anonymous namespace
20
21 namespace util {
22
23 inline ImageCtx *get_image_ctx(MockImageCtx *image_ctx) {
24 return image_ctx->image_ctx;
25 }
26
27 } // namespace util
28 } // namespace librbd
29
30 #include "librbd/crypto/luks/FlattenRequest.cc"
31
32 namespace librbd {
33 namespace crypto {
34 namespace luks {
35
36 using ::testing::_;
37 using ::testing::Invoke;
38 using ::testing::Return;
39
40 struct TestMockCryptoLuksFlattenRequest : public TestMockFixture {
41 typedef FlattenRequest<MockTestImageCtx> MockFlattenRequest;
42
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;
47
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;
57
58 void SetUp() override {
59 TestMockFixture::SetUp();
60
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);
68 }
69
70 void TearDown() override {
71 delete mock_image_ctx;
72 TestMockFixture::TearDown();
73 }
74
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);
79
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));
85 if (magic_switched) {
86 ASSERT_EQ(0, Magic::replace_magic(mock_image_ctx->cct, header_bl));
87 }
88 }
89
90 void expect_get_crypto() {
91 EXPECT_CALL(*mock_encryption_format, get_crypto()).WillOnce(
92 Return(&mock_crypto));
93 }
94
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>(
100 &spec->request);
101 ASSERT_TRUE(read != nullptr);
102
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);
106
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());
116 }
117 ctx->bl.substr_of(header_bl, offset, length);
118 image_read_request = ctx;
119 }));
120 }
121
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>(
126 &spec->request);
127 ASSERT_TRUE(write != nullptr);
128
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);
132
133 spec->dispatch_result = io::DISPATCH_RESULT_COMPLETE;
134 aio_comp = spec->aio_comp;
135
136 // patch header_bl with write
137 bufferlist bl;
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);
142 }));
143 }
144
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);
154 }));
155 }
156
157 void complete_aio(int r) {
158 if (r < 0) {
159 aio_comp->fail(r);
160 } else {
161 aio_comp->set_request_count(1);
162 aio_comp->add_request();
163 aio_comp->complete_request(r);
164 }
165 }
166
167 void verify_header(const char* expected_format) {
168 Header header(mock_image_ctx->cct);
169
170 ASSERT_EQ(0, header.init());
171 ASSERT_EQ(0, header.write(header_bl));
172 ASSERT_EQ(0, header.load(expected_format));
173 }
174 };
175
176 TEST_F(TestMockCryptoLuksFlattenRequest, LUKS1) {
177 generate_header(CRYPT_LUKS1, "aes", 32, "xts-plain64", 512, true);
178 expect_get_crypto();
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);
186 complete_aio(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());
190 }
191
192 TEST_F(TestMockCryptoLuksFlattenRequest, LUKS2) {
193 generate_header(CRYPT_LUKS2, "aes", 32, "xts-plain64", 4096, true);
194 expect_get_crypto();
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);
202 complete_aio(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());
206 }
207
208 TEST_F(TestMockCryptoLuksFlattenRequest, FailedRead) {
209 generate_header(CRYPT_LUKS2, "aes", 32, "xts-plain64", 4096, true);
210 expect_get_crypto();
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());
217 }
218
219 TEST_F(TestMockCryptoLuksFlattenRequest, AlreadyFlattened) {
220 generate_header(CRYPT_LUKS2, "aes", 32, "xts-plain64", 4096, false);
221 expect_get_crypto();
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);
229 complete_aio(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());
233 }
234
235 TEST_F(TestMockCryptoLuksFlattenRequest, FailedWrite) {
236 generate_header(CRYPT_LUKS2, "aes", 32, "xts-plain64", 4096, true);
237 expect_get_crypto();
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));
244 complete_aio(-EIO);
245 ASSERT_EQ(-EIO, finished_cond.wait());
246 ASSERT_EQ(mock_encryption_format, mock_image_ctx->encryption_format.get());
247 }
248
249 TEST_F(TestMockCryptoLuksFlattenRequest, FailedFlush) {
250 generate_header(CRYPT_LUKS2, "aes", 32, "xts-plain64", 4096, true);
251 expect_get_crypto();
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);
259 complete_aio(0);
260 ASSERT_EQ(-EIO, finished_cond.wait());
261 ASSERT_EQ(mock_encryption_format, mock_image_ctx->encryption_format.get());
262 }
263
264 } // namespace luks
265 } // namespace crypto
266 } // namespace librbd