xref: /openbmc/phosphor-logging/test/openpower-pels/registry_test.cpp (revision 40fb54935ce7367636a7156039396ee91cc4d5e2)
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