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 std::optional<std::string> presence{}; 777 std::optional<uint8_t> page{2}; 778 bool isPowerSupplyRail{false}; 779 bool checkStatusVout{true}; 780 bool compareVoltageToLimit{true}; 781 bool activeLow{true}; 782 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 783 Rail rail{name, 784 presence, 785 page, 786 isPowerSupplyRail, 787 checkStatusVout, 788 compareVoltageToLimit, 789 gpio}; 790 791 // No fault detected 792 { 793 MockDevice device{}; 794 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 795 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 796 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 797 .Times(1) 798 .WillOnce(Return(1.0)); 799 800 MockServices services{}; 801 802 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 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 // Fault detected via STATUS_VOUT 810 { 811 MockDevice device{}; 812 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x10)); 813 EXPECT_CALL(device, getReadVout(2)).Times(0); 814 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 815 816 MockServices services{}; 817 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 818 .Times(1); 819 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 820 .Times(1); 821 EXPECT_CALL( 822 services, 823 logErrorMsg("Rail VDD2 has fault bits set in STATUS_VOUT: 0x10")) 824 .Times(1); 825 826 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 827 std::map<std::string, std::string> additionalData{}; 828 EXPECT_TRUE( 829 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 830 EXPECT_EQ(additionalData.size(), 3); 831 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 832 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x10"); 833 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 834 } 835 836 // Fault detected via GPIO 837 { 838 MockDevice device{}; 839 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 840 EXPECT_CALL(device, getReadVout(2)).Times(0); 841 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 842 843 MockServices services{}; 844 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 845 .Times(1); 846 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 847 .Times(1); 848 EXPECT_CALL( 849 services, 850 logErrorMsg( 851 "Rail VDD2 pgood GPIO line offset 3 has inactive value 1")) 852 .Times(1); 853 854 std::vector<int> gpioValues{0, 0, 0, 1, 0, 0}; 855 std::map<std::string, std::string> additionalData{}; 856 EXPECT_TRUE( 857 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 858 EXPECT_EQ(additionalData.size(), 4); 859 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 860 EXPECT_EQ(additionalData["GPIO_LINE"], "3"); 861 EXPECT_EQ(additionalData["GPIO_VALUE"], "1"); 862 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 863 } 864 865 // Fault detected via output voltage 866 { 867 MockDevice device{}; 868 EXPECT_CALL(device, getStatusVout(2)).Times(1).WillOnce(Return(0x00)); 869 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 870 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 871 .Times(1) 872 .WillOnce(Return(1.1)); 873 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 874 875 MockServices services{}; 876 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 877 .Times(1); 878 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 879 .Times(1); 880 EXPECT_CALL( 881 services, 882 logErrorMsg( 883 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.1V")) 884 .Times(1); 885 886 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 887 std::map<std::string, std::string> additionalData{}; 888 EXPECT_TRUE( 889 rail.hasPgoodFault(device, services, gpioValues, additionalData)); 890 EXPECT_EQ(additionalData.size(), 4); 891 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 892 EXPECT_EQ(additionalData["READ_VOUT"], "1.1"); 893 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.1"); 894 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 895 } 896 } 897 898 TEST(RailTests, HasPgoodFaultStatusVout) 899 { 900 std::string name{"VDD2"}; 901 std::optional<uint8_t> page{3}; 902 bool isPowerSupplyRail{false}; 903 bool compareVoltageToLimit{false}; 904 std::optional<GPIO> gpio{}; 905 906 // Test where presence check defined: Rail is not present 907 { 908 std::optional<std::string> presence{ 909 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 910 bool checkStatusVout{true}; 911 Rail rail{name, 912 presence, 913 page, 914 isPowerSupplyRail, 915 checkStatusVout, 916 compareVoltageToLimit, 917 gpio}; 918 919 MockDevice device{}; 920 EXPECT_CALL(device, getStatusVout(3)).Times(0); 921 922 MockServices services{}; 923 EXPECT_CALL(services, isPresent(*presence)) 924 .Times(1) 925 .WillOnce(Return(false)); 926 927 std::map<std::string, std::string> additionalData{}; 928 EXPECT_FALSE( 929 rail.hasPgoodFaultStatusVout(device, services, additionalData)); 930 EXPECT_EQ(additionalData.size(), 0); 931 } 932 933 // Test where presence check defined: Rail is present: No fault detected 934 { 935 std::optional<std::string> presence{ 936 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 937 bool checkStatusVout{true}; 938 Rail rail{name, 939 presence, 940 page, 941 isPowerSupplyRail, 942 checkStatusVout, 943 compareVoltageToLimit, 944 gpio}; 945 946 MockDevice device{}; 947 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00)); 948 949 MockServices services{}; 950 EXPECT_CALL(services, isPresent(*presence)) 951 .Times(1) 952 .WillOnce(Return(true)); 953 954 std::map<std::string, std::string> additionalData{}; 955 EXPECT_FALSE( 956 rail.hasPgoodFaultStatusVout(device, services, additionalData)); 957 EXPECT_EQ(additionalData.size(), 0); 958 } 959 960 // Test where STATUS_VOUT check is not defined 961 { 962 std::optional<std::string> presence{}; 963 bool checkStatusVout{false}; 964 Rail rail{name, 965 presence, 966 page, 967 isPowerSupplyRail, 968 checkStatusVout, 969 compareVoltageToLimit, 970 gpio}; 971 972 MockDevice device{}; 973 EXPECT_CALL(device, getStatusVout(3)).Times(0); 974 975 MockServices services{}; 976 977 std::map<std::string, std::string> additionalData{}; 978 EXPECT_FALSE( 979 rail.hasPgoodFaultStatusVout(device, services, additionalData)); 980 EXPECT_EQ(additionalData.size(), 0); 981 } 982 983 // Test where no fault detected: No warning bits set 984 { 985 std::optional<std::string> presence{}; 986 bool checkStatusVout{true}; 987 Rail rail{name, 988 presence, 989 page, 990 isPowerSupplyRail, 991 checkStatusVout, 992 compareVoltageToLimit, 993 gpio}; 994 995 MockDevice device{}; 996 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x00)); 997 998 MockServices services{}; 999 EXPECT_CALL(services, logInfoMsg).Times(0); 1000 1001 std::map<std::string, std::string> additionalData{}; 1002 EXPECT_FALSE( 1003 rail.hasPgoodFaultStatusVout(device, services, additionalData)); 1004 EXPECT_EQ(additionalData.size(), 0); 1005 } 1006 1007 // Test where no fault detected: Warning bits set 1008 { 1009 std::optional<std::string> presence{}; 1010 bool checkStatusVout{true}; 1011 Rail rail{name, 1012 presence, 1013 page, 1014 isPowerSupplyRail, 1015 checkStatusVout, 1016 compareVoltageToLimit, 1017 gpio}; 1018 1019 MockDevice device{}; 1020 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x6a)); 1021 1022 MockServices services{}; 1023 EXPECT_CALL( 1024 services, 1025 logInfoMsg("Rail VDD2 has warning bits set in STATUS_VOUT: 0x6a")) 1026 .Times(1); 1027 1028 std::map<std::string, std::string> additionalData{}; 1029 EXPECT_FALSE( 1030 rail.hasPgoodFaultStatusVout(device, services, additionalData)); 1031 EXPECT_EQ(additionalData.size(), 0); 1032 } 1033 1034 // Test where fault detected 1035 // STATUS_WORD captured in additional data 1036 { 1037 std::optional<std::string> presence{}; 1038 bool checkStatusVout{true}; 1039 Rail rail{name, 1040 presence, 1041 page, 1042 isPowerSupplyRail, 1043 checkStatusVout, 1044 compareVoltageToLimit, 1045 gpio}; 1046 1047 MockDevice device{}; 1048 EXPECT_CALL(device, getStatusVout(3)).Times(1).WillOnce(Return(0x10)); 1049 EXPECT_CALL(device, getStatusWord(3)).Times(1).WillOnce(Return(0xbeef)); 1050 1051 MockServices services{}; 1052 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 1053 .Times(1); 1054 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1055 .Times(1); 1056 EXPECT_CALL( 1057 services, 1058 logErrorMsg("Rail VDD2 has fault bits set in STATUS_VOUT: 0x10")) 1059 .Times(1); 1060 1061 std::map<std::string, std::string> additionalData{}; 1062 EXPECT_TRUE( 1063 rail.hasPgoodFaultStatusVout(device, services, additionalData)); 1064 EXPECT_EQ(additionalData.size(), 3); 1065 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1066 EXPECT_EQ(additionalData["STATUS_VOUT"], "0x10"); 1067 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 1068 } 1069 1070 // Test where exception thrown 1071 { 1072 std::optional<std::string> presence{}; 1073 bool checkStatusVout{true}; 1074 Rail rail{name, 1075 presence, 1076 page, 1077 isPowerSupplyRail, 1078 checkStatusVout, 1079 compareVoltageToLimit, 1080 gpio}; 1081 1082 MockDevice device{}; 1083 EXPECT_CALL(device, getStatusVout(3)) 1084 .Times(1) 1085 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 1086 1087 MockServices services{}; 1088 1089 std::map<std::string, std::string> additionalData{}; 1090 try 1091 { 1092 rail.hasPgoodFaultStatusVout(device, services, additionalData); 1093 ADD_FAILURE() << "Should not have reached this line."; 1094 } 1095 catch (const std::exception& e) 1096 { 1097 EXPECT_STREQ(e.what(), 1098 "Unable to read STATUS_VOUT value for rail VDD2: " 1099 "File does not exist"); 1100 } 1101 } 1102 } 1103 1104 TEST(RailTests, HasPgoodFaultGPIO) 1105 { 1106 std::string name{"VDD2"}; 1107 bool isPowerSupplyRail{false}; 1108 bool checkStatusVout{false}; 1109 bool compareVoltageToLimit{false}; 1110 1111 // Test where presence check defined: Rail is not present 1112 { 1113 std::optional<std::string> presence{ 1114 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 1115 std::optional<uint8_t> page{3}; 1116 bool activeLow{false}; 1117 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1118 Rail rail{name, 1119 presence, 1120 page, 1121 isPowerSupplyRail, 1122 checkStatusVout, 1123 compareVoltageToLimit, 1124 gpio}; 1125 1126 MockDevice device{}; 1127 1128 MockServices services{}; 1129 EXPECT_CALL(services, isPresent(*presence)) 1130 .Times(1) 1131 .WillOnce(Return(false)); 1132 1133 std::vector<int> gpioValues{1, 1, 1, 0, 1, 1}; 1134 std::map<std::string, std::string> additionalData{}; 1135 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues, 1136 additionalData)); 1137 EXPECT_EQ(additionalData.size(), 0); 1138 } 1139 1140 // Test where presence check defined: Rail is present: No fault detected 1141 { 1142 std::optional<std::string> presence{ 1143 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 1144 std::optional<uint8_t> page{3}; 1145 bool activeLow{false}; 1146 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1147 Rail rail{name, 1148 presence, 1149 page, 1150 isPowerSupplyRail, 1151 checkStatusVout, 1152 compareVoltageToLimit, 1153 gpio}; 1154 1155 MockDevice device{}; 1156 1157 MockServices services{}; 1158 EXPECT_CALL(services, isPresent(*presence)) 1159 .Times(1) 1160 .WillOnce(Return(true)); 1161 1162 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1}; 1163 std::map<std::string, std::string> additionalData{}; 1164 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues, 1165 additionalData)); 1166 EXPECT_EQ(additionalData.size(), 0); 1167 } 1168 1169 // Test where GPIO check not defined 1170 { 1171 std::optional<std::string> presence{}; 1172 std::optional<uint8_t> page{3}; 1173 std::optional<GPIO> gpio{}; 1174 Rail rail{name, 1175 presence, 1176 page, 1177 isPowerSupplyRail, 1178 checkStatusVout, 1179 compareVoltageToLimit, 1180 gpio}; 1181 1182 MockDevice device{}; 1183 1184 MockServices services{}; 1185 1186 std::vector<int> gpioValues{0, 0, 0, 0, 0, 0}; 1187 std::map<std::string, std::string> additionalData{}; 1188 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues, 1189 additionalData)); 1190 EXPECT_EQ(additionalData.size(), 0); 1191 } 1192 1193 // Test where no fault detected 1194 // GPIO value is 1 and GPIO is active high 1195 { 1196 std::optional<std::string> presence{}; 1197 std::optional<uint8_t> page{}; 1198 bool activeLow{false}; 1199 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1200 Rail rail{name, 1201 presence, 1202 page, 1203 isPowerSupplyRail, 1204 checkStatusVout, 1205 compareVoltageToLimit, 1206 gpio}; 1207 1208 MockDevice device{}; 1209 1210 MockServices services{}; 1211 1212 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1}; 1213 std::map<std::string, std::string> additionalData{}; 1214 EXPECT_FALSE(rail.hasPgoodFaultGPIO(device, services, gpioValues, 1215 additionalData)); 1216 EXPECT_EQ(additionalData.size(), 0); 1217 } 1218 1219 // Test where fault detected 1220 // GPIO value is 0 and GPIO is active high 1221 // STATUS_WORD not captured since no PMBus page defined 1222 { 1223 std::optional<std::string> presence{}; 1224 std::optional<uint8_t> page{}; 1225 bool activeLow{false}; 1226 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1227 Rail rail{name, 1228 presence, 1229 page, 1230 isPowerSupplyRail, 1231 checkStatusVout, 1232 compareVoltageToLimit, 1233 gpio}; 1234 1235 MockDevice device{}; 1236 1237 MockServices services{}; 1238 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1239 .Times(1); 1240 EXPECT_CALL( 1241 services, 1242 logErrorMsg( 1243 "Rail VDD2 pgood GPIO line offset 3 has inactive value 0")) 1244 .Times(1); 1245 1246 std::vector<int> gpioValues{1, 1, 1, 0, 1, 1}; 1247 std::map<std::string, std::string> additionalData{}; 1248 EXPECT_TRUE(rail.hasPgoodFaultGPIO(device, services, gpioValues, 1249 additionalData)); 1250 EXPECT_EQ(additionalData.size(), 3); 1251 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1252 EXPECT_EQ(additionalData["GPIO_LINE"], "3"); 1253 EXPECT_EQ(additionalData["GPIO_VALUE"], "0"); 1254 } 1255 1256 // Test where fault detected 1257 // GPIO value is 1 and GPIO is active low 1258 { 1259 std::optional<std::string> presence{}; 1260 std::optional<uint8_t> page{2}; 1261 bool activeLow{true}; 1262 std::optional<GPIO> gpio{GPIO(3, activeLow)}; 1263 Rail rail{name, 1264 presence, 1265 page, 1266 isPowerSupplyRail, 1267 checkStatusVout, 1268 compareVoltageToLimit, 1269 gpio}; 1270 1271 MockDevice device{}; 1272 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 1273 1274 MockServices services{}; 1275 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 1276 .Times(1); 1277 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1278 .Times(1); 1279 EXPECT_CALL( 1280 services, 1281 logErrorMsg( 1282 "Rail VDD2 pgood GPIO line offset 3 has inactive value 1")) 1283 .Times(1); 1284 1285 std::vector<int> gpioValues{0, 0, 0, 1, 0, 0}; 1286 std::map<std::string, std::string> additionalData{}; 1287 EXPECT_TRUE(rail.hasPgoodFaultGPIO(device, services, gpioValues, 1288 additionalData)); 1289 EXPECT_EQ(additionalData.size(), 4); 1290 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1291 EXPECT_EQ(additionalData["GPIO_LINE"], "3"); 1292 EXPECT_EQ(additionalData["GPIO_VALUE"], "1"); 1293 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 1294 } 1295 1296 // Test where exception thrown 1297 { 1298 std::optional<std::string> presence{}; 1299 std::optional<uint8_t> page{}; 1300 bool activeLow{false}; 1301 std::optional<GPIO> gpio{GPIO(6, activeLow)}; 1302 Rail rail{name, 1303 presence, 1304 page, 1305 isPowerSupplyRail, 1306 checkStatusVout, 1307 compareVoltageToLimit, 1308 gpio}; 1309 1310 MockDevice device{}; 1311 1312 MockServices services{}; 1313 1314 std::vector<int> gpioValues{1, 1, 1, 1, 1, 1}; 1315 std::map<std::string, std::string> additionalData{}; 1316 try 1317 { 1318 rail.hasPgoodFaultGPIO(device, services, gpioValues, 1319 additionalData); 1320 ADD_FAILURE() << "Should not have reached this line."; 1321 } 1322 catch (const std::exception& e) 1323 { 1324 EXPECT_STREQ(e.what(), "Invalid GPIO line offset 6 for rail VDD2: " 1325 "Device only has 6 GPIO values"); 1326 } 1327 } 1328 } 1329 1330 TEST(RailTests, HasPgoodFaultOutputVoltage) 1331 { 1332 std::string name{"VDD2"}; 1333 std::optional<uint8_t> page{2}; 1334 bool isPowerSupplyRail{false}; 1335 bool checkStatusVout{false}; 1336 std::optional<GPIO> gpio{}; 1337 1338 // Test where presence check defined: Rail is not present 1339 { 1340 std::optional<std::string> presence{ 1341 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 1342 bool compareVoltageToLimit{true}; 1343 Rail rail{name, 1344 presence, 1345 page, 1346 isPowerSupplyRail, 1347 checkStatusVout, 1348 compareVoltageToLimit, 1349 gpio}; 1350 1351 MockDevice device{}; 1352 EXPECT_CALL(device, getReadVout(2)).Times(0); 1353 EXPECT_CALL(device, getVoutUVFaultLimit(2)).Times(0); 1354 1355 MockServices services{}; 1356 EXPECT_CALL(services, isPresent(*presence)) 1357 .Times(1) 1358 .WillOnce(Return(false)); 1359 1360 std::map<std::string, std::string> additionalData{}; 1361 EXPECT_FALSE( 1362 rail.hasPgoodFaultOutputVoltage(device, services, additionalData)); 1363 EXPECT_EQ(additionalData.size(), 0); 1364 } 1365 1366 // Test where presence check defined: Rail is present: No fault detected 1367 { 1368 std::optional<std::string> presence{ 1369 "/xyz/openbmc_project/inventory/system/chassis/motherboard/cpu2"}; 1370 bool compareVoltageToLimit{true}; 1371 Rail rail{name, 1372 presence, 1373 page, 1374 isPowerSupplyRail, 1375 checkStatusVout, 1376 compareVoltageToLimit, 1377 gpio}; 1378 1379 MockDevice device{}; 1380 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1381 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1382 .Times(1) 1383 .WillOnce(Return(1.0)); 1384 1385 MockServices services{}; 1386 EXPECT_CALL(services, isPresent(*presence)) 1387 .Times(1) 1388 .WillOnce(Return(true)); 1389 1390 std::map<std::string, std::string> additionalData{}; 1391 EXPECT_FALSE( 1392 rail.hasPgoodFaultOutputVoltage(device, services, additionalData)); 1393 EXPECT_EQ(additionalData.size(), 0); 1394 } 1395 1396 // Test where voltage output check not specified 1397 { 1398 std::optional<std::string> presence{}; 1399 bool compareVoltageToLimit{false}; 1400 Rail rail{name, 1401 presence, 1402 page, 1403 isPowerSupplyRail, 1404 checkStatusVout, 1405 compareVoltageToLimit, 1406 gpio}; 1407 1408 MockDevice device{}; 1409 EXPECT_CALL(device, getReadVout(2)).Times(0); 1410 EXPECT_CALL(device, getVoutUVFaultLimit(2)).Times(0); 1411 1412 MockServices services{}; 1413 1414 std::map<std::string, std::string> additionalData{}; 1415 EXPECT_FALSE( 1416 rail.hasPgoodFaultOutputVoltage(device, services, additionalData)); 1417 EXPECT_EQ(additionalData.size(), 0); 1418 } 1419 1420 // Test where no fault detected: Output voltage > UV limit 1421 { 1422 std::optional<std::string> presence{}; 1423 bool compareVoltageToLimit{true}; 1424 Rail rail{name, 1425 presence, 1426 page, 1427 isPowerSupplyRail, 1428 checkStatusVout, 1429 compareVoltageToLimit, 1430 gpio}; 1431 1432 MockDevice device{}; 1433 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1434 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1435 .Times(1) 1436 .WillOnce(Return(1.0)); 1437 1438 MockServices services{}; 1439 1440 std::map<std::string, std::string> additionalData{}; 1441 EXPECT_FALSE( 1442 rail.hasPgoodFaultOutputVoltage(device, services, additionalData)); 1443 EXPECT_EQ(additionalData.size(), 0); 1444 } 1445 1446 // Test where fault detected: Output voltage < UV limit 1447 { 1448 std::optional<std::string> presence{}; 1449 bool compareVoltageToLimit{true}; 1450 Rail rail{name, 1451 presence, 1452 page, 1453 isPowerSupplyRail, 1454 checkStatusVout, 1455 compareVoltageToLimit, 1456 gpio}; 1457 1458 MockDevice device{}; 1459 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1460 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1461 .Times(1) 1462 .WillOnce(Return(1.2)); 1463 EXPECT_CALL(device, getStatusWord(2)).Times(1).WillOnce(Return(0xbeef)); 1464 1465 MockServices services{}; 1466 EXPECT_CALL(services, logInfoMsg("Rail VDD2 STATUS_WORD: 0xbeef")) 1467 .Times(1); 1468 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1469 .Times(1); 1470 EXPECT_CALL( 1471 services, 1472 logErrorMsg( 1473 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.2V")) 1474 .Times(1); 1475 1476 std::map<std::string, std::string> additionalData{}; 1477 EXPECT_TRUE( 1478 rail.hasPgoodFaultOutputVoltage(device, services, additionalData)); 1479 EXPECT_EQ(additionalData.size(), 4); 1480 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1481 EXPECT_EQ(additionalData["READ_VOUT"], "1.1"); 1482 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.2"); 1483 EXPECT_EQ(additionalData["STATUS_WORD"], "0xbeef"); 1484 } 1485 1486 // Test where fault detected: Output voltage == UV limit 1487 // STATUS_WORD not captured because reading it caused an exception 1488 { 1489 std::optional<std::string> presence{}; 1490 bool compareVoltageToLimit{true}; 1491 Rail rail{name, 1492 presence, 1493 page, 1494 isPowerSupplyRail, 1495 checkStatusVout, 1496 compareVoltageToLimit, 1497 gpio}; 1498 1499 MockDevice device{}; 1500 EXPECT_CALL(device, getReadVout(2)).Times(1).WillOnce(Return(1.1)); 1501 EXPECT_CALL(device, getVoutUVFaultLimit(2)) 1502 .Times(1) 1503 .WillOnce(Return(1.1)); 1504 EXPECT_CALL(device, getStatusWord(2)) 1505 .Times(1) 1506 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 1507 1508 MockServices services{}; 1509 EXPECT_CALL(services, logErrorMsg("Pgood fault detected in rail VDD2")) 1510 .Times(1); 1511 EXPECT_CALL( 1512 services, 1513 logErrorMsg( 1514 "Rail VDD2 output voltage 1.1V is <= UV fault limit 1.1V")) 1515 .Times(1); 1516 1517 std::map<std::string, std::string> additionalData{}; 1518 EXPECT_TRUE( 1519 rail.hasPgoodFaultOutputVoltage(device, services, additionalData)); 1520 EXPECT_EQ(additionalData.size(), 3); 1521 EXPECT_EQ(additionalData["RAIL_NAME"], "VDD2"); 1522 EXPECT_EQ(additionalData["READ_VOUT"], "1.1"); 1523 EXPECT_EQ(additionalData["VOUT_UV_FAULT_LIMIT"], "1.1"); 1524 } 1525 1526 // Test where exception thrown 1527 { 1528 std::optional<std::string> presence{}; 1529 bool compareVoltageToLimit{true}; 1530 Rail rail{name, 1531 presence, 1532 page, 1533 isPowerSupplyRail, 1534 checkStatusVout, 1535 compareVoltageToLimit, 1536 gpio}; 1537 1538 MockDevice device{}; 1539 EXPECT_CALL(device, getReadVout(2)) 1540 .Times(1) 1541 .WillOnce(Throw(std::runtime_error{"File does not exist"})); 1542 1543 MockServices services{}; 1544 1545 std::map<std::string, std::string> additionalData{}; 1546 try 1547 { 1548 rail.hasPgoodFaultOutputVoltage(device, services, additionalData); 1549 ADD_FAILURE() << "Should not have reached this line."; 1550 } 1551 catch (const std::exception& e) 1552 { 1553 EXPECT_STREQ(e.what(), 1554 "Unable to read READ_VOUT value for rail VDD2: " 1555 "File does not exist"); 1556 } 1557 } 1558 } 1559