blob: f925db2658ae30989d89d93b5a9109656770b0d9 [file] [log] [blame]
Christopher Meis3cbff972025-04-09 14:07:22 +02001#include "fru_device/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
Ed Tanous23e3f452025-04-08 10:37:56 -07007#include "gmock/gmock.h"
Patrick Venturea62466c2021-02-08 14:55:18 -08008#include "gtest/gtest.h"
9
Ed Tanous23e3f452025-04-08 10:37:56 -070010using ::testing::Pair;
11using ::testing::UnorderedElementsAre;
12
Patrick Venturea62466c2021-02-08 14:55:18 -080013extern "C"
14{
15// Include for I2C_SMBUS_BLOCK_MAX
16#include <linux/i2c.h>
17}
18
Zev Weiss309c0b12022-02-25 01:44:12 +000019static constexpr size_t blockSize = I2C_SMBUS_BLOCK_MAX;
20
Patrick Venturea62466c2021-02-08 14:55:18 -080021TEST(ValidateHeaderTest, InvalidFruVersionReturnsFalse)
22{
23 // Validates the FruVersion is checked for the only legal value.
Ed Tanous07d467b2021-02-23 14:48:37 -080024 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Patrick Venturea62466c2021-02-08 14:55:18 -080025 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
26
Ed Tanous07d467b2021-02-23 14:48:37 -080027 EXPECT_FALSE(validateHeader(fruHeader));
Patrick Venturea62466c2021-02-08 14:55:18 -080028}
Vijay Khemka1694ef62021-02-12 23:14:49 +000029
Vijay Khemka7a682a32021-04-12 22:15:00 +000030TEST(ValidateHeaderTest, InvalidReservedReturnsFalse)
31{
32 // Validates the reserved bit(7:4) of first bytes.
Ed Tanous07d467b2021-02-23 14:48:37 -080033 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000034 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
35
Ed Tanous07d467b2021-02-23 14:48:37 -080036 EXPECT_FALSE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000037}
38
39TEST(ValidateHeaderTest, InvalidPaddingReturnsFalse)
40{
41 // Validates the padding byte (7th byte).
Ed Tanous07d467b2021-02-23 14:48:37 -080042 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000043 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
44
Ed Tanous07d467b2021-02-23 14:48:37 -080045 EXPECT_FALSE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000046}
47
48TEST(ValidateHeaderTest, InvalidChecksumReturnsFalse)
49{
50 // Validates the checksum, check for incorrect value.
Ed Tanous07d467b2021-02-23 14:48:37 -080051 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000052 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00};
53
Ed Tanous07d467b2021-02-23 14:48:37 -080054 EXPECT_FALSE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000055}
56
57TEST(ValidateHeaderTest, ValidChecksumReturnsTrue)
58{
59 // Validates the checksum, check for correct value.
Ed Tanous07d467b2021-02-23 14:48:37 -080060 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
Vijay Khemka7a682a32021-04-12 22:15:00 +000061 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
62
Ed Tanous07d467b2021-02-23 14:48:37 -080063 EXPECT_TRUE(validateHeader(fruHeader));
Vijay Khemka7a682a32021-04-12 22:15:00 +000064}
65
Vijay Khemka1694ef62021-02-12 23:14:49 +000066TEST(VerifyOffsetTest, EmptyFruDataReturnsFalse)
67{
68 // Validates the FruData size is checked for non empty.
Ed Tanous07d467b2021-02-23 14:48:37 -080069 std::vector<uint8_t> fruData = {};
Vijay Khemka1694ef62021-02-12 23:14:49 +000070
Ed Tanous07d467b2021-02-23 14:48:37 -080071 EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaChassis, 0));
Vijay Khemka1694ef62021-02-12 23:14:49 +000072}
73
74TEST(VerifyOffsetTest, AreaOutOfRangeReturnsFalse)
75{
76 // Validates the FruArea value, check if it is within range.
Ed Tanous07d467b2021-02-23 14:48:37 -080077 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x00, 0x00, 0x00,
78 0x00, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +000079
80 unsigned int areaOutOfRange = 8;
81 EXPECT_FALSE(
Ed Tanous07d467b2021-02-23 14:48:37 -080082 verifyOffset(fruData, static_cast<fruAreas>(areaOutOfRange), 0));
Vijay Khemka1694ef62021-02-12 23:14:49 +000083}
84
85TEST(VerifyOffsetTest, OverlapNextAreaReturnsFalse)
86{
87 // Validates the Overlap of offsets with overlapped values.
Ed Tanous07d467b2021-02-23 14:48:37 -080088 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x02, 0x03,
89 0x04, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +000090
Ed Tanous07d467b2021-02-23 14:48:37 -080091 EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaChassis, 2));
Vijay Khemka1694ef62021-02-12 23:14:49 +000092}
93
94TEST(VerifyOffsetTest, OverlapPrevAreaReturnsFalse)
95{
96 // Validates the Overlap of offsets with overlapped values.
Ed Tanous07d467b2021-02-23 14:48:37 -080097 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x03, 0x02,
98 0x07, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +000099
Ed Tanous07d467b2021-02-23 14:48:37 -0800100 EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaProduct, 2));
Vijay Khemka1694ef62021-02-12 23:14:49 +0000101}
102
103TEST(VerifyOffsetTest, ValidInputDataNoOverlapReturnsTrue)
104{
105 // Validates all inputs with expected value and no overlap.
Ed Tanous07d467b2021-02-23 14:48:37 -0800106 const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x02, 0x03,
107 0x04, 0x00, 0x00, 0x00};
Vijay Khemka1694ef62021-02-12 23:14:49 +0000108
Ed Tanous07d467b2021-02-23 14:48:37 -0800109 EXPECT_TRUE(verifyOffset(fruData, fruAreas::fruAreaChassis, 1));
Vijay Khemka1694ef62021-02-12 23:14:49 +0000110}
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930111
112TEST(VerifyChecksumTest, EmptyInput)
113{
114 std::vector<uint8_t> data = {};
115
116 EXPECT_EQ(calculateChecksum(data), 0);
117}
118
119TEST(VerifyChecksumTest, SingleOneInput)
120{
121 std::vector<uint8_t> data(1, 1);
122
123 EXPECT_EQ(calculateChecksum(data), 255);
124}
125
126TEST(VerifyChecksumTest, AllOneInput)
127{
128 std::vector<uint8_t> data(256, 1);
129
130 EXPECT_EQ(calculateChecksum(data), 0);
131}
132
133TEST(VerifyChecksumTest, WrapBoundaryLow)
134{
Ed Tanousfbce8e22021-09-02 15:29:12 -0700135 std::vector<uint8_t> data = {255, 0};
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930136
137 EXPECT_EQ(calculateChecksum(data), 1);
138}
139
140TEST(VerifyChecksumTest, WrapBoundaryExact)
141{
Ed Tanousfbce8e22021-09-02 15:29:12 -0700142 std::vector<uint8_t> data = {255, 1};
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930143
144 EXPECT_EQ(calculateChecksum(data), 0);
145}
146
147TEST(VerifyChecksumTest, WrapBoundaryHigh)
148{
Ed Tanousfbce8e22021-09-02 15:29:12 -0700149 std::vector<uint8_t> data = {255, 2};
Andrew Jeffery8dacf6a2021-08-02 22:17:18 +0930150
151 EXPECT_EQ(calculateChecksum(data), 255);
152}
Oskar Senftbd4075f2021-10-05 23:42:43 -0400153
Ed Tanous10c57652025-09-30 10:24:57 -0700154int64_t getDataTempl(std::span<const uint8_t> data, off_t offset, size_t length,
155 uint8_t* outBuf)
Oskar Senftbd4075f2021-10-05 23:42:43 -0400156{
Zev Weiss1525e852022-03-22 22:27:43 +0000157 if (offset >= static_cast<off_t>(data.size()))
Oskar Senftbd4075f2021-10-05 23:42:43 -0400158 {
159 return 0;
160 }
161
Ed Tanous3013fb42022-07-09 08:27:06 -0700162 uint16_t idx = offset;
163 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
164 for (; idx < std::min(data.size(), offset + length); ++idx, ++outBuf)
Oskar Senftbd4075f2021-10-05 23:42:43 -0400165 {
166 *outBuf = data[idx];
167 }
168
169 return idx - offset;
170}
171
Zev Weiss309c0b12022-02-25 01:44:12 +0000172TEST(FRUReaderTest, ReadData)
173{
174 std::vector<uint8_t> data = {};
Patrick Williams849f13a2024-12-18 15:43:19 -0500175 data.reserve(blockSize * 2);
Zev Weiss309c0b12022-02-25 01:44:12 +0000176 for (size_t i = 0; i < blockSize * 2; i++)
177 {
178 data.push_back(i);
179 }
Ed Tanous3013fb42022-07-09 08:27:06 -0700180 std::array<uint8_t, blockSize * 2> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000181 auto getData = [&data](auto o, auto l, auto* b) {
182 return getDataTempl(data, o, l, b);
183 };
184 FRUReader reader(getData);
185
186 EXPECT_EQ(reader.read(0, data.size(), rdbuf.data()),
187 static_cast<ssize_t>(data.size()));
188 EXPECT_TRUE(std::equal(rdbuf.begin(), rdbuf.end(), data.begin()));
189 for (size_t i = 0; i < blockSize * 2; i++)
190 {
191 EXPECT_EQ(reader.read(i, 1, rdbuf.data()), 1);
192 EXPECT_EQ(rdbuf[i], i);
193 }
194 EXPECT_EQ(reader.read(blockSize - 1, 2, rdbuf.data()), 2);
195 EXPECT_EQ(rdbuf[0], blockSize - 1);
196 EXPECT_EQ(rdbuf[1], blockSize);
197}
198
199TEST(FRUReaderTest, StartPastUnknownEOF)
200{
201 const std::vector<uint8_t> data = {};
202 auto getData = [&data](auto o, auto l, auto* b) {
203 return getDataTempl(data, o, l, b);
204 };
205 FRUReader reader(getData);
206
207 EXPECT_EQ(reader.read(1, 1, nullptr), 0);
208}
209
210TEST(FRUReaderTest, StartPastKnownEOF)
211{
212 std::vector<uint8_t> data = {};
213 data.resize(blockSize / 2);
Ed Tanous3013fb42022-07-09 08:27:06 -0700214 std::array<uint8_t, blockSize> blockData{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000215 auto getData = [&data](auto o, auto l, auto* b) {
216 return getDataTempl(data, o, l, b);
217 };
218 FRUReader reader(getData);
219
220 EXPECT_EQ(reader.read(0, blockSize, blockData.data()),
221 static_cast<ssize_t>(data.size()));
222 EXPECT_EQ(reader.read(data.size(), 1, nullptr), 0);
223 EXPECT_EQ(reader.read(data.size() + 1, 1, nullptr), 0);
224 EXPECT_EQ(reader.read(blockSize, 1, nullptr), 0);
225 EXPECT_EQ(reader.read(blockSize + 1, 1, nullptr), 0);
226}
227
228TEST(FRUReaderTest, DecreasingEOF)
229{
230 const std::vector<uint8_t> data = {};
231 auto getData = [&data](auto o, auto l, auto* b) {
232 return getDataTempl(data, o, l, b);
233 };
234 FRUReader reader(getData);
235
236 EXPECT_EQ(reader.read(blockSize * 2, 1, nullptr), 0);
237 EXPECT_EQ(reader.read(blockSize + (blockSize / 2), 1, nullptr), 0);
238 EXPECT_EQ(reader.read(blockSize, 1, nullptr), 0);
239 EXPECT_EQ(reader.read(blockSize / 2, 1, nullptr), 0);
240 EXPECT_EQ(reader.read(0, 1, nullptr), 0);
241}
242
243TEST(FRUReaderTest, CacheHit)
244{
245 std::vector<uint8_t> data = {'X'};
Ed Tanous3013fb42022-07-09 08:27:06 -0700246 std::array<uint8_t, blockSize> read1{};
247 std::array<uint8_t, blockSize> read2{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000248 auto getData = [&data](auto o, auto l, auto* b) {
249 return getDataTempl(data, o, l, b);
250 };
251 FRUReader reader(getData);
252
253 // cache hit should return the same data for the second read even if we
254 // change it behind the FRUReader's back after the first
255 EXPECT_EQ(reader.read(0, blockSize, read1.data()), 1);
256 data[0] = 'Y';
257 EXPECT_EQ(reader.read(0, blockSize, read2.data()), 1);
258 EXPECT_EQ(read1[0], read2[0]);
259}
260
261TEST(FRUReaderTest, ReadPastKnownEnd)
262{
263 const std::vector<uint8_t> data = {'X', 'Y'};
Ed Tanous3013fb42022-07-09 08:27:06 -0700264 std::array<uint8_t, blockSize> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000265 auto getData = [&data](auto o, auto l, auto* b) {
266 return getDataTempl(data, o, l, b);
267 };
268 FRUReader reader(getData);
269
270 EXPECT_EQ(reader.read(0, data.size(), rdbuf.data()),
271 static_cast<ssize_t>(data.size()));
272 EXPECT_EQ(rdbuf[0], 'X');
273 EXPECT_EQ(rdbuf[1], 'Y');
274 EXPECT_EQ(reader.read(1, data.size(), rdbuf.data()),
275 static_cast<ssize_t>(data.size() - 1));
276 EXPECT_EQ(rdbuf[0], 'Y');
277}
278
279TEST(FRUReaderTest, MultiBlockRead)
280{
281 std::vector<uint8_t> data = {};
282 data.resize(blockSize, 'X');
283 data.resize(2 * blockSize, 'Y');
Ed Tanous3013fb42022-07-09 08:27:06 -0700284 std::array<uint8_t, 2 * blockSize> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000285 auto getData = [&data](auto o, auto l, auto* b) {
286 return getDataTempl(data, o, l, b);
287 };
288 FRUReader reader(getData);
289
290 EXPECT_EQ(reader.read(0, 2 * blockSize, rdbuf.data()),
291 static_cast<ssize_t>(2 * blockSize));
292 EXPECT_TRUE(std::equal(rdbuf.begin(), rdbuf.end(), data.begin()));
293}
294
295TEST(FRUReaderTest, ShrinkingEEPROM)
296{
297 std::vector<uint8_t> data = {};
298 data.resize(3 * blockSize, 'X');
Ed Tanous3013fb42022-07-09 08:27:06 -0700299 std::array<uint8_t, blockSize> rdbuf{};
Zev Weiss309c0b12022-02-25 01:44:12 +0000300 auto getData = [&data](auto o, auto l, auto* b) {
301 return getDataTempl(data, o, l, b);
302 };
303 FRUReader reader(getData);
304
305 EXPECT_EQ(reader.read(data.size() - 1, 2, rdbuf.data()), 1);
306 data.resize(blockSize);
307 EXPECT_EQ(reader.read(data.size() - 1, 2, rdbuf.data()), 1);
308}
309
Oskar Senftbd4075f2021-10-05 23:42:43 -0400310TEST(FindFRUHeaderTest, InvalidHeader)
311{
312 const std::vector<uint8_t> data = {255, 16};
Zev Weiss1525e852022-03-22 22:27:43 +0000313 off_t offset = 0;
Zev Weiss309c0b12022-02-25 01:44:12 +0000314 auto getData = [&data](auto o, auto l, auto* b) {
315 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030316 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000317 FRUReader reader(getData);
Ed Tanous10c57652025-09-30 10:24:57 -0700318 auto sections = findFRUHeader(reader, "error", offset);
319 EXPECT_EQ(sections, std::nullopt);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400320}
321
322TEST(FindFRUHeaderTest, NoData)
323{
324 const std::vector<uint8_t> data = {};
Zev Weiss1525e852022-03-22 22:27:43 +0000325 off_t offset = 0;
Zev Weiss309c0b12022-02-25 01:44:12 +0000326 auto getData = [&data](auto o, auto l, auto* b) {
327 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030328 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000329 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400330
Ed Tanous10c57652025-09-30 10:24:57 -0700331 auto sections = findFRUHeader(reader, "error", offset);
332 EXPECT_EQ(sections, std::nullopt);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400333}
334
335TEST(FindFRUHeaderTest, ValidHeader)
336{
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030337 const std::vector<uint8_t> data = {0x01, 0x00, 0x01, 0x02,
338 0x03, 0x04, 0x00, 0xf5};
Zev Weiss1525e852022-03-22 22:27:43 +0000339 off_t offset = 0;
Zev Weiss309c0b12022-02-25 01:44:12 +0000340 auto getData = [&data](auto o, auto l, auto* b) {
341 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030342 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000343 FRUReader reader(getData);
Ed Tanous10c57652025-09-30 10:24:57 -0700344 auto sections = findFRUHeader(reader, "error", offset);
345 ASSERT_NE(sections, std::nullopt);
346 if (sections)
347 {
348 EXPECT_EQ(0, sections->IpmiFruOffset);
349 }
Oskar Senftbd4075f2021-10-05 23:42:43 -0400350}
351
352TEST(FindFRUHeaderTest, TyanInvalidHeader)
353{
354 std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
355 data.resize(0x6000 + I2C_SMBUS_BLOCK_MAX);
Zev Weiss1525e852022-03-22 22:27:43 +0000356 off_t offset = 0;
Zev Weiss309c0b12022-02-25 01:44:12 +0000357 auto getData = [&data](auto o, auto l, auto* b) {
358 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030359 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000360 FRUReader reader(getData);
Ed Tanous10c57652025-09-30 10:24:57 -0700361 auto sections = findFRUHeader(reader, "error", offset);
362 EXPECT_EQ(sections, std::nullopt);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400363}
364
365TEST(FindFRUHeaderTest, TyanNoData)
366{
367 const std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
Zev Weiss1525e852022-03-22 22:27:43 +0000368 off_t offset = 0;
Zev Weiss309c0b12022-02-25 01:44:12 +0000369 auto getData = [&data](auto o, auto l, auto* b) {
370 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030371 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000372 FRUReader reader(getData);
Ed Tanous10c57652025-09-30 10:24:57 -0700373 auto sections = findFRUHeader(reader, "error", offset);
374 EXPECT_EQ(sections, std::nullopt);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400375}
376
377TEST(FindFRUHeaderTest, TyanValidHeader)
378{
379 std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
380 data.resize(0x6000);
381 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
382 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
383 copy(fruHeader.begin(), fruHeader.end(), back_inserter(data));
384
Zev Weiss1525e852022-03-22 22:27:43 +0000385 off_t offset = 0;
Zev Weiss309c0b12022-02-25 01:44:12 +0000386 auto getData = [&data](auto o, auto l, auto* b) {
387 return getDataTempl(data, o, l, b);
Andrew Jefferyf8ae2ba2022-03-25 15:13:55 +1030388 };
Zev Weiss309c0b12022-02-25 01:44:12 +0000389 FRUReader reader(getData);
Oskar Senftbd4075f2021-10-05 23:42:43 -0400390
Ed Tanous10c57652025-09-30 10:24:57 -0700391 auto sections = findFRUHeader(reader, "error", offset);
392
393 ASSERT_NE(sections, std::nullopt);
394 if (sections)
395 {
396 EXPECT_EQ(0x6000, sections->IpmiFruOffset);
397 }
398}
399
400TEST(FindFRUHeaderTest, GigaInvalidHeader)
401{
402 std::vector<uint8_t> data = {'G', 'I', 'G', 'A', 'B', 'Y', 'T', 'E'};
403 data.resize(0x6000 + I2C_SMBUS_BLOCK_MAX);
404 off_t offset = 0;
405 auto getData = [&data](auto o, auto l, auto* b) {
406 return getDataTempl(data, o, l, b);
407 };
408 FRUReader reader(getData);
409 auto sections = findFRUHeader(reader, "error", offset);
410 EXPECT_EQ(sections, std::nullopt);
411}
412
413TEST(FindFRUHeaderTest, GigaNoData)
414{
415 const std::vector<uint8_t> data = {'G', 'I', 'G', 'A', 'B', 'Y', 'T', 'E'};
416 off_t offset = 0;
417 auto getData = [&data](auto o, auto l, auto* b) {
418 return getDataTempl(data, o, l, b);
419 };
420 FRUReader reader(getData);
421 auto sections = findFRUHeader(reader, "error", offset);
422 EXPECT_EQ(sections, std::nullopt);
423}
424
425TEST(FindFRUHeaderTest, GigaValidHeader)
426{
427 std::vector<uint8_t> data = {'G', 'I', 'G', 'A', 'B', 'Y', 'T', 'E'};
428 data.resize(0x4000);
429 constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
430 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
431 copy(fruHeader.begin(), fruHeader.end(), back_inserter(data));
432
433 off_t offset = 0;
434 auto getData = [&data](auto o, auto l, auto* b) {
435 return getDataTempl(data, o, l, b);
436 };
437 FRUReader reader(getData);
438
439 auto sections = findFRUHeader(reader, "error", offset);
440
441 ASSERT_NE(sections, std::nullopt);
442 if (sections)
443 {
444 EXPECT_EQ(0x4000, sections->IpmiFruOffset);
445 EXPECT_EQ(512, sections->GigabyteXmlOffset);
446 }
Oskar Senftbd4075f2021-10-05 23:42:43 -0400447}
Ed Tanous23e3f452025-04-08 10:37:56 -0700448
449TEST(formatIPMIFRU, FullDecode)
450{
451 const std::array<uint8_t, 176> bmcFru = {
452 0x01, 0x00, 0x00, 0x01, 0x0b, 0x00, 0x00, 0xf3, 0x01, 0x0a, 0x19, 0x1f,
453 0x0f, 0xe6, 0xc6, 0x4e, 0x56, 0x49, 0x44, 0x49, 0x41, 0xc5, 0x50, 0x33,
454 0x38, 0x30, 0x39, 0xcd, 0x31, 0x35, 0x38, 0x33, 0x33, 0x32, 0x34, 0x38,
455 0x30, 0x30, 0x31, 0x35, 0x30, 0xd2, 0x36, 0x39, 0x39, 0x2d, 0x31, 0x33,
456 0x38, 0x30, 0x39, 0x2d, 0x30, 0x34, 0x30, 0x34, 0x2d, 0x36, 0x30, 0x30,
457 0xc0, 0x01, 0x01, 0xd6, 0x4d, 0x41, 0x43, 0x3a, 0x20, 0x33, 0x43, 0x3a,
458 0x36, 0x44, 0x3a, 0x36, 0x36, 0x3a, 0x31, 0x34, 0x3a, 0x43, 0x38, 0x3a,
459 0x37, 0x41, 0xc1, 0x3b, 0x01, 0x09, 0x19, 0xc6, 0x4e, 0x56, 0x49, 0x44,
460 0x49, 0x41, 0xc9, 0x50, 0x33, 0x38, 0x30, 0x39, 0x2d, 0x42, 0x4d, 0x43,
461 0xd2, 0x36, 0x39, 0x39, 0x2d, 0x31, 0x33, 0x38, 0x30, 0x39, 0x2d, 0x30,
462 0x34, 0x30, 0x34, 0x2d, 0x36, 0x30, 0x30, 0xc4, 0x41, 0x45, 0x2e, 0x31,
463 0xcd, 0x31, 0x35, 0x38, 0x33, 0x33, 0x32, 0x34, 0x38, 0x30, 0x30, 0x31,
464 0x35, 0x30, 0xc0, 0xc4, 0x76, 0x30, 0x2e, 0x31, 0xc1, 0x00, 0x00, 0x00,
465 0x00, 0x00, 0x00, 0xb4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
466 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
467 boost::container::flat_map<std::string, std::string> result;
468 ASSERT_EQ(formatIPMIFRU(bmcFru, result), resCodes::resOK);
469
470 EXPECT_THAT(
471 result,
472 UnorderedElementsAre(
473 Pair("BOARD_FRU_VERSION_ID", ""), Pair("BOARD_INFO_AM1", "01"),
474 Pair("BOARD_INFO_AM2", "MAC: 3C:6D:66:14:C8:7A"),
475 Pair("BOARD_LANGUAGE_CODE", "25"),
476 Pair("BOARD_MANUFACTURER", "NVIDIA"),
477 Pair("BOARD_MANUFACTURE_DATE", "20240831T055100Z"),
478 Pair("BOARD_PART_NUMBER", "699-13809-0404-600"),
479 Pair("BOARD_PRODUCT_NAME", "P3809"),
480 Pair("BOARD_SERIAL_NUMBER", "1583324800150"),
481 Pair("Common_Format_Version", "1"), Pair("PRODUCT_ASSET_TAG", ""),
Ed Tanous7f2db482025-04-04 16:38:42 -0700482 Pair("MAC_BOARD_INFO_AM2", "3C:6D:66:14:C8:7A"),
Ed Tanous23e3f452025-04-08 10:37:56 -0700483 Pair("PRODUCT_FRU_VERSION_ID", "v0.1"),
484 Pair("PRODUCT_LANGUAGE_CODE", "25"),
485 Pair("PRODUCT_MANUFACTURER", "NVIDIA"),
486 Pair("PRODUCT_PART_NUMBER", "699-13809-0404-600"),
487 Pair("PRODUCT_PRODUCT_NAME", "P3809-BMC"),
488 Pair("PRODUCT_SERIAL_NUMBER", "1583324800150"),
489 Pair("PRODUCT_VERSION", "AE.1")));
490}
Naresh Solanki89092a92025-06-02 15:48:04 +0530491
492// Test for the `isFieldEditable` function
493TEST(IsFieldEditableTest, ValidField)
494{
495 // Test with a valid field name that is editable
496 // All PRODUCT fields are editable
497 EXPECT_TRUE(isFieldEditable("PRODUCT_MANUFACTURER"));
498 EXPECT_TRUE(isFieldEditable("PRODUCT_PART_NUMBER"));
499 EXPECT_TRUE(isFieldEditable("PRODUCT_SERIAL_NUMBER"));
500 EXPECT_TRUE(isFieldEditable("PRODUCT_VERSION"));
501 EXPECT_TRUE(isFieldEditable("PRODUCT_PART_NUMBER"));
502 EXPECT_TRUE(isFieldEditable("PRODUCT_PRODUCT_NAME"));
503 EXPECT_TRUE(isFieldEditable("PRODUCT_ASSET_TAG"));
504 EXPECT_TRUE(isFieldEditable("PRODUCT_FRU_VERSION_ID"));
505 EXPECT_TRUE(isFieldEditable("PRODUCT_INFO_AM0"));
506
507 // All BOARD fields are editable
508 EXPECT_TRUE(isFieldEditable("BOARD_MANUFACTURER"));
509 EXPECT_TRUE(isFieldEditable("BOARD_PART_NUMBER"));
510 EXPECT_TRUE(isFieldEditable("BOARD_SERIAL_NUMBER"));
511 EXPECT_TRUE(isFieldEditable("BOARD_FRU_VERSION_ID"));
512 EXPECT_TRUE(isFieldEditable("BOARD_PRODUCT_NAME"));
513 EXPECT_TRUE(isFieldEditable("BOARD_INFO_AM0"));
514 EXPECT_TRUE(isFieldEditable("BOARD_INFO_AM10"));
515
516 // All CHASSIS fields are editable
517 EXPECT_TRUE(isFieldEditable("CHASSIS_PART_NUMBER"));
518 EXPECT_TRUE(isFieldEditable("CHASSIS_SERIAL_NUMBER"));
519 EXPECT_TRUE(isFieldEditable("CHASSIS_INFO_AM0"));
520 EXPECT_TRUE(isFieldEditable("CHASSIS_INFO_AM10"));
521}
522
523TEST(IsFieldEditableTest, InvalidField)
524{
525 // Test with an invalid field name that is not editable
526 EXPECT_FALSE(isFieldEditable("INVALID_FIELD"));
527 EXPECT_FALSE(isFieldEditable("PRODUCT_INVALID_FIELD"));
528 EXPECT_FALSE(isFieldEditable("BOARD_INVALID_FIELD"));
529 EXPECT_FALSE(isFieldEditable("CHASSIS_INVALID_FIELD"));
530
531 // Test with a field that does not match the expected pattern
532 EXPECT_FALSE(isFieldEditable("PRODUCT_12345"));
533 EXPECT_FALSE(isFieldEditable("BOARD_67890"));
534 EXPECT_FALSE(isFieldEditable("ABCD_CHASSIS"));
535 EXPECT_FALSE(isFieldEditable("ABCD_PRODUCT"));
536 EXPECT_FALSE(isFieldEditable("ABCD_BOARD"));
537}
Naresh Solankicf288962025-06-06 15:26:11 +0530538
Naresh Solankicf288962025-06-06 15:26:11 +0530539TEST(UpdateAreaChecksumTest, EmptyArea)
540{
541 // Validates that an empty area does not cause any issues.
542 std::vector<uint8_t> fruArea = {};
Marc Olberding25680e32025-10-03 12:38:10 -0700543 EXPECT_FALSE(updateAreaChecksum(fruArea));
Naresh Solankicf288962025-06-06 15:26:11 +0530544}
545
546TEST(UpdateAreaChecksumTest, ValidArea)
547{
548 // Validates that a valid area updates the checksum correctly.
549 std::vector<uint8_t> fruArea = {0x01, 0x00, 0x01, 0x02,
550 0x03, 0x04, 0x00, 0x00};
Marc Olberding25680e32025-10-03 12:38:10 -0700551 EXPECT_TRUE(updateAreaChecksum(fruArea));
Naresh Solankicf288962025-06-06 15:26:11 +0530552 EXPECT_EQ(fruArea.back(), 0xf5);
553}
554
555TEST(UpdateAreaChecksumTest, InvalidArea)
556{
557 // Validates that an invalid area does not update the checksum.
558 std::vector<uint8_t> fruArea = {0x01, 0x00, 0x01, 0x02, 0x03,
559 0x04, 0x00, 0x00, 0xAA};
Marc Olberding25680e32025-10-03 12:38:10 -0700560 EXPECT_FALSE(updateAreaChecksum(fruArea));
Naresh Solankicf288962025-06-06 15:26:11 +0530561}
562
563TEST(DisassembleFruDataTest, EmptyData)
564{
565 // Validates that an empty data vector returns false.
566 std::vector<uint8_t> fruData = {};
567 std::vector<std::vector<uint8_t>> areasData;
568 EXPECT_FALSE(disassembleFruData(fruData, areasData));
569}
570
571TEST(DisassembleFruDataTest, ValidData)
572{
573 // Taken from qemu fby35_bmc_fruid
574 std::vector<uint8_t> fruData = {
575 0x01, 0x00, 0x00, 0x01, 0x0d, 0x00, 0x00, 0xf1, 0x01, 0x0c, 0x00, 0x36,
576 0xe6, 0xd0, 0xc6, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, 0x42, 0x4d,
577 0x43, 0x20, 0x53, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x20, 0x4d, 0x6f,
578 0x64, 0x75, 0x6c, 0x65, 0xcd, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
579 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xce, 0x58, 0x58, 0x58, 0x58, 0x58,
580 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc3, 0x31, 0x2e,
581 0x30, 0xc9, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2,
582 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
583 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc1, 0x39, 0x01, 0x0c, 0x00, 0xc6,
584 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xd2, 0x59, 0x6f, 0x73, 0x65, 0x6d,
585 0x69, 0x74, 0x65, 0x20, 0x56, 0x33, 0x2e, 0x35, 0x20, 0x45, 0x56, 0x54,
586 0x32, 0xce, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58,
587 0x58, 0x58, 0x58, 0x58, 0xc4, 0x45, 0x56, 0x54, 0x32, 0xcd, 0x58, 0x58,
588 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc7,
589 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc3, 0x31, 0x2e, 0x30, 0xc9,
590 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0x58, 0xc8, 0x43, 0x6f,
591 0x6e, 0x66, 0x69, 0x67, 0x20, 0x41, 0xc1, 0x45,
592 };
593
594 std::vector<std::vector<uint8_t>> areasData;
Marc Olberding25680e32025-10-03 12:38:10 -0700595 ASSERT_TRUE(disassembleFruData(fruData, areasData));
Ed Tanousa9158842025-09-30 10:28:55 -0700596 EXPECT_GT(areasData.size(), 1U);
Naresh Solankicf288962025-06-06 15:26:11 +0530597
598 // Internal area is size is zero
599 EXPECT_EQ(areasData[static_cast<size_t>(fruAreas::fruAreaInternal)].size(),
Ed Tanousa9158842025-09-30 10:28:55 -0700600 0U);
Naresh Solankicf288962025-06-06 15:26:11 +0530601 // Chassis are is zero
602 EXPECT_EQ(areasData[static_cast<size_t>(fruAreas::fruAreaChassis)].size(),
Ed Tanousa9158842025-09-30 10:28:55 -0700603 0U);
Naresh Solankicf288962025-06-06 15:26:11 +0530604 // Board area is 96 byte
605 EXPECT_EQ(areasData[static_cast<size_t>(fruAreas::fruAreaBoard)].size(),
Ed Tanousa9158842025-09-30 10:28:55 -0700606 96U);
Naresh Solankicf288962025-06-06 15:26:11 +0530607 // Product area is 96 byte
608 EXPECT_EQ(areasData[static_cast<size_t>(fruAreas::fruAreaProduct)].size(),
Ed Tanousa9158842025-09-30 10:28:55 -0700609 96U);
Naresh Solankicf288962025-06-06 15:26:11 +0530610
611 // Multi-record area is 64 byte.
612 EXPECT_EQ(
Ed Tanousa9158842025-09-30 10:28:55 -0700613 areasData[static_cast<size_t>(fruAreas::fruAreaMultirecord)].size(),
614 0U);
Naresh Solankicf288962025-06-06 15:26:11 +0530615
616 EXPECT_TRUE(setField(fruAreas::fruAreaBoard,
617 areasData[static_cast<size_t>(fruAreas::fruAreaBoard)],
618 "BOARD_INFO_AM1", "01"));
619 EXPECT_TRUE(setField(fruAreas::fruAreaBoard,
620 areasData[static_cast<size_t>(fruAreas::fruAreaBoard)],
621 "BOARD_INFO_AM2", "MAC: 3C:6D:66:14:C8:7A"));
622 // set Product fields
623 EXPECT_TRUE(
624 setField(fruAreas::fruAreaProduct,
625 areasData[static_cast<size_t>(fruAreas::fruAreaProduct)],
626 "PRODUCT_ASSET_TAG", "123"));
627 EXPECT_TRUE(
628 setField(fruAreas::fruAreaProduct,
629 areasData[static_cast<size_t>(fruAreas::fruAreaProduct)],
630 "PRODUCT_PART_NUMBER", "699-13809-0404-600"));
631 EXPECT_TRUE(
632 setField(fruAreas::fruAreaProduct,
633 areasData[static_cast<size_t>(fruAreas::fruAreaProduct)],
634 "PRODUCT_PRODUCT_NAME", "OpenBMC-test1"));
635
Marc Olberding25680e32025-10-03 12:38:10 -0700636 EXPECT_EQ(
637 areasData[static_cast<size_t>(fruAreas::fruAreaProduct)].size() % 8, 0);
638 EXPECT_EQ(areasData[static_cast<size_t>(fruAreas::fruAreaBoard)].size() % 8,
639 0);
640
Naresh Solankicf288962025-06-06 15:26:11 +0530641 std::vector<uint8_t> assembledData;
642 EXPECT_TRUE(assembleFruData(assembledData, areasData));
Marc Olberding25680e32025-10-03 12:38:10 -0700643
644 boost::container::flat_map<std::string, std::string> result;
645 auto rescode = formatIPMIFRU(assembledData, result);
646 EXPECT_NE(rescode, resCodes::resErr);
647
648 EXPECT_EQ(result["PRODUCT_ASSET_TAG"], "123");
649 EXPECT_EQ(result["PRODUCT_PART_NUMBER"], "699-13809-0404-600");
650 EXPECT_EQ(result["PRODUCT_PRODUCT_NAME"], "OpenBMC-test1");
651 EXPECT_EQ(result["BOARD_INFO_AM1"], "01");
652 EXPECT_EQ(result["BOARD_INFO_AM2"], "MAC: 3C:6D:66:14:C8:7A");
653}
654
655TEST(ReassembleFruDataTest, UnalignedFails)
656{
657 std::vector<uint8_t> areaOne{0, 35};
658 std::vector<uint8_t> areaTwo{0, 32};
659 std::vector<std::vector<uint8_t>> areas;
660 areas.push_back(areaOne);
661 areas.push_back(areaTwo);
662
663 std::vector<uint8_t> fruData;
664 EXPECT_FALSE(assembleFruData(fruData, areas));
Naresh Solankicf288962025-06-06 15:26:11 +0530665}
Ed Tanous10c57652025-09-30 10:24:57 -0700666
667constexpr auto gzip = std::to_array<uint8_t>(
668 {0x1f, 0x8b, 0x08, 0x08, 0x74, 0x47, 0xe4, 0x68, 0x00, 0x03, 0x66, 0x72,
669 0x75, 0x2e, 0x62, 0x69, 0x6e, 0x00, 0x9d, 0x91, 0xdf, 0x0a, 0x82, 0x30,
670 0x18, 0xc5, 0xef, 0x7d, 0x8a, 0xe1, 0x7d, 0x4d, 0xad, 0x0b, 0x1b, 0x73,
671 0x52, 0x9a, 0x21, 0x51, 0x37, 0xcb, 0x07, 0x18, 0x6e, 0xea, 0xa0, 0x36,
672 0x58, 0x12, 0x3d, 0x7e, 0x29, 0x5a, 0x5a, 0x08, 0xd1, 0xdd, 0x7e, 0xdf,
673 0x9f, 0x9d, 0xc3, 0xf9, 0x70, 0x78, 0xbf, 0x9c, 0xc1, 0x4d, 0x98, 0xab,
674 0xd4, 0x2a, 0xb0, 0xdd, 0xb9, 0x63, 0x03, 0xa1, 0x72, 0xcd, 0xa5, 0x2a,
675 0x03, 0x3b, 0x3b, 0x25, 0x33, 0xdf, 0x0e, 0x89, 0x85, 0x77, 0x94, 0xee,
676 0x33, 0x62, 0x01, 0x00, 0xf0, 0x46, 0x33, 0xc3, 0x53, 0x55, 0xe8, 0x16,
677 0x9b, 0xca, 0x81, 0x49, 0xd5, 0x43, 0xc3, 0xc7, 0x34, 0x1a, 0x60, 0x53,
678 0x49, 0x55, 0x2d, 0x4c, 0xc1, 0x72, 0xe1, 0x8e, 0x1b, 0xed, 0xb6, 0xe6,
679 0x82, 0xc4, 0x82, 0xcb, 0x9c, 0xd5, 0x82, 0x63, 0xd8, 0xf2, 0xf7, 0x14,
680 0xcb, 0xd7, 0x9c, 0x1b, 0x87, 0xb8, 0x0e, 0x4a, 0x12, 0xb4, 0x75, 0xd0,
681 0x62, 0x85, 0xfc, 0x25, 0x8a, 0xa3, 0xe7, 0x46, 0xdf, 0x1b, 0x8b, 0xc2,
682 0x29, 0xd5, 0xb7, 0x1d, 0x6f, 0xc2, 0x0e, 0xad, 0x98, 0xf9, 0xc3, 0x4b,
683 0xfc, 0x83, 0x97, 0x0f, 0x49, 0x4c, 0x6b, 0x23, 0x54, 0x59, 0x57, 0xc4,
684 0xc3, 0xf0, 0xf5, 0x1e, 0x84, 0x09, 0x07, 0x69, 0x36, 0xdf, 0x77, 0x51,
685 0x63, 0x38, 0xb8, 0x03, 0x86, 0xdd, 0x7d, 0x1e, 0x15, 0xc1, 0xa2, 0x29,
686 0xcf, 0x01, 0x00, 0x00});
687
688TEST(GzipUtils, parseMacFromGzipXmlHeader)
689{
690 FRUReader reader(std::bind_front(getDataTempl, gzip));
691
692 std::string mac = parseMacFromGzipXmlHeader(reader, 0);
693 EXPECT_EQ(mac, "10:FF:E0:39:84:DC");
694}