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 uint64_t size = 4096; 99 size_t shortSize = 128; 100 static auto shortData1 = std::vector<std::byte>(shortSize); 101 static auto shortData2 = std::vector<std::byte>(shortSize); 102 static auto restOfData = std::vector<std::byte>(size - shortSize * 2); 103 104 TEST(pattern, shortReadWritePass) 105 { 106 std::string testFileName = "testfile_shortRead"; 107 108 uint64_t size = 4096; 109 Pattern pass(testFileName); 110 stdplus::fd::FdMock mock; 111 112 testing::Sequence s; 113 114 // test write pattern with short blocks 115 EXPECT_CALL(mock, write(_)) 116 .WillOnce(Invoke([](std::span<const std::byte> x) { 117 std::copy_n(x.begin(), shortData1.size(), shortData1.begin()); 118 return shortData1; 119 })) 120 .RetiresOnSaturation(); 121 EXPECT_CALL(mock, write(_)) 122 .WillOnce(Invoke([](std::span<const std::byte> x) { 123 std::copy_n(x.begin(), restOfData.size(), restOfData.begin()); 124 return restOfData; 125 })) 126 .RetiresOnSaturation(); 127 EXPECT_CALL(mock, write(_)) 128 .WillOnce(Invoke([](std::span<const std::byte> x) { 129 std::copy_n(x.begin(), shortData2.size(), shortData2.begin()); 130 return shortData2; 131 })) 132 .RetiresOnSaturation(); 133 134 // test read pattern 135 EXPECT_CALL(mock, read(_)) 136 .WillOnce(Invoke([](nonstd::span<std::byte> x) { 137 std::copy_n(shortData1.begin(), shortData1.size(), x.data()); 138 nonstd::span ret(shortData1); 139 return ret; 140 })) 141 .RetiresOnSaturation(); 142 143 EXPECT_CALL(mock, read(_)) 144 .WillOnce(Invoke([](nonstd::span<std::byte> x) { 145 std::copy_n(restOfData.begin(), restOfData.size(), x.data()); 146 nonstd::span ret(restOfData); 147 return ret; 148 })) 149 .RetiresOnSaturation(); 150 151 EXPECT_CALL(mock, read(_)) 152 .WillOnce(Invoke([](nonstd::span<std::byte> x) { 153 std::copy_n(shortData2.begin(), shortData2.size(), x.data()); 154 nonstd::span ret(shortData2); 155 return ret; 156 })) 157 .RetiresOnSaturation(); 158 159 EXPECT_NO_THROW(pass.writePattern(size, mock)); 160 EXPECT_NO_THROW(pass.verifyPattern(size, mock)); 161 } 162 163 TEST(Zeros, shortReadWriteFail) 164 { 165 std::string testFileName = "testfile_shortRead"; 166 167 uint64_t size = 4096; 168 size_t shortSize = 128; 169 Pattern tryPattern(testFileName); 170 auto shortData = std::vector<std::byte>(shortSize, std::byte{0}); 171 auto restOfData = 172 std::vector<std::byte>(size - shortSize * 3, std::byte{0}); 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(shortData)) 180 .WillOnce(Return(shortData)) 181 .WillOnce(Return(restOfData)) 182 .WillOnce(Return(restOfData)); // 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(shortData)) 189 .WillOnce(Return(shortData)) 190 .WillOnce(Return(restOfData)) 191 .WillOnce(Return(restOfData)); // 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::vector<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::vector<std::byte>{})) 218 .RetiresOnSaturation(); 219 220 EXPECT_THROW(tryPattern.verifyPattern(size, mocks), InternalFailure); 221 } 222 223 } // namespace estoraged_test 224