1 #include "estoraged_conf.hpp"
2 #include "zero.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::Zero;
23 using sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure;
24 using testing::_;
25 using testing::Return;
26
TEST(Zeros,zeroPass)27 TEST(Zeros, zeroPass)
28 {
29 std::string testFileName = "testfile_pass";
30 std::ofstream testFile;
31
32 testFile.open(testFileName,
33 std::ios::out | std::ios::binary | std::ios::trunc);
34 testFile.close();
35 uint64_t size = 4096;
36 Zero pass(testFileName);
37 stdplus::fd::Fd&& write =
38 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
39 EXPECT_NO_THROW(pass.writeZero(size, write));
40 stdplus::fd::Fd&& read =
41 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
42 EXPECT_NO_THROW(pass.verifyZero(size, read));
43 }
44
45 /* This test that pattern writes the correct number of bytes even if
46 * size of the drive is not divisible by the block size
47 */
TEST(Zeros,notDivisible)48 TEST(Zeros, notDivisible)
49 {
50 std::string testFileName = "testfile_notDivisible";
51 std::ofstream testFile;
52
53 testFile.open(testFileName,
54 std::ios::out | std::ios::binary | std::ios::trunc);
55 testFile.close();
56
57 uint64_t size = 4097;
58 // 4097 is not divisible by the block size, and we expect no errors
59
60 stdplus::fd::Fd&& write =
61 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
62 Zero pass(testFileName);
63 EXPECT_NO_THROW(pass.writeZero(size, write));
64 stdplus::fd::Fd&& read =
65 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
66 EXPECT_NO_THROW(pass.verifyZero(size, read));
67 }
68
TEST(Zeros,notZeroStart)69 TEST(Zeros, notZeroStart)
70 {
71 std::string testFileName = "testfile_notZeroStart";
72 std::ofstream testFile;
73
74 // open the file and write none zero to it
75 uint32_t dummyValue = 0x88776655;
76 testFile.open(testFileName, std::ios::binary | std::ios::out);
77 testFile.write((reinterpret_cast<const char*>(&dummyValue)),
78 sizeof(dummyValue));
79 testFile.close();
80 uint64_t size = 4096;
81 stdplus::fd::Fd&& readWrite =
82 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
83
84 Zero pass(testFileName);
85 EXPECT_NO_THROW(pass.writeZero(size - sizeof(dummyValue), readWrite));
86
87 // force flush, needed for unit testing
88 std::ofstream file;
89 file.open(testFileName);
90 file.close();
91
92 EXPECT_THROW(pass.verifyZero(size, readWrite), InternalFailure);
93 }
94
TEST(Zeros,notZeroEnd)95 TEST(Zeros, notZeroEnd)
96 {
97 std::string testFileName = "testfile_notZeroEnd";
98 std::ofstream testFile;
99
100 testFile.open(testFileName,
101 std::ios::out | std::ios::binary | std::ios::trunc);
102 testFile.close();
103
104 uint64_t size = 4096;
105 Zero pass(testFileName);
106 uint32_t dummyValue = 88;
107 stdplus::fd::Fd&& write =
108 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
109 EXPECT_NO_THROW(pass.writeZero(size - sizeof(dummyValue), write));
110
111 // open the file and write none zero to it
112 testFile.open(testFileName, std::ios::out);
113 testFile << dummyValue;
114 testFile.close();
115
116 stdplus::fd::Fd&& read =
117 stdplus::fd::open(testFileName, stdplus::fd::OpenAccess::ReadWrite);
118 EXPECT_THROW(pass.verifyZero(size, read), InternalFailure);
119 }
120
TEST(Zeros,shortReadWritePass)121 TEST(Zeros, shortReadWritePass)
122 {
123 std::string testFileName = "testfile_shortRead";
124
125 uint64_t size = 4096;
126 size_t shortSize = 128;
127 Zero pass(testFileName);
128 auto shortData = std::vector<std::byte>(shortSize, std::byte{0});
129 auto restOfData =
130 std::vector<std::byte>(size - shortSize * 3, std::byte{0});
131 std::span shortDataSpan{shortData};
132 std::span restOfDataSpan{restOfData};
133 stdplus::fd::FdMock mock;
134
135 // test write zeros with short blocks
136 EXPECT_CALL(mock, write(_))
137 .WillOnce(Return(shortDataSpan))
138 .WillOnce(Return(shortDataSpan))
139 .WillOnce(Return(restOfDataSpan))
140 .WillOnce(Return(shortDataSpan));
141
142 EXPECT_NO_THROW(pass.writeZero(size, mock));
143
144 // test read zeros with short blocks
145 EXPECT_CALL(mock, read(_))
146 .WillOnce(Return(shortDataSpan))
147 .WillOnce(Return(shortDataSpan))
148 .WillOnce(Return(restOfDataSpan))
149 .WillOnce(Return(shortDataSpan));
150
151 EXPECT_NO_THROW(pass.verifyZero(size, mock));
152 }
153
TEST(Zeros,shortReadWriteFail)154 TEST(Zeros, shortReadWriteFail)
155 {
156 std::string testFileName = "testfile_shortRead";
157
158 uint64_t size = 4096;
159 size_t shortSize = 128;
160 Zero tryZero(testFileName);
161 auto shortData = std::vector<std::byte>(shortSize, std::byte{0});
162 auto restOfData =
163 std::vector<std::byte>(size - shortSize * 3, std::byte{0});
164 std::span shortDataSpan{shortData};
165 std::span restOfDataSpan{restOfData};
166 // open the file and write none zero to it
167
168 stdplus::fd::FdMock mock;
169
170 // test writes
171 EXPECT_CALL(mock, write(_))
172 .WillOnce(Return(shortDataSpan))
173 .WillOnce(Return(shortDataSpan))
174 .WillOnce(Return(restOfDataSpan))
175 .WillOnce(Return(restOfDataSpan)); // return too much data!
176
177 EXPECT_THROW(tryZero.writeZero(size, mock), InternalFailure);
178
179 // test reads
180 EXPECT_CALL(mock, read(_))
181 .WillOnce(Return(shortDataSpan))
182 .WillOnce(Return(shortDataSpan))
183 .WillOnce(Return(restOfDataSpan))
184 .WillOnce(Return(restOfDataSpan)); // return too much data!
185
186 EXPECT_THROW(tryZero.verifyZero(size, mock), InternalFailure);
187 }
188
TEST(Zeros,driveIsSmaller)189 TEST(Zeros, driveIsSmaller)
190 {
191 std::string testFileName = "testfile_driveIsSmaller";
192
193 uint64_t size = 4096;
194 Zero tryZero(testFileName);
195
196 stdplus::fd::FdMock mocks;
197 testing::InSequence s;
198
199 // test writes
200 EXPECT_CALL(mocks, write(_))
201 .Times(33)
202 .WillRepeatedly(Return(std::span<std::byte>{}))
203 .RetiresOnSaturation();
204 EXPECT_THROW(tryZero.writeZero(size, mocks), InternalFailure);
205 // test reads
206 EXPECT_CALL(mocks, read(_))
207 .Times(33)
208 .WillRepeatedly(Return(std::span<std::byte>{}))
209 .RetiresOnSaturation();
210 EXPECT_THROW(tryZero.verifyZero(size, mocks), InternalFailure);
211 }
212
213 } // namespace estoraged_test
214