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: 187 static void SetUpTestCase() 188 { 189 char path[] = "/tmp/regtestXXXXXX"; 190 regDir = mkdtemp(path); 191 } 192 193 static void TearDownTestCase() 194 { 195 fs::remove_all(regDir); 196 } 197 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 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 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 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 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. 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 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 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 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 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 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. 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::vector<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::vector<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::vector<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::vector<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 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 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 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 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 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 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 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