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