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 divisable 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 })) 118 .RetiresOnSaturation(); 119 EXPECT_CALL(mock, write(_)) 120 .WillOnce(Invoke([](std::span<const std::byte> x) { 121 std::copy_n(x.begin(), restOfData.size(), restOfData.begin()); 122 return restOfData; 123 })) 124 .RetiresOnSaturation(); 125 EXPECT_CALL(mock, write(_)) 126 .WillOnce(Invoke([](std::span<const std::byte> x) { 127 std::copy_n(x.begin(), shortData2.size(), shortData2.begin()); 128 return shortData2; 129 })) 130 .RetiresOnSaturation(); 131 132 // test read pattern 133 EXPECT_CALL(mock, read(_)) 134 .WillOnce(Invoke([](std::span<std::byte> x) { 135 std::copy_n(shortData1.begin(), shortData1.size(), x.data()); 136 std::span ret(shortData1); 137 return ret; 138 })) 139 .RetiresOnSaturation(); 140 141 EXPECT_CALL(mock, read(_)) 142 .WillOnce(Invoke([](std::span<std::byte> x) { 143 std::copy_n(restOfData.begin(), restOfData.size(), x.data()); 144 std::span ret(restOfData); 145 return ret; 146 })) 147 .RetiresOnSaturation(); 148 149 EXPECT_CALL(mock, read(_)) 150 .WillOnce(Invoke([](std::span<std::byte> x) { 151 std::copy_n(shortData2.begin(), shortData2.size(), x.data()); 152 std::span ret(shortData2); 153 return ret; 154 })) 155 .RetiresOnSaturation(); 156 157 EXPECT_NO_THROW(pass.writePattern(size, mock)); 158 EXPECT_NO_THROW(pass.verifyPattern(size, mock)); 159 } 160 161 TEST(Zeros, shortReadWriteFail) 162 { 163 std::string testFileName = "testfile_shortRead"; 164 165 uint64_t size = 4096; 166 size_t shortSize = 128; 167 Pattern tryPattern(testFileName); 168 auto shortData = std::vector<std::byte>(shortSize, std::byte{0}); 169 auto restOfData = 170 std::vector<std::byte>(size - shortSize * 3, std::byte{0}); 171 std::span shortDataSpan{shortData}; 172 std::span restOfDataSpan{restOfData}; 173 // open the file and write none to it 174 175 stdplus::fd::FdMock mock; 176 177 // test writes 178 EXPECT_CALL(mock, write(_)) 179 .WillOnce(Return(shortDataSpan)) 180 .WillOnce(Return(shortDataSpan)) 181 .WillOnce(Return(restOfDataSpan)) 182 .WillOnce(Return(restOfDataSpan)); // return too much data! 183 184 EXPECT_THROW(tryPattern.writePattern(size, mock), InternalFailure); 185 186 // test reads 187 EXPECT_CALL(mock, read(_)) 188 .WillOnce(Return(shortDataSpan)) 189 .WillOnce(Return(shortDataSpan)) 190 .WillOnce(Return(restOfDataSpan)) 191 .WillOnce(Return(restOfDataSpan)); // return too much data! 192 193 EXPECT_THROW(tryPattern.verifyPattern(size, mock), InternalFailure); 194 } 195 196 TEST(pattern, driveIsSmaller) 197 { 198 std::string testFileName = "testfile_driveIsSmaller"; 199 200 uint64_t size = 4096; 201 Pattern tryPattern(testFileName); 202 203 stdplus::fd::FdMock mocks; 204 testing::InSequence s; 205 206 // test writes 207 EXPECT_CALL(mocks, write(_)) 208 .Times(33) 209 .WillRepeatedly(Return(std::span<std::byte>{})) 210 .RetiresOnSaturation(); 211 212 EXPECT_THROW(tryPattern.writePattern(size, mocks), InternalFailure); 213 214 // test reads 215 EXPECT_CALL(mocks, read(_)) 216 .Times(33) 217 .WillRepeatedly(Return(std::span<std::byte>{})) 218 .RetiresOnSaturation(); 219 220 EXPECT_THROW(tryPattern.verifyPattern(size, mocks), InternalFailure); 221 } 222 223 } // namespace estoraged_test 224