blob: 4690074d1a5117e0006f1389c77dfa7ce7bf66a4 [file] [log] [blame]
John Edward Broadbent59dffa62022-01-13 17:41:32 -08001#include "estoraged_test.hpp"
John Wedigb810c922021-11-17 16:38:03 -08002
John Wedigb810c922021-11-17 16:38:03 -08003#include "estoraged.hpp"
Tom Tung043af592023-11-24 13:37:05 +08004#include "estoraged_conf.hpp"
John Wedigb810c922021-11-17 16:38:03 -08005
Willy Tuda5aa612025-12-18 07:32:34 +00006#include <linux/mmc/core.h>
7#include <linux/mmc/ioctl.h>
8#include <linux/mmc/mmc.h>
John Wedigb810c922021-11-17 16:38:03 -08009#include <unistd.h>
10
John Wedig67a47442022-04-05 17:21:29 -070011#include <boost/asio/io_context.hpp>
12#include <sdbusplus/asio/connection.hpp>
13#include <sdbusplus/asio/object_server.hpp>
Willy Tu6c39e6a2026-01-06 19:05:37 +000014#include <stdplus/fd/gmock.hpp>
John Wedig972c3fa2021-12-29 17:30:41 -080015#include <xyz/openbmc_project/Common/error.hpp>
Patrick Williams0e2a46f2023-05-10 14:35:52 -050016#include <xyz/openbmc_project/Inventory/Item/Volume/server.hpp>
John Wedigb810c922021-11-17 16:38:03 -080017
Rom Lemarchand530ce1e2025-12-16 21:45:08 +000018#include <array>
John Wedigb810c922021-11-17 16:38:03 -080019#include <exception>
20#include <filesystem>
21#include <fstream>
22#include <iterator>
John Wedig67a47442022-04-05 17:21:29 -070023#include <memory>
Willy Tuda5aa612025-12-18 07:32:34 +000024#include <span>
John Wedigb810c922021-11-17 16:38:03 -080025#include <string>
26#include <vector>
27
28#include <gmock/gmock.h>
29#include <gtest/gtest.h>
30
31namespace estoraged_test
32{
33
Patrick Williams0e2a46f2023-05-10 14:35:52 -050034using sdbusplus::server::xyz::openbmc_project::inventory::item::Volume;
John Wedig972c3fa2021-12-29 17:30:41 -080035using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
36using sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound;
John Wedigb810c922021-11-17 16:38:03 -080037using std::filesystem::path;
Willy Tu6c39e6a2026-01-06 19:05:37 +000038using stdplus::fd::FdMock;
John Wedigb810c922021-11-17 16:38:03 -080039using ::testing::_;
Rom Lemarchand530ce1e2025-12-16 21:45:08 +000040using ::testing::ElementsAreArray;
John Wedigb810c922021-11-17 16:38:03 -080041using ::testing::Return;
42using ::testing::StrEq;
43
Ed Tanous82897c32022-02-21 14:11:59 -080044class EStoragedTest : public testing::Test
John Wedigb810c922021-11-17 16:38:03 -080045{
46 public:
Ed Tanous82897c32022-02-21 14:11:59 -080047 const char* testFileName = "testfile";
48 const char* testLuksDevName = "testfile_luksDev";
John Wedig2443a022023-03-17 13:42:32 -070049 const char* testCryptDir = "/tmp";
John Wedig6c0d8ce2022-04-22 14:00:43 -070050 const std::string testConfigPath =
51 "/xyz/openbmc_project/inventory/system/board/test_board/test_emmc";
John Wedig67a47442022-04-05 17:21:29 -070052 const uint64_t testSize = 24;
John Edward Broadbent5d799bb2022-03-22 16:14:24 -070053 const uint8_t testLifeTime = 25;
John Wedigb4838302022-07-22 13:51:16 -070054 const std::string testPartNumber = "12345678";
55 const std::string testSerialNumber = "ABCDEF1234";
Rahul Kapoor19825052023-05-27 01:52:23 +000056 const std::string testLocationCode = "U102020";
John Wedigd7be42b2024-01-19 16:07:19 -080057 const std::string testDriveType = "SSD";
John Wedigc0d66eb2024-02-26 15:54:47 -080058 const std::string testDriveProtocol = "eMMC";
John Wedigb810c922021-11-17 16:38:03 -080059 std::ofstream testFile;
John Wedigb810c922021-11-17 16:38:03 -080060 std::string passwordString;
61 std::vector<uint8_t> password;
Ed Tanous82897c32022-02-21 14:11:59 -080062 MockCryptsetupInterface* mockCryptIface{};
Rom Lemarchand530ce1e2025-12-16 21:45:08 +000063 static const constexpr std::array<const char*, 2> options = {
64 "-E", "discard"};
Ed Tanous82897c32022-02-21 14:11:59 -080065 MockFilesystemInterface* mockFsIface{};
John Wedig67a47442022-04-05 17:21:29 -070066 boost::asio::io_context io;
67 std::shared_ptr<sdbusplus::asio::connection> conn;
68 std::unique_ptr<sdbusplus::asio::object_server> objectServer;
69 std::unique_ptr<estoraged::EStoraged> esObject;
John Wedigb810c922021-11-17 16:38:03 -080070
Ed Tanous82897c32022-02-21 14:11:59 -080071 EStoragedTest() :
John Wedig67a47442022-04-05 17:21:29 -070072 passwordString("password"),
John Wedigb810c922021-11-17 16:38:03 -080073 password(passwordString.begin(), passwordString.end())
74 {}
75
76 void SetUp() override
77 {
78 /* Create an empty file that we'll pretend is a 'storage device'. */
79 testFile.open(testFileName,
80 std::ios::out | std::ios::binary | std::ios::trunc);
81 testFile.close();
82 if (testFile.fail())
83 {
84 throw std::runtime_error("Failed to open test file");
85 }
86
John Wedigb810c922021-11-17 16:38:03 -080087 std::unique_ptr<MockCryptsetupInterface> cryptIface =
88 std::make_unique<MockCryptsetupInterface>();
89 mockCryptIface = cryptIface.get();
90 std::unique_ptr<MockFilesystemInterface> fsIface =
91 std::make_unique<MockFilesystemInterface>();
92 mockFsIface = fsIface.get();
93
John Wedig2443a022023-03-17 13:42:32 -070094 /* Set up location of dummy mapped crypt file. */
95 EXPECT_CALL(*cryptIface, cryptGetDir).WillOnce(Return(testCryptDir));
96
John Wedig67a47442022-04-05 17:21:29 -070097 conn = std::make_shared<sdbusplus::asio::connection>(io);
98 // request D-Bus server name.
99 conn->request_name("xyz.openbmc_project.eStoraged.test");
100 objectServer = std::make_unique<sdbusplus::asio::object_server>(conn);
101
Willy Tu6c39e6a2026-01-06 19:05:37 +0000102 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
Ed Tanous82897c32022-02-21 14:11:59 -0800103 esObject = std::make_unique<estoraged::EStoraged>(
Willy Tuda5aa612025-12-18 07:32:34 +0000104 std::move(mockFd), *objectServer, testConfigPath, testFileName,
105 testLuksDevName, testSize, testLifeTime, testPartNumber,
106 testSerialNumber, testLocationCode, ERASE_MAX_GEOMETRY,
107 ERASE_MIN_GEOMETRY, testDriveType, testDriveProtocol,
108 std::move(cryptIface), std::move(fsIface));
John Wedigb810c922021-11-17 16:38:03 -0800109 }
110
111 void TearDown() override
112 {
113 EXPECT_EQ(0, unlink(testFileName));
114 }
115};
116
John Wedig2443a022023-03-17 13:42:32 -0700117const char* mappedDevicePath = "/tmp/testfile_luksDev";
118std::ofstream mappedDevice;
119
120int createMappedDev()
121{
122 mappedDevice.open(mappedDevicePath,
123 std::ios::out | std::ios::binary | std::ios::trunc);
124 mappedDevice.close();
125 if (mappedDevice.fail())
126 {
127 throw std::runtime_error("Failed to open test mapped device");
128 }
129
130 return 0;
131}
132
133int removeMappedDev()
134{
135 EXPECT_EQ(0, unlink(mappedDevicePath));
136
137 return 0;
138}
139
John Wedigb810c922021-11-17 16:38:03 -0800140/* Test case to format and then lock the LUKS device. */
Ed Tanous82897c32022-02-21 14:11:59 -0800141TEST_F(EStoragedTest, FormatPass)
John Wedigb810c922021-11-17 16:38:03 -0800142{
John Wedigb810c922021-11-17 16:38:03 -0800143 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
144
145 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
146 .Times(1);
147
148 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
149
150 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700151 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800152
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000153 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
154 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700155 .WillOnce(Return(0));
John Wedigb810c922021-11-17 16:38:03 -0800156
John Wedig1d6665f2025-12-04 19:08:06 +0000157 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
158 StrEq("-t ext4 -p")))
159 .WillOnce(Return(0));
160
John Wedigb17f8252022-01-12 14:24:26 -0800161 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
162 .WillOnce(Return(false));
163
John Wedigb810c922021-11-17 16:38:03 -0800164 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
165 .WillOnce(Return(true));
166
167 EXPECT_CALL(*mockFsIface,
John Wedig2443a022023-03-17 13:42:32 -0700168 doMount(StrEq(esObject->getCryptDevicePath()),
John Wedigb810c922021-11-17 16:38:03 -0800169 StrEq(esObject->getMountPoint()), _, _, _))
170 .WillOnce(Return(0));
171
172 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
173 .WillOnce(Return(0));
174
175 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
176 .WillOnce(Return(true));
177
John Wedig2443a022023-03-17 13:42:32 -0700178 EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _))
179 .WillOnce(&removeMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800180
181 /* Format the encrypted device. */
John Wedig972c3fa2021-12-29 17:30:41 -0800182 esObject->formatLuks(password, Volume::FilesystemType::ext4);
John Wedigb810c922021-11-17 16:38:03 -0800183 EXPECT_FALSE(esObject->isLocked());
184
John Wedig972c3fa2021-12-29 17:30:41 -0800185 esObject->lock();
John Wedigb810c922021-11-17 16:38:03 -0800186 EXPECT_TRUE(esObject->isLocked());
187}
188
John Wedigb17f8252022-01-12 14:24:26 -0800189/*
190 * Test case where the mount point directory already exists, so it shouldn't
191 * try to create it.
192 */
Ed Tanous82897c32022-02-21 14:11:59 -0800193TEST_F(EStoragedTest, MountPointExistsPass)
John Wedigb17f8252022-01-12 14:24:26 -0800194{
John Wedigb17f8252022-01-12 14:24:26 -0800195 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
196
197 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
198 .Times(1);
199
200 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
201
202 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700203 .WillOnce(&createMappedDev);
John Wedigb17f8252022-01-12 14:24:26 -0800204
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000205 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
206 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700207 .WillOnce(Return(0));
John Wedigb17f8252022-01-12 14:24:26 -0800208
John Wedig1d6665f2025-12-04 19:08:06 +0000209 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
210 StrEq("-t ext4 -p")))
211 .WillOnce(Return(0));
212
John Wedigb17f8252022-01-12 14:24:26 -0800213 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
214 .WillOnce(Return(true));
215
216 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
217 .Times(0);
218
219 EXPECT_CALL(*mockFsIface,
John Wedig2443a022023-03-17 13:42:32 -0700220 doMount(StrEq(esObject->getCryptDevicePath()),
John Wedigb17f8252022-01-12 14:24:26 -0800221 StrEq(esObject->getMountPoint()), _, _, _))
222 .WillOnce(Return(0));
223
224 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
225 .WillOnce(Return(0));
226
227 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
228 .WillOnce(Return(true));
229
John Wedig2443a022023-03-17 13:42:32 -0700230 EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _))
231 .WillOnce(&removeMappedDev);
John Wedigb17f8252022-01-12 14:24:26 -0800232
233 /* Format the encrypted device. */
234 esObject->formatLuks(password, Volume::FilesystemType::ext4);
235 EXPECT_FALSE(esObject->isLocked());
236
237 esObject->lock();
238 EXPECT_TRUE(esObject->isLocked());
239}
240
John Wedigb810c922021-11-17 16:38:03 -0800241/* Test case where the device/file doesn't exist. */
Ed Tanous82897c32022-02-21 14:11:59 -0800242TEST_F(EStoragedTest, FormatNoDeviceFail)
John Wedigb810c922021-11-17 16:38:03 -0800243{
244 /* Delete the test file. */
245 EXPECT_EQ(0, unlink(testFileName));
246
John Wedig972c3fa2021-12-29 17:30:41 -0800247 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
248 ResourceNotFound);
John Wedig2443a022023-03-17 13:42:32 -0700249 EXPECT_TRUE(esObject->isLocked());
John Wedigb810c922021-11-17 16:38:03 -0800250
251 /* Create the test file again, so that the TearDown function works. */
252 testFile.open(testFileName,
253 std::ios::out | std::ios::binary | std::ios::trunc);
254 testFile.close();
255}
256
257/* Test case where we fail to format the LUKS device. */
Ed Tanous82897c32022-02-21 14:11:59 -0800258TEST_F(EStoragedTest, FormatFail)
John Wedigb810c922021-11-17 16:38:03 -0800259{
260 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _))
261 .WillOnce(Return(-1));
262
John Wedig972c3fa2021-12-29 17:30:41 -0800263 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
264 InternalFailure);
John Wedig2443a022023-03-17 13:42:32 -0700265 EXPECT_TRUE(esObject->isLocked());
John Wedigb810c922021-11-17 16:38:03 -0800266}
267
268/* Test case where we fail to set the password for the LUKS device. */
Ed Tanous82897c32022-02-21 14:11:59 -0800269TEST_F(EStoragedTest, AddKeyslotFail)
John Wedigb810c922021-11-17 16:38:03 -0800270{
John Wedigb810c922021-11-17 16:38:03 -0800271 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
272
273 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
274 .WillOnce(Return(-1));
275
John Wedig972c3fa2021-12-29 17:30:41 -0800276 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
277 InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800278 EXPECT_TRUE(esObject->isLocked());
279}
280
281/* Test case where we fail to load the LUKS header. */
Ed Tanous82897c32022-02-21 14:11:59 -0800282TEST_F(EStoragedTest, LoadLuksHeaderFail)
John Wedigb810c922021-11-17 16:38:03 -0800283{
John Wedigb810c922021-11-17 16:38:03 -0800284 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
285
286 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
287 .Times(1);
288
289 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).WillOnce(Return(-1));
290
John Wedig972c3fa2021-12-29 17:30:41 -0800291 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
292 InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800293 EXPECT_TRUE(esObject->isLocked());
294}
295
296/* Test case where we fail to activate the LUKS device. */
Ed Tanous82897c32022-02-21 14:11:59 -0800297TEST_F(EStoragedTest, ActivateFail)
John Wedigb810c922021-11-17 16:38:03 -0800298{
John Wedigb810c922021-11-17 16:38:03 -0800299 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
300
301 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
302 .Times(1);
303
304 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
305
306 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
307 .WillOnce(Return(-1));
308
John Wedig972c3fa2021-12-29 17:30:41 -0800309 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
310 InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800311 EXPECT_TRUE(esObject->isLocked());
312}
313
314/* Test case where we fail to create the filesystem. */
Ed Tanous82897c32022-02-21 14:11:59 -0800315TEST_F(EStoragedTest, CreateFilesystemFail)
John Wedigb810c922021-11-17 16:38:03 -0800316{
John Wedigb810c922021-11-17 16:38:03 -0800317 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
318
319 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
320 .Times(1);
321
322 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
323
324 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700325 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800326
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000327 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
328 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700329 .WillOnce(Return(-1));
John Wedigb810c922021-11-17 16:38:03 -0800330
John Wedig972c3fa2021-12-29 17:30:41 -0800331 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
332 InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800333 EXPECT_FALSE(esObject->isLocked());
John Wedig2443a022023-03-17 13:42:32 -0700334
335 EXPECT_EQ(0, removeMappedDev());
John Wedigb810c922021-11-17 16:38:03 -0800336}
337
338/* Test case where we fail to create the mount point. */
Ed Tanous82897c32022-02-21 14:11:59 -0800339TEST_F(EStoragedTest, CreateMountPointFail)
John Wedigb810c922021-11-17 16:38:03 -0800340{
John Wedigb810c922021-11-17 16:38:03 -0800341 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
342
343 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
344 .Times(1);
345
346 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
347
348 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700349 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800350
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000351 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
352 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700353 .WillOnce(Return(0));
John Wedigb810c922021-11-17 16:38:03 -0800354
John Wedig1d6665f2025-12-04 19:08:06 +0000355 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
356 StrEq("-t ext4 -p")))
357 .WillOnce(Return(0));
358
John Wedigb17f8252022-01-12 14:24:26 -0800359 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
360 .WillOnce(Return(false));
361
John Wedigb810c922021-11-17 16:38:03 -0800362 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
363 .WillOnce(Return(false));
364
John Wedig972c3fa2021-12-29 17:30:41 -0800365 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
366 InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800367 EXPECT_FALSE(esObject->isLocked());
John Wedig2443a022023-03-17 13:42:32 -0700368
369 EXPECT_EQ(0, removeMappedDev());
John Wedigb810c922021-11-17 16:38:03 -0800370}
371
372/* Test case where we fail to mount the filesystem. */
Ed Tanous82897c32022-02-21 14:11:59 -0800373TEST_F(EStoragedTest, MountFail)
John Wedigb810c922021-11-17 16:38:03 -0800374{
John Wedigb810c922021-11-17 16:38:03 -0800375 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
376
377 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
378 .Times(1);
379
380 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
381
382 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700383 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800384
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000385 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
386 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700387 .WillOnce(Return(0));
John Wedigb810c922021-11-17 16:38:03 -0800388
John Wedig1d6665f2025-12-04 19:08:06 +0000389 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
390 StrEq("-t ext4 -p")))
391 .WillOnce(Return(0));
392
John Wedigb17f8252022-01-12 14:24:26 -0800393 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
394 .WillOnce(Return(false));
395
John Wedigb810c922021-11-17 16:38:03 -0800396 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
397 .WillOnce(Return(true));
398
399 EXPECT_CALL(*mockFsIface,
John Wedig2443a022023-03-17 13:42:32 -0700400 doMount(StrEq(esObject->getCryptDevicePath()),
John Wedigb810c922021-11-17 16:38:03 -0800401 StrEq(esObject->getMountPoint()), _, _, _))
402 .WillOnce(Return(-1));
403
404 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
405 .WillOnce(Return(true));
406
John Wedig972c3fa2021-12-29 17:30:41 -0800407 EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
408 InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800409 EXPECT_FALSE(esObject->isLocked());
John Wedig2443a022023-03-17 13:42:32 -0700410
411 EXPECT_EQ(0, removeMappedDev());
John Wedigb810c922021-11-17 16:38:03 -0800412}
413
414/* Test case where we fail to unmount the filesystem. */
Ed Tanous82897c32022-02-21 14:11:59 -0800415TEST_F(EStoragedTest, UnmountFail)
John Wedigb810c922021-11-17 16:38:03 -0800416{
John Wedigb810c922021-11-17 16:38:03 -0800417 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
418
419 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
420 .Times(1);
421
422 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
423
424 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700425 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800426
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000427 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
428 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700429 .WillOnce(Return(0));
John Wedigb810c922021-11-17 16:38:03 -0800430
John Wedig1d6665f2025-12-04 19:08:06 +0000431 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
432 StrEq("-t ext4 -p")))
433 .WillOnce(Return(0));
434
John Wedigb17f8252022-01-12 14:24:26 -0800435 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
436 .WillOnce(Return(false));
437
John Wedigb810c922021-11-17 16:38:03 -0800438 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
439 .WillOnce(Return(true));
440
441 EXPECT_CALL(*mockFsIface,
John Wedig2443a022023-03-17 13:42:32 -0700442 doMount(StrEq(esObject->getCryptDevicePath()),
John Wedigb810c922021-11-17 16:38:03 -0800443 StrEq(esObject->getMountPoint()), _, _, _))
444 .WillOnce(Return(0));
445
446 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
447 .WillOnce(Return(-1));
448
John Wedig972c3fa2021-12-29 17:30:41 -0800449 esObject->formatLuks(password, Volume::FilesystemType::ext4);
John Wedigb810c922021-11-17 16:38:03 -0800450 EXPECT_FALSE(esObject->isLocked());
451
John Wedig972c3fa2021-12-29 17:30:41 -0800452 EXPECT_THROW(esObject->lock(), InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800453 EXPECT_FALSE(esObject->isLocked());
John Wedig2443a022023-03-17 13:42:32 -0700454
455 EXPECT_EQ(0, removeMappedDev());
John Wedigb810c922021-11-17 16:38:03 -0800456}
457
458/* Test case where we fail to remove the mount point. */
Ed Tanous82897c32022-02-21 14:11:59 -0800459TEST_F(EStoragedTest, RemoveMountPointFail)
John Wedigb810c922021-11-17 16:38:03 -0800460{
John Wedigb810c922021-11-17 16:38:03 -0800461 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
462
463 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
464 .Times(1);
465
466 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
467
468 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700469 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800470
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000471 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
472 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700473 .WillOnce(Return(0));
John Wedigb810c922021-11-17 16:38:03 -0800474
John Wedig1d6665f2025-12-04 19:08:06 +0000475 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
476 StrEq("-t ext4 -p")))
477 .WillOnce(Return(0));
478
John Wedigb17f8252022-01-12 14:24:26 -0800479 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
480 .WillOnce(Return(false));
481
John Wedigb810c922021-11-17 16:38:03 -0800482 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
483 .WillOnce(Return(true));
484
485 EXPECT_CALL(*mockFsIface,
John Wedig2443a022023-03-17 13:42:32 -0700486 doMount(StrEq(esObject->getCryptDevicePath()),
John Wedigb810c922021-11-17 16:38:03 -0800487 StrEq(esObject->getMountPoint()), _, _, _))
488 .WillOnce(Return(0));
489
490 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
491 .WillOnce(Return(0));
492
493 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
494 .WillOnce(Return(false));
495
John Wedig972c3fa2021-12-29 17:30:41 -0800496 esObject->formatLuks(password, Volume::FilesystemType::ext4);
John Wedigb810c922021-11-17 16:38:03 -0800497 EXPECT_FALSE(esObject->isLocked());
498
499 /* This will fail to remove the mount point. */
John Wedig972c3fa2021-12-29 17:30:41 -0800500 EXPECT_THROW(esObject->lock(), InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800501 EXPECT_FALSE(esObject->isLocked());
John Wedig2443a022023-03-17 13:42:32 -0700502
503 EXPECT_EQ(0, removeMappedDev());
John Wedigb810c922021-11-17 16:38:03 -0800504}
505
506/* Test case where we fail to deactivate the LUKS device. */
Ed Tanous82897c32022-02-21 14:11:59 -0800507TEST_F(EStoragedTest, DeactivateFail)
John Wedigb810c922021-11-17 16:38:03 -0800508{
John Wedigb810c922021-11-17 16:38:03 -0800509 EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
510
511 EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
512 .Times(1);
513
514 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
515
516 EXPECT_CALL(*mockCryptIface, cryptActivateByPassphrase(_, _, _, _, _, _))
John Wedig2443a022023-03-17 13:42:32 -0700517 .WillOnce(&createMappedDev);
John Wedigb810c922021-11-17 16:38:03 -0800518
Rom Lemarchand530ce1e2025-12-16 21:45:08 +0000519 EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
520 ElementsAreArray(EStoragedTest::options)))
John Wedig2443a022023-03-17 13:42:32 -0700521 .WillOnce(Return(0));
John Wedigb810c922021-11-17 16:38:03 -0800522
John Wedig1d6665f2025-12-04 19:08:06 +0000523 EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
524 StrEq("-t ext4 -p")))
525 .WillOnce(Return(0));
526
John Wedigb17f8252022-01-12 14:24:26 -0800527 EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
528 .WillOnce(Return(false));
529
John Wedigb810c922021-11-17 16:38:03 -0800530 EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
531 .WillOnce(Return(true));
532
533 EXPECT_CALL(*mockFsIface,
John Wedig2443a022023-03-17 13:42:32 -0700534 doMount(StrEq(esObject->getCryptDevicePath()),
John Wedigb810c922021-11-17 16:38:03 -0800535 StrEq(esObject->getMountPoint()), _, _, _))
536 .WillOnce(Return(0));
537
538 EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
539 .WillOnce(Return(0));
540
541 EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
542 .WillOnce(Return(true));
543
544 EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _)).WillOnce(Return(-1));
545
546 /* Format the encrypted device. */
John Wedig972c3fa2021-12-29 17:30:41 -0800547 esObject->formatLuks(password, Volume::FilesystemType::ext4);
John Wedigb810c922021-11-17 16:38:03 -0800548 EXPECT_FALSE(esObject->isLocked());
549
John Wedig972c3fa2021-12-29 17:30:41 -0800550 EXPECT_THROW(esObject->lock(), InternalFailure);
John Wedigb810c922021-11-17 16:38:03 -0800551 EXPECT_FALSE(esObject->isLocked());
John Wedig2443a022023-03-17 13:42:32 -0700552
553 EXPECT_EQ(0, removeMappedDev());
John Wedigb810c922021-11-17 16:38:03 -0800554}
555
John Wedig8d5a3a02022-09-29 15:25:58 -0700556/* Test case where we successfully change the password. */
557TEST_F(EStoragedTest, ChangePasswordSuccess)
558{
559 std::string newPasswordString("newPassword");
560 std::vector<uint8_t> newPassword(newPasswordString.begin(),
561 newPasswordString.end());
562
563 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
564
565 EXPECT_CALL(*mockCryptIface,
566 cryptKeyslotChangeByPassphrase(
567 _, _, _, reinterpret_cast<const char*>(password.data()),
568 password.size(),
569 reinterpret_cast<const char*>(newPassword.data()),
570 newPassword.size()))
571 .WillOnce(Return(0));
572
573 /* Change the password for the LUKS-encrypted device. */
574 esObject->changePassword(password, newPassword);
575}
576
577/* Test case where we fail to change the password. */
578TEST_F(EStoragedTest, ChangePasswordFail)
579{
580 std::string newPasswordString("newPassword");
581 std::vector<uint8_t> newPassword(newPasswordString.begin(),
582 newPasswordString.end());
583
584 EXPECT_CALL(*mockCryptIface, cryptLoad(_, _, _)).Times(1);
585
586 EXPECT_CALL(*mockCryptIface,
587 cryptKeyslotChangeByPassphrase(
588 _, _, _, reinterpret_cast<const char*>(password.data()),
589 password.size(),
590 reinterpret_cast<const char*>(newPassword.data()),
591 newPassword.size()))
592 .WillOnce(Return(-1));
593
594 EXPECT_THROW(esObject->changePassword(password, newPassword),
595 InternalFailure);
596}
597
Willy Tuda5aa612025-12-18 07:32:34 +0000598TEST(EMMCBackgroundOperation, IoCtlFailure)
599{
Willy Tu6c39e6a2026-01-06 19:05:37 +0000600 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
Willy Tuda5aa612025-12-18 07:32:34 +0000601
602 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_)).WillOnce(Return(1));
603 EXPECT_THROW(estoraged::EStoraged::enableBackgroundOperation(
604 std::move(mockFd), "/dev/test"),
605 estoraged::BkopsIoctlFailure);
606}
607
608TEST(EMMCBackgroundOperation, BkOpsNotSupported)
609{
Willy Tu6c39e6a2026-01-06 19:05:37 +0000610 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
Willy Tuda5aa612025-12-18 07:32:34 +0000611
612 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_)).WillOnce(Return(0));
613 EXPECT_FALSE(estoraged::EStoraged::enableBackgroundOperation(
614 std::move(mockFd), "/dev/test"));
615}
616
617TEST(EMMCBackgroundOperation, EnableFailure)
618{
Willy Tu6c39e6a2026-01-06 19:05:37 +0000619 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
Willy Tuda5aa612025-12-18 07:32:34 +0000620
621 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
622 .WillOnce(testing::Invoke([](unsigned long, void* data) {
623 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
624 EXPECT_EQ(idata->opcode, MMC_SEND_EXT_CSD);
625 EXPECT_EQ(idata->blksz, 512);
626 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC);
627
628 // Set specific bytes to simulate a hardware state
629 // NOLINTNEXTLINE(performance-no-int-to-ptr)
630 *reinterpret_cast<uint8_t*>(idata->data_ptr + 502) =
631 0x01; // BKOPS_SUPPORT = Supported
632 // NOLINTNEXTLINE(performance-no-int-to-ptr)
633 *reinterpret_cast<uint8_t*>(idata->data_ptr + 163) =
634 0x00; // BKOPS_EN = Disabled
635 return 0; // Success
636 }))
637 .WillOnce(Return(1));
638 EXPECT_THROW(estoraged::EStoraged::enableBackgroundOperation(
639 std::move(mockFd), "/dev/test"),
640 estoraged::BkopsEnableFailure);
641}
642
643TEST(EMMCBackgroundOperation, AlreadyEnabled)
644{
Willy Tu6c39e6a2026-01-06 19:05:37 +0000645 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
Willy Tuda5aa612025-12-18 07:32:34 +0000646
647 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
648 .WillOnce(testing::Invoke([](unsigned long, void* data) {
649 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
650 EXPECT_EQ(idata->opcode, MMC_SEND_EXT_CSD);
651 EXPECT_EQ(idata->blksz, 512);
652 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC);
653
654 // Set specific bytes to simulate a hardware state
655 // NOLINTNEXTLINE(performance-no-int-to-ptr)
656 *reinterpret_cast<uint8_t*>(idata->data_ptr + 502) =
657 0x01; // BKOPS_SUPPORT = Supported
658 // NOLINTNEXTLINE(performance-no-int-to-ptr)
659 *reinterpret_cast<uint8_t*>(idata->data_ptr + 163) =
660 EXT_CSD_MANUAL_BKOPS_MASK; // BKOPS_EN = Manual Mode
661 return 0; // Success
662 }));
663 EXPECT_FALSE(estoraged::EStoraged::enableBackgroundOperation(
664 std::move(mockFd), "/dev/test"));
665}
666
667TEST(EMMCBackgroundOperation, EnableSuccess)
668{
Willy Tu6c39e6a2026-01-06 19:05:37 +0000669 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
Willy Tuda5aa612025-12-18 07:32:34 +0000670
671 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
672 .WillOnce(testing::Invoke([](unsigned long, void* data) {
673 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
674 EXPECT_EQ(idata->opcode, MMC_SEND_EXT_CSD);
675 EXPECT_EQ(idata->blksz, 512);
676 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC);
677
678 // Set specific bytes to simulate a hardware state
679 // NOLINTNEXTLINE(performance-no-int-to-ptr)
680 *reinterpret_cast<uint8_t*>(idata->data_ptr + 502) =
681 0x01; // BKOPS_SUPPORT = Supported
682 // NOLINTNEXTLINE(performance-no-int-to-ptr)
683 *reinterpret_cast<uint8_t*>(idata->data_ptr + 163) =
684 0x00; // BKOPS_EN = Disabled
685 return 0; // Success
686 }))
687 .WillOnce(testing::Invoke([](unsigned long, void* data) {
688 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
689 EXPECT_EQ(idata->opcode, MMC_SWITCH);
690 EXPECT_EQ(idata->arg, (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
691 (EXT_CSD_BKOPS_EN << 16) |
692 (EXT_CSD_MANUAL_BKOPS_MASK << 8) |
693 EXT_CSD_CMD_SET_NORMAL);
694 EXPECT_EQ(idata->flags, MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC);
695 return 0; // Success
696 }));
697 EXPECT_TRUE(estoraged::EStoraged::enableBackgroundOperation(
698 std::move(mockFd), "/dev/test"));
699}
700
Willy Tu30bfe8e2025-12-30 19:47:52 +0000701TEST(HSMode, HsModeError)
702{
703 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
704 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_)).WillOnce(Return(1));
705 EXPECT_THROW(estoraged::EStoraged::changeHsTimingIfNeeded(
706 mockFd.get(), "/dev/test", "TestPart"),
707 estoraged::HsModeError);
708}
709
710TEST(HSMode, EnableSuccess)
711{
712 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
713
714 EXPECT_CALL(*mockFd, ioctl(MMC_IOC_CMD, testing::_))
715 .WillOnce(testing::Invoke([](unsigned long, void* data) {
716 struct mmc_ioc_cmd* idata = static_cast<struct mmc_ioc_cmd*>(data);
717 EXPECT_EQ(idata->opcode, MMC_SWITCH);
718 EXPECT_EQ(idata->arg, (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
719 (EXT_CSD_HS_TIMING << 16) |
720 (EXT_CSD_TIMING_HS400 << 8));
721 EXPECT_EQ(idata->flags, MMC_RSP_R1B | MMC_CMD_AC);
722 return 0; // Success
723 }));
724 EXPECT_TRUE(estoraged::EStoraged::changeHsTimingIfNeeded(
725 mockFd.get(), "/dev/test", "TestPart"));
726}
727
728TEST(HSMode, InvalidPart)
729{
730 std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
731 EXPECT_FALSE(estoraged::EStoraged::changeHsTimingIfNeeded(
732 mockFd.get(), "/dev/test", "InvalidPart"));
733}
734
735TEST(HSMode, Null)
736{
737 EXPECT_FALSE(estoraged::EStoraged::changeHsTimingIfNeeded(
738 nullptr, "/dev/test", "TestPart"));
739}
740
John Wedigb810c922021-11-17 16:38:03 -0800741} // namespace estoraged_test