blob: 69dc7ddb830da982fc927bb09859beb48a283822 [file] [log] [blame]
Alexander Hansen40fb5492025-10-28 17:56:12 +01001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
Matt Spinler6c9662c2019-10-09 11:27:20 -05004#include "extensions/openpower-pels/callout.hpp"
5#include "pel_utils.hpp"
6
7#include <gtest/gtest.h>
8
9using namespace openpower::pels;
10using namespace openpower::pels::src;
11
12// Unflatten the callout section with all three substructures
13TEST(CalloutTest, TestUnflattenAllSubstructures)
14{
15 // The base data.
16 std::vector<uint8_t> data{
17 0xFF, 0x2F, 'H', 8, // size, flags, priority, LC length
18 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
19 };
20
21 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
22 auto pceIdentity = srcDataFactory(TestSRCType::pceIdentityStructure);
23 auto mrus = srcDataFactory(TestSRCType::mruStructure);
24
25 // Add all 3 substructures
26 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
27 data.insert(data.end(), pceIdentity.begin(), pceIdentity.end());
28 data.insert(data.end(), mrus.begin(), mrus.end());
29
30 // The final size
31 data[0] = data.size();
32
33 Stream stream{data};
34 Callout callout{stream};
35
36 EXPECT_EQ(callout.flattenedSize(), data.size());
37 EXPECT_EQ(callout.priority(), 'H');
38 EXPECT_EQ(callout.locationCode(), "U12-P1");
39
40 // Spot check the 3 substructures
41 EXPECT_TRUE(callout.fruIdentity());
42 EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
43
44 EXPECT_TRUE(callout.pceIdentity());
45 EXPECT_EQ(callout.pceIdentity()->enclosureName(), "PCENAME12");
46
47 EXPECT_TRUE(callout.mru());
48 EXPECT_EQ(callout.mru()->mrus().size(), 4);
49 EXPECT_EQ(callout.mru()->mrus().at(3).id, 0x04040404);
50
51 // Now flatten
52 std::vector<uint8_t> newData;
53 Stream newStream{newData};
54
55 callout.flatten(newStream);
56 EXPECT_EQ(data, newData);
57}
58
59TEST(CalloutTest, TestUnflattenOneSubstructure)
60{
61 std::vector<uint8_t> data{
62 0xFF, 0x28, 'H', 0x08, // size, flags, priority, LC length
63 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
64 };
65
66 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
67
68 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
69
70 // The final size
71 data[0] = data.size();
72
73 Stream stream{data};
74 Callout callout{stream};
75
76 EXPECT_EQ(callout.flattenedSize(), data.size());
77
78 // Spot check the substructure
79 EXPECT_TRUE(callout.fruIdentity());
80 EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
81
82 // Not present
83 EXPECT_FALSE(callout.pceIdentity());
84 EXPECT_FALSE(callout.mru());
85
86 // Now flatten
87 std::vector<uint8_t> newData;
88 Stream newStream{newData};
89
90 callout.flatten(newStream);
91 EXPECT_EQ(data, newData);
92}
93
94TEST(CalloutTest, TestUnflattenTwoSubstructures)
95{
96 std::vector<uint8_t> data{
97 0xFF, 0x2B, 'H', 0x08, // size, flags, priority, LC length
98 'U', '1', '2', '-', 'P', '1', 0x00, 0x00 // LC
99 };
100
101 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
102 auto pceIdentity = srcDataFactory(TestSRCType::pceIdentityStructure);
103
104 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
105 data.insert(data.end(), pceIdentity.begin(), pceIdentity.end());
106
107 // The final size
108 data[0] = data.size();
109
110 Stream stream{data};
111 Callout callout{stream};
112
113 EXPECT_EQ(callout.flattenedSize(), data.size());
114
115 // Spot check the 2 substructures
116 EXPECT_TRUE(callout.fruIdentity());
117 EXPECT_EQ(callout.fruIdentity()->getSN(), "123456789ABC");
118
119 EXPECT_TRUE(callout.pceIdentity());
120 EXPECT_EQ(callout.pceIdentity()->enclosureName(), "PCENAME12");
121
122 // Not present
123 EXPECT_FALSE(callout.mru());
124
125 // Now flatten
126 std::vector<uint8_t> newData;
127 Stream newStream{newData};
128
129 callout.flatten(newStream);
130 EXPECT_EQ(data, newData);
131}
132
133TEST(CalloutTest, TestNoLocationCode)
134{
135 std::vector<uint8_t> data{
136 0xFF, 0x2B, 'H', 0x00 // size, flags, priority, LC length
137 };
138
139 auto fruIdentity = srcDataFactory(TestSRCType::fruIdentityStructure);
140 data.insert(data.end(), fruIdentity.begin(), fruIdentity.end());
141
142 // The final size
143 data[0] = data.size();
144
145 Stream stream{data};
146 Callout callout{stream};
147
148 EXPECT_TRUE(callout.locationCode().empty());
149}
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500150
151// Create a callout object by passing in the hardware fields to add
152TEST(CalloutTest, TestHardwareCallout)
153{
154 constexpr size_t fruIdentitySize = 28;
155
156 {
157 Callout callout{CalloutPriority::high, "U99-42.5-P1-C2-E1", "1234567",
158 "ABCD", "123456789ABC"};
159
160 // size/flags/pri/locsize fields +
161 // rounded up location code length +
162 // FRUIdentity size
163 size_t size = 4 + 20 + fruIdentitySize;
164
165 EXPECT_EQ(callout.flags(),
166 Callout::calloutType | Callout::fruIdentIncluded);
167
168 EXPECT_EQ(callout.flattenedSize(), size);
169 EXPECT_EQ(callout.priority(), 'H');
170 EXPECT_EQ(callout.locationCode(), "U99-42.5-P1-C2-E1");
171 EXPECT_EQ(callout.locationCodeSize(), 20);
172
173 auto& fru = callout.fruIdentity();
174 EXPECT_EQ(fru->getPN().value(), "1234567");
175 EXPECT_EQ(fru->getCCIN().value(), "ABCD");
176 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
177 }
178
179 {
180 // A 3B location code, plus null = 4
181 Callout callout{CalloutPriority::high, "123", "1234567", "ABCD",
182 "123456789ABC"};
183
184 size_t size = 4 + 4 + fruIdentitySize;
185 EXPECT_EQ(callout.locationCodeSize(), 4);
186 EXPECT_EQ(callout.flattenedSize(), size);
187 EXPECT_EQ(callout.locationCode(), "123");
188 }
189
190 {
191 // A 4B location code, plus null = 5, then pad to 8
192 Callout callout{CalloutPriority::high, "1234", "1234567", "ABCD",
193 "123456789ABC"};
194
195 size_t size = 4 + 8 + fruIdentitySize;
196 EXPECT_EQ(callout.locationCodeSize(), 8);
197 EXPECT_EQ(callout.flattenedSize(), size);
198 EXPECT_EQ(callout.locationCode(), "1234");
199 }
200
201 {
202 // A truncated location code (80 is max size, including null)
203 std::string locCode(81, 'L');
204 Callout callout{CalloutPriority::high, locCode, "1234567", "ABCD",
205 "123456789ABC"};
206
207 size_t size = 4 + 80 + fruIdentitySize;
208 EXPECT_EQ(callout.locationCodeSize(), 80);
209 EXPECT_EQ(callout.flattenedSize(), size);
210
211 // take off 1 to get to 80, and another for the null
212 locCode = locCode.substr(0, locCode.size() - 2);
213 EXPECT_EQ(callout.locationCode(), locCode);
214 }
215
216 {
217 // A truncated location code by 1 because of the null
218 std::string locCode(80, 'L');
219 Callout callout{CalloutPriority::high, locCode, "1234567", "ABCD",
220 "123456789ABC"};
221
222 size_t size = 4 + 80 + fruIdentitySize;
223 EXPECT_EQ(callout.locationCodeSize(), 80);
224 EXPECT_EQ(callout.flattenedSize(), size);
225
226 locCode.pop_back();
227 EXPECT_EQ(callout.locationCode(), locCode);
228 }
229
230 {
231 // Max size location code
232 std::string locCode(79, 'L');
233 Callout callout{CalloutPriority::low, locCode, "1234567", "ABCD",
234 "123456789ABC"};
235
236 size_t size = 4 + 80 + fruIdentitySize;
237 EXPECT_EQ(callout.locationCodeSize(), 80);
238 EXPECT_EQ(callout.flattenedSize(), size);
239
240 EXPECT_EQ(callout.locationCode(), locCode);
241
242 // How about we flatten/unflatten this last one
243 std::vector<uint8_t> data;
244 Stream stream{data};
245
246 callout.flatten(stream);
247
248 {
249 Stream newStream{data};
250 Callout newCallout{newStream};
251
252 EXPECT_EQ(newCallout.flags(),
253 Callout::calloutType | Callout::fruIdentIncluded);
254
255 EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
256 EXPECT_EQ(newCallout.priority(), callout.priority());
257 EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
258 EXPECT_EQ(newCallout.locationCodeSize(),
259 callout.locationCodeSize());
260
261 auto& fru = newCallout.fruIdentity();
262 EXPECT_EQ(fru->getPN().value(), "1234567");
263 EXPECT_EQ(fru->getCCIN().value(), "ABCD");
264 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
265 }
266 }
Matt Spinler5ab39972020-08-13 13:02:28 -0500267
268 {
269 // With MRUs
270 std::vector<MRU::MRUCallout> mruList{{'H', 1}, {'H', 2}};
271
272 Callout callout{CalloutPriority::high, "U99-P5", "1234567", "ABCD",
273 "123456789ABC", mruList};
274
Patrick Williams075c7922024-08-16 15:19:49 -0400275 EXPECT_EQ(callout.flags(),
276 Callout::calloutType | Callout::fruIdentIncluded |
277 Callout::mruIncluded);
Matt Spinler5ab39972020-08-13 13:02:28 -0500278
279 EXPECT_EQ(callout.priority(), 'H');
280 EXPECT_EQ(callout.locationCode(), "U99-P5");
281 EXPECT_EQ(callout.locationCodeSize(), 8);
282
283 auto& fru = callout.fruIdentity();
284 EXPECT_EQ(fru->getPN().value(), "1234567");
285 EXPECT_EQ(fru->getCCIN().value(), "ABCD");
286 EXPECT_EQ(fru->getSN().value(), "123456789ABC");
287
288 auto& mruSection = callout.mru();
289 EXPECT_EQ(mruSection->mrus().size(), 2);
290 EXPECT_EQ(mruSection->mrus().at(0).priority, 'H');
291 EXPECT_EQ(mruSection->mrus().at(0).id, 1);
292 EXPECT_EQ(mruSection->mrus().at(1).priority, 'H');
293 EXPECT_EQ(mruSection->mrus().at(1).id, 2);
294 }
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500295}
296
297// Create a callout object by passing in the maintenance procedure to add.
298TEST(CalloutTest, TestProcedureCallout)
299{
Matt Spinler479b6922021-08-17 16:34:59 -0500300 Callout callout{CalloutPriority::medium, "bmc_code"};
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500301
302 // size/flags/pri/locsize fields + FRUIdentity size
303 // No location code.
304 size_t size = 4 + 12;
305
306 EXPECT_EQ(callout.flags(),
307 Callout::calloutType | Callout::fruIdentIncluded);
308
309 EXPECT_EQ(callout.flattenedSize(), size);
310 EXPECT_EQ(callout.priority(), 'M');
311 EXPECT_EQ(callout.locationCode(), "");
312 EXPECT_EQ(callout.locationCodeSize(), 0);
313
314 auto& fru = callout.fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500315 EXPECT_EQ(fru->getMaintProc().value(), "BMC0001");
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500316
317 // flatten/unflatten
318 std::vector<uint8_t> data;
319 Stream stream{data};
320
321 callout.flatten(stream);
322
323 Stream newStream{data};
324 Callout newCallout{newStream};
325
326 EXPECT_EQ(newCallout.flags(),
327 Callout::calloutType | Callout::fruIdentIncluded);
328
329 EXPECT_EQ(newCallout.flattenedSize(), callout.flattenedSize());
330 EXPECT_EQ(newCallout.priority(), callout.priority());
331 EXPECT_EQ(newCallout.locationCode(), callout.locationCode());
332 EXPECT_EQ(newCallout.locationCodeSize(), callout.locationCodeSize());
333
334 auto& newFRU = newCallout.fruIdentity();
335 EXPECT_EQ(newFRU->getMaintProc().value(), fru->getMaintProc().value());
Matt Spinler468aab52020-08-13 11:04:31 -0500336
337 // Use raw procedure value
338
Matt Spinlerea2873d2021-08-18 10:35:40 -0500339 Callout rawCallout{CalloutPriority::medium, "BMCXXXX",
Matt Spinler468aab52020-08-13 11:04:31 -0500340 CalloutValueType::raw};
341 auto& rawFRU = rawCallout.fruIdentity();
Matt Spinlerea2873d2021-08-18 10:35:40 -0500342 EXPECT_EQ(rawFRU->getMaintProc().value(), "BMCXXXX");
Matt Spinler0a5d10c2020-03-13 12:54:02 -0500343}
Matt Spinlera86ec992020-04-09 12:42:07 -0500344
345// Create a callout object by passing in the symbolic FRU to add.
346TEST(CalloutTest, TestSymbolicFRUCallout)
347{
348 // symbolic FRU with a location code
349 {
350 Callout callout{CalloutPriority::high, "service_docs", "P1-C3", false};
351
352 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
353 size_t size = 4 + 8 + 12;
354
355 EXPECT_EQ(callout.flags(),
356 Callout::calloutType | Callout::fruIdentIncluded);
357
358 EXPECT_EQ(callout.flattenedSize(), size);
359 EXPECT_EQ(callout.priority(), 'H');
360 EXPECT_EQ(callout.locationCode(), "P1-C3");
361 EXPECT_EQ(callout.locationCodeSize(), 8);
362
363 auto& fru = callout.fruIdentity();
364
365 EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
366 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
367 }
368
369 // symbolic FRU without a location code
370 {
371 Callout callout{CalloutPriority::high, "service_docs", "", false};
372
373 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
374 size_t size = 4 + 0 + 12;
375
376 EXPECT_EQ(callout.flags(),
377 Callout::calloutType | Callout::fruIdentIncluded);
378
379 EXPECT_EQ(callout.flattenedSize(), size);
380 EXPECT_EQ(callout.priority(), 'H');
381 EXPECT_EQ(callout.locationCode(), "");
382 EXPECT_EQ(callout.locationCodeSize(), 0);
383
384 auto& fru = callout.fruIdentity();
385
386 EXPECT_EQ(fru->failingComponentType(), FRUIdentity::symbolicFRU);
387 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
388 }
389
390 // symbolic FRU with a trusted location code
391 {
392 Callout callout{CalloutPriority::high, "service_docs", "P1-C3", true};
393
394 // size/flags/pri/locsize fields + plus loc + FRUIdentity size
395 size_t size = 4 + 8 + 12;
396
397 EXPECT_EQ(callout.flags(),
398 Callout::calloutType | Callout::fruIdentIncluded);
399
400 EXPECT_EQ(callout.flattenedSize(), size);
401 EXPECT_EQ(callout.priority(), 'H');
402 EXPECT_EQ(callout.locationCode(), "P1-C3");
403 EXPECT_EQ(callout.locationCodeSize(), 8);
404
405 auto& fru = callout.fruIdentity();
406 EXPECT_EQ(fru->failingComponentType(),
407 FRUIdentity::symbolicFRUTrustedLocCode);
408 EXPECT_EQ(fru->getPN().value(), "SVCDOCS");
409 }
Matt Spinler468aab52020-08-13 11:04:31 -0500410
411 // symbolic FRU with raw FRU value
412 {
413 {
414 Callout callout{CalloutPriority::high, "SYMBFRU",
415 CalloutValueType::raw, "", false};
416
417 auto& fru = callout.fruIdentity();
418
419 EXPECT_EQ(fru->getPN().value(), "SYMBFRU");
420 }
421 }
Matt Spinlera86ec992020-04-09 12:42:07 -0500422}
Matt Spinler4efed0e2024-02-26 11:16:07 -0600423
424TEST(CalloutTest, OperatorEqualTest)
425{
426 {
427 Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
428 "123456789ABC"};
429 Callout c2{CalloutPriority::high, "A1", "1234567", "ABCD",
430 "123456789ABC"};
431 EXPECT_EQ(c1, c2);
432 }
433
434 {
435 // Different location code
436 Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
437 "123456789ABC"};
438 Callout c2{CalloutPriority::high, "A2", "1234567", "ABCD",
439 "123456789ABC"};
440 EXPECT_NE(c1, c2);
441 }
442
443 {
444 // maintenance procedure
445 Callout c1{CalloutPriority::medium, "bmc_code"};
446 Callout c2{CalloutPriority::medium, "bmc_code"};
447 EXPECT_EQ(c1, c2);
448 }
449
450 {
451 // different maintenance procedures
452 Callout c1{CalloutPriority::medium, "bmc_code"};
453 Callout c2{CalloutPriority::medium, "sbe_code"};
454 EXPECT_NE(c1, c2);
455 }
456
457 {
458 // symbolic FRU
459 Callout c1{CalloutPriority::high, "service_docs", "", false};
460 Callout c2{CalloutPriority::high, "service_docs", "", false};
461 EXPECT_EQ(c1, c2);
462 }
463
464 {
465 // different symbolic FRUs
466 Callout c1{CalloutPriority::high, "service_docs", "", false};
467 Callout c2{CalloutPriority::high, "air_mover", "", false};
468 EXPECT_NE(c1, c2);
469 }
470
471 {
472 // HW callout vs symbolic FRU
473 Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
474 "123456789ABC"};
475 Callout c2{CalloutPriority::high, "service_docs", "", false};
476 EXPECT_NE(c1, c2);
477 }
478
479 {
480 // HW callout vs maintenance procedure
481 Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
482 "123456789ABC"};
483 Callout c2{CalloutPriority::medium, "bmc_code"};
484 EXPECT_NE(c1, c2);
485 }
486
487 {
488 // symbolic FRU vs maintenance procedure
489 Callout c1{CalloutPriority::high, "service_docs", "", false};
490 Callout c2{CalloutPriority::medium, "bmc_code"};
491 EXPECT_NE(c1, c2);
492 }
493
494 {
495 // HW callout vs symbolic FRU is still considered equal if
496 // the location code is the same
497 Callout c1{CalloutPriority::high, "A1", "1234567", "ABCD",
498 "123456789ABC"};
499 Callout c2{CalloutPriority::high, "service_docs", "A1", true};
500 EXPECT_EQ(c1, c2);
501 }
502}
503
504TEST(CalloutTest, OperatorGreaterThanTest)
505{
506 {
507 Callout c1{CalloutPriority::high, "bmc_code"};
508 Callout c2{CalloutPriority::medium, "bmc_code"};
509 EXPECT_TRUE(c1 > c2);
510 }
511 {
512 Callout c1{CalloutPriority::high, "bmc_code"};
513 Callout c2{CalloutPriority::low, "bmc_code"};
514 EXPECT_TRUE(c1 > c2);
515 }
516 {
517 Callout c1{CalloutPriority::medium, "bmc_code"};
518 Callout c2{CalloutPriority::low, "bmc_code"};
519 EXPECT_TRUE(c1 > c2);
520 }
521 {
522 Callout c1{CalloutPriority::mediumGroupA, "bmc_code"};
523 Callout c2{CalloutPriority::low, "bmc_code"};
524 EXPECT_TRUE(c1 > c2);
525 }
526 {
527 Callout c1{CalloutPriority::medium, "bmc_code"};
528 Callout c2{CalloutPriority::high, "bmc_code"};
529 EXPECT_FALSE(c1 > c2);
530 }
531 {
532 Callout c1{CalloutPriority::high, "bmc_code"};
533 Callout c2{CalloutPriority::high, "bmc_code"};
534 EXPECT_FALSE(c1 > c2);
535 }
536 {
537 Callout c1{CalloutPriority::low, "bmc_code"};
538 Callout c2{CalloutPriority::high, "bmc_code"};
539 EXPECT_FALSE(c1 > c2);
540 }
541 {
542 // Treat the different mediums the same
543 Callout c1{CalloutPriority::medium, "bmc_code"};
544 Callout c2{CalloutPriority::mediumGroupA, "bmc_code"};
545 EXPECT_FALSE(c1 > c2);
546 }
547}