xref: /openbmc/estoraged/src/test/estoraged_test.cpp (revision 6c39e6ac11c168148f9c34a528752e4b6c2002db)
1 #include "estoraged_test.hpp"
2 
3 #include "estoraged.hpp"
4 #include "estoraged_conf.hpp"
5 
6 #include <linux/mmc/core.h>
7 #include <linux/mmc/ioctl.h>
8 #include <linux/mmc/mmc.h>
9 #include <unistd.h>
10 
11 #include <boost/asio/io_context.hpp>
12 #include <sdbusplus/asio/connection.hpp>
13 #include <sdbusplus/asio/object_server.hpp>
14 #include <stdplus/fd/gmock.hpp>
15 #include <xyz/openbmc_project/Common/error.hpp>
16 #include <xyz/openbmc_project/Inventory/Item/Volume/server.hpp>
17 
18 #include <array>
19 #include <exception>
20 #include <filesystem>
21 #include <fstream>
22 #include <iterator>
23 #include <memory>
24 #include <span>
25 #include <string>
26 #include <vector>
27 
28 #include <gmock/gmock.h>
29 #include <gtest/gtest.h>
30 
31 namespace estoraged_test
32 {
33 
34 using sdbusplus::server::xyz::openbmc_project::inventory::item::Volume;
35 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
36 using sdbusplus::xyz::openbmc_project::Common::Error::ResourceNotFound;
37 using std::filesystem::path;
38 using stdplus::fd::FdMock;
39 using ::testing::_;
40 using ::testing::ElementsAreArray;
41 using ::testing::Return;
42 using ::testing::StrEq;
43 
44 class EStoragedTest : public testing::Test
45 {
46   public:
47     const char* testFileName = "testfile";
48     const char* testLuksDevName = "testfile_luksDev";
49     const char* testCryptDir = "/tmp";
50     const std::string testConfigPath =
51         "/xyz/openbmc_project/inventory/system/board/test_board/test_emmc";
52     const uint64_t testSize = 24;
53     const uint8_t testLifeTime = 25;
54     const std::string testPartNumber = "12345678";
55     const std::string testSerialNumber = "ABCDEF1234";
56     const std::string testLocationCode = "U102020";
57     const std::string testDriveType = "SSD";
58     const std::string testDriveProtocol = "eMMC";
59     std::ofstream testFile;
60     std::string passwordString;
61     std::vector<uint8_t> password;
62     MockCryptsetupInterface* mockCryptIface{};
63     static const constexpr std::array<const char*, 2> options = {
64         "-E", "discard"};
65     MockFilesystemInterface* mockFsIface{};
66     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;
70 
EStoragedTest()71     EStoragedTest() :
72         passwordString("password"),
73         password(passwordString.begin(), passwordString.end())
74     {}
75 
SetUp()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 
87         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 
94         /* Set up location of dummy mapped crypt file. */
95         EXPECT_CALL(*cryptIface, cryptGetDir).WillOnce(Return(testCryptDir));
96 
97         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 
102         std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
103         esObject = std::make_unique<estoraged::EStoraged>(
104             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));
109     }
110 
TearDown()111     void TearDown() override
112     {
113         EXPECT_EQ(0, unlink(testFileName));
114     }
115 };
116 
117 const char* mappedDevicePath = "/tmp/testfile_luksDev";
118 std::ofstream mappedDevice;
119 
createMappedDev()120 int 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 
removeMappedDev()133 int removeMappedDev()
134 {
135     EXPECT_EQ(0, unlink(mappedDevicePath));
136 
137     return 0;
138 }
139 
140 /* Test case to format and then lock the LUKS device. */
TEST_F(EStoragedTest,FormatPass)141 TEST_F(EStoragedTest, FormatPass)
142 {
143     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(_, _, _, _, _, _))
151         .WillOnce(&createMappedDev);
152 
153     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
154                                       ElementsAreArray(EStoragedTest::options)))
155         .WillOnce(Return(0));
156 
157     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
158                                       StrEq("-t ext4 -p")))
159         .WillOnce(Return(0));
160 
161     EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
162         .WillOnce(Return(false));
163 
164     EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
165         .WillOnce(Return(true));
166 
167     EXPECT_CALL(*mockFsIface,
168                 doMount(StrEq(esObject->getCryptDevicePath()),
169                         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 
178     EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _))
179         .WillOnce(&removeMappedDev);
180 
181     /* Format the encrypted device. */
182     esObject->formatLuks(password, Volume::FilesystemType::ext4);
183     EXPECT_FALSE(esObject->isLocked());
184 
185     esObject->lock();
186     EXPECT_TRUE(esObject->isLocked());
187 }
188 
189 /*
190  * Test case where the mount point directory already exists, so it shouldn't
191  * try to create it.
192  */
TEST_F(EStoragedTest,MountPointExistsPass)193 TEST_F(EStoragedTest, MountPointExistsPass)
194 {
195     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(_, _, _, _, _, _))
203         .WillOnce(&createMappedDev);
204 
205     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
206                                       ElementsAreArray(EStoragedTest::options)))
207         .WillOnce(Return(0));
208 
209     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
210                                       StrEq("-t ext4 -p")))
211         .WillOnce(Return(0));
212 
213     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,
220                 doMount(StrEq(esObject->getCryptDevicePath()),
221                         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 
230     EXPECT_CALL(*mockCryptIface, cryptDeactivate(_, _))
231         .WillOnce(&removeMappedDev);
232 
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 
241 /* Test case where the device/file doesn't exist. */
TEST_F(EStoragedTest,FormatNoDeviceFail)242 TEST_F(EStoragedTest, FormatNoDeviceFail)
243 {
244     /* Delete the test file. */
245     EXPECT_EQ(0, unlink(testFileName));
246 
247     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
248                  ResourceNotFound);
249     EXPECT_TRUE(esObject->isLocked());
250 
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. */
TEST_F(EStoragedTest,FormatFail)258 TEST_F(EStoragedTest, FormatFail)
259 {
260     EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _))
261         .WillOnce(Return(-1));
262 
263     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
264                  InternalFailure);
265     EXPECT_TRUE(esObject->isLocked());
266 }
267 
268 /* Test case where we fail to set the password for the LUKS device. */
TEST_F(EStoragedTest,AddKeyslotFail)269 TEST_F(EStoragedTest, AddKeyslotFail)
270 {
271     EXPECT_CALL(*mockCryptIface, cryptFormat(_, _, _, _, _, _, _, _)).Times(1);
272 
273     EXPECT_CALL(*mockCryptIface, cryptKeyslotAddByVolumeKey(_, _, _, _, _, _))
274         .WillOnce(Return(-1));
275 
276     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
277                  InternalFailure);
278     EXPECT_TRUE(esObject->isLocked());
279 }
280 
281 /* Test case where we fail to load the LUKS header. */
TEST_F(EStoragedTest,LoadLuksHeaderFail)282 TEST_F(EStoragedTest, LoadLuksHeaderFail)
283 {
284     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 
291     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
292                  InternalFailure);
293     EXPECT_TRUE(esObject->isLocked());
294 }
295 
296 /* Test case where we fail to activate the LUKS device. */
TEST_F(EStoragedTest,ActivateFail)297 TEST_F(EStoragedTest, ActivateFail)
298 {
299     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 
309     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
310                  InternalFailure);
311     EXPECT_TRUE(esObject->isLocked());
312 }
313 
314 /* Test case where we fail to create the filesystem. */
TEST_F(EStoragedTest,CreateFilesystemFail)315 TEST_F(EStoragedTest, CreateFilesystemFail)
316 {
317     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(_, _, _, _, _, _))
325         .WillOnce(&createMappedDev);
326 
327     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
328                                       ElementsAreArray(EStoragedTest::options)))
329         .WillOnce(Return(-1));
330 
331     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
332                  InternalFailure);
333     EXPECT_FALSE(esObject->isLocked());
334 
335     EXPECT_EQ(0, removeMappedDev());
336 }
337 
338 /* Test case where we fail to create the mount point. */
TEST_F(EStoragedTest,CreateMountPointFail)339 TEST_F(EStoragedTest, CreateMountPointFail)
340 {
341     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(_, _, _, _, _, _))
349         .WillOnce(&createMappedDev);
350 
351     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
352                                       ElementsAreArray(EStoragedTest::options)))
353         .WillOnce(Return(0));
354 
355     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
356                                       StrEq("-t ext4 -p")))
357         .WillOnce(Return(0));
358 
359     EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
360         .WillOnce(Return(false));
361 
362     EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
363         .WillOnce(Return(false));
364 
365     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
366                  InternalFailure);
367     EXPECT_FALSE(esObject->isLocked());
368 
369     EXPECT_EQ(0, removeMappedDev());
370 }
371 
372 /* Test case where we fail to mount the filesystem. */
TEST_F(EStoragedTest,MountFail)373 TEST_F(EStoragedTest, MountFail)
374 {
375     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(_, _, _, _, _, _))
383         .WillOnce(&createMappedDev);
384 
385     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
386                                       ElementsAreArray(EStoragedTest::options)))
387         .WillOnce(Return(0));
388 
389     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
390                                       StrEq("-t ext4 -p")))
391         .WillOnce(Return(0));
392 
393     EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
394         .WillOnce(Return(false));
395 
396     EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
397         .WillOnce(Return(true));
398 
399     EXPECT_CALL(*mockFsIface,
400                 doMount(StrEq(esObject->getCryptDevicePath()),
401                         StrEq(esObject->getMountPoint()), _, _, _))
402         .WillOnce(Return(-1));
403 
404     EXPECT_CALL(*mockFsIface, removeDirectory(path(esObject->getMountPoint())))
405         .WillOnce(Return(true));
406 
407     EXPECT_THROW(esObject->formatLuks(password, Volume::FilesystemType::ext4),
408                  InternalFailure);
409     EXPECT_FALSE(esObject->isLocked());
410 
411     EXPECT_EQ(0, removeMappedDev());
412 }
413 
414 /* Test case where we fail to unmount the filesystem. */
TEST_F(EStoragedTest,UnmountFail)415 TEST_F(EStoragedTest, UnmountFail)
416 {
417     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(_, _, _, _, _, _))
425         .WillOnce(&createMappedDev);
426 
427     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
428                                       ElementsAreArray(EStoragedTest::options)))
429         .WillOnce(Return(0));
430 
431     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
432                                       StrEq("-t ext4 -p")))
433         .WillOnce(Return(0));
434 
435     EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
436         .WillOnce(Return(false));
437 
438     EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
439         .WillOnce(Return(true));
440 
441     EXPECT_CALL(*mockFsIface,
442                 doMount(StrEq(esObject->getCryptDevicePath()),
443                         StrEq(esObject->getMountPoint()), _, _, _))
444         .WillOnce(Return(0));
445 
446     EXPECT_CALL(*mockFsIface, doUnmount(StrEq(esObject->getMountPoint())))
447         .WillOnce(Return(-1));
448 
449     esObject->formatLuks(password, Volume::FilesystemType::ext4);
450     EXPECT_FALSE(esObject->isLocked());
451 
452     EXPECT_THROW(esObject->lock(), InternalFailure);
453     EXPECT_FALSE(esObject->isLocked());
454 
455     EXPECT_EQ(0, removeMappedDev());
456 }
457 
458 /* Test case where we fail to remove the mount point. */
TEST_F(EStoragedTest,RemoveMountPointFail)459 TEST_F(EStoragedTest, RemoveMountPointFail)
460 {
461     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(_, _, _, _, _, _))
469         .WillOnce(&createMappedDev);
470 
471     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
472                                       ElementsAreArray(EStoragedTest::options)))
473         .WillOnce(Return(0));
474 
475     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
476                                       StrEq("-t ext4 -p")))
477         .WillOnce(Return(0));
478 
479     EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
480         .WillOnce(Return(false));
481 
482     EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
483         .WillOnce(Return(true));
484 
485     EXPECT_CALL(*mockFsIface,
486                 doMount(StrEq(esObject->getCryptDevicePath()),
487                         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 
496     esObject->formatLuks(password, Volume::FilesystemType::ext4);
497     EXPECT_FALSE(esObject->isLocked());
498 
499     /* This will fail to remove the mount point. */
500     EXPECT_THROW(esObject->lock(), InternalFailure);
501     EXPECT_FALSE(esObject->isLocked());
502 
503     EXPECT_EQ(0, removeMappedDev());
504 }
505 
506 /* Test case where we fail to deactivate the LUKS device. */
TEST_F(EStoragedTest,DeactivateFail)507 TEST_F(EStoragedTest, DeactivateFail)
508 {
509     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(_, _, _, _, _, _))
517         .WillOnce(&createMappedDev);
518 
519     EXPECT_CALL(*mockFsIface, runMkfs(StrEq(esObject->getCryptDevicePath()),
520                                       ElementsAreArray(EStoragedTest::options)))
521         .WillOnce(Return(0));
522 
523     EXPECT_CALL(*mockFsIface, runFsck(StrEq(esObject->getCryptDevicePath()),
524                                       StrEq("-t ext4 -p")))
525         .WillOnce(Return(0));
526 
527     EXPECT_CALL(*mockFsIface, directoryExists(path(esObject->getMountPoint())))
528         .WillOnce(Return(false));
529 
530     EXPECT_CALL(*mockFsIface, createDirectory(path(esObject->getMountPoint())))
531         .WillOnce(Return(true));
532 
533     EXPECT_CALL(*mockFsIface,
534                 doMount(StrEq(esObject->getCryptDevicePath()),
535                         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. */
547     esObject->formatLuks(password, Volume::FilesystemType::ext4);
548     EXPECT_FALSE(esObject->isLocked());
549 
550     EXPECT_THROW(esObject->lock(), InternalFailure);
551     EXPECT_FALSE(esObject->isLocked());
552 
553     EXPECT_EQ(0, removeMappedDev());
554 }
555 
556 /* Test case where we successfully change the password. */
TEST_F(EStoragedTest,ChangePasswordSuccess)557 TEST_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. */
TEST_F(EStoragedTest,ChangePasswordFail)578 TEST_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 
TEST(EMMCBackgroundOperation,IoCtlFailure)598 TEST(EMMCBackgroundOperation, IoCtlFailure)
599 {
600     std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
601 
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 
TEST(EMMCBackgroundOperation,BkOpsNotSupported)608 TEST(EMMCBackgroundOperation, BkOpsNotSupported)
609 {
610     std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
611 
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 
TEST(EMMCBackgroundOperation,EnableFailure)617 TEST(EMMCBackgroundOperation, EnableFailure)
618 {
619     std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
620 
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 
TEST(EMMCBackgroundOperation,AlreadyEnabled)643 TEST(EMMCBackgroundOperation, AlreadyEnabled)
644 {
645     std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
646 
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 
TEST(EMMCBackgroundOperation,EnableSuccess)667 TEST(EMMCBackgroundOperation, EnableSuccess)
668 {
669     std::unique_ptr<FdMock> mockFd = std::make_unique<FdMock>();
670 
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 
701 } // namespace estoraged_test
702