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