1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright 2019 IBM Corporation
3
4 #include "extensions/openpower-pels/registry.hpp"
5
6 #include <nlohmann/json.hpp>
7
8 #include <filesystem>
9 #include <fstream>
10
11 #include <gtest/gtest.h>
12
13 using namespace openpower::pels::message;
14 using namespace openpower::pels;
15 namespace fs = std::filesystem;
16
17 const auto registryData = R"(
18 {
19 "PELs":
20 [
21 {
22 "Name": "xyz.openbmc_project.Power.Fault",
23 "Subsystem": "power_supply",
24
25 "SRC":
26 {
27 "ReasonCode": "0x2030"
28 },
29
30 "Documentation":
31 {
32 "Description": "A PGOOD Fault",
33 "Message": "PS had a PGOOD Fault"
34 }
35 },
36
37 {
38 "Name": "xyz.openbmc_project.Power.OverVoltage",
39 "Subsystem": "power_control_hw",
40 "Severity":
41 [
42 {
43 "System": "systemA",
44 "SevValue": "unrecoverable"
45 },
46 {
47 "System": "systemB",
48 "SevValue": "recovered"
49 },
50 {
51 "SevValue": "predictive"
52 }
53 ],
54 "MfgSeverity": "non_error",
55 "ActionFlags": ["service_action", "report", "call_home"],
56 "MfgActionFlags": ["hidden"],
57
58 "SRC":
59 {
60 "ReasonCode": "0x2333",
61 "Type": "BD",
62 "SymptomIDFields": ["SRCWord5", "SRCWord6", "SRCWord7"],
63 "Words6To9":
64 {
65 "6":
66 {
67 "Description": "Failing unit number",
68 "AdditionalDataPropSource": "PS_NUM"
69 },
70
71 "7":
72 {
73 "Description": "bad voltage",
74 "AdditionalDataPropSource": "VOLTAGE"
75 }
76 },
77 "DeconfigFlag": true,
78 "CheckstopFlag": true
79 },
80
81 "Documentation":
82 {
83 "Description": "A PGOOD Fault",
84 "Message": "PS %1 had a PGOOD Fault",
85 "MessageArgSources":
86 [
87 "SRCWord6"
88 ],
89 "Notes": [
90 "In the UserData section there is a JSON",
91 "dump that provides debug information."
92 ]
93 },
94
95 "JournalCapture":
96 {
97 "NumLines": 7
98 }
99 },
100
101 {
102 "Name": "xyz.openbmc_project.Common.Error.Timeout",
103 "PossibleSubsystems": ["processor", "memory"],
104
105 "SRC":
106 {
107 "ReasonCode": "0x2030"
108 },
109 "Documentation":
110 {
111 "Description": "A PGOOD Fault",
112 "Message": "PS had a PGOOD Fault"
113 }
114 },
115
116 {
117 "Name": "xyz.openbmc_project.Journal.Capture",
118 "Subsystem": "power_supply",
119
120 "SRC":
121 {
122 "ReasonCode": "0x2030"
123 },
124
125 "Documentation":
126 {
127 "Description": "journal capture test",
128 "Message": "journal capture test"
129 },
130
131 "JournalCapture":
132 {
133 "Sections": [
134 {
135 "NumLines": 5,
136 "SyslogID": "test1"
137 },
138 {
139 "NumLines": 6,
140 "SyslogID": "test2"
141 }
142 ]
143 }
144 },
145
146 {
147 "Name": "org.open_power.PHAL.Info.ClockDailyLog",
148 "Subsystem": "cec_clocks",
149 "ComponentID": "0x3000",
150 "Severity": "non_error",
151 "ActionFlags": ["report", "call_home", "heartbeat_call_home"],
152
153 "SRC":
154 {
155 "ReasonCode": "0x300A",
156 "Words6To9": {}
157 },
158
159 "Documentation":
160 {
161 "Description": "Informational error to house clock debug info",
162 "Message": "Informational error to house clock debug info",
163 "Notes": [
164 "User data includes processor and clock register state information."
165 ]
166 }
167 }
168 ]
169 }
170 )";
171
172 class RegistryTest : public ::testing::Test
173 {
174 protected:
SetUpTestCase()175 static void SetUpTestCase()
176 {
177 char path[] = "/tmp/regtestXXXXXX";
178 regDir = mkdtemp(path);
179 }
180
TearDownTestCase()181 static void TearDownTestCase()
182 {
183 fs::remove_all(regDir);
184 }
185
writeData(const char * data)186 static std::string writeData(const char* data)
187 {
188 fs::path path = regDir / "registry.json";
189 std::ofstream stream{path};
190 stream << data;
191 return path;
192 }
193
194 static fs::path regDir;
195 };
196
197 fs::path RegistryTest::regDir{};
198
TEST_F(RegistryTest,TestNoEntry)199 TEST_F(RegistryTest, TestNoEntry)
200 {
201 auto path = RegistryTest::writeData(registryData);
202 Registry registry{path};
203
204 auto entry = registry.lookup("foo", LookupType::name);
205 EXPECT_FALSE(entry);
206 }
207
TEST_F(RegistryTest,TestFindEntry)208 TEST_F(RegistryTest, TestFindEntry)
209 {
210 auto path = RegistryTest::writeData(registryData);
211 Registry registry{path};
212
213 auto entry = registry.lookup("xyz.openbmc_project.Power.OverVoltage",
214 LookupType::name);
215 ASSERT_TRUE(entry);
216 EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.OverVoltage");
217 EXPECT_EQ(entry->subsystem, 0x62);
218
219 ASSERT_EQ(entry->severity->size(), 3);
220 EXPECT_EQ((*entry->severity)[0].severity, 0x40);
221 EXPECT_EQ((*entry->severity)[0].system, "systemA");
222 EXPECT_EQ((*entry->severity)[1].severity, 0x10);
223 EXPECT_EQ((*entry->severity)[1].system, "systemB");
224 EXPECT_EQ((*entry->severity)[2].severity, 0x20);
225 EXPECT_EQ((*entry->severity)[2].system, "");
226
227 EXPECT_EQ(entry->mfgSeverity->size(), 1);
228 EXPECT_EQ((*entry->mfgSeverity)[0].severity, 0x00);
229
230 EXPECT_EQ(*(entry->actionFlags), 0xA800);
231 EXPECT_EQ(*(entry->mfgActionFlags), 0x4000);
232 EXPECT_EQ(entry->componentID, 0x2300);
233 EXPECT_FALSE(entry->eventType);
234 EXPECT_FALSE(entry->eventScope);
235
236 EXPECT_EQ(entry->src.type, 0xBD);
237 EXPECT_EQ(entry->src.reasonCode, 0x2333);
238 EXPECT_TRUE(entry->src.deconfigFlag);
239 EXPECT_TRUE(entry->src.checkstopFlag);
240
241 auto& hexwords = entry->src.hexwordADFields;
242 EXPECT_TRUE(hexwords);
243 EXPECT_EQ((*hexwords).size(), 2);
244
245 auto word = (*hexwords).find(6);
246 EXPECT_NE(word, (*hexwords).end());
247 EXPECT_EQ(std::get<0>(word->second), "PS_NUM");
248
249 word = (*hexwords).find(7);
250 EXPECT_NE(word, (*hexwords).end());
251 EXPECT_EQ(std::get<0>(word->second), "VOLTAGE");
252
253 auto& sid = entry->src.symptomID;
254 EXPECT_TRUE(sid);
255 EXPECT_EQ((*sid).size(), 3);
256 EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 5), (*sid).end());
257 EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 6), (*sid).end());
258 EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 7), (*sid).end());
259
260 EXPECT_EQ(entry->doc.description, "A PGOOD Fault");
261 EXPECT_EQ(entry->doc.message, "PS %1 had a PGOOD Fault");
262 auto& hexwordSource = entry->doc.messageArgSources;
263 EXPECT_TRUE(hexwordSource);
264 EXPECT_EQ((*hexwordSource).size(), 1);
265 EXPECT_EQ((*hexwordSource).front(), "SRCWord6");
266
267 const auto& jc = entry->journalCapture;
268 ASSERT_TRUE(jc);
269 ASSERT_TRUE(std::holds_alternative<size_t>(*jc));
270 EXPECT_EQ(std::get<size_t>(*jc), 7);
271
272 entry = registry.lookup("0x2333", LookupType::reasonCode);
273 ASSERT_TRUE(entry);
274 EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.OverVoltage");
275
276 entry = registry.lookup("org.open_power.PHAL.Info.ClockDailyLog",
277 LookupType::name);
278 ASSERT_TRUE(entry);
279 EXPECT_EQ(entry->name, "org.open_power.PHAL.Info.ClockDailyLog");
280 EXPECT_EQ(*(entry->actionFlags), 0x2820);
281 }
282
283 // Check the entry that mostly uses defaults
TEST_F(RegistryTest,TestFindEntryMinimal)284 TEST_F(RegistryTest, TestFindEntryMinimal)
285 {
286 auto path = RegistryTest::writeData(registryData);
287 Registry registry{path};
288
289 auto entry =
290 registry.lookup("xyz.openbmc_project.Power.Fault", LookupType::name);
291 ASSERT_TRUE(entry);
292 EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.Fault");
293 EXPECT_EQ(entry->subsystem, 0x61);
294 EXPECT_FALSE(entry->severity);
295 EXPECT_FALSE(entry->mfgSeverity);
296 EXPECT_FALSE(entry->mfgActionFlags);
297 EXPECT_FALSE(entry->actionFlags);
298 EXPECT_EQ(entry->componentID, 0x2000);
299 EXPECT_FALSE(entry->eventType);
300 EXPECT_FALSE(entry->eventScope);
301
302 EXPECT_EQ(entry->src.reasonCode, 0x2030);
303 EXPECT_EQ(entry->src.type, 0xBD);
304 EXPECT_FALSE(entry->src.hexwordADFields);
305 EXPECT_FALSE(entry->src.symptomID);
306 EXPECT_FALSE(entry->src.deconfigFlag);
307 EXPECT_FALSE(entry->src.checkstopFlag);
308 }
309
TEST_F(RegistryTest,TestBadJSON)310 TEST_F(RegistryTest, TestBadJSON)
311 {
312 auto path = RegistryTest::writeData("bad {} json");
313
314 Registry registry{path};
315
316 EXPECT_FALSE(registry.lookup("foo", LookupType::name));
317 }
318
319 // Test the helper functions the use the pel_values data.
TEST_F(RegistryTest,TestHelperFunctions)320 TEST_F(RegistryTest, TestHelperFunctions)
321 {
322 using namespace openpower::pels::message::helper;
323 EXPECT_EQ(getSubsystem("input_power_source"), 0xA1);
324 EXPECT_THROW(getSubsystem("foo"), std::runtime_error);
325
326 EXPECT_EQ(getSeverity("symptom_recovered"), 0x71);
327 EXPECT_THROW(getSeverity("foo"), std::runtime_error);
328
329 EXPECT_EQ(getEventType("dump_notification"), 0x08);
330 EXPECT_THROW(getEventType("foo"), std::runtime_error);
331
332 EXPECT_EQ(getEventScope("possibly_multiple_platforms"), 0x04);
333 EXPECT_THROW(getEventScope("foo"), std::runtime_error);
334
335 std::vector<std::string> flags{"service_action", "dont_report",
336 "termination"};
337 EXPECT_EQ(getActionFlags(flags), 0x9100);
338
339 flags.push_back("heartbeat_call_home");
340 EXPECT_EQ(getActionFlags(flags), 0x9120);
341 flags.clear();
342 flags.push_back("heartbeat_call_home");
343 EXPECT_EQ(getActionFlags(flags), 0x0020);
344
345 flags.clear();
346 flags.push_back("foo");
347 EXPECT_THROW(getActionFlags(flags), std::runtime_error);
348 }
349
TEST_F(RegistryTest,TestGetSRCReasonCode)350 TEST_F(RegistryTest, TestGetSRCReasonCode)
351 {
352 using namespace openpower::pels::message::helper;
353 EXPECT_EQ(getSRCReasonCode(R"({"ReasonCode": "0x5555"})"_json, "foo"),
354 0x5555);
355
356 EXPECT_THROW(getSRCReasonCode(R"({"ReasonCode": "ZZZZ"})"_json, "foo"),
357 std::runtime_error);
358 }
359
TEST_F(RegistryTest,TestGetSRCType)360 TEST_F(RegistryTest, TestGetSRCType)
361 {
362 using namespace openpower::pels::message::helper;
363 EXPECT_EQ(getSRCType(R"({"Type": "11"})"_json, "foo"), 0x11);
364 EXPECT_EQ(getSRCType(R"({"Type": "BF"})"_json, "foo"), 0xBF);
365
366 EXPECT_THROW(getSRCType(R"({"Type": "1"})"_json, "foo"),
367 std::runtime_error);
368
369 EXPECT_THROW(getSRCType(R"({"Type": "111"})"_json, "foo"),
370 std::runtime_error);
371 }
372
TEST_F(RegistryTest,TestGetSRCHexwordFields)373 TEST_F(RegistryTest, TestGetSRCHexwordFields)
374 {
375 using namespace openpower::pels::message::helper;
376 const auto hexwords = R"(
377 {"Words6To9":
378 {
379 "8":
380 {
381 "Description": "TEST",
382 "AdditionalDataPropSource": "TEST"
383 }
384 }
385 })"_json;
386
387 auto fields = getSRCHexwordFields(hexwords, "foo");
388 EXPECT_TRUE(fields);
389 auto word = fields->find(8);
390 EXPECT_NE(word, fields->end());
391
392 const auto theInvalidRWord = R"(
393 {"Words6To9":
394 {
395 "R":
396 {
397 "Description": "TEST",
398 "AdditionalDataPropSource": "TEST"
399 }
400 }
401 })"_json;
402
403 EXPECT_THROW(getSRCHexwordFields(theInvalidRWord, "foo"),
404 std::runtime_error);
405 }
406
TEST_F(RegistryTest,TestGetSRCSymptomIDFields)407 TEST_F(RegistryTest, TestGetSRCSymptomIDFields)
408 {
409 using namespace openpower::pels::message::helper;
410 const auto sID = R"(
411 {
412 "SymptomIDFields": ["SRCWord3", "SRCWord4", "SRCWord5"]
413 })"_json;
414
415 auto fields = getSRCSymptomIDFields(sID, "foo");
416 EXPECT_NE(std::find(fields->begin(), fields->end(), 3), fields->end());
417 EXPECT_NE(std::find(fields->begin(), fields->end(), 4), fields->end());
418 EXPECT_NE(std::find(fields->begin(), fields->end(), 5), fields->end());
419
420 const auto badField = R"(
421 {
422 "SymptomIDFields": ["SRCWord3", "SRCWord4", "SRCWord"]
423 })"_json;
424
425 EXPECT_THROW(getSRCSymptomIDFields(badField, "foo"), std::runtime_error);
426 }
427
TEST_F(RegistryTest,TestGetComponentID)428 TEST_F(RegistryTest, TestGetComponentID)
429 {
430 using namespace openpower::pels::message::helper;
431
432 // Get it from the JSON
433 auto id =
434 getComponentID(0xBD, 0x4200, R"({"ComponentID":"0x4200"})"_json, "foo");
435 EXPECT_EQ(id, 0x4200);
436
437 // Get it from the reason code on a 0xBD SRC
438 id = getComponentID(0xBD, 0x6700, R"({})"_json, "foo");
439 EXPECT_EQ(id, 0x6700);
440
441 // Not present on a 0x11 SRC
442 EXPECT_THROW(getComponentID(0x11, 0x8800, R"({})"_json, "foo"),
443 std::runtime_error);
444 }
445
446 // Test when callouts are in the JSON.
TEST_F(RegistryTest,TestGetCallouts)447 TEST_F(RegistryTest, TestGetCallouts)
448 {
449 std::vector<std::string> systemNames;
450
451 {
452 // Callouts without AD, that depend on system type,
453 // where there is a default entry without a system type.
454 auto json = R"(
455 [
456 {
457 "System": "system1",
458 "CalloutList":
459 [
460 {
461 "Priority": "high",
462 "LocCode": "P1-C1"
463 },
464 {
465 "Priority": "low",
466 "LocCode": "P1"
467 },
468 {
469 "Priority": "low",
470 "SymbolicFRU": "service_docs"
471 },
472 {
473 "Priority": "low",
474 "SymbolicFRUTrusted": "air_mover",
475 "UseInventoryLocCode": true
476 }
477 ]
478 },
479 {
480 "CalloutList":
481 [
482 {
483 "Priority": "medium",
484 "Procedure": "BMC0001"
485 },
486 {
487 "Priority": "low",
488 "LocCode": "P3-C8",
489 "SymbolicFRUTrusted": "service_docs"
490 }
491 ]
492
493 }
494 ])"_json;
495
496 AdditionalData ad;
497 systemNames.push_back("system1");
498
499 auto callouts = Registry::getCallouts(json, systemNames, ad);
500 EXPECT_EQ(callouts.size(), 4);
501 EXPECT_EQ(callouts[0].priority, "high");
502 EXPECT_EQ(callouts[0].locCode, "P1-C1");
503 EXPECT_EQ(callouts[0].procedure, "");
504 EXPECT_EQ(callouts[0].symbolicFRU, "");
505 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
506 EXPECT_EQ(callouts[1].priority, "low");
507 EXPECT_EQ(callouts[1].locCode, "P1");
508 EXPECT_EQ(callouts[1].procedure, "");
509 EXPECT_EQ(callouts[1].symbolicFRU, "");
510 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
511 EXPECT_EQ(callouts[2].priority, "low");
512 EXPECT_EQ(callouts[2].locCode, "");
513 EXPECT_EQ(callouts[2].procedure, "");
514 EXPECT_EQ(callouts[2].symbolicFRU, "service_docs");
515 EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
516 EXPECT_EQ(callouts[3].priority, "low");
517 EXPECT_EQ(callouts[3].locCode, "");
518 EXPECT_EQ(callouts[3].procedure, "");
519 EXPECT_EQ(callouts[3].symbolicFRU, "");
520 EXPECT_EQ(callouts[3].symbolicFRUTrusted, "air_mover");
521 EXPECT_EQ(callouts[3].useInventoryLocCode, true);
522
523 // system2 isn't in the JSON, so it will pick the default one
524 systemNames[0] = "system2";
525 callouts = Registry::getCallouts(json, systemNames, ad);
526 EXPECT_EQ(callouts.size(), 2);
527 EXPECT_EQ(callouts[0].priority, "medium");
528 EXPECT_EQ(callouts[0].locCode, "");
529 EXPECT_EQ(callouts[0].procedure, "BMC0001");
530 EXPECT_EQ(callouts[0].symbolicFRU, "");
531 EXPECT_EQ(callouts[1].priority, "low");
532 EXPECT_EQ(callouts[1].locCode, "P3-C8");
533 EXPECT_EQ(callouts[1].procedure, "");
534 EXPECT_EQ(callouts[1].symbolicFRU, "");
535 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "service_docs");
536 EXPECT_EQ(callouts[1].useInventoryLocCode, false);
537 }
538
539 // Empty JSON array (treated as an error)
540 {
541 auto json = R"([])"_json;
542 AdditionalData ad;
543 systemNames[0] = "system1";
544 EXPECT_THROW(Registry::getCallouts(json, systemNames, ad),
545 std::runtime_error);
546 }
547
548 {
549 // Callouts without AD, that depend on system type,
550 // where there isn't a default entry without a system type.
551 auto json = R"(
552 [
553 {
554 "System": "system1",
555 "CalloutList":
556 [
557 {
558 "Priority": "high",
559 "LocCode": "P1-C1"
560 },
561 {
562 "Priority": "low",
563 "LocCode": "P1",
564 "SymbolicFRU": "1234567"
565 }
566 ]
567 },
568 {
569 "System": "system2",
570 "CalloutList":
571 [
572 {
573 "Priority": "medium",
574 "LocCode": "P7",
575 "CalloutType": "tool_fru"
576 }
577 ]
578
579 }
580 ])"_json;
581
582 AdditionalData ad;
583 systemNames[0] = "system1";
584
585 auto callouts = Registry::getCallouts(json, systemNames, ad);
586 EXPECT_EQ(callouts.size(), 2);
587 EXPECT_EQ(callouts[0].priority, "high");
588 EXPECT_EQ(callouts[0].locCode, "P1-C1");
589 EXPECT_EQ(callouts[0].procedure, "");
590 EXPECT_EQ(callouts[0].symbolicFRU, "");
591 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
592 EXPECT_EQ(callouts[1].priority, "low");
593 EXPECT_EQ(callouts[1].locCode, "P1");
594 EXPECT_EQ(callouts[1].procedure, "");
595 EXPECT_EQ(callouts[1].symbolicFRU, "1234567");
596 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
597
598 systemNames[0] = "system2";
599 callouts = Registry::getCallouts(json, systemNames, ad);
600 EXPECT_EQ(callouts.size(), 1);
601 EXPECT_EQ(callouts[0].priority, "medium");
602 EXPECT_EQ(callouts[0].locCode, "P7");
603 EXPECT_EQ(callouts[0].procedure, "");
604 EXPECT_EQ(callouts[0].symbolicFRU, "");
605 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
606
607 // There is no entry for system3 or a default system,
608 // so this should fail.
609 systemNames[0] = "system3";
610 EXPECT_THROW(Registry::getCallouts(json, systemNames, ad),
611 std::runtime_error);
612 }
613
614 {
615 // Callouts that use the AdditionalData key PROC_NUM
616 // as an index into them, along with a system type.
617 // It supports PROC_NUMs 0 and 1.
618 auto json = R"(
619 {
620 "ADName": "PROC_NUM",
621 "CalloutsWithTheirADValues":
622 [
623 {
624 "ADValue": "0",
625 "Callouts":
626 [
627 {
628 "System": "system3",
629 "CalloutList":
630 [
631 {
632 "Priority": "high",
633 "LocCode": "P1-C5"
634 },
635 {
636 "Priority": "medium",
637 "LocCode": "P1-C6",
638 "SymbolicFRU": "1234567"
639 },
640 {
641 "Priority": "low",
642 "Procedure": "BMC0001",
643 "CalloutType": "config_procedure"
644 }
645 ]
646 },
647 {
648 "CalloutList":
649 [
650 {
651 "Priority": "low",
652 "LocCode": "P55"
653 }
654 ]
655 }
656 ]
657 },
658 {
659 "ADValue": "1",
660 "Callouts":
661 [
662 {
663 "CalloutList":
664 [
665 {
666 "Priority": "high",
667 "LocCode": "P1-C6",
668 "CalloutType": "external_fru"
669 }
670 ]
671 }
672 ]
673 }
674 ]
675 })"_json;
676
677 {
678 // Find callouts for PROC_NUM 0 on system3
679 std::map<std::string, std::string> adData{{"PROC_NUM", "0"}};
680 AdditionalData ad{adData};
681 systemNames[0] = "system3";
682
683 auto callouts = Registry::getCallouts(json, systemNames, ad);
684 EXPECT_EQ(callouts.size(), 3);
685 EXPECT_EQ(callouts[0].priority, "high");
686 EXPECT_EQ(callouts[0].locCode, "P1-C5");
687 EXPECT_EQ(callouts[0].procedure, "");
688 EXPECT_EQ(callouts[0].symbolicFRU, "");
689 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
690 EXPECT_EQ(callouts[1].priority, "medium");
691 EXPECT_EQ(callouts[1].locCode, "P1-C6");
692 EXPECT_EQ(callouts[1].procedure, "");
693 EXPECT_EQ(callouts[1].symbolicFRU, "1234567");
694 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
695 EXPECT_EQ(callouts[2].priority, "low");
696 EXPECT_EQ(callouts[2].locCode, "");
697 EXPECT_EQ(callouts[2].procedure, "BMC0001");
698 EXPECT_EQ(callouts[2].symbolicFRU, "");
699 EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
700
701 // Find callouts for PROC_NUM 0 that uses the default system entry.
702 systemNames[0] = "system99";
703
704 callouts = Registry::getCallouts(json, systemNames, ad);
705 EXPECT_EQ(callouts.size(), 1);
706 EXPECT_EQ(callouts[0].priority, "low");
707 EXPECT_EQ(callouts[0].locCode, "P55");
708 EXPECT_EQ(callouts[0].procedure, "");
709 EXPECT_EQ(callouts[0].symbolicFRU, "");
710 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
711 }
712 {
713 // Find callouts for PROC_NUM 1 that uses a default system entry.
714 std::map<std::string, std::string> adData{{"PROC_NUM", "1"}};
715 AdditionalData ad{adData};
716 systemNames[0] = "system1";
717
718 auto callouts = Registry::getCallouts(json, systemNames, ad);
719 EXPECT_EQ(callouts.size(), 1);
720 EXPECT_EQ(callouts[0].priority, "high");
721 EXPECT_EQ(callouts[0].locCode, "P1-C6");
722 EXPECT_EQ(callouts[0].procedure, "");
723 EXPECT_EQ(callouts[0].symbolicFRU, "");
724 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
725 }
726 {
727 // There is no entry for PROC_NUM 2, so no callouts
728 std::map<std::string, std::string> adData{{"PROC_NUM", "2"}};
729 AdditionalData ad{adData};
730
731 auto callouts = Registry::getCallouts(json, systemNames, ad);
732 EXPECT_TRUE(callouts.empty());
733 }
734 }
735
736 {
737 // Callouts with a 'CalloutsWhenNoADMatch' section that will
738 // be used when the AdditionalData value doesn't match.
739 auto json = R"(
740 {
741 "ADName": "PROC_NUM",
742 "CalloutsWithTheirADValues":
743 [
744 {
745 "ADValue": "0",
746 "Callouts":
747 [
748 {
749 "CalloutList":
750 [
751 {
752 "Priority": "high",
753 "LocCode": "P0-C0"
754 }
755 ]
756 }
757 ]
758 }
759 ],
760 "CalloutsWhenNoADMatch": [
761 {
762 "CalloutList": [
763 {
764 "Priority": "medium",
765 "LocCode": "P1-C1"
766 }
767 ]
768 }
769 ]
770 })"_json;
771
772 // There isn't an entry in the JSON for a PROC_NUM of 8
773 // so it should choose the P1-C1 callout.
774 std::map<std::string, std::string> adData{{"PROC_NUM", "8"}};
775 AdditionalData ad{adData};
776 systemNames.clear();
777
778 auto callouts = Registry::getCallouts(json, systemNames, ad);
779 EXPECT_EQ(callouts.size(), 1);
780 EXPECT_EQ(callouts[0].priority, "medium");
781 EXPECT_EQ(callouts[0].locCode, "P1-C1");
782 }
783 }
784
TEST_F(RegistryTest,TestGetCalloutsWithSystems)785 TEST_F(RegistryTest, TestGetCalloutsWithSystems)
786 {
787 std::vector<std::string> systemNames;
788
789 auto json = R"(
790 [
791 {
792 "Systems": ["system1", "system2"],
793 "CalloutList":
794 [
795 {
796 "Priority": "high",
797 "LocCode": "P1-C1"
798 },
799 {
800 "Priority": "low",
801 "LocCode": "P1"
802 },
803 {
804 "Priority": "low",
805 "SymbolicFRU": "service_docs"
806 },
807 {
808 "Priority": "low",
809 "SymbolicFRUTrusted": "air_mover",
810 "UseInventoryLocCode": true
811 }
812 ]
813 },
814 {
815 "CalloutList":
816 [
817 {
818 "Priority": "medium",
819 "Procedure": "BMC0001"
820 },
821 {
822 "Priority": "low",
823 "LocCode": "P3-C8",
824 "SymbolicFRUTrusted": "service_docs"
825 }
826 ]
827
828 }
829 ])"_json;
830
831 AdditionalData ad;
832 systemNames.push_back("system1");
833
834 auto callouts = Registry::getCallouts(json, systemNames, ad);
835 EXPECT_EQ(callouts.size(), 4);
836 EXPECT_EQ(callouts[0].priority, "high");
837 EXPECT_EQ(callouts[0].locCode, "P1-C1");
838 EXPECT_EQ(callouts[0].procedure, "");
839 EXPECT_EQ(callouts[0].symbolicFRU, "");
840 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
841 EXPECT_EQ(callouts[1].priority, "low");
842 EXPECT_EQ(callouts[1].locCode, "P1");
843 EXPECT_EQ(callouts[1].procedure, "");
844 EXPECT_EQ(callouts[1].symbolicFRU, "");
845 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
846 EXPECT_EQ(callouts[2].priority, "low");
847 EXPECT_EQ(callouts[2].locCode, "");
848 EXPECT_EQ(callouts[2].procedure, "");
849 EXPECT_EQ(callouts[2].symbolicFRU, "service_docs");
850 EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
851 EXPECT_EQ(callouts[3].priority, "low");
852 EXPECT_EQ(callouts[3].locCode, "");
853 EXPECT_EQ(callouts[3].procedure, "");
854 EXPECT_EQ(callouts[3].symbolicFRU, "");
855 EXPECT_EQ(callouts[3].symbolicFRUTrusted, "air_mover");
856 EXPECT_EQ(callouts[3].useInventoryLocCode, true);
857
858 // System3 isn't in the JSON, so it will pick the default one
859 systemNames[0] = "system3";
860
861 callouts = Registry::getCallouts(json, systemNames, ad);
862 EXPECT_EQ(callouts.size(), 2);
863 EXPECT_EQ(callouts[0].priority, "medium");
864 EXPECT_EQ(callouts[0].locCode, "");
865 EXPECT_EQ(callouts[0].procedure, "BMC0001");
866 EXPECT_EQ(callouts[0].symbolicFRU, "");
867 EXPECT_EQ(callouts[1].priority, "low");
868 EXPECT_EQ(callouts[1].locCode, "P3-C8");
869 EXPECT_EQ(callouts[1].procedure, "");
870 EXPECT_EQ(callouts[1].symbolicFRU, "");
871 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "service_docs");
872 EXPECT_EQ(callouts[1].useInventoryLocCode, false);
873 }
874
TEST_F(RegistryTest,TestGetCalloutsWithSystemAndSystems)875 TEST_F(RegistryTest, TestGetCalloutsWithSystemAndSystems)
876 {
877 std::vector<std::string> systemNames;
878
879 auto json = R"(
880 [
881 {
882 "Systems": ["system1", "system2"],
883 "CalloutList":
884 [
885 {
886 "Priority": "high",
887 "LocCode": "P1-C1"
888 },
889 {
890 "Priority": "low",
891 "LocCode": "P1"
892 }
893 ]
894 },
895 {
896 "System": "system1",
897 "CalloutList":
898 [
899 {
900 "Priority": "low",
901 "SymbolicFRU": "service_docs"
902 },
903 {
904 "Priority": "low",
905 "SymbolicFRUTrusted": "air_mover",
906 "UseInventoryLocCode": true
907 }
908 ]
909 },
910 {
911 "CalloutList":
912 [
913 {
914 "Priority": "medium",
915 "Procedure": "BMC0001"
916 },
917 {
918 "Priority": "low",
919 "LocCode": "P3-C8",
920 "SymbolicFRUTrusted": "service_docs"
921 }
922 ]
923 }
924 ])"_json;
925
926 AdditionalData ad;
927 systemNames.push_back("system1");
928
929 auto callouts = Registry::getCallouts(json, systemNames, ad);
930 EXPECT_EQ(callouts.size(), 4);
931 EXPECT_EQ(callouts[0].priority, "high");
932 EXPECT_EQ(callouts[0].locCode, "P1-C1");
933 EXPECT_EQ(callouts[0].procedure, "");
934 EXPECT_EQ(callouts[0].symbolicFRU, "");
935 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
936 EXPECT_EQ(callouts[1].priority, "low");
937 EXPECT_EQ(callouts[1].locCode, "P1");
938 EXPECT_EQ(callouts[1].procedure, "");
939 EXPECT_EQ(callouts[1].symbolicFRU, "");
940 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
941 EXPECT_EQ(callouts[2].priority, "low");
942 EXPECT_EQ(callouts[2].locCode, "");
943 EXPECT_EQ(callouts[2].procedure, "");
944 EXPECT_EQ(callouts[2].symbolicFRU, "service_docs");
945 EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
946 EXPECT_EQ(callouts[3].priority, "low");
947 EXPECT_EQ(callouts[3].locCode, "");
948 EXPECT_EQ(callouts[3].procedure, "");
949 EXPECT_EQ(callouts[3].symbolicFRU, "");
950 EXPECT_EQ(callouts[3].symbolicFRUTrusted, "air_mover");
951 EXPECT_EQ(callouts[3].useInventoryLocCode, true);
952
953 // if system name is "System2"
954 systemNames[0] = "system2";
955
956 callouts = Registry::getCallouts(json, systemNames, ad);
957 EXPECT_EQ(callouts.size(), 2);
958 EXPECT_EQ(callouts[0].priority, "high");
959 EXPECT_EQ(callouts[0].locCode, "P1-C1");
960 EXPECT_EQ(callouts[0].procedure, "");
961 EXPECT_EQ(callouts[0].symbolicFRU, "");
962 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
963 EXPECT_EQ(callouts[1].priority, "low");
964 EXPECT_EQ(callouts[1].locCode, "P1");
965 EXPECT_EQ(callouts[1].procedure, "");
966 EXPECT_EQ(callouts[1].symbolicFRU, "");
967 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
968
969 // system name is System3 which is not in json thereby will take default
970 systemNames[0] = "system3";
971
972 callouts = Registry::getCallouts(json, systemNames, ad);
973 EXPECT_EQ(callouts.size(), 2);
974 EXPECT_EQ(callouts[0].priority, "medium");
975 EXPECT_EQ(callouts[0].locCode, "");
976 EXPECT_EQ(callouts[0].procedure, "BMC0001");
977 EXPECT_EQ(callouts[0].symbolicFRU, "");
978 EXPECT_EQ(callouts[1].priority, "low");
979 EXPECT_EQ(callouts[1].locCode, "P3-C8");
980 EXPECT_EQ(callouts[1].procedure, "");
981 EXPECT_EQ(callouts[1].symbolicFRU, "");
982 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "service_docs");
983 EXPECT_EQ(callouts[1].useInventoryLocCode, false);
984 }
985
TEST_F(RegistryTest,TestGetCalloutsWithOnlySystemAndSystems)986 TEST_F(RegistryTest, TestGetCalloutsWithOnlySystemAndSystems)
987 {
988 std::vector<std::string> systemNames;
989
990 auto json = R"(
991 [
992 {
993 "Systems": ["system1", "system2"],
994 "CalloutList":
995 [
996 {
997 "Priority": "high",
998 "LocCode": "P1-C1"
999 },
1000 {
1001 "Priority": "low",
1002 "LocCode": "P1"
1003 }
1004 ]
1005 },
1006 {
1007 "System": "system1",
1008 "CalloutList":
1009 [
1010 {
1011 "Priority": "low",
1012 "SymbolicFRU": "service_docs"
1013 },
1014 {
1015 "Priority": "low",
1016 "SymbolicFRUTrusted": "air_mover",
1017 "UseInventoryLocCode": true
1018 }
1019 ]
1020 }
1021 ])"_json;
1022
1023 AdditionalData ad;
1024 systemNames.push_back("system1");
1025
1026 auto callouts = Registry::getCallouts(json, systemNames, ad);
1027 EXPECT_EQ(callouts.size(), 4);
1028 EXPECT_EQ(callouts[0].priority, "high");
1029 EXPECT_EQ(callouts[0].locCode, "P1-C1");
1030 EXPECT_EQ(callouts[0].procedure, "");
1031 EXPECT_EQ(callouts[0].symbolicFRU, "");
1032 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
1033 EXPECT_EQ(callouts[1].priority, "low");
1034 EXPECT_EQ(callouts[1].locCode, "P1");
1035 EXPECT_EQ(callouts[1].procedure, "");
1036 EXPECT_EQ(callouts[1].symbolicFRU, "");
1037 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
1038 EXPECT_EQ(callouts[2].priority, "low");
1039 EXPECT_EQ(callouts[2].locCode, "");
1040 EXPECT_EQ(callouts[2].procedure, "");
1041 EXPECT_EQ(callouts[2].symbolicFRU, "service_docs");
1042 EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
1043 EXPECT_EQ(callouts[3].priority, "low");
1044 EXPECT_EQ(callouts[3].locCode, "");
1045 EXPECT_EQ(callouts[3].procedure, "");
1046 EXPECT_EQ(callouts[3].symbolicFRU, "");
1047 EXPECT_EQ(callouts[3].symbolicFRUTrusted, "air_mover");
1048 EXPECT_EQ(callouts[3].useInventoryLocCode, true);
1049
1050 // if system name is "System2"
1051 systemNames[0] = "system2";
1052
1053 callouts = Registry::getCallouts(json, systemNames, ad);
1054 EXPECT_EQ(callouts.size(), 2);
1055 EXPECT_EQ(callouts[0].priority, "high");
1056 EXPECT_EQ(callouts[0].locCode, "P1-C1");
1057 EXPECT_EQ(callouts[0].procedure, "");
1058 EXPECT_EQ(callouts[0].symbolicFRU, "");
1059 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
1060 EXPECT_EQ(callouts[1].priority, "low");
1061 EXPECT_EQ(callouts[1].locCode, "P1");
1062 EXPECT_EQ(callouts[1].procedure, "");
1063 EXPECT_EQ(callouts[1].symbolicFRU, "");
1064 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
1065
1066 // There is no entry for system3 or a default system,
1067 // so this should fail.
1068 systemNames[0] = "system3";
1069 EXPECT_THROW(Registry::getCallouts(json, systemNames, ad),
1070 std::runtime_error);
1071 }
1072
TEST_F(RegistryTest,TestGetCalloutsWithOnlySystems)1073 TEST_F(RegistryTest, TestGetCalloutsWithOnlySystems)
1074 {
1075 std::vector<std::string> systemNames;
1076
1077 auto json = R"(
1078 [
1079 {
1080 "Systems": ["system1", "system2"],
1081 "CalloutList":
1082 [
1083 {
1084 "Priority": "high",
1085 "LocCode": "P1-C1"
1086 },
1087 {
1088 "Priority": "low",
1089 "LocCode": "P1"
1090 }
1091 ]
1092 }
1093 ])"_json;
1094
1095 AdditionalData ad;
1096 systemNames.push_back("system1");
1097
1098 // system1 is available in JSON array
1099 auto callouts = Registry::getCallouts(json, systemNames, ad);
1100 EXPECT_EQ(callouts.size(), 2);
1101 EXPECT_EQ(callouts[0].priority, "high");
1102 EXPECT_EQ(callouts[0].locCode, "P1-C1");
1103 EXPECT_EQ(callouts[0].procedure, "");
1104 EXPECT_EQ(callouts[0].symbolicFRU, "");
1105 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
1106 EXPECT_EQ(callouts[1].priority, "low");
1107 EXPECT_EQ(callouts[1].locCode, "P1");
1108 EXPECT_EQ(callouts[1].procedure, "");
1109 EXPECT_EQ(callouts[1].symbolicFRU, "");
1110 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
1111
1112 // There is no entry for system3 or a default system,
1113 // so this should fail.
1114 systemNames[0] = "system3";
1115 EXPECT_THROW(Registry::getCallouts(json, systemNames, ad),
1116 std::runtime_error);
1117 }
1118
TEST_F(RegistryTest,TestGetCalloutsWithOnlyDefaults)1119 TEST_F(RegistryTest, TestGetCalloutsWithOnlyDefaults)
1120 {
1121 std::vector<std::string> systemNames;
1122
1123 auto json = R"(
1124 [
1125 {
1126 "CalloutList":
1127 [
1128 {
1129 "Priority": "high",
1130 "LocCode": "P1-C1"
1131 },
1132 {
1133 "Priority": "low",
1134 "LocCode": "P1"
1135 }
1136 ]
1137 }
1138 ])"_json;
1139
1140 AdditionalData ad;
1141 systemNames.push_back("system1");
1142
1143 // Since neither System or Systems available, it will pick the default one
1144 // only
1145 auto callouts = Registry::getCallouts(json, systemNames, ad);
1146 EXPECT_EQ(callouts.size(), 2);
1147 EXPECT_EQ(callouts[0].priority, "high");
1148 EXPECT_EQ(callouts[0].locCode, "P1-C1");
1149 EXPECT_EQ(callouts[0].procedure, "");
1150 EXPECT_EQ(callouts[0].symbolicFRU, "");
1151 EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
1152 EXPECT_EQ(callouts[1].priority, "low");
1153 EXPECT_EQ(callouts[1].locCode, "P1");
1154 EXPECT_EQ(callouts[1].procedure, "");
1155 EXPECT_EQ(callouts[1].symbolicFRU, "");
1156 EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
1157 }
1158
TEST_F(RegistryTest,TestNoSubsystem)1159 TEST_F(RegistryTest, TestNoSubsystem)
1160 {
1161 auto path = RegistryTest::writeData(registryData);
1162 Registry registry{path};
1163
1164 auto entry = registry.lookup("xyz.openbmc_project.Common.Error.Timeout",
1165 LookupType::name);
1166 ASSERT_TRUE(entry);
1167 EXPECT_FALSE(entry->subsystem);
1168 }
1169
TEST_F(RegistryTest,TestJournalSectionCapture)1170 TEST_F(RegistryTest, TestJournalSectionCapture)
1171 {
1172 auto path = RegistryTest::writeData(registryData);
1173 Registry registry{path};
1174
1175 auto entry = registry.lookup("xyz.openbmc_project.Journal.Capture",
1176 LookupType::name);
1177 ASSERT_TRUE(entry);
1178
1179 const auto& jc = entry->journalCapture;
1180 ASSERT_TRUE(jc);
1181 ASSERT_TRUE(std::holds_alternative<AppCaptureList>(*jc));
1182 const auto& acl = std::get<AppCaptureList>(*jc);
1183
1184 ASSERT_EQ(acl.size(), 2);
1185
1186 EXPECT_EQ(acl[0].syslogID, "test1");
1187 EXPECT_EQ(acl[0].numLines, 5);
1188
1189 EXPECT_EQ(acl[1].syslogID, "test2");
1190 EXPECT_EQ(acl[1].numLines, 6);
1191 }
1192