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/registry.hpp"
17 
18 #include <nlohmann/json.hpp>
19 
20 #include <filesystem>
21 #include <fstream>
22 
23 #include <gtest/gtest.h>
24 
25 using namespace openpower::pels::message;
26 using namespace openpower::pels;
27 namespace fs = std::filesystem;
28 
29 const auto registryData = R"(
30 {
31     "PELs":
32     [
33         {
34             "Name": "xyz.openbmc_project.Power.Fault",
35             "Subsystem": "power_supply",
36 
37             "SRC":
38             {
39                 "ReasonCode": "0x2030"
40             },
41 
42             "Documentation":
43             {
44                 "Description": "A PGOOD Fault",
45                 "Message": "PS had a PGOOD Fault"
46             }
47         },
48 
49         {
50             "Name": "xyz.openbmc_project.Power.OverVoltage",
51             "Subsystem": "power_control_hw",
52             "Severity":
53             [
54                 {
55                     "System": "systemA",
56                     "SevValue": "unrecoverable"
57                 },
58                 {
59                     "System": "systemB",
60                     "SevValue": "recovered"
61                 },
62                 {
63                     "SevValue": "predictive"
64                 }
65             ],
66             "MfgSeverity": "non_error",
67             "ActionFlags": ["service_action", "report", "call_home"],
68             "MfgActionFlags": ["hidden"],
69 
70             "SRC":
71             {
72                 "ReasonCode": "0x2333",
73                 "Type": "BD",
74                 "SymptomIDFields": ["SRCWord5", "SRCWord6", "SRCWord7"],
75                 "Words6To9":
76                 {
77                     "6":
78                     {
79                         "Description": "Failing unit number",
80                         "AdditionalDataPropSource": "PS_NUM"
81                     },
82 
83                     "7":
84                     {
85                         "Description": "bad voltage",
86                         "AdditionalDataPropSource": "VOLTAGE"
87                     }
88                 },
89                 "DeconfigFlag": true,
90                 "CheckstopFlag": true
91             },
92 
93             "Documentation":
94             {
95                 "Description": "A PGOOD Fault",
96                 "Message": "PS %1 had a PGOOD Fault",
97                 "MessageArgSources":
98                 [
99                     "SRCWord6"
100                 ],
101                 "Notes": [
102                     "In the UserData section there is a JSON",
103                     "dump that provides debug information."
104                 ]
105             },
106 
107             "JournalCapture":
108             {
109                 "NumLines": 7
110             }
111         },
112 
113         {
114             "Name": "xyz.openbmc_project.Common.Error.Timeout",
115             "PossibleSubsystems": ["processor", "memory"],
116 
117             "SRC":
118             {
119                 "ReasonCode": "0x2030"
120             },
121             "Documentation":
122             {
123                 "Description": "A PGOOD Fault",
124                 "Message": "PS had a PGOOD Fault"
125             }
126         },
127 
128         {
129             "Name": "xyz.openbmc_project.Journal.Capture",
130             "Subsystem": "power_supply",
131 
132             "SRC":
133             {
134                 "ReasonCode": "0x2030"
135             },
136 
137             "Documentation":
138             {
139                 "Description": "journal capture test",
140                 "Message": "journal capture test"
141             },
142 
143             "JournalCapture":
144             {
145                 "Sections": [
146                     {
147                         "NumLines": 5,
148                         "SyslogID": "test1"
149                     },
150                     {
151                         "NumLines": 6,
152                         "SyslogID": "test2"
153                     }
154                 ]
155             }
156         }
157     ]
158 }
159 )";
160 
161 class RegistryTest : public ::testing::Test
162 {
163   protected:
164     static void SetUpTestCase()
165     {
166         char path[] = "/tmp/regtestXXXXXX";
167         regDir = mkdtemp(path);
168     }
169 
170     static void TearDownTestCase()
171     {
172         fs::remove_all(regDir);
173     }
174 
175     static std::string writeData(const char* data)
176     {
177         fs::path path = regDir / "registry.json";
178         std::ofstream stream{path};
179         stream << data;
180         return path;
181     }
182 
183     static fs::path regDir;
184 };
185 
186 fs::path RegistryTest::regDir{};
187 
188 TEST_F(RegistryTest, TestNoEntry)
189 {
190     auto path = RegistryTest::writeData(registryData);
191     Registry registry{path};
192 
193     auto entry = registry.lookup("foo", LookupType::name);
194     EXPECT_FALSE(entry);
195 }
196 
197 TEST_F(RegistryTest, TestFindEntry)
198 {
199     auto path = RegistryTest::writeData(registryData);
200     Registry registry{path};
201 
202     auto entry = registry.lookup("xyz.openbmc_project.Power.OverVoltage",
203                                  LookupType::name);
204     ASSERT_TRUE(entry);
205     EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.OverVoltage");
206     EXPECT_EQ(entry->subsystem, 0x62);
207 
208     ASSERT_EQ(entry->severity->size(), 3);
209     EXPECT_EQ((*entry->severity)[0].severity, 0x40);
210     EXPECT_EQ((*entry->severity)[0].system, "systemA");
211     EXPECT_EQ((*entry->severity)[1].severity, 0x10);
212     EXPECT_EQ((*entry->severity)[1].system, "systemB");
213     EXPECT_EQ((*entry->severity)[2].severity, 0x20);
214     EXPECT_EQ((*entry->severity)[2].system, "");
215 
216     EXPECT_EQ(entry->mfgSeverity->size(), 1);
217     EXPECT_EQ((*entry->mfgSeverity)[0].severity, 0x00);
218 
219     EXPECT_EQ(*(entry->actionFlags), 0xA800);
220     EXPECT_EQ(*(entry->mfgActionFlags), 0x4000);
221     EXPECT_EQ(entry->componentID, 0x2300);
222     EXPECT_FALSE(entry->eventType);
223     EXPECT_FALSE(entry->eventScope);
224 
225     EXPECT_EQ(entry->src.type, 0xBD);
226     EXPECT_EQ(entry->src.reasonCode, 0x2333);
227     EXPECT_TRUE(entry->src.deconfigFlag);
228     EXPECT_TRUE(entry->src.checkstopFlag);
229 
230     auto& hexwords = entry->src.hexwordADFields;
231     EXPECT_TRUE(hexwords);
232     EXPECT_EQ((*hexwords).size(), 2);
233 
234     auto word = (*hexwords).find(6);
235     EXPECT_NE(word, (*hexwords).end());
236     EXPECT_EQ(std::get<0>(word->second), "PS_NUM");
237 
238     word = (*hexwords).find(7);
239     EXPECT_NE(word, (*hexwords).end());
240     EXPECT_EQ(std::get<0>(word->second), "VOLTAGE");
241 
242     auto& sid = entry->src.symptomID;
243     EXPECT_TRUE(sid);
244     EXPECT_EQ((*sid).size(), 3);
245     EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 5), (*sid).end());
246     EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 6), (*sid).end());
247     EXPECT_NE(std::find((*sid).begin(), (*sid).end(), 7), (*sid).end());
248 
249     EXPECT_EQ(entry->doc.description, "A PGOOD Fault");
250     EXPECT_EQ(entry->doc.message, "PS %1 had a PGOOD Fault");
251     auto& hexwordSource = entry->doc.messageArgSources;
252     EXPECT_TRUE(hexwordSource);
253     EXPECT_EQ((*hexwordSource).size(), 1);
254     EXPECT_EQ((*hexwordSource).front(), "SRCWord6");
255 
256     const auto& jc = entry->journalCapture;
257     ASSERT_TRUE(jc);
258     ASSERT_TRUE(std::holds_alternative<size_t>(*jc));
259     EXPECT_EQ(std::get<size_t>(*jc), 7);
260 
261     entry = registry.lookup("0x2333", LookupType::reasonCode);
262     ASSERT_TRUE(entry);
263     EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.OverVoltage");
264 }
265 
266 // Check the entry that mostly uses defaults
267 TEST_F(RegistryTest, TestFindEntryMinimal)
268 {
269     auto path = RegistryTest::writeData(registryData);
270     Registry registry{path};
271 
272     auto entry = registry.lookup("xyz.openbmc_project.Power.Fault",
273                                  LookupType::name);
274     ASSERT_TRUE(entry);
275     EXPECT_EQ(entry->name, "xyz.openbmc_project.Power.Fault");
276     EXPECT_EQ(entry->subsystem, 0x61);
277     EXPECT_FALSE(entry->severity);
278     EXPECT_FALSE(entry->mfgSeverity);
279     EXPECT_FALSE(entry->mfgActionFlags);
280     EXPECT_FALSE(entry->actionFlags);
281     EXPECT_EQ(entry->componentID, 0x2000);
282     EXPECT_FALSE(entry->eventType);
283     EXPECT_FALSE(entry->eventScope);
284 
285     EXPECT_EQ(entry->src.reasonCode, 0x2030);
286     EXPECT_EQ(entry->src.type, 0xBD);
287     EXPECT_FALSE(entry->src.hexwordADFields);
288     EXPECT_FALSE(entry->src.symptomID);
289     EXPECT_FALSE(entry->src.deconfigFlag);
290     EXPECT_FALSE(entry->src.checkstopFlag);
291 }
292 
293 TEST_F(RegistryTest, TestBadJSON)
294 {
295     auto path = RegistryTest::writeData("bad {} json");
296 
297     Registry registry{path};
298 
299     EXPECT_FALSE(registry.lookup("foo", LookupType::name));
300 }
301 
302 // Test the helper functions the use the pel_values data.
303 TEST_F(RegistryTest, TestHelperFunctions)
304 {
305     using namespace openpower::pels::message::helper;
306     EXPECT_EQ(getSubsystem("input_power_source"), 0xA1);
307     EXPECT_THROW(getSubsystem("foo"), std::runtime_error);
308 
309     EXPECT_EQ(getSeverity("symptom_recovered"), 0x71);
310     EXPECT_THROW(getSeverity("foo"), std::runtime_error);
311 
312     EXPECT_EQ(getEventType("dump_notification"), 0x08);
313     EXPECT_THROW(getEventType("foo"), std::runtime_error);
314 
315     EXPECT_EQ(getEventScope("possibly_multiple_platforms"), 0x04);
316     EXPECT_THROW(getEventScope("foo"), std::runtime_error);
317 
318     std::vector<std::string> flags{"service_action", "dont_report",
319                                    "termination"};
320     EXPECT_EQ(getActionFlags(flags), 0x9100);
321 
322     flags.clear();
323     flags.push_back("foo");
324     EXPECT_THROW(getActionFlags(flags), std::runtime_error);
325 }
326 
327 TEST_F(RegistryTest, TestGetSRCReasonCode)
328 {
329     using namespace openpower::pels::message::helper;
330     EXPECT_EQ(getSRCReasonCode(R"({"ReasonCode": "0x5555"})"_json, "foo"),
331               0x5555);
332 
333     EXPECT_THROW(getSRCReasonCode(R"({"ReasonCode": "ZZZZ"})"_json, "foo"),
334                  std::runtime_error);
335 }
336 
337 TEST_F(RegistryTest, TestGetSRCType)
338 {
339     using namespace openpower::pels::message::helper;
340     EXPECT_EQ(getSRCType(R"({"Type": "11"})"_json, "foo"), 0x11);
341     EXPECT_EQ(getSRCType(R"({"Type": "BF"})"_json, "foo"), 0xBF);
342 
343     EXPECT_THROW(getSRCType(R"({"Type": "1"})"_json, "foo"),
344                  std::runtime_error);
345 
346     EXPECT_THROW(getSRCType(R"({"Type": "111"})"_json, "foo"),
347                  std::runtime_error);
348 }
349 
350 TEST_F(RegistryTest, TestGetSRCHexwordFields)
351 {
352     using namespace openpower::pels::message::helper;
353     const auto hexwords = R"(
354     {"Words6To9":
355       {
356         "8":
357         {
358             "Description": "TEST",
359             "AdditionalDataPropSource": "TEST"
360         }
361       }
362     })"_json;
363 
364     auto fields = getSRCHexwordFields(hexwords, "foo");
365     EXPECT_TRUE(fields);
366     auto word = fields->find(8);
367     EXPECT_NE(word, fields->end());
368 
369     const auto theInvalidRWord = R"(
370     {"Words6To9":
371       {
372         "R":
373         {
374             "Description": "TEST",
375             "AdditionalDataPropSource": "TEST"
376         }
377       }
378     })"_json;
379 
380     EXPECT_THROW(getSRCHexwordFields(theInvalidRWord, "foo"),
381                  std::runtime_error);
382 }
383 
384 TEST_F(RegistryTest, TestGetSRCSymptomIDFields)
385 {
386     using namespace openpower::pels::message::helper;
387     const auto sID = R"(
388     {
389         "SymptomIDFields": ["SRCWord3", "SRCWord4", "SRCWord5"]
390     })"_json;
391 
392     auto fields = getSRCSymptomIDFields(sID, "foo");
393     EXPECT_NE(std::find(fields->begin(), fields->end(), 3), fields->end());
394     EXPECT_NE(std::find(fields->begin(), fields->end(), 4), fields->end());
395     EXPECT_NE(std::find(fields->begin(), fields->end(), 5), fields->end());
396 
397     const auto badField = R"(
398     {
399         "SymptomIDFields": ["SRCWord3", "SRCWord4", "SRCWord"]
400     })"_json;
401 
402     EXPECT_THROW(getSRCSymptomIDFields(badField, "foo"), std::runtime_error);
403 }
404 
405 TEST_F(RegistryTest, TestGetComponentID)
406 {
407     using namespace openpower::pels::message::helper;
408 
409     // Get it from the JSON
410     auto id = getComponentID(0xBD, 0x4200, R"({"ComponentID":"0x4200"})"_json,
411                              "foo");
412     EXPECT_EQ(id, 0x4200);
413 
414     // Get it from the reason code on a 0xBD SRC
415     id = getComponentID(0xBD, 0x6700, R"({})"_json, "foo");
416     EXPECT_EQ(id, 0x6700);
417 
418     // Not present on a 0x11 SRC
419     EXPECT_THROW(getComponentID(0x11, 0x8800, R"({})"_json, "foo"),
420                  std::runtime_error);
421 }
422 
423 // Test when callouts are in the JSON.
424 TEST_F(RegistryTest, TestGetCallouts)
425 {
426     std::vector<std::string> names;
427 
428     {
429         // Callouts without AD, that depend on system type,
430         // where there is a default entry without a system type.
431         auto json = R"(
432         [
433         {
434             "System": "system1",
435             "CalloutList":
436             [
437                 {
438                     "Priority": "high",
439                     "LocCode": "P1-C1"
440                 },
441                 {
442                     "Priority": "low",
443                     "LocCode": "P1"
444                 },
445                 {
446                     "Priority": "low",
447                     "SymbolicFRU": "service_docs"
448                 },
449                 {
450                     "Priority": "low",
451                     "SymbolicFRUTrusted": "air_mover",
452                     "UseInventoryLocCode": true
453                 }
454             ]
455         },
456         {
457             "CalloutList":
458             [
459                 {
460                     "Priority": "medium",
461                     "Procedure": "bmc_code"
462                 },
463                 {
464                     "Priority": "low",
465                     "LocCode": "P3-C8",
466                     "SymbolicFRUTrusted": "service_docs"
467                 }
468             ]
469 
470         }
471         ])"_json;
472 
473         AdditionalData ad;
474         names.push_back("system1");
475 
476         auto callouts = Registry::getCallouts(json, names, ad);
477         EXPECT_EQ(callouts.size(), 4);
478         EXPECT_EQ(callouts[0].priority, "high");
479         EXPECT_EQ(callouts[0].locCode, "P1-C1");
480         EXPECT_EQ(callouts[0].procedure, "");
481         EXPECT_EQ(callouts[0].symbolicFRU, "");
482         EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
483         EXPECT_EQ(callouts[1].priority, "low");
484         EXPECT_EQ(callouts[1].locCode, "P1");
485         EXPECT_EQ(callouts[1].procedure, "");
486         EXPECT_EQ(callouts[1].symbolicFRU, "");
487         EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
488         EXPECT_EQ(callouts[2].priority, "low");
489         EXPECT_EQ(callouts[2].locCode, "");
490         EXPECT_EQ(callouts[2].procedure, "");
491         EXPECT_EQ(callouts[2].symbolicFRU, "service_docs");
492         EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
493         EXPECT_EQ(callouts[3].priority, "low");
494         EXPECT_EQ(callouts[3].locCode, "");
495         EXPECT_EQ(callouts[3].procedure, "");
496         EXPECT_EQ(callouts[3].symbolicFRU, "");
497         EXPECT_EQ(callouts[3].symbolicFRUTrusted, "air_mover");
498         EXPECT_EQ(callouts[3].useInventoryLocCode, true);
499 
500         // system2 isn't in the JSON, so it will pick the default one
501         names[0] = "system2";
502         callouts = Registry::getCallouts(json, names, ad);
503         EXPECT_EQ(callouts.size(), 2);
504         EXPECT_EQ(callouts[0].priority, "medium");
505         EXPECT_EQ(callouts[0].locCode, "");
506         EXPECT_EQ(callouts[0].procedure, "bmc_code");
507         EXPECT_EQ(callouts[0].symbolicFRU, "");
508         EXPECT_EQ(callouts[1].priority, "low");
509         EXPECT_EQ(callouts[1].locCode, "P3-C8");
510         EXPECT_EQ(callouts[1].procedure, "");
511         EXPECT_EQ(callouts[1].symbolicFRU, "");
512         EXPECT_EQ(callouts[1].symbolicFRUTrusted, "service_docs");
513         EXPECT_EQ(callouts[1].useInventoryLocCode, false);
514     }
515 
516     // Empty JSON array (treated as an error)
517     {
518         auto json = R"([])"_json;
519         AdditionalData ad;
520         names[0] = "system1";
521         EXPECT_THROW(Registry::getCallouts(json, names, ad),
522                      std::runtime_error);
523     }
524 
525     {
526         // Callouts without AD, that depend on system type,
527         // where there isn't a default entry without a system type.
528         auto json = R"(
529         [
530         {
531             "System": "system1",
532             "CalloutList":
533             [
534                 {
535                     "Priority": "high",
536                     "LocCode": "P1-C1"
537                 },
538                 {
539                     "Priority": "low",
540                     "LocCode": "P1",
541                     "SymbolicFRU": "1234567"
542                 }
543             ]
544         },
545         {
546             "System": "system2",
547             "CalloutList":
548             [
549                 {
550                     "Priority": "medium",
551                     "LocCode": "P7",
552                     "CalloutType": "tool_fru"
553                 }
554             ]
555 
556         }
557         ])"_json;
558 
559         AdditionalData ad;
560         names[0] = "system1";
561 
562         auto callouts = Registry::getCallouts(json, names, ad);
563         EXPECT_EQ(callouts.size(), 2);
564         EXPECT_EQ(callouts[0].priority, "high");
565         EXPECT_EQ(callouts[0].locCode, "P1-C1");
566         EXPECT_EQ(callouts[0].procedure, "");
567         EXPECT_EQ(callouts[0].symbolicFRU, "");
568         EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
569         EXPECT_EQ(callouts[1].priority, "low");
570         EXPECT_EQ(callouts[1].locCode, "P1");
571         EXPECT_EQ(callouts[1].procedure, "");
572         EXPECT_EQ(callouts[1].symbolicFRU, "1234567");
573         EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
574 
575         names[0] = "system2";
576         callouts = Registry::getCallouts(json, names, ad);
577         EXPECT_EQ(callouts.size(), 1);
578         EXPECT_EQ(callouts[0].priority, "medium");
579         EXPECT_EQ(callouts[0].locCode, "P7");
580         EXPECT_EQ(callouts[0].procedure, "");
581         EXPECT_EQ(callouts[0].symbolicFRU, "");
582         EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
583 
584         // There is no entry for system3 or a default system,
585         // so this should fail.
586         names[0] = "system3";
587         EXPECT_THROW(Registry::getCallouts(json, names, ad),
588                      std::runtime_error);
589     }
590 
591     {
592         // Callouts that use the AdditionalData key PROC_NUM
593         // as an index into them, along with a system type.
594         // It supports PROC_NUMs 0 and 1.
595         auto json = R"(
596         {
597             "ADName": "PROC_NUM",
598             "CalloutsWithTheirADValues":
599             [
600                 {
601                     "ADValue": "0",
602                     "Callouts":
603                     [
604                         {
605                             "System": "system3",
606                             "CalloutList":
607                             [
608                                 {
609                                     "Priority": "high",
610                                     "LocCode": "P1-C5"
611                                 },
612                                 {
613                                     "Priority": "medium",
614                                     "LocCode": "P1-C6",
615                                     "SymbolicFRU": "1234567"
616                                 },
617                                 {
618                                     "Priority": "low",
619                                     "Procedure": "bmc_code",
620                                     "CalloutType": "config_procedure"
621                                 }
622                             ]
623                         },
624                         {
625                             "CalloutList":
626                             [
627                                 {
628                                     "Priority": "low",
629                                     "LocCode": "P55"
630                                 }
631                             ]
632                         }
633                     ]
634                 },
635                 {
636                     "ADValue": "1",
637                     "Callouts":
638                     [
639                         {
640                             "CalloutList":
641                             [
642                                 {
643                                     "Priority": "high",
644                                     "LocCode": "P1-C6",
645                                     "CalloutType": "external_fru"
646                                 }
647                             ]
648                         }
649                     ]
650                 }
651             ]
652         })"_json;
653 
654         {
655             // Find callouts for PROC_NUM 0 on system3
656             std::vector<std::string> adData{"PROC_NUM=0"};
657             AdditionalData ad{adData};
658             names[0] = "system3";
659 
660             auto callouts = Registry::getCallouts(json, names, ad);
661             EXPECT_EQ(callouts.size(), 3);
662             EXPECT_EQ(callouts[0].priority, "high");
663             EXPECT_EQ(callouts[0].locCode, "P1-C5");
664             EXPECT_EQ(callouts[0].procedure, "");
665             EXPECT_EQ(callouts[0].symbolicFRU, "");
666             EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
667             EXPECT_EQ(callouts[1].priority, "medium");
668             EXPECT_EQ(callouts[1].locCode, "P1-C6");
669             EXPECT_EQ(callouts[1].procedure, "");
670             EXPECT_EQ(callouts[1].symbolicFRU, "1234567");
671             EXPECT_EQ(callouts[1].symbolicFRUTrusted, "");
672             EXPECT_EQ(callouts[2].priority, "low");
673             EXPECT_EQ(callouts[2].locCode, "");
674             EXPECT_EQ(callouts[2].procedure, "bmc_code");
675             EXPECT_EQ(callouts[2].symbolicFRU, "");
676             EXPECT_EQ(callouts[2].symbolicFRUTrusted, "");
677 
678             // Find callouts for PROC_NUM 0 that uses the default system entry.
679             names[0] = "system99";
680 
681             callouts = Registry::getCallouts(json, names, ad);
682             EXPECT_EQ(callouts.size(), 1);
683             EXPECT_EQ(callouts[0].priority, "low");
684             EXPECT_EQ(callouts[0].locCode, "P55");
685             EXPECT_EQ(callouts[0].procedure, "");
686             EXPECT_EQ(callouts[0].symbolicFRU, "");
687             EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
688         }
689         {
690             // Find callouts for PROC_NUM 1 that uses a default system entry.
691             std::vector<std::string> adData{"PROC_NUM=1"};
692             AdditionalData ad{adData};
693             names[0] = "system1";
694 
695             auto callouts = Registry::getCallouts(json, names, ad);
696             EXPECT_EQ(callouts.size(), 1);
697             EXPECT_EQ(callouts[0].priority, "high");
698             EXPECT_EQ(callouts[0].locCode, "P1-C6");
699             EXPECT_EQ(callouts[0].procedure, "");
700             EXPECT_EQ(callouts[0].symbolicFRU, "");
701             EXPECT_EQ(callouts[0].symbolicFRUTrusted, "");
702         }
703         {
704             // There is no entry for PROC_NUM 2, so no callouts
705             std::vector<std::string> adData{"PROC_NUM=2"};
706             AdditionalData ad{adData};
707 
708             auto callouts = Registry::getCallouts(json, names, ad);
709             EXPECT_TRUE(callouts.empty());
710         }
711     }
712 
713     {
714         // Callouts with a 'CalloutsWhenNoADMatch' section that will
715         // be used when the AdditionalData value doesn't match.
716         auto json = R"(
717         {
718             "ADName": "PROC_NUM",
719             "CalloutsWithTheirADValues":
720             [
721                 {
722                     "ADValue": "0",
723                     "Callouts":
724                     [
725                         {
726                             "CalloutList":
727                             [
728                                 {
729                                     "Priority": "high",
730                                     "LocCode": "P0-C0"
731                                 }
732                             ]
733                         }
734                     ]
735                 }
736             ],
737             "CalloutsWhenNoADMatch": [
738                 {
739                     "CalloutList": [
740                         {
741                             "Priority": "medium",
742                             "LocCode": "P1-C1"
743                         }
744                     ]
745                 }
746             ]
747         })"_json;
748 
749         // There isn't an entry in the JSON for a PROC_NUM of 8
750         // so it should choose the P1-C1 callout.
751         std::vector<std::string> adData{"PROC_NUM=8"};
752         AdditionalData ad{adData};
753         names.clear();
754 
755         auto callouts = Registry::getCallouts(json, names, ad);
756         EXPECT_EQ(callouts.size(), 1);
757         EXPECT_EQ(callouts[0].priority, "medium");
758         EXPECT_EQ(callouts[0].locCode, "P1-C1");
759     }
760 }
761 
762 TEST_F(RegistryTest, TestNoSubsystem)
763 {
764     auto path = RegistryTest::writeData(registryData);
765     Registry registry{path};
766 
767     auto entry = registry.lookup("xyz.openbmc_project.Common.Error.Timeout",
768                                  LookupType::name);
769     ASSERT_TRUE(entry);
770     EXPECT_FALSE(entry->subsystem);
771 }
772 
773 TEST_F(RegistryTest, TestJournalSectionCapture)
774 {
775     auto path = RegistryTest::writeData(registryData);
776     Registry registry{path};
777 
778     auto entry = registry.lookup("xyz.openbmc_project.Journal.Capture",
779                                  LookupType::name);
780     ASSERT_TRUE(entry);
781 
782     const auto& jc = entry->journalCapture;
783     ASSERT_TRUE(jc);
784     ASSERT_TRUE(std::holds_alternative<AppCaptureList>(*jc));
785     const auto& acl = std::get<AppCaptureList>(*jc);
786 
787     ASSERT_EQ(acl.size(), 2);
788 
789     EXPECT_EQ(acl[0].syslogID, "test1");
790     EXPECT_EQ(acl[0].numLines, 5);
791 
792     EXPECT_EQ(acl[1].syslogID, "test2");
793     EXPECT_EQ(acl[1].numLines, 6);
794 }
795