xref: /openbmc/estoraged/src/test/erase/pattern_test.cpp (revision d6071fc25a9880e8b622792b1e48d83fb5010e5e)
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