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