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
TEST(pattern,patternPass)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
TEST(pattern,patternNotDivisible)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
TEST(pattern,patternsDontMatch)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
TEST(pattern,shortReadWritePass)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
TEST(Zeros,shortReadWriteFail)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
TEST(pattern,driveIsSmaller)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