blob: 9470e4c35d32d344846f770a513624b3c52f37bb [file] [log] [blame]
Brad Bishope45d8c72022-05-25 15:12:53 -04001#include "fru_utils.hpp"
Patrick Venturea62466c2021-02-08 14:55:18 -08002
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +10303#include <algorithm>
Patrick Venturea62466c2021-02-08 14:55:18 -08004#include <array>
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +10305#include <iterator>
Patrick Venturea62466c2021-02-08 14:55:18 -08006
7#include "gtest/gtest.h"
8
9extern "C"
10{
11// Include for I2C_SMBUS_BLOCK_MAX
12#include <linux/i2c.h>
13}
14
Zev Weiss309c0b12022-02-25 01:44:12 +000015static constexpr size_t blockSize = I2C_SMBUS_BLOCK_MAX;
16
Patrick Venturea62466c2021-02-08 14:55:18 -080017TEST(ValidateHeaderTest, InvalidFruVersionReturnsFalse)
18{
19 // Validates the FruVersion is checked for the only legal value.
Ed Tanous07d467b2021-02-23 14:48:37 -080020 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Patrick Venturea62466c2021-02-08 14:55:18 -080021 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
22
Ed Tanous07d467b2021-02-23 14:48:37 -080023 EXPECT_FALSE(validateHeader(fruHeader));
Patrick Venturea62466c2021-02-08 14:55:18 -080024}
Vijay Khemka1694ef62021-02-12 23:14:49 +000025
Vijay Khemka7a682a32021-04-12 22:15:00 +000026TEST(ValidateHeaderTest, InvalidReservedReturnsFalse)
27{
28 // Validates the reserved bit(7:4) of first bytes.
Ed Tanous07d467b2021-02-23 14:48:37 -080029 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000030 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
31
Ed Tanous07d467b2021-02-23 14:48:37 -080032 EXPECT_FALSE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000033}
34
35TEST(ValidateHeaderTest, InvalidPaddingReturnsFalse)
36{
37 // Validates the padding byte (7th byte).
Ed Tanous07d467b2021-02-23 14:48:37 -080038 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000039 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
40
Ed Tanous07d467b2021-02-23 14:48:37 -080041 EXPECT_FALSE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000042}
43
44TEST(ValidateHeaderTest, InvalidChecksumReturnsFalse)
45{
46 // Validates the checksum, check for incorrect value.
Ed Tanous07d467b2021-02-23 14:48:37 -080047 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000048 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00};
49
Ed Tanous07d467b2021-02-23 14:48:37 -080050 EXPECT_FALSE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000051}
52
53TEST(ValidateHeaderTest, ValidChecksumReturnsTrue)
54{
55 // Validates the checksum, check for correct value.
Ed Tanous07d467b2021-02-23 14:48:37 -080056 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000057 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
58
Ed Tanous07d467b2021-02-23 14:48:37 -080059 EXPECT_TRUE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000060}
61
Vijay Khemka1694ef62021-02-12 23:14:49 +000062TEST(VerifyOffsetTest, EmptyFruDataReturnsFalse)
63{
64 // Validates the FruData size is checked for non empty.
Ed Tanous07d467b2021-02-23 14:48:37 -080065 std::vector<uint8_t> fruData = {};
Vijay Khemka1694ef62021-02-12 23:14:49 +000066
Ed Tanous07d467b2021-02-23 14:48:37 -080067 EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaChassis, 0));
Vijay Khemka1694ef62021-02-12 23:14:49 +000068}
69
70TEST(VerifyOffsetTest, AreaOutOfRangeReturnsFalse)
71{
72 // Validates the FruArea value, check if it is within range.
Ed Tanous07d467b2021-02-23 14:48:37 -080073 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x00, 0x00, 0x00,
74 0x00, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +000075
76 unsigned int areaOutOfRange = 8;
77 EXPECT_FALSE(
Ed Tanous07d467b2021-02-23 14:48:37 -080078 verifyOffset(fruData, static_cast<fruAreas>(areaOutOfRange), 0));
Vijay Khemka1694ef62021-02-12 23:14:49 +000079}
80
81TEST(VerifyOffsetTest, OverlapNextAreaReturnsFalse)
82{
83 // Validates the Overlap of offsets with overlapped values.
Ed Tanous07d467b2021-02-23 14:48:37 -080084 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x02, 0x03,
85 0x04, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +000086
Ed Tanous07d467b2021-02-23 14:48:37 -080087 EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaChassis, 2));
Vijay Khemka1694ef62021-02-12 23:14:49 +000088}
89
90TEST(VerifyOffsetTest, OverlapPrevAreaReturnsFalse)
91{
92 // Validates the Overlap of offsets with overlapped values.
Ed Tanous07d467b2021-02-23 14:48:37 -080093 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x03, 0x02,
94 0x07, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +000095
Ed Tanous07d467b2021-02-23 14:48:37 -080096 EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaProduct, 2));
Vijay Khemka1694ef62021-02-12 23:14:49 +000097}
98
99TEST(VerifyOffsetTest, ValidInputDataNoOverlapReturnsTrue)
100{
101 // Validates all inputs with expected value and no overlap.
Ed Tanous07d467b2021-02-23 14:48:37 -0800102 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x02, 0x03,
103 0x04, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +0000104
Ed Tanous07d467b2021-02-23 14:48:37 -0800105 EXPECT_TRUE(verifyOffset(fruData, fruAreas::fruAreaChassis, 1));
Vijay Khemka1694ef62021-02-12 23:14:49 +0000106}
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930107
108TEST(VerifyChecksumTest, EmptyInput)
109{
110 std::vector<uint8_t> data = {};
111
112 EXPECT_EQ(calculateChecksum(data), 0);
113}
114
115TEST(VerifyChecksumTest, SingleOneInput)
116{
117 std::vector<uint8_t> data(1, 1);
118
119 EXPECT_EQ(calculateChecksum(data), 255);
120}
121
122TEST(VerifyChecksumTest, AllOneInput)
123{
124 std::vector<uint8_t> data(256, 1);
125
126 EXPECT_EQ(calculateChecksum(data), 0);
127}
128
129TEST(VerifyChecksumTest, WrapBoundaryLow)
130{
Ed Tanousfbce8e22021-09-02 15:29:12 -0700131 std::vector<uint8_t> data = {255, 0};
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930132
133 EXPECT_EQ(calculateChecksum(data), 1);
134}
135
136TEST(VerifyChecksumTest, WrapBoundaryExact)
137{
Ed Tanousfbce8e22021-09-02 15:29:12 -0700138 std::vector<uint8_t> data = {255, 1};
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930139
140 EXPECT_EQ(calculateChecksum(data), 0);
141}
142
143TEST(VerifyChecksumTest, WrapBoundaryHigh)
144{
Ed Tanousfbce8e22021-09-02 15:29:12 -0700145 std::vector<uint8_t> data = {255, 2};
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930146
147 EXPECT_EQ(calculateChecksum(data), 255);
148}
Oskar Senftbd4075f2021-10-05 23:42:43 -0400149
Zev Weiss309c0b12022-02-25 01:44:12 +0000150int64_t getDataTempl(const std::vector<uint8_t>& data, off_t offset,
Zev Weiss1525e852022-03-22 22:27:43 +0000151 size_t length, uint8_t* outBuf)
Oskar Senftbd4075f2021-10-05 23:42:43 -0400152{
Zev Weiss1525e852022-03-22 22:27:43 +0000153 if (offset >= static_cast<off_t>(data.size()))
Oskar Senftbd4075f2021-10-05 23:42:43 -0400154 {
155 return 0;
156 }
157
Ed Tanous3013fb42022-07-09 08:27:06 -0700158 uint16_t idx = offset;
159 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
160 for (; idx < std::min(data.size(), offset + length); ++idx, ++outBuf)
Oskar Senftbd4075f2021-10-05 23:42:43 -0400161 {
162 *outBuf = data[idx];
163 }
164
165 return idx - offset;
166}
167
Zev Weiss309c0b12022-02-25 01:44:12 +0000168TEST(FRUReaderTest, ReadData)
169{
170 std::vector<uint8_t> data = {};
171 for (size_t i = 0; i < blockSize * 2; i++)
172 {
173 data.push_back(i);
174 }
Ed Tanous3013fb42022-07-09 08:27:06 -0700175 std::array<uint8_t, blockSize * 2> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000176 auto getData = [&data](auto o, auto l, auto* b) {
177 return getDataTempl(data, o, l, b);
178 };
179 FRUReader reader(getData);
180
181 EXPECT_EQ(reader.read(0, data.size(), rdbuf.data()),
182 static_cast<ssize_t>(data.size()));
183 EXPECT_TRUE(std::equal(rdbuf.begin(), rdbuf.end(), data.begin()));
184 for (size_t i = 0; i < blockSize * 2; i++)
185 {
186 EXPECT_EQ(reader.read(i, 1, rdbuf.data()), 1);
187 EXPECT_EQ(rdbuf[i], i);
188 }
189 EXPECT_EQ(reader.read(blockSize - 1, 2, rdbuf.data()), 2);
190 EXPECT_EQ(rdbuf[0], blockSize - 1);
191 EXPECT_EQ(rdbuf[1], blockSize);
192}
193
194TEST(FRUReaderTest, StartPastUnknownEOF)
195{
196 const std::vector<uint8_t> data = {};
197 auto getData = [&data](auto o, auto l, auto* b) {
198 return getDataTempl(data, o, l, b);
199 };
200 FRUReader reader(getData);
201
202 EXPECT_EQ(reader.read(1, 1, nullptr), 0);
203}
204
205TEST(FRUReaderTest, StartPastKnownEOF)
206{
207 std::vector<uint8_t> data = {};
208 data.resize(blockSize / 2);
Ed Tanous3013fb42022-07-09 08:27:06 -0700209 std::array<uint8_t, blockSize> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000210 auto getData = [&data](auto o, auto l, auto* b) {
211 return getDataTempl(data, o, l, b);
212 };
213 FRUReader reader(getData);
214
215 EXPECT_EQ(reader.read(0, blockSize, blockData.data()),
216 static_cast<ssize_t>(data.size()));
217 EXPECT_EQ(reader.read(data.size(), 1, nullptr), 0);
218 EXPECT_EQ(reader.read(data.size() + 1, 1, nullptr), 0);
219 EXPECT_EQ(reader.read(blockSize, 1, nullptr), 0);
220 EXPECT_EQ(reader.read(blockSize + 1, 1, nullptr), 0);
221}
222
223TEST(FRUReaderTest, DecreasingEOF)
224{
225 const std::vector<uint8_t> data = {};
226 auto getData = [&data](auto o, auto l, auto* b) {
227 return getDataTempl(data, o, l, b);
228 };
229 FRUReader reader(getData);
230
231 EXPECT_EQ(reader.read(blockSize * 2, 1, nullptr), 0);
232 EXPECT_EQ(reader.read(blockSize + (blockSize / 2), 1, nullptr), 0);
233 EXPECT_EQ(reader.read(blockSize, 1, nullptr), 0);
234 EXPECT_EQ(reader.read(blockSize / 2, 1, nullptr), 0);
235 EXPECT_EQ(reader.read(0, 1, nullptr), 0);
236}
237
238TEST(FRUReaderTest, CacheHit)
239{
240 std::vector<uint8_t> data = {'X'};
Ed Tanous3013fb42022-07-09 08:27:06 -0700241 std::array<uint8_t, blockSize> read1{};
242 std::array<uint8_t, blockSize> read2{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000243 auto getData = [&data](auto o, auto l, auto* b) {
244 return getDataTempl(data, o, l, b);
245 };
246 FRUReader reader(getData);
247
248 // cache hit should return the same data for the second read even if we
249 // change it behind the FRUReader's back after the first
250 EXPECT_EQ(reader.read(0, blockSize, read1.data()), 1);
251 data[0] = 'Y';
252 EXPECT_EQ(reader.read(0, blockSize, read2.data()), 1);
253 EXPECT_EQ(read1[0], read2[0]);
254}
255
256TEST(FRUReaderTest, ReadPastKnownEnd)
257{
258 const std::vector<uint8_t> data = {'X', 'Y'};
Ed Tanous3013fb42022-07-09 08:27:06 -0700259 std::array<uint8_t, blockSize> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000260 auto getData = [&data](auto o, auto l, auto* b) {
261 return getDataTempl(data, o, l, b);
262 };
263 FRUReader reader(getData);
264
265 EXPECT_EQ(reader.read(0, data.size(), rdbuf.data()),
266 static_cast<ssize_t>(data.size()));
267 EXPECT_EQ(rdbuf[0], 'X');
268 EXPECT_EQ(rdbuf[1], 'Y');
269 EXPECT_EQ(reader.read(1, data.size(), rdbuf.data()),
270 static_cast<ssize_t>(data.size() - 1));
271 EXPECT_EQ(rdbuf[0], 'Y');
272}
273
274TEST(FRUReaderTest, MultiBlockRead)
275{
276 std::vector<uint8_t> data = {};
277 data.resize(blockSize, 'X');
278 data.resize(2 * blockSize, 'Y');
Ed Tanous3013fb42022-07-09 08:27:06 -0700279 std::array<uint8_t, 2 * blockSize> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000280 auto getData = [&data](auto o, auto l, auto* b) {
281 return getDataTempl(data, o, l, b);
282 };
283 FRUReader reader(getData);
284
285 EXPECT_EQ(reader.read(0, 2 * blockSize, rdbuf.data()),
286 static_cast<ssize_t>(2 * blockSize));
287 EXPECT_TRUE(std::equal(rdbuf.begin(), rdbuf.end(), data.begin()));
288}
289
290TEST(FRUReaderTest, ShrinkingEEPROM)
291{
292 std::vector<uint8_t> data = {};
293 data.resize(3 * blockSize, 'X');
Ed Tanous3013fb42022-07-09 08:27:06 -0700294 std::array<uint8_t, blockSize> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000295 auto getData = [&data](auto o, auto l, auto* b) {
296 return getDataTempl(data, o, l, b);
297 };
298 FRUReader reader(getData);
299
300 EXPECT_EQ(reader.read(data.size() - 1, 2, rdbuf.data()), 1);
301 data.resize(blockSize);
302 EXPECT_EQ(reader.read(data.size() - 1, 2, rdbuf.data()), 1);
303}
304
Oskar Senftbd4075f2021-10-05 23:42:43 -0400305TEST(FindFRUHeaderTest, InvalidHeader)
306{
307 const std::vector<uint8_t> data = {255, 16};
Zev Weiss1525e852022-03-22 22:27:43 +0000308 off_t offset = 0;
Ed Tanous3013fb42022-07-09 08:27:06 -0700309 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000310 auto getData = [&data](auto o, auto l, auto* b) {
311 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030312 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000313 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400314
Zev Weiss309c0b12022-02-25 01:44:12 +0000315 EXPECT_FALSE(findFRUHeader(reader, "error", blockData, offset));
Oskar Senftbd4075f2021-10-05 23:42:43 -0400316}
317
318TEST(FindFRUHeaderTest, NoData)
319{
320 const std::vector<uint8_t> data = {};
Zev Weiss1525e852022-03-22 22:27:43 +0000321 off_t offset = 0;
Ed Tanous3013fb42022-07-09 08:27:06 -0700322 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000323 auto getData = [&data](auto o, auto l, auto* b) {
324 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030325 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000326 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400327
Zev Weiss309c0b12022-02-25 01:44:12 +0000328 EXPECT_FALSE(findFRUHeader(reader, "error", blockData, offset));
Oskar Senftbd4075f2021-10-05 23:42:43 -0400329}
330
331TEST(FindFRUHeaderTest, ValidHeader)
332{
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030333 const std::vector<uint8_t> data = {0x01, 0x00, 0x01, 0x02,
334 0x03, 0x04, 0x00, 0xf5};
Zev Weiss1525e852022-03-22 22:27:43 +0000335 off_t offset = 0;
Ed Tanous3013fb42022-07-09 08:27:06 -0700336 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000337 auto getData = [&data](auto o, auto l, auto* b) {
338 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030339 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000340 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400341
Zev Weiss309c0b12022-02-25 01:44:12 +0000342 EXPECT_TRUE(findFRUHeader(reader, "error", blockData, offset));
Oskar Senftbd4075f2021-10-05 23:42:43 -0400343 EXPECT_EQ(0, offset);
344}
345
346TEST(FindFRUHeaderTest, TyanInvalidHeader)
347{
348 std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
349 data.resize(0x6000 + I2C_SMBUS_BLOCK_MAX);
Zev Weiss1525e852022-03-22 22:27:43 +0000350 off_t offset = 0;
Ed Tanous3013fb42022-07-09 08:27:06 -0700351 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000352 auto getData = [&data](auto o, auto l, auto* b) {
353 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030354 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000355 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400356
Zev Weiss309c0b12022-02-25 01:44:12 +0000357 EXPECT_FALSE(findFRUHeader(reader, "error", blockData, offset));
Oskar Senftbd4075f2021-10-05 23:42:43 -0400358}
359
360TEST(FindFRUHeaderTest, TyanNoData)
361{
362 const std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
Zev Weiss1525e852022-03-22 22:27:43 +0000363 off_t offset = 0;
Ed Tanous3013fb42022-07-09 08:27:06 -0700364 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000365 auto getData = [&data](auto o, auto l, auto* b) {
366 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030367 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000368 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400369
Zev Weiss309c0b12022-02-25 01:44:12 +0000370 EXPECT_FALSE(findFRUHeader(reader, "error", blockData, offset));
Oskar Senftbd4075f2021-10-05 23:42:43 -0400371}
372
373TEST(FindFRUHeaderTest, TyanValidHeader)
374{
375 std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
376 data.resize(0x6000);
377 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
378 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
379 copy(fruHeader.begin(), fruHeader.end(), back_inserter(data));
380
Zev Weiss1525e852022-03-22 22:27:43 +0000381 off_t offset = 0;
Ed Tanous3013fb42022-07-09 08:27:06 -0700382 std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000383 auto getData = [&data](auto o, auto l, auto* b) {
384 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030385 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000386 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400387
Zev Weiss309c0b12022-02-25 01:44:12 +0000388 EXPECT_TRUE(findFRUHeader(reader, "error", blockData, offset));
Oskar Senftbd4075f2021-10-05 23:42:43 -0400389 EXPECT_EQ(0x6000, offset);
390}