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