1 #include "estoraged_conf.hpp" 2 #include "pattern.hpp" 3 4 #include <fcntl.h> 5 #include <unistd.h> 6 7 #include <stdplus/fd/create.hpp> 8 #include <stdplus/fd/gmock.hpp> 9 #include <stdplus/fd/managed.hpp> 10 #include <xyz/openbmc_project/Common/error.hpp> 11 12 #include <fstream> 13 #include <span> 14 #include <system_error> 15 16 #include <gmock/gmock-matchers.h> 17 #include <gmock/gmock.h> 18 #include <gtest/gtest.h> 19 20 namespace estoraged_test 21 { 22 23 using estoraged::Pattern; 24 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure; 25 using testing::_; 26 using testing::Invoke; 27 using testing::Return; 28 29 TEST(pattern, patternPass) 30 { 31 std::string testFileName = "patternPass"; 32 uint64_t size = 4096; 33 std::ofstream testFile; 34 testFile.open(testFileName, 35 std::ios::out | std::ios::binary | std::ios::trunc); 36 testFile.close(); 37 38 stdplus::fd::Fd&& writeFd = 39 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::WriteOnly); 40 41 Pattern pass(testFileName); 42 EXPECT_NO_THROW(pass.writePattern(size, writeFd)); 43 44 stdplus::fd::Fd&& readFd = 45 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadOnly); 46 47 EXPECT_NO_THROW(pass.verifyPattern(size, readFd)); 48 } 49 50 /* This test that pattern writes the correct number of bytes even if 51 * size of the drive is not divisible by the block size 52 */ 53 54 TEST(pattern, patternNotDivisible) 55 { 56 std::string testFileName = "notDivisible"; 57 uint64_t size = 4097; 58 // 4097 is not divisible by the block size, and we expect no errors 59 std::ofstream testFile; 60 testFile.open(testFileName, 61 std::ios::out | std::ios::binary | std::ios::trunc); 62 testFile.close(); 63 64 stdplus::fd::Fd&& writeFd = 65 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::WriteOnly); 66 Pattern pass(testFileName); 67 EXPECT_NO_THROW(pass.writePattern(size, writeFd)); 68 69 stdplus::fd::Fd&& readFd = 70 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadOnly); 71 EXPECT_NO_THROW(pass.verifyPattern(size, readFd)); 72 } 73 74 TEST(pattern, patternsDontMatch) 75 { 76 std::string testFileName = "patternsDontMatch"; 77 uint64_t size = 4096; 78 std::ofstream testFile; 79 80 Pattern pass(testFileName); 81 82 int dummyValue = 88; 83 testFile.open(testFileName, std::ios::binary | std::ios::out); 84 testFile.write((reinterpret_cast<const char*>(&dummyValue)), 85 sizeof(dummyValue)); 86 testFile.close(); 87 88 stdplus::fd::Fd&& writeFd = 89 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::WriteOnly); 90 91 EXPECT_NO_THROW(pass.writePattern(size - sizeof(dummyValue), writeFd)); 92 93 stdplus::fd::Fd&& readFd = 94 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadOnly); 95 96 EXPECT_THROW(pass.verifyPattern(size, readFd), InternalFailure); 97 } 98 99 TEST(pattern, shortReadWritePass) 100 { 101 std::string testFileName = "testfile_shortRead"; 102 uint64_t size = 4096; 103 size_t shortSize = 128; 104 static auto shortData1 = std::vector<std::byte>(shortSize); 105 static auto shortData2 = std::vector<std::byte>(shortSize); 106 static auto restOfData = std::vector<std::byte>(size - shortSize * 2); 107 Pattern pass(testFileName); 108 stdplus::fd::FdMock mock; 109 110 testing::Sequence s; 111 112 // test write pattern with short blocks 113 EXPECT_CALL(mock, write(_)) 114 .WillOnce(Invoke([](std::span<const std::byte> x) { 115 std::copy_n(x.begin(), shortData1.size(), shortData1.begin()); 116 return shortData1; 117 })).RetiresOnSaturation(); 118 EXPECT_CALL(mock, write(_)) 119 .WillOnce(Invoke([](std::span<const std::byte> x) { 120 std::copy_n(x.begin(), restOfData.size(), restOfData.begin()); 121 return restOfData; 122 })).RetiresOnSaturation(); 123 EXPECT_CALL(mock, write(_)) 124 .WillOnce(Invoke([](std::span<const std::byte> x) { 125 std::copy_n(x.begin(), shortData2.size(), shortData2.begin()); 126 return shortData2; 127 })).RetiresOnSaturation(); 128 129 // test read pattern 130 EXPECT_CALL(mock, read(_)) 131 .WillOnce(Invoke([](std::span<std::byte> x) { 132 std::copy_n(shortData1.begin(), shortData1.size(), x.data()); 133 std::span ret(shortData1); 134 return ret; 135 })).RetiresOnSaturation(); 136 137 EXPECT_CALL(mock, read(_)) 138 .WillOnce(Invoke([](std::span<std::byte> x) { 139 std::copy_n(restOfData.begin(), restOfData.size(), x.data()); 140 std::span ret(restOfData); 141 return ret; 142 })).RetiresOnSaturation(); 143 144 EXPECT_CALL(mock, read(_)) 145 .WillOnce(Invoke([](std::span<std::byte> x) { 146 std::copy_n(shortData2.begin(), shortData2.size(), x.data()); 147 std::span ret(shortData2); 148 return ret; 149 })).RetiresOnSaturation(); 150 151 EXPECT_NO_THROW(pass.writePattern(size, mock)); 152 EXPECT_NO_THROW(pass.verifyPattern(size, mock)); 153 } 154 155 TEST(Zeros, shortReadWriteFail) 156 { 157 std::string testFileName = "testfile_shortRead"; 158 159 uint64_t size = 4096; 160 size_t shortSize = 128; 161 Pattern tryPattern(testFileName); 162 auto shortData = std::vector<std::byte>(shortSize, std::byte{0}); 163 auto restOfData = std::vector<std::byte>(size - shortSize * 3, 164 std::byte{0}); 165 std::span shortDataSpan{shortData}; 166 std::span restOfDataSpan{restOfData}; 167 // open the file and write none to it 168 169 stdplus::fd::FdMock mock; 170 171 // test writes 172 EXPECT_CALL(mock, write(_)) 173 .WillOnce(Return(shortDataSpan)) 174 .WillOnce(Return(shortDataSpan)) 175 .WillOnce(Return(restOfDataSpan)) 176 .WillOnce(Return(restOfDataSpan)); // return too much data! 177 178 EXPECT_THROW(tryPattern.writePattern(size, mock), InternalFailure); 179 180 // test reads 181 EXPECT_CALL(mock, read(_)) 182 .WillOnce(Return(shortDataSpan)) 183 .WillOnce(Return(shortDataSpan)) 184 .WillOnce(Return(restOfDataSpan)) 185 .WillOnce(Return(restOfDataSpan)); // return too much data! 186 187 EXPECT_THROW(tryPattern.verifyPattern(size, mock), InternalFailure); 188 } 189 190 TEST(pattern, driveIsSmaller) 191 { 192 std::string testFileName = "testfile_driveIsSmaller"; 193 194 uint64_t size = 4096; 195 Pattern tryPattern(testFileName); 196 197 stdplus::fd::FdMock mocks; 198 testing::InSequence s; 199 200 // test writes 201 EXPECT_CALL(mocks, write(_)) 202 .Times(33) 203 .WillRepeatedly(Return(std::span<std::byte>{})) 204 .RetiresOnSaturation(); 205 206 EXPECT_THROW(tryPattern.writePattern(size, mocks), InternalFailure); 207 208 // test reads 209 EXPECT_CALL(mocks, read(_)) 210 .Times(33) 211 .WillRepeatedly(Return(std::span<std::byte>{})) 212 .RetiresOnSaturation(); 213 214 EXPECT_THROW(tryPattern.verifyPattern(size, mocks), InternalFailure); 215 } 216 217 } // namespace estoraged_test 218