1 /** 2 * Copyright © 2024 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 17 #include "mock_device.hpp" 18 #include "mock_services.hpp" 19 #include "rail.hpp" 20 21 #include <cstdint> 22 #include <map> 23 #include <optional> 24 #include <string> 25 #include <vector> 26 27 #include <gmock/gmock.h> 28 #include <gtest/gtest.h> 29 30 using namespace phosphor::power::sequencer; 31 32 using ::testing::Return; 33 using ::testing::Throw; 34 35 TEST(GPIOTests, Initialization) 36 { 37 // Default initialization 38 { 39 GPIO gpio; 40 EXPECT_EQ(gpio.line, 0); 41 EXPECT_FALSE(gpio.activeLow); 42 } 43 44 // Explicit initialization 45 { 46 GPIO gpio{48, true}; 47 EXPECT_EQ(gpio.line, 48); 48 EXPECT_TRUE(gpio.activeLow); 49 } 50 } 51 52 TEST(RailTests, Constructor) 53 { 54 // Test where succeeds: No optional parameters have values 55 { 56 std::string name{"12.0V"}; 57 std::optional<std::string> presence{}; 58 std::optional<uint8_t> page{}; 59 bool isPowerSupplyRail{true}; 60 bool checkStatusVout{false}; 61 bool compareVoltageToLimit{false}; 62 std::optional<GPIO> gpio{}; 63 Rail rail{name, 64 presence, 65 page, 66 isPowerSupplyRail, 67 checkStatusVout, 68 compareVoltageToLimit, 69 gpio}; 70 71 EXPECT_EQ(rail.getName(), "12.0V"); 72 EXPECT_FALSE(rail.getPresence().has_value()); 73 EXPECT_FALSE(rail.getPage().has_value()); 74 EXPECT_TRUE(rail.isPowerSupplyRail()); 75 EXPECT_FALSE(rail.getCheckStatusVout()); 76 EXPECT_FALSE(rail.getCompareVoltageToLimit()); 77 EXPECT_FALSE(rail.getGPIO().has_value()); 78 } 79 80 // Test where succeeds: All optional parameters have values 81 { 82 std::string name{"VCS_CPU1"}; 83 std::optional<std::string> presence{ 84 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1"}; 85 std::optional<uint8_t> page{11}; 86 bool isPowerSupplyRail{false}; 87 bool checkStatusVout{true}; 88 bool compareVoltageToLimit{true}; 89 std::optional<GPIO> gpio{GPIO(60, true)}; 90 Rail rail{name, 91 presence, 92 page, 93 isPowerSupplyRail, 94 checkStatusVout, 95 compareVoltageToLimit, 96 gpio}; 97 98 EXPECT_EQ(rail.getName(), "VCS_CPU1"); 99 EXPECT_TRUE(rail.getPresence().has_value()); 100 EXPECT_EQ( 101 rail.getPresence().value(), 102 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu1"); 103 EXPECT_TRUE(rail.getPage().has_value()); 104 EXPECT_EQ(rail.getPage().value(), 11); 105 EXPECT_FALSE(rail.isPowerSupplyRail()); 106 EXPECT_TRUE(rail.getCheckStatusVout()); 107 EXPECT_TRUE(rail.getCompareVoltageToLimit()); 108 EXPECT_TRUE(rail.getGPIO().has_value()); 109 EXPECT_EQ(rail.getGPIO().value().line, 60); 110 EXPECT_TRUE(rail.getGPIO().value().activeLow); 111 } 112 113 // Test where fails: checkStatusVout is true and page has no value 114 { 115 std::string name{"VDD1"}; 116 std::optional<std::string> presence{}; 117 std::optional<uint8_t> page{}; 118 bool isPowerSupplyRail{false}; 119 bool checkStatusVout{true}; 120 bool compareVoltageToLimit{false}; 121 std::optional<GPIO> gpio{}; 122 EXPECT_THROW((Rail{name, presence, page, isPowerSupplyRail, 123 checkStatusVout, compareVoltageToLimit, gpio}), 124 std::invalid_argument); 125 } 126 127 // Test where fails: compareVoltageToLimit is true and page has no value 128 { 129 std::string name{"VDD1"}; 130 std::optional<std::string> presence{}; 131 std::optional<uint8_t> page{}; 132 bool isPowerSupplyRail{false}; 133 bool checkStatusVout{false}; 134 bool compareVoltageToLimit{true}; 135 std::optional<GPIO> gpio{}; 136 EXPECT_THROW((Rail{name, presence, page, isPowerSupplyRail, 137 checkStatusVout, compareVoltageToLimit, gpio}), 138 std::invalid_argument); 139 } 140 } 141 142 TEST(RailTests, GetName) 143 { 144 std::string name{"VDD2"}; 145 std::optional<std::string> presence{}; 146 std::optional<uint8_t> page{}; 147 bool isPowerSupplyRail{false}; 148 bool checkStatusVout{false}; 149 bool compareVoltageToLimit{false}; 150 std::optional<GPIO> gpio{}; 151 Rail rail{name, 152 presence, 153 page, 154 isPowerSupplyRail, 155 checkStatusVout, 156 compareVoltageToLimit, 157 gpio}; 158 159 EXPECT_EQ(rail.getName(), "VDD2"); 160 } 161 162 TEST(RailTests, GetPresence) 163 { 164 std::string name{"VDDR2"}; 165 std::optional<uint8_t> page{}; 166 bool isPowerSupplyRail{false}; 167 bool checkStatusVout{false}; 168 bool compareVoltageToLimit{false}; 169 std::optional<GPIO> gpio{}; 170 171 // Test where presence has no value 172 { 173 std::optional<std::string> presence{}; 174 Rail rail{name, 175 presence, 176 page, 177 isPowerSupplyRail, 178 checkStatusVout, 179 compareVoltageToLimit, 180 gpio}; 181 EXPECT_FALSE(rail.getPresence().has_value()); 182 } 183 184 // Test where presence has a value 185 { 186 std::optional<std::string> presence{ 187 "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm2"}; 188 Rail rail{name, 189 presence, 190 page, 191 isPowerSupplyRail, 192 checkStatusVout, 193 compareVoltageToLimit, 194 gpio}; 195 EXPECT_TRUE(rail.getPresence().has_value()); 196 EXPECT_EQ( 197 rail.getPresence().value(), 198 "/xyz/openbmc_project/inventory/system/chassis/motherboard/dimm2"); 199 } 200 } 201 202 TEST(RailTests, GetPage) 203 { 204 std::string name{"VDD2"}; 205 std::optional<std::string> presence{}; 206 bool isPowerSupplyRail{false}; 207 bool checkStatusVout{false}; 208 bool compareVoltageToLimit{false}; 209 std::optional<GPIO> gpio{}; 210 211 // Test where page has no value 212 { 213 std::optional<uint8_t> page{}; 214 Rail rail{name, 215 presence, 216 page, 217 isPowerSupplyRail, 218 checkStatusVout, 219 compareVoltageToLimit, 220 gpio}; 221 EXPECT_FALSE(rail.getPage().has_value()); 222 } 223 224 // Test where page has a value 225 { 226 std::optional<uint8_t> page{7}; 227 Rail rail{name, 228 presence, 229 page, 230 isPowerSupplyRail, 231 checkStatusVout, 232 compareVoltageToLimit, 233 gpio}; 234 EXPECT_TRUE(rail.getPage().has_value()); 235 EXPECT_EQ(rail.getPage().value(), 7); 236 } 237 } 238 239 TEST(RailTests, IsPowerSupplyRail) 240 { 241 std::string name{"12.0V"}; 242 std::optional<std::string> presence{}; 243 std::optional<uint8_t> page{}; 244 bool isPowerSupplyRail{true}; 245 bool checkStatusVout{false}; 246 bool compareVoltageToLimit{false}; 247 std::optional<GPIO> gpio{}; 248 Rail rail{name, 249 presence, 250 page, 251 isPowerSupplyRail, 252 checkStatusVout, 253 compareVoltageToLimit, 254 gpio}; 255 256 EXPECT_TRUE(rail.isPowerSupplyRail()); 257 } 258 259 TEST(RailTests, GetCheckStatusVout) 260 { 261 std::string name{"VDD2"}; 262 std::optional<std::string> presence{}; 263 std::optional<uint8_t> page{}; 264 bool isPowerSupplyRail{false}; 265 bool checkStatusVout{false}; 266 bool compareVoltageToLimit{false}; 267 std::optional<GPIO> gpio{}; 268 Rail rail{name, 269 presence, 270 page, 271 isPowerSupplyRail, 272 checkStatusVout, 273 compareVoltageToLimit, 274 gpio}; 275 276 EXPECT_FALSE(rail.getCheckStatusVout()); 277 } 278 279 TEST(RailTests, GetCompareVoltageToLimit) 280 { 281 std::string name{"VDD2"}; 282 std::optional<std::string> presence{}; 283 std::optional<uint8_t> page{13}; 284 bool isPowerSupplyRail{false}; 285 bool checkStatusVout{false}; 286 bool compareVoltageToLimit{true}; 287 std::optional<GPIO> gpio{}; 288 Rail rail{name, 289 presence, 290 page, 291 isPowerSupplyRail, 292 checkStatusVout, 293 compareVoltageToLimit, 294 gpio}; 295 296 EXPECT_TRUE(rail.getCompareVoltageToLimit()); 297 } 298 299 TEST(RailTests, GetGPIO) 300 { 301 std::string name{"VDD2"}; 302 std::optional<std::string> presence{}; 303 std::optional<uint8_t> page{}; 304 bool isPowerSupplyRail{false}; 305 bool checkStatusVout{false}; 306 bool compareVoltageToLimit{false}; 307 308 // Test where gpio has no value 309 { 310 std::optional<GPIO> gpio{}; 311 Rail rail{name, 312 presence, 313 page, 314 isPowerSupplyRail, 315 checkStatusVout, 316 compareVoltageToLimit, 317 gpio}; 318 EXPECT_FALSE(rail.getGPIO().has_value()); 319 } 320 321 // Test where gpio has a value 322 { 323 std::optional<GPIO> gpio{GPIO(12, false)}; 324 Rail rail{name, 325 presence, 326 page, 327 isPowerSupplyRail, 328 checkStatusVout, 329 compareVoltageToLimit, 330 gpio}; 331 EXPECT_TRUE(rail.getGPIO().has_value()); 332 EXPECT_EQ(rail.getGPIO().value().line, 12); 333 EXPECT_FALSE(rail.getGPIO().value().activeLow); 334 } 335 } 336 337 TEST(RailTests, IsPresent) 338 { 339 std::string name{"VDD2"}; 340 std::optional<uint8_t> page{}; 341 bool isPowerSupplyRail{false}; 342 bool checkStatusVout{false}; 343 bool compareVoltageToLimit{false}; 344 std::optional<GPIO> gpio{}; 345 346 // Test where inventory path not specified; always returns true 347 { 348 std::optional<std::string> presence{}; 349 Rail rail{name, 350 presence, 351 page, 352 isPowerSupplyRail, 353 checkStatusVout, 354 compareVoltageToLimit, 355 gpio}; 356 357 MockServices services{}; 358 EXPECT_CALL(services, isPresent).Times(0); 359 360 EXPECT_TRUE(rail.isPresent(services)); 361 } 362 363 // Test where inventory path is not present 364 { 365 std::optional<std::string> presence{ 366 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 367 Rail rail{name, 368 presence, 369 page, 370 isPowerSupplyRail, 371 checkStatusVout, 372 compareVoltageToLimit, 373 gpio}; 374 375 MockServices services{}; 376 EXPECT_CALL(services, isPresent(*presence)) 377 .Times(1) 378 .WillOnce(Return(false)); 379 380 EXPECT_FALSE(rail.isPresent(services)); 381 } 382 383 // Test where inventory path is present 384 { 385 std::optional<std::string> presence{ 386 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 387 Rail rail{name, 388 presence, 389 page, 390 isPowerSupplyRail, 391 checkStatusVout, 392 compareVoltageToLimit, 393 gpio}; 394 395 MockServices services{}; 396 EXPECT_CALL(services, isPresent(*presence)) 397 .Times(1) 398 .WillOnce(Return(true)); 399 400 EXPECT_TRUE(rail.isPresent(services)); 401 } 402 403 // Test where exception occurs trying to get presence 404 { 405 std::optional<std::string> presence{ 406 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 407 Rail rail{name, 408 presence, 409 page, 410 isPowerSupplyRail, 411 checkStatusVout, 412 compareVoltageToLimit, 413 gpio}; 414 415 MockServices services{}; 416 EXPECT_CALL(services, isPresent(*presence)) 417 .Times(1) 418 .WillOnce(Throw(std::runtime_error{"Invalid object path"})); 419 420 try 421 { 422 rail.isPresent(services); 423 ADD_FAILURE() << "Should not have reached this line."; 424 } 425 catch (const std::exception& e) 426 { 427 EXPECT_STREQ( 428 e.what(), 429 "Unable to determine presence of rail VDD2 using " 430 "inventory path " 431 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2: " 432 "Invalid object path"); 433 } 434 } 435 } 436 437 TEST(RailTests, GetStatusWord) 438 { 439 std::string name{"VDD2"}; 440 std::optional<std::string> presence{}; 441 bool isPowerSupplyRail{false}; 442 bool checkStatusVout{false}; 443 bool compareVoltageToLimit{false}; 444 std::optional<GPIO> gpio{}; 445 446 // Test where page was not specified: Throws exception 447 { 448 std::optional<uint8_t> page{}; 449 Rail rail{name, 450 presence, 451 page, 452 isPowerSupplyRail, 453 checkStatusVout, 454 compareVoltageToLimit, 455 gpio}; 456 457 MockDevice device{}; 458 EXPECT_CALL(device, getStatusWord).Times(0); 459 460 try 461 { 462 rail.getStatusWord(device); 463 ADD_FAILURE() << "Should not have reached this line."; 464 } 465 catch (const std::exception& e) 466 { 467 EXPECT_STREQ(e.what(), 468 "Unable to read STATUS_WORD value for rail VDD2: " 469 "No PAGE number defined for rail VDD2"); 470 } 471 } 472 473 // Test where value read successfully 474 { 475 std::optional<uint8_t> page{2}; 476 Rail rail{name, 477 presence, 478 page, 479 isPowerSupplyRail, 480 checkStatusVout, 481 compareVoltageToLimit, 482 gpio}; 483 484 MockDevice device{}; 485 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 486 487 EXPECT_EQ(rail.getStatusWord(device), 0xbeef); 488 } 489 490 // Test where exception occurs trying to read value 491 { 492 std::optional<uint8_t> page{2}; 493 Rail rail{name, 494 presence, 495 page, 496 isPowerSupplyRail, 497 checkStatusVout, 498 compareVoltageToLimit, 499 gpio}; 500 501 MockDevice device{}; 502 EXPECT_CALL(device, getStatusWord(2)) 503 .Times(1) 504 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 505 506 try 507 { 508 rail.getStatusWord(device); 509 ADD_FAILURE() << "Should not have reached this line."; 510 } 511 catch (const std::exception& e) 512 { 513 EXPECT_STREQ(e.what(), 514 "Unable to read STATUS_WORD value for rail VDD2: " 515 "File does not exist"); 516 } 517 } 518 } 519 520 TEST(RailTests, GetStatusVout) 521 { 522 std::string name{"VDD2"}; 523 std::optional<std::string> presence{}; 524 bool isPowerSupplyRail{false}; 525 bool checkStatusVout{false}; 526 bool compareVoltageToLimit{false}; 527 std::optional<GPIO> gpio{}; 528 529 // Test where page was not specified: Throws exception 530 { 531 std::optional<uint8_t> page{}; 532 Rail rail{name, 533 presence, 534 page, 535 isPowerSupplyRail, 536 checkStatusVout, 537 compareVoltageToLimit, 538 gpio}; 539 540 MockDevice device{}; 541 EXPECT_CALL(device, getStatusVout).Times(0); 542 543 try 544 { 545 rail.getStatusVout(device); 546 ADD_FAILURE() << "Should not have reached this line."; 547 } 548 catch (const std::exception& e) 549 { 550 EXPECT_STREQ(e.what(), 551 "Unable to read STATUS_VOUT value for rail VDD2: " 552 "No PAGE number defined for rail VDD2"); 553 } 554 } 555 556 // Test where value read successfully 557 { 558 std::optional<uint8_t> page{2}; 559 Rail rail{name, 560 presence, 561 page, 562 isPowerSupplyRail, 563 checkStatusVout, 564 compareVoltageToLimit, 565 gpio}; 566 567 MockDevice device{}; 568 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0xad)); 569 570 EXPECT_EQ(rail.getStatusVout(device), 0xad); 571 } 572 573 // Test where exception occurs trying to read value 574 { 575 std::optional<uint8_t> page{2}; 576 Rail rail{name, 577 presence, 578 page, 579 isPowerSupplyRail, 580 checkStatusVout, 581 compareVoltageToLimit, 582 gpio}; 583 584 MockDevice device{}; 585 EXPECT_CALL(device, getStatusVout(2)) 586 .Times(1) 587 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 588 589 try 590 { 591 rail.getStatusVout(device); 592 ADD_FAILURE() << "Should not have reached this line."; 593 } 594 catch (const std::exception& e) 595 { 596 EXPECT_STREQ(e.what(), 597 "Unable to read STATUS_VOUT value for rail VDD2: " 598 "File does not exist"); 599 } 600 } 601 } 602 603 TEST(RailTests, GetReadVout) 604 { 605 std::string name{"VDD2"}; 606 std::optional<std::string> presence{}; 607 bool isPowerSupplyRail{false}; 608 bool checkStatusVout{false}; 609 bool compareVoltageToLimit{false}; 610 std::optional<GPIO> gpio{}; 611 612 // Test where page was not specified: Throws exception 613 { 614 std::optional<uint8_t> page{}; 615 Rail rail{name, 616 presence, 617 page, 618 isPowerSupplyRail, 619 checkStatusVout, 620 compareVoltageToLimit, 621 gpio}; 622 623 MockDevice device{}; 624 EXPECT_CALL(device, getReadVout).Times(0); 625 626 try 627 { 628 rail.getReadVout(device); 629 ADD_FAILURE() << "Should not have reached this line."; 630 } 631 catch (const std::exception& e) 632 { 633 EXPECT_STREQ(e.what(), 634 "Unable to read READ_VOUT value for rail VDD2: " 635 "No PAGE number defined for rail VDD2"); 636 } 637 } 638 639 // Test where value read successfully 640 { 641 std::optional<uint8_t> page{2}; 642 Rail rail{name, 643 presence, 644 page, 645 isPowerSupplyRail, 646 checkStatusVout, 647 compareVoltageToLimit, 648 gpio}; 649 650 MockDevice device{}; 651 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.23)); 652 653 EXPECT_EQ(rail.getReadVout(device), 1.23); 654 } 655 656 // Test where exception occurs trying to read value 657 { 658 std::optional<uint8_t> page{2}; 659 Rail rail{name, 660 presence, 661 page, 662 isPowerSupplyRail, 663 checkStatusVout, 664 compareVoltageToLimit, 665 gpio}; 666 667 MockDevice device{}; 668 EXPECT_CALL(device, getReadVout(2)) 669 .Times(1) 670 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 671 672 try 673 { 674 rail.getReadVout(device); 675 ADD_FAILURE() << "Should not have reached this line."; 676 } 677 catch (const std::exception& e) 678 { 679 EXPECT_STREQ(e.what(), 680 "Unable to read READ_VOUT value for rail VDD2: " 681 "File does not exist"); 682 } 683 } 684 } 685 686 TEST(RailTests, GetVoutUVFaultLimit) 687 { 688 std::string name{"VDD2"}; 689 std::optional<std::string> presence{}; 690 bool isPowerSupplyRail{false}; 691 bool checkStatusVout{false}; 692 bool compareVoltageToLimit{false}; 693 std::optional<GPIO> gpio{}; 694 695 // Test where page was not specified: Throws exception 696 { 697 std::optional<uint8_t> page{}; 698 Rail rail{name, 699 presence, 700 page, 701 isPowerSupplyRail, 702 checkStatusVout, 703 compareVoltageToLimit, 704 gpio}; 705 706 MockDevice device{}; 707 EXPECT_CALL(device, getVoutUVFaultLimit).Times(0); 708 709 try 710 { 711 rail.getVoutUVFaultLimit(device); 712 ADD_FAILURE() << "Should not have reached this line."; 713 } 714 catch (const std::exception& e) 715 { 716 EXPECT_STREQ( 717 e.what(), 718 "Unable to read VOUT_UV_FAULT_LIMIT value for rail VDD2: " 719 "No PAGE number defined for rail VDD2"); 720 } 721 } 722 723 // Test where value read successfully 724 { 725 std::optional<uint8_t> page{2}; 726 Rail rail{name, 727 presence, 728 page, 729 isPowerSupplyRail, 730 checkStatusVout, 731 compareVoltageToLimit, 732 gpio}; 733 734 MockDevice device{}; 735 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 736 .Times(1) 737 .WillOnce(Return(0.9)); 738 739 EXPECT_EQ(rail.getVoutUVFaultLimit(device), 0.9); 740 } 741 742 // Test where exception occurs trying to read value 743 { 744 std::optional<uint8_t> page{2}; 745 Rail rail{name, 746 presence, 747 page, 748 isPowerSupplyRail, 749 checkStatusVout, 750 compareVoltageToLimit, 751 gpio}; 752 753 MockDevice device{}; 754 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 755 .Times(1) 756 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 757 758 try 759 { 760 rail.getVoutUVFaultLimit(device); 761 ADD_FAILURE() << "Should not have reached this line."; 762 } 763 catch (const std::exception& e) 764 { 765 EXPECT_STREQ( 766 e.what(), 767 "Unable to read VOUT_UV_FAULT_LIMIT value for rail VDD2: " 768 "File does not exist"); 769 } 770 } 771 } 772 773 TEST(RailTests, HasPgoodFault) 774 { 775 std::string name{"VDD2"}; 776 bool isPowerSupplyRail{false}; 777 778 // Test where presence check defined: Rail is not present 779 { 780 std::optional<std::string> presence{ 781 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 782 std::optional<uint8_t> page{3}; 783 bool checkStatusVout{true}; 784 bool compareVoltageToLimit{false}; 785 std::optional<GPIO> gpio{}; 786 Rail rail{name, 787 presence, 788 page, 789 isPowerSupplyRail, 790 checkStatusVout, 791 compareVoltageToLimit, 792 gpio}; 793 794 MockDevice device{}; 795 796 MockServices services{}; 797 EXPECT_CALL(services, isPresent(*presence)) 798 .Times(1) 799 .WillOnce(Return(false)); 800 EXPECT_CALL(services, logInfoMsg("Rail VDD2 is not present")).Times(1); 801 802 std::vector<int> gpioValues{}; 803 std::map<std::string, std::string> additionalData{}; 804 EXPECT_FALSE( 805 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 806 EXPECT_EQ(additionalData.size(), 0); 807 } 808 809 // Test where presence check defined: Rail is present 810 { 811 std::optional<std::string> presence{ 812 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 813 std::optional<uint8_t> page{}; 814 bool checkStatusVout{false}; 815 bool compareVoltageToLimit{false}; 816 std::optional<GPIO> gpio{}; 817 Rail rail{name, 818 presence, 819 page, 820 isPowerSupplyRail, 821 checkStatusVout, 822 compareVoltageToLimit, 823 gpio}; 824 825 MockDevice device{}; 826 827 MockServices services{}; 828 EXPECT_CALL(services, isPresent(*presence)) 829 .Times(1) 830 .WillOnce(Return(true)); 831 EXPECT_CALL(services, logInfoMsg).Times(0); 832 833 std::vector<int> gpioValues{}; 834 std::map<std::string, std::string> additionalData{}; 835 EXPECT_FALSE( 836 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 837 EXPECT_EQ(additionalData.size(), 0); 838 } 839 840 // Test where no checks are specified 841 { 842 std::optional<std::string> presence{}; 843 std::optional<uint8_t> page{}; 844 bool checkStatusVout{false}; 845 bool compareVoltageToLimit{false}; 846 std::optional<GPIO> gpio{}; 847 Rail rail{name, 848 presence, 849 page, 850 isPowerSupplyRail, 851 checkStatusVout, 852 compareVoltageToLimit, 853 gpio}; 854 855 MockDevice device{}; 856 857 MockServices services{}; 858 859 std::vector<int> gpioValues{}; 860 std::map<std::string, std::string> additionalData{}; 861 EXPECT_FALSE( 862 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 863 EXPECT_EQ(additionalData.size(), 0); 864 } 865 866 // Test where 1 check defined: STATUS_VOUT: No fault detected 867 { 868 std::optional<std::string> presence{}; 869 std::optional<uint8_t> page{2}; 870 bool checkStatusVout{true}; 871 bool compareVoltageToLimit{false}; 872 std::optional<GPIO> gpio{}; 873 Rail rail{name, 874 presence, 875 page, 876 isPowerSupplyRail, 877 checkStatusVout, 878 compareVoltageToLimit, 879 gpio}; 880 881 MockDevice device{}; 882 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 883 884 MockServices services{}; 885 886 std::vector<int> gpioValues{}; 887 std::map<std::string, std::string> additionalData{}; 888 EXPECT_FALSE( 889 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 890 EXPECT_EQ(additionalData.size(), 0); 891 } 892 893 // Test where 1 check defined: STATUS_VOUT: No fault detected, but warning 894 // bits set 895 { 896 std::optional<std::string> presence{}; 897 std::optional<uint8_t> page{2}; 898 bool checkStatusVout{true}; 899 bool compareVoltageToLimit{false}; 900 std::optional<GPIO> gpio{}; 901 Rail rail{name, 902 presence, 903 page, 904 isPowerSupplyRail, 905 checkStatusVout, 906 compareVoltageToLimit, 907 gpio}; 908 909 MockDevice device{}; 910 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x6a)); 911 912 MockServices services{}; 913 EXPECT_CALL( 914 services, 915 logInfoMsg("Rail VDD2 has warning bits set in STATUS_VOUT: 0x6a")) 916 .Times(1); 917 918 std::vector<int> gpioValues{}; 919 std::map<std::string, std::string> additionalData{}; 920 EXPECT_FALSE( 921 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 922 EXPECT_EQ(additionalData.size(), 0); 923 } 924 925 // Test where 1 check defined: STATUS_VOUT: Fault detected 926 // STATUS_WORD captured in additional data 927 { 928 std::optional<std::string> presence{}; 929 std::optional<uint8_t> page{2}; 930 bool checkStatusVout{true}; 931 bool compareVoltageToLimit{false}; 932 std::optional<GPIO> gpio{}; 933 Rail rail{name, 934 presence, 935 page, 936 isPowerSupplyRail, 937 checkStatusVout, 938 compareVoltageToLimit, 939 gpio}; 940 941 MockDevice device{}; 942 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x10)); 943 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 944 945 MockServices services{}; 946 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 947 .Times(1); 948 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 949 .Times(1); 950 EXPECT_CALL( 951 services, 952 logErrorMsg("Rail VDD2 has fault bits set in STATUS_VOUT: 0x10")) 953 .Times(1); 954 955 std::vector<int> gpioValues{}; 956 std::map<std::string, std::string> additionalData{}; 957 EXPECT_TRUE( 958 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 959 EXPECT_EQ(additionalData.size(), 3); 960 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 961 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x10"); 962 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 963 } 964 965 // Test where 1 check defined: STATUS_VOUT: Exception thrown 966 { 967 std::optional<std::string> presence{}; 968 std::optional<uint8_t> page{2}; 969 bool checkStatusVout{true}; 970 bool compareVoltageToLimit{false}; 971 std::optional<GPIO> gpio{}; 972 Rail rail{name, 973 presence, 974 page, 975 isPowerSupplyRail, 976 checkStatusVout, 977 compareVoltageToLimit, 978 gpio}; 979 980 MockDevice device{}; 981 EXPECT_CALL(device, getStatusVout(2)) 982 .Times(1) 983 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 984 985 MockServices services{}; 986 987 std::vector<int> gpioValues{}; 988 std::map<std::string, std::string> additionalData{}; 989 try 990 { 991 rail.hasPgoodFault(device, services, gpioValues, additionalData); 992 ADD_FAILURE() << "Should not have reached this line."; 993 } 994 catch (const std::exception& e) 995 { 996 EXPECT_STREQ(e.what(), 997 "Unable to read STATUS_VOUT value for rail VDD2: " 998 "File does not exist"); 999 } 1000 } 1001 1002 // Test where 1 check defined: GPIO: No fault detected 1003 // GPIO value is 1 and GPIO is active high 1004 { 1005 std::optional<std::string> presence{}; 1006 std::optional<uint8_t> page{}; 1007 bool checkStatusVout{false}; 1008 bool compareVoltageToLimit{false}; 1009 bool activeLow{false}; 1010 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1011 Rail rail{name, 1012 presence, 1013 page, 1014 isPowerSupplyRail, 1015 checkStatusVout, 1016 compareVoltageToLimit, 1017 gpio}; 1018 1019 MockDevice device{}; 1020 1021 MockServices services{}; 1022 1023 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1}; 1024 std::map<std::string, std::string> additionalData{}; 1025 EXPECT_FALSE( 1026 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1027 EXPECT_EQ(additionalData.size(), 0); 1028 } 1029 1030 // Test where 1 check defined: GPIO: Fault detected 1031 // GPIO value is 0 and GPIO is active high 1032 // STATUS_WORD not captured since no PMBus page defined 1033 { 1034 std::optional<std::string> presence{}; 1035 std::optional<uint8_t> page{}; 1036 bool checkStatusVout{false}; 1037 bool compareVoltageToLimit{false}; 1038 bool activeLow{false}; 1039 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1040 Rail rail{name, 1041 presence, 1042 page, 1043 isPowerSupplyRail, 1044 checkStatusVout, 1045 compareVoltageToLimit, 1046 gpio}; 1047 1048 MockDevice device{}; 1049 1050 MockServices services{}; 1051 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1052 .Times(1); 1053 EXPECT_CALL( 1054 services, 1055 logErrorMsg( 1056 "Rail VDD2 pgood GPIO line offset 3 has inactive value 0")) 1057 .Times(1); 1058 1059 std::vector<int> gpioValues{1, 1, 1, 0, 1, 1}; 1060 std::map<std::string, std::string> additionalData{}; 1061 EXPECT_TRUE( 1062 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1063 EXPECT_EQ(additionalData.size(), 3); 1064 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1065 EXPECT_EQ(additionalData["GPIO_LINE"], "3"); 1066 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 1067 } 1068 1069 // Test where 1 check defined: GPIO: Exception thrown: Invalid line offset 1070 { 1071 std::optional<std::string> presence{}; 1072 std::optional<uint8_t> page{}; 1073 bool checkStatusVout{false}; 1074 bool compareVoltageToLimit{false}; 1075 bool activeLow{false}; 1076 std::optional<GPIO> gpio{GPIO(6, activeLow)}; 1077 Rail rail{name, 1078 presence, 1079 page, 1080 isPowerSupplyRail, 1081 checkStatusVout, 1082 compareVoltageToLimit, 1083 gpio}; 1084 1085 MockDevice device{}; 1086 1087 MockServices services{}; 1088 1089 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1}; 1090 std::map<std::string, std::string> additionalData{}; 1091 try 1092 { 1093 rail.hasPgoodFault(device, services, gpioValues, additionalData); 1094 ADD_FAILURE() << "Should not have reached this line."; 1095 } 1096 catch (const std::exception& e) 1097 { 1098 EXPECT_STREQ(e.what(), "Invalid GPIO line offset 6 for rail VDD2: " 1099 "Device only has 6 GPIO values"); 1100 } 1101 } 1102 1103 // Test where 1 check defined: READ_VOUT: No fault detected 1104 // Output voltage > UV limit 1105 { 1106 std::optional<std::string> presence{}; 1107 std::optional<uint8_t> page{2}; 1108 bool checkStatusVout{false}; 1109 bool compareVoltageToLimit{true}; 1110 std::optional<GPIO> gpio{}; 1111 Rail rail{name, 1112 presence, 1113 page, 1114 isPowerSupplyRail, 1115 checkStatusVout, 1116 compareVoltageToLimit, 1117 gpio}; 1118 1119 MockDevice device{}; 1120 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1121 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1122 .Times(1) 1123 .WillOnce(Return(1.0)); 1124 1125 MockServices services{}; 1126 1127 std::vector<int> gpioValues{}; 1128 std::map<std::string, std::string> additionalData{}; 1129 EXPECT_FALSE( 1130 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1131 EXPECT_EQ(additionalData.size(), 0); 1132 } 1133 1134 // Test where 1 check defined: READ_VOUT: Fault detected 1135 // Output voltage < UV limit 1136 { 1137 std::optional<std::string> presence{}; 1138 std::optional<uint8_t> page{2}; 1139 bool checkStatusVout{false}; 1140 bool compareVoltageToLimit{true}; 1141 std::optional<GPIO> gpio{}; 1142 Rail rail{name, 1143 presence, 1144 page, 1145 isPowerSupplyRail, 1146 checkStatusVout, 1147 compareVoltageToLimit, 1148 gpio}; 1149 1150 MockDevice device{}; 1151 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1152 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1153 .Times(1) 1154 .WillOnce(Return(1.2)); 1155 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 1156 1157 MockServices services{}; 1158 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 1159 .Times(1); 1160 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1161 .Times(1); 1162 EXPECT_CALL( 1163 services, 1164 logErrorMsg( 1165 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.2V")) 1166 .Times(1); 1167 1168 std::vector<int> gpioValues{}; 1169 std::map<std::string, std::string> additionalData{}; 1170 EXPECT_TRUE( 1171 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1172 EXPECT_EQ(additionalData.size(), 4); 1173 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1174 EXPECT_EQ(additionalData["READ_VOUT"], "1.1"); 1175 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2"); 1176 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 1177 } 1178 1179 // Test where 1 check defined: READ_VOUT: Exception thrown 1180 { 1181 std::optional<std::string> presence{}; 1182 std::optional<uint8_t> page{2}; 1183 bool checkStatusVout{false}; 1184 bool compareVoltageToLimit{true}; 1185 std::optional<GPIO> gpio{}; 1186 Rail rail{name, 1187 presence, 1188 page, 1189 isPowerSupplyRail, 1190 checkStatusVout, 1191 compareVoltageToLimit, 1192 gpio}; 1193 1194 MockDevice device{}; 1195 EXPECT_CALL(device, getReadVout(2)) 1196 .Times(1) 1197 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 1198 1199 MockServices services{}; 1200 1201 std::vector<int> gpioValues{}; 1202 std::map<std::string, std::string> additionalData{}; 1203 try 1204 { 1205 rail.hasPgoodFault(device, services, gpioValues, additionalData); 1206 ADD_FAILURE() << "Should not have reached this line."; 1207 } 1208 catch (const std::exception& e) 1209 { 1210 EXPECT_STREQ(e.what(), 1211 "Unable to read READ_VOUT value for rail VDD2: " 1212 "File does not exist"); 1213 } 1214 } 1215 1216 // Test where 3 checks defined: No fault detected 1217 // GPIO value is 0 and GPIO is active low 1218 { 1219 std::optional<std::string> presence{}; 1220 std::optional<uint8_t> page{2}; 1221 bool checkStatusVout{true}; 1222 bool compareVoltageToLimit{true}; 1223 bool activeLow{true}; 1224 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1225 Rail rail{name, 1226 presence, 1227 page, 1228 isPowerSupplyRail, 1229 checkStatusVout, 1230 compareVoltageToLimit, 1231 gpio}; 1232 1233 MockDevice device{}; 1234 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 1235 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1236 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1237 .Times(1) 1238 .WillOnce(Return(0.9)); 1239 1240 MockServices services{}; 1241 1242 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 1243 std::map<std::string, std::string> additionalData{}; 1244 EXPECT_FALSE( 1245 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1246 EXPECT_EQ(additionalData.size(), 0); 1247 } 1248 1249 // Test where 3 checks defined: Fault detected via STATUS_VOUT 1250 { 1251 std::optional<std::string> presence{}; 1252 std::optional<uint8_t> page{2}; 1253 bool checkStatusVout{true}; 1254 bool compareVoltageToLimit{true}; 1255 bool activeLow{true}; 1256 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1257 Rail rail{name, 1258 presence, 1259 page, 1260 isPowerSupplyRail, 1261 checkStatusVout, 1262 compareVoltageToLimit, 1263 gpio}; 1264 1265 MockDevice device{}; 1266 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x10)); 1267 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 1268 1269 MockServices services{}; 1270 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 1271 .Times(1); 1272 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1273 .Times(1); 1274 EXPECT_CALL( 1275 services, 1276 logErrorMsg("Rail VDD2 has fault bits set in STATUS_VOUT: 0x10")) 1277 .Times(1); 1278 1279 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 1280 std::map<std::string, std::string> additionalData{}; 1281 EXPECT_TRUE( 1282 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1283 EXPECT_EQ(additionalData.size(), 3); 1284 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1285 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x10"); 1286 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 1287 } 1288 1289 // Test where 3 checks defined: Fault detected via GPIO 1290 // GPIO value is 1 and GPIO is active low 1291 { 1292 std::optional<std::string> presence{}; 1293 std::optional<uint8_t> page{2}; 1294 bool checkStatusVout{true}; 1295 bool compareVoltageToLimit{true}; 1296 bool activeLow{true}; 1297 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1298 Rail rail{name, 1299 presence, 1300 page, 1301 isPowerSupplyRail, 1302 checkStatusVout, 1303 compareVoltageToLimit, 1304 gpio}; 1305 1306 MockDevice device{}; 1307 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 1308 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 1309 1310 MockServices services{}; 1311 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 1312 .Times(1); 1313 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1314 .Times(1); 1315 EXPECT_CALL( 1316 services, 1317 logErrorMsg( 1318 "Rail VDD2 pgood GPIO line offset 3 has inactive value 1")) 1319 .Times(1); 1320 1321 std::vector<int> gpioValues{0, 0, 0, 1, 0, 0}; 1322 std::map<std::string, std::string> additionalData{}; 1323 EXPECT_TRUE( 1324 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1325 EXPECT_EQ(additionalData.size(), 4); 1326 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1327 EXPECT_EQ(additionalData["GPIO_LINE"], "3"); 1328 EXPECT_EQ(additionalData["GPIO_VALUE"], "1"); 1329 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 1330 } 1331 1332 // Test where 3 checks defined: Fault detected via READ_VOUT 1333 // Output voltage == UV limit 1334 // STATUS_WORD not captured because reading it caused an exception 1335 { 1336 std::optional<std::string> presence{}; 1337 std::optional<uint8_t> page{2}; 1338 bool checkStatusVout{true}; 1339 bool compareVoltageToLimit{true}; 1340 bool activeLow{true}; 1341 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1342 Rail rail{name, 1343 presence, 1344 page, 1345 isPowerSupplyRail, 1346 checkStatusVout, 1347 compareVoltageToLimit, 1348 gpio}; 1349 1350 MockDevice device{}; 1351 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 1352 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1353 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1354 .Times(1) 1355 .WillOnce(Return(1.1)); 1356 EXPECT_CALL(device, getStatusWord(2)) 1357 .Times(1) 1358 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 1359 1360 MockServices services{}; 1361 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1362 .Times(1); 1363 EXPECT_CALL( 1364 services, 1365 logErrorMsg( 1366 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.1V")) 1367 .Times(1); 1368 1369 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 1370 std::map<std::string, std::string> additionalData{}; 1371 EXPECT_TRUE( 1372 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 1373 EXPECT_EQ(additionalData.size(), 3); 1374 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1375 EXPECT_EQ(additionalData["READ_VOUT"], "1.1"); 1376 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.1"); 1377 } 1378 } 1379