xref: /openbmc/phosphor-logging/test/openpower-pels/src_callout_test.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3 
4 #include "extensions/openpower-pels/callout.hpp"
5 #include "pel_utils.hpp"
6 
7 #include <gtest/gtest.h>
8 
9 using namespace openpower::pels;
10 using namespace openpower::pels::src;
11 
12 // Unflatten the callout section with all three substructures
TEST(CalloutTest,TestUnflattenAllSubstructures)13 TEST(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 
TEST(CalloutTest,TestUnflattenOneSubstructure)59 TEST(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 
TEST(CalloutTest,TestUnflattenTwoSubstructures)94 TEST(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 
TEST(CalloutTest,TestNoLocationCode)133 TEST(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 }
150 
151 // Create a callout object by passing in the hardware fields to add
TEST(CalloutTest,TestHardwareCallout)152 TEST(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     }
267 
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 
275         EXPECT_EQ(callout.flags(),
276                   Callout::calloutType | Callout::fruIdentIncluded |
277                       Callout::mruIncluded);
278 
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     }
295 }
296 
297 // Create a callout object by passing in the maintenance procedure to add.
TEST(CalloutTest,TestProcedureCallout)298 TEST(CalloutTest, TestProcedureCallout)
299 {
300     Callout callout{CalloutPriority::medium, "bmc_code"};
301 
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();
315     EXPECT_EQ(fru->getMaintProc().value(), "BMC0001");
316 
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());
336 
337     // Use raw procedure value
338 
339     Callout rawCallout{CalloutPriority::medium, "BMCXXXX",
340                        CalloutValueType::raw};
341     auto& rawFRU = rawCallout.fruIdentity();
342     EXPECT_EQ(rawFRU->getMaintProc().value(), "BMCXXXX");
343 }
344 
345 // Create a callout object by passing in the symbolic FRU to add.
TEST(CalloutTest,TestSymbolicFRUCallout)346 TEST(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     }
410 
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     }
422 }
423 
TEST(CalloutTest,OperatorEqualTest)424 TEST(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 
TEST(CalloutTest,OperatorGreaterThanTest)504 TEST(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 }
548