1 #include "../power_supply.hpp" 2 #include "mock.hpp" 3 4 #include <xyz/openbmc_project/Common/Device/error.hpp> 5 #include <xyz/openbmc_project/Common/error.hpp> 6 7 #include <gmock/gmock.h> 8 #include <gtest/gtest.h> 9 10 using namespace phosphor::power::psu; 11 using namespace phosphor::pmbus; 12 13 using ::testing::_; 14 using ::testing::Args; 15 using ::testing::Assign; 16 using ::testing::DoAll; 17 using ::testing::ElementsAre; 18 using ::testing::NotNull; 19 using ::testing::Return; 20 using ::testing::StrEq; 21 22 static auto PSUInventoryPath = "/xyz/bmc/inv/sys/chassis/board/powersupply0"; 23 static auto PSUGPIOLineName = "presence-ps0"; 24 25 // Helper function to setup expectations for various STATUS_* commands 26 void setPMBusExpectations(MockedPMBus& mockPMBus, uint16_t statusWordValue, 27 uint8_t statusInputValue = 0, 28 uint8_t statusMFRValue = 0, 29 uint8_t statusCMLValue = 0, 30 uint8_t statusVOUTValue = 0) 31 { 32 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 33 .Times(1) 34 .WillOnce(Return(statusWordValue)); 35 36 if (statusWordValue != 0) 37 { 38 // If fault bits are on in STATUS_WORD, there will also be a read of 39 // STATUS_INPUT, STATUS_MFR, and STATUS_CML. 40 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 41 .Times(1) 42 .WillOnce(Return(statusInputValue)); 43 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)) 44 .Times(1) 45 .WillOnce(Return(statusMFRValue)); 46 EXPECT_CALL(mockPMBus, read(STATUS_CML, _)) 47 .Times(1) 48 .WillOnce(Return(statusCMLValue)); 49 // Page will need to be set to 0 to read STATUS_VOUT. 50 EXPECT_CALL(mockPMBus, insertPageNum(STATUS_VOUT, 0)) 51 .Times(1) 52 .WillOnce(Return("status0_vout")); 53 EXPECT_CALL(mockPMBus, read("status0_vout", _)) 54 .Times(1) 55 .WillOnce(Return(statusVOUTValue)); 56 } 57 } 58 59 class PowerSupplyTests : public ::testing::Test 60 { 61 public: 62 PowerSupplyTests() : 63 mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils())) 64 { 65 ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false)); 66 } 67 68 ~PowerSupplyTests() override 69 { 70 freeUtils(); 71 } 72 73 const MockedUtil& mockedUtil; 74 }; 75 76 TEST_F(PowerSupplyTests, Constructor) 77 { 78 /** 79 * @param[in] invpath - String for inventory path to use 80 * @param[in] i2cbus - The bus number this power supply is on 81 * @param[in] i2caddr - The 16-bit I2C address of the power supply 82 * @param[in] gpioLineName - The string for the gpio-line-name to read for 83 * presence. 84 * @param[in] bindDelay - Time in milliseconds to delay binding the device 85 * driver after seeing the presence line go active. 86 */ 87 auto bus = sdbusplus::bus::new_default(); 88 89 // Try where inventory path is empty, constructor should fail. 90 try 91 { 92 auto psu = 93 std::make_unique<PowerSupply>(bus, "", 3, 0x68, PSUGPIOLineName); 94 ADD_FAILURE() << "Should not have reached this line."; 95 } 96 catch (const std::invalid_argument& e) 97 { 98 EXPECT_STREQ(e.what(), "Invalid empty inventoryPath"); 99 } 100 catch (...) 101 { 102 ADD_FAILURE() << "Should not have caught exception."; 103 } 104 105 // TODO: Try invalid i2c address? 106 107 // Try where gpioLineName is empty. 108 try 109 { 110 auto psu = 111 std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68, ""); 112 ADD_FAILURE() 113 << "Should not have reached this line. Invalid gpioLineName."; 114 } 115 catch (const std::invalid_argument& e) 116 { 117 EXPECT_STREQ(e.what(), "Invalid empty gpioLineName"); 118 } 119 catch (...) 120 { 121 ADD_FAILURE() << "Should not have caught exception."; 122 } 123 124 // Test with valid arguments 125 // NOT using D-Bus inventory path for presence. 126 try 127 { 128 auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68, 129 PSUGPIOLineName); 130 131 EXPECT_EQ(psu->isPresent(), false); 132 EXPECT_EQ(psu->isFaulted(), false); 133 EXPECT_EQ(psu->hasCommFault(), false); 134 EXPECT_EQ(psu->hasInputFault(), false); 135 EXPECT_EQ(psu->hasMFRFault(), false); 136 EXPECT_EQ(psu->hasVINUVFault(), false); 137 EXPECT_EQ(psu->hasVoutOVFault(), false); 138 } 139 catch (...) 140 { 141 ADD_FAILURE() << "Should not have caught exception."; 142 } 143 144 // Test with valid arguments 145 // TODO: Using D-Bus inventory path for presence. 146 try 147 { 148 // FIXME: How do I get that presenceGPIO.read() in the startup to throw 149 // an exception? 150 151 // EXPECT_CALL(mockedUtil, getPresence(_, 152 // StrEq(PSUInventoryPath))) 153 // .Times(1); 154 } 155 catch (...) 156 { 157 ADD_FAILURE() << "Should not have caught exception."; 158 } 159 } 160 161 TEST_F(PowerSupplyTests, Analyze) 162 { 163 auto bus = sdbusplus::bus::new_default(); 164 165 // If I default to reading the GPIO, I will NOT expect a call to 166 // getPresence(). 167 168 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName}; 169 MockedGPIOInterface* mockPresenceGPIO = 170 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 171 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(0)); 172 173 psu.analyze(); 174 // By default, nothing should change. 175 EXPECT_EQ(psu.isPresent(), false); 176 EXPECT_EQ(psu.isFaulted(), false); 177 EXPECT_EQ(psu.hasInputFault(), false); 178 EXPECT_EQ(psu.hasMFRFault(), false); 179 EXPECT_EQ(psu.hasVINUVFault(), false); 180 EXPECT_EQ(psu.hasCommFault(), false); 181 EXPECT_EQ(psu.hasVoutOVFault(), false); 182 183 PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName}; 184 // In order to get the various faults tested, the power supply needs to 185 // be present in order to read from the PMBus device(s). 186 MockedGPIOInterface* mockPresenceGPIO2 = 187 static_cast<MockedGPIOInterface*>(psu2.getPresenceGPIO()); 188 ON_CALL(*mockPresenceGPIO2, read()).WillByDefault(Return(1)); 189 190 EXPECT_EQ(psu2.isPresent(), false); 191 192 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus()); 193 // Presence change from missing to present will trigger write to 194 // ON_OFF_CONFIG. 195 EXPECT_CALL(mockPMBus, writeBinary(ON_OFF_CONFIG, _, _)); 196 // Presence change from missing to present will trigger in1_input read in 197 // an attempt to get CLEAR_FAULTS called. 198 EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000)); 199 // STATUS_WORD 0x0000 is powered on, no faults. 200 uint16_t statusWordValue = 0; 201 uint8_t statusInputValue = 0; 202 setPMBusExpectations(mockPMBus, statusWordValue); 203 psu2.analyze(); 204 EXPECT_EQ(psu2.isPresent(), true); 205 EXPECT_EQ(psu2.isFaulted(), false); 206 EXPECT_EQ(psu2.hasInputFault(), false); 207 EXPECT_EQ(psu2.hasMFRFault(), false); 208 EXPECT_EQ(psu2.hasVINUVFault(), false); 209 EXPECT_EQ(psu2.hasCommFault(), false); 210 EXPECT_EQ(psu2.hasVoutOVFault(), false); 211 212 // STATUS_WORD input fault/warn 213 statusWordValue = (status_word::INPUT_FAULT_WARN); 214 // STATUS_INPUT fault bits ... on. 215 statusInputValue = 0x38; 216 // STATUS_MFR, STATUS_CML, and STATUS_VOUT don't care 217 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue); 218 psu2.analyze(); 219 EXPECT_EQ(psu2.isPresent(), true); 220 EXPECT_EQ(psu2.isFaulted(), true); 221 EXPECT_EQ(psu2.hasInputFault(), true); 222 EXPECT_EQ(psu2.hasMFRFault(), false); 223 EXPECT_EQ(psu2.hasVINUVFault(), false); 224 EXPECT_EQ(psu2.hasCommFault(), false); 225 EXPECT_EQ(psu2.hasVoutOVFault(), false); 226 227 // STATUS_WORD INPUT/UV fault. 228 // First need it to return good status, then the fault 229 statusWordValue = 0; 230 setPMBusExpectations(mockPMBus, statusWordValue); 231 psu2.analyze(); 232 // Now set fault bits in STATUS_WORD 233 statusWordValue = 234 (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT); 235 // STATUS_INPUT fault bits ... on. 236 statusInputValue = 0x38; 237 // STATUS_MFR, STATUS_CML, and STATUS_VOUT don't care 238 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue); 239 psu2.analyze(); 240 EXPECT_EQ(psu2.isPresent(), true); 241 EXPECT_EQ(psu2.isFaulted(), true); 242 EXPECT_EQ(psu2.hasInputFault(), true); 243 EXPECT_EQ(psu2.hasMFRFault(), false); 244 EXPECT_EQ(psu2.hasVINUVFault(), true); 245 EXPECT_EQ(psu2.hasCommFault(), false); 246 EXPECT_EQ(psu2.hasVoutOVFault(), false); 247 248 // STATUS_WORD MFR fault. 249 // First need it to return good status, then the fault 250 statusWordValue = 0; 251 setPMBusExpectations(mockPMBus, statusWordValue); 252 psu2.analyze(); 253 // Now STATUS_WORD with MFR fault bit on. 254 statusWordValue = (status_word::MFR_SPECIFIC_FAULT); 255 // STATUS_INPUT fault bits ... don't care. 256 statusInputValue = 0; 257 // STATUS_MFR bits on. 258 uint8_t statusMFRValue = 0xFF; 259 // STATUS_CML and STATUS_VOUT don't care 260 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 261 statusMFRValue); 262 psu2.analyze(); 263 EXPECT_EQ(psu2.isPresent(), true); 264 EXPECT_EQ(psu2.isFaulted(), true); 265 EXPECT_EQ(psu2.hasInputFault(), false); 266 EXPECT_EQ(psu2.hasMFRFault(), true); 267 EXPECT_EQ(psu2.hasVINUVFault(), false); 268 EXPECT_EQ(psu2.hasCommFault(), false); 269 EXPECT_EQ(psu2.hasVoutOVFault(), false); 270 271 // Ignore Temperature fault. 272 // First STATUS_WORD with no bits set, then with temperature fault. 273 statusWordValue = 0; 274 setPMBusExpectations(mockPMBus, statusWordValue); 275 psu2.analyze(); 276 // STATUS_WORD with temperature fault bit on. 277 statusWordValue = (status_word::TEMPERATURE_FAULT_WARN); 278 // STATUS_INPUT, STATUS_MFR, STATUS_CML, and STATUS_VOUT fault bits ... 279 // don't care. 280 setPMBusExpectations(mockPMBus, statusWordValue); 281 psu2.analyze(); 282 EXPECT_EQ(psu2.isPresent(), true); 283 EXPECT_EQ(psu2.isFaulted(), false); 284 EXPECT_EQ(psu2.hasInputFault(), false); 285 EXPECT_EQ(psu2.hasMFRFault(), false); 286 EXPECT_EQ(psu2.hasVINUVFault(), false); 287 EXPECT_EQ(psu2.hasCommFault(), false); 288 EXPECT_EQ(psu2.hasVoutOVFault(), false); 289 290 // CML fault 291 // First STATUS_WORD wit no bits set, then with CML fault. 292 statusWordValue = 0; 293 setPMBusExpectations(mockPMBus, statusWordValue); 294 psu2.analyze(); 295 // STATUS_WORD with CML fault bit on. 296 statusWordValue = (status_word::CML_FAULT); 297 // STATUS_INPUT fault bits ... don't care. 298 statusInputValue = 0; 299 // STATUS_MFR don't care 300 statusMFRValue = 0; 301 // Turn on STATUS_CML fault bit(s) 302 uint8_t statusCMLValue = 0xFF; 303 // STATUS_VOUT don't care 304 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 305 statusMFRValue, statusCMLValue); 306 psu2.analyze(); 307 EXPECT_EQ(psu2.isPresent(), true); 308 EXPECT_EQ(psu2.isFaulted(), true); 309 EXPECT_EQ(psu2.hasInputFault(), false); 310 EXPECT_EQ(psu2.hasMFRFault(), false); 311 EXPECT_EQ(psu2.hasVINUVFault(), false); 312 EXPECT_EQ(psu2.hasCommFault(), true); 313 EXPECT_EQ(psu2.hasVoutOVFault(), false); 314 315 // VOUT_OV_FAULT fault 316 // First STATUS_WORD with no bits set, then with VOUT/VOUT_OV fault. 317 statusWordValue = 0; 318 setPMBusExpectations(mockPMBus, statusWordValue); 319 psu2.analyze(); 320 // STATUS_WORD with VOUT/VOUT_OV fault. 321 statusWordValue = 322 ((status_word::VOUT_FAULT) | (status_word::VOUT_OV_FAULT)); 323 // STATUS_INPUT fault bits ... don't care. 324 statusInputValue = 0; 325 // STATUS_MFR don't care 326 statusMFRValue = 0; 327 // STATUS_CML don't care 328 statusCMLValue = 0; 329 // Turn on STATUS_VOUT fault bit(s) 330 uint8_t statusVOUTValue = 0xA0; 331 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 332 statusMFRValue, statusCMLValue, statusVOUTValue); 333 psu2.analyze(); 334 EXPECT_EQ(psu2.isPresent(), true); 335 EXPECT_EQ(psu2.isFaulted(), true); 336 EXPECT_EQ(psu2.hasInputFault(), false); 337 EXPECT_EQ(psu2.hasMFRFault(), false); 338 EXPECT_EQ(psu2.hasVINUVFault(), false); 339 EXPECT_EQ(psu2.hasCommFault(), false); 340 EXPECT_EQ(psu2.hasVoutOVFault(), true); 341 342 // Ignore fan fault 343 // First STATUS_WORD with no bits set, then with fan 344 // fault. 345 statusWordValue = 0; 346 setPMBusExpectations(mockPMBus, statusWordValue); 347 psu2.analyze(); 348 statusWordValue = (status_word::FAN_FAULT); 349 // STATUS_INPUT, STATUS_MFR, STATUS_CML, STATUS_VOUT: Don't care if 350 // bits set or not. 351 setPMBusExpectations(mockPMBus, statusWordValue); 352 psu2.analyze(); 353 EXPECT_EQ(psu2.isPresent(), true); 354 EXPECT_EQ(psu2.isFaulted(), false); 355 EXPECT_EQ(psu2.hasInputFault(), false); 356 EXPECT_EQ(psu2.hasMFRFault(), false); 357 EXPECT_EQ(psu2.hasVINUVFault(), false); 358 EXPECT_EQ(psu2.hasCommFault(), false); 359 EXPECT_EQ(psu2.hasVoutOVFault(), false); 360 361 // TODO: ReadFailure 362 } 363 364 TEST_F(PowerSupplyTests, OnOffConfig) 365 { 366 auto bus = sdbusplus::bus::new_default(); 367 uint8_t data = 0x15; 368 369 // Test where PSU is NOT present 370 try 371 { 372 // Assume GPIO presence, not inventory presence? 373 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName}; 374 375 MockedGPIOInterface* mockPresenceGPIO = 376 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 377 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(0)); 378 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 379 // Constructor should set initial presence, default read returns 0. 380 // If it is not present, I should not be trying to write to it. 381 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0); 382 psu.onOffConfig(data); 383 } 384 catch (...) 385 {} 386 387 // Test where PSU is present 388 try 389 { 390 // Assume GPIO presence, not inventory presence? 391 PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName}; 392 MockedGPIOInterface* mockPresenceGPIO = 393 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 394 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1)); 395 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 396 // TODO: expect setPresence call? 397 // updatePresence() private function reads gpio, called by analyze(). 398 psu.analyze(); 399 // TODO: ???should I check the filename? 400 EXPECT_CALL(mockPMBus, 401 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug)) 402 .Times(1); 403 psu.onOffConfig(data); 404 } 405 catch (...) 406 {} 407 } 408 409 TEST_F(PowerSupplyTests, ClearFaults) 410 { 411 auto bus = sdbusplus::bus::new_default(); 412 PowerSupply psu{bus, PSUInventoryPath, 13, 0x68, PSUGPIOLineName}; 413 MockedGPIOInterface* mockPresenceGPIO = 414 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 415 // GPIO read return 1 to indicate present. 416 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1)); 417 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 418 // Presence change from missing to present will trigger in1_input read in 419 // an attempt to get CLEAR_FAULTS called. 420 EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000)); 421 // STATUS_WORD 0x0000 is powered on, no faults. 422 uint16_t statusWordValue = 0; 423 setPMBusExpectations(mockPMBus, statusWordValue); 424 psu.analyze(); 425 EXPECT_EQ(psu.isPresent(), true); 426 EXPECT_EQ(psu.isFaulted(), false); 427 EXPECT_EQ(psu.hasInputFault(), false); 428 EXPECT_EQ(psu.hasMFRFault(), false); 429 EXPECT_EQ(psu.hasVINUVFault(), false); 430 EXPECT_EQ(psu.hasCommFault(), false); 431 EXPECT_EQ(psu.hasVoutOVFault(), false); 432 // STATUS_WORD with fault bits galore! 433 statusWordValue = 0xFFFF; 434 // STATUS_INPUT with fault bits on. 435 uint8_t statusInputValue = 0xFF; 436 // STATUS_MFR_SPEFIC with bits on. 437 uint8_t statusMFRValue = 0xFF; 438 // STATUS_CML with bits on. 439 uint8_t statusCMLValue = 0xFF; 440 // STATUS_VOUT with bits on. 441 uint8_t statusVOUTValue = 0xFF; 442 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 443 statusMFRValue, statusCMLValue, statusVOUTValue); 444 psu.analyze(); 445 EXPECT_EQ(psu.isPresent(), true); 446 EXPECT_EQ(psu.isFaulted(), true); 447 EXPECT_EQ(psu.hasInputFault(), true); 448 EXPECT_EQ(psu.hasMFRFault(), true); 449 EXPECT_EQ(psu.hasVINUVFault(), true); 450 EXPECT_EQ(psu.hasCommFault(), true); 451 EXPECT_EQ(psu.hasVoutOVFault(), true); 452 EXPECT_CALL(mockPMBus, read("in1_input", _)) 453 .Times(1) 454 .WillOnce(Return(209000)); 455 psu.clearFaults(); 456 EXPECT_EQ(psu.isPresent(), true); 457 EXPECT_EQ(psu.isFaulted(), false); 458 EXPECT_EQ(psu.hasInputFault(), false); 459 EXPECT_EQ(psu.hasMFRFault(), false); 460 EXPECT_EQ(psu.hasVINUVFault(), false); 461 EXPECT_EQ(psu.hasCommFault(), false); 462 EXPECT_EQ(psu.hasVoutOVFault(), false); 463 464 // TODO: Faults clear on missing/present? 465 } 466 467 TEST_F(PowerSupplyTests, UpdateInventory) 468 { 469 auto bus = sdbusplus::bus::new_default(); 470 471 try 472 { 473 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 474 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 475 // If it is not present, I should not be trying to read a string 476 EXPECT_CALL(mockPMBus, readString(_, _)).Times(0); 477 psu.updateInventory(); 478 } 479 catch (...) 480 { 481 ADD_FAILURE() << "Should not have caught exception."; 482 } 483 484 try 485 { 486 PowerSupply psu{bus, PSUInventoryPath, 13, 0x69, PSUGPIOLineName}; 487 MockedGPIOInterface* mockPresenceGPIO = 488 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 489 // GPIO read return 1 to indicate present. 490 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1)); 491 psu.analyze(); 492 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 493 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return("")); 494 psu.updateInventory(); 495 496 #if IBM_VPD 497 EXPECT_CALL(mockPMBus, readString(_, _)) 498 .WillOnce(Return("CCIN")) 499 .WillOnce(Return("PN3456")) 500 .WillOnce(Return("FN3456")) 501 .WillOnce(Return("HEADER")) 502 .WillOnce(Return("SN3456")) 503 .WillOnce(Return("FW3456")); 504 #endif 505 psu.updateInventory(); 506 // TODO: D-Bus mocking to verify values stored on D-Bus (???) 507 } 508 catch (...) 509 { 510 ADD_FAILURE() << "Should not have caught exception."; 511 } 512 } 513 514 TEST_F(PowerSupplyTests, IsPresent) 515 { 516 auto bus = sdbusplus::bus::new_default(); 517 518 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 519 MockedGPIOInterface* mockPresenceGPIO = 520 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 521 EXPECT_EQ(psu.isPresent(), false); 522 523 // Change GPIO read to return 1 to indicate present. 524 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1)); 525 psu.analyze(); 526 EXPECT_EQ(psu.isPresent(), true); 527 } 528 529 TEST_F(PowerSupplyTests, IsFaulted) 530 { 531 auto bus = sdbusplus::bus::new_default(); 532 533 PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f, PSUGPIOLineName}; 534 MockedGPIOInterface* mockPresenceGPIO = 535 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 536 // Always return 1 to indicate present. 537 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 538 psu.analyze(); 539 EXPECT_EQ(psu.isFaulted(), false); 540 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 541 // STATUS_WORD with fault bits on. 542 uint16_t statusWordValue = 0xFFFF; 543 // STATUS_INPUT with fault bits on. 544 uint8_t statusInputValue = 0xFF; 545 // STATUS_MFR_SPECIFIC with faults bits on. 546 uint8_t statusMFRValue = 0xFF; 547 // STATUS_CML with faults bits on. 548 uint8_t statusCMLValue = 0xFF; 549 // STATUS_VOUT with fault bits on. 550 uint8_t statusVOUTValue = 0xFF; 551 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 552 statusMFRValue, statusCMLValue, statusVOUTValue); 553 psu.analyze(); 554 EXPECT_EQ(psu.isFaulted(), true); 555 } 556 557 TEST_F(PowerSupplyTests, HasInputFault) 558 { 559 auto bus = sdbusplus::bus::new_default(); 560 561 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 562 MockedGPIOInterface* mockPresenceGPIO = 563 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 564 // Always return 1 to indicate present. 565 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 566 psu.analyze(); 567 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 568 EXPECT_EQ(psu.hasInputFault(), false); 569 // STATUS_WORD 0x0000 is powered on, no faults. 570 uint16_t statusWordValue = 0; 571 setPMBusExpectations(mockPMBus, statusWordValue); 572 psu.analyze(); 573 EXPECT_EQ(psu.hasInputFault(), false); 574 // STATUS_WORD with input fault/warn on. 575 statusWordValue = (status_word::INPUT_FAULT_WARN); 576 // STATUS_INPUT with an input fault bit on. 577 uint8_t statusInputValue = 0x80; 578 // STATUS_MFR, STATUS_CML, and STATUS_VOUT don't care. 579 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue); 580 psu.analyze(); 581 EXPECT_EQ(psu.hasInputFault(), true); 582 // STATUS_WORD with no bits on. 583 statusWordValue = 0; 584 setPMBusExpectations(mockPMBus, statusWordValue); 585 psu.analyze(); 586 EXPECT_EQ(psu.hasInputFault(), false); 587 } 588 589 TEST_F(PowerSupplyTests, HasMFRFault) 590 { 591 auto bus = sdbusplus::bus::new_default(); 592 593 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 594 MockedGPIOInterface* mockPresenceGPIO = 595 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 596 // Always return 1 to indicate present. 597 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 598 psu.analyze(); 599 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 600 EXPECT_EQ(psu.hasMFRFault(), false); 601 // First return STATUS_WORD with no bits on. 602 // STATUS_WORD 0x0000 is powered on, no faults. 603 uint16_t statusWordValue = 0; 604 setPMBusExpectations(mockPMBus, statusWordValue); 605 psu.analyze(); 606 EXPECT_EQ(psu.hasMFRFault(), false); 607 // Next return STATUS_WORD with MFR fault bit on. 608 statusWordValue = (status_word::MFR_SPECIFIC_FAULT); 609 // STATUS_INPUT don't care 610 uint8_t statusInputValue = 0; 611 // STATUS_MFR_SPEFIC with bit(s) on. 612 uint8_t statusMFRValue = 0xFF; 613 // STATUS_CML and STATUS_VOUT don't care. 614 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 615 statusMFRValue); 616 psu.analyze(); 617 EXPECT_EQ(psu.hasMFRFault(), true); 618 // Back to no bits on in STATUS_WORD 619 statusWordValue = 0; 620 setPMBusExpectations(mockPMBus, statusWordValue); 621 psu.analyze(); 622 EXPECT_EQ(psu.hasMFRFault(), false); 623 } 624 625 TEST_F(PowerSupplyTests, HasVINUVFault) 626 { 627 auto bus = sdbusplus::bus::new_default(); 628 629 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 630 MockedGPIOInterface* mockPresenceGPIO = 631 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 632 // Always return 1 to indicate present. 633 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 634 psu.analyze(); 635 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 636 EXPECT_EQ(psu.hasVINUVFault(), false); 637 // STATUS_WORD 0x0000 is powered on, no faults. 638 uint16_t statusWordValue = 0; 639 setPMBusExpectations(mockPMBus, statusWordValue); 640 psu.analyze(); 641 EXPECT_EQ(psu.hasVINUVFault(), false); 642 // Turn fault on. 643 statusWordValue = (status_word::VIN_UV_FAULT); 644 // Curious disagreement between PMBus Spec. Part II Figure 16 and 33. Go by 645 // Figure 16, and assume bits on in STATUS_INPUT. 646 uint8_t statusInputValue = 0x18; 647 // STATUS_MFR, STATUS_CML, and STATUS_VOUT don't care. 648 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue); 649 psu.analyze(); 650 EXPECT_EQ(psu.hasVINUVFault(), true); 651 // Back to no fault bits on in STATUS_WORD 652 statusWordValue = 0; 653 setPMBusExpectations(mockPMBus, statusWordValue); 654 psu.analyze(); 655 EXPECT_EQ(psu.hasVINUVFault(), false); 656 } 657 658 TEST_F(PowerSupplyTests, HasVoutOVFault) 659 { 660 auto bus = sdbusplus::bus::new_default(); 661 662 PowerSupply psu{bus, PSUInventoryPath, 3, 0x69, PSUGPIOLineName}; 663 MockedGPIOInterface* mockPresenceGPIO = 664 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 665 // Always return 1 to indicate present. 666 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 667 psu.analyze(); 668 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 669 EXPECT_EQ(psu.hasVoutOVFault(), false); 670 // STATUS_WORD 0x0000 is powered on, no faults. 671 uint16_t statusWordValue = 0; 672 setPMBusExpectations(mockPMBus, statusWordValue); 673 psu.analyze(); 674 EXPECT_EQ(psu.hasVoutOVFault(), false); 675 // Turn fault on. 676 statusWordValue = (status_word::VOUT_OV_FAULT); 677 // STATUS_INPUT don't care. 678 uint8_t statusInputValue = 0; 679 // STATUS_MFR don't care. 680 uint8_t statusMFRValue = 0; 681 // STATUS_CML don't care. 682 uint8_t statusCMLValue = 0; 683 // STATUS_VOUT fault bit(s) 684 uint8_t statusVOUTValue = 0x80; 685 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue, 686 statusMFRValue, statusCMLValue, statusVOUTValue); 687 psu.analyze(); 688 EXPECT_EQ(psu.hasVoutOVFault(), true); 689 // Back to no fault bits on in STATUS_WORD 690 statusWordValue = 0; 691 setPMBusExpectations(mockPMBus, statusWordValue); 692 psu.analyze(); 693 EXPECT_EQ(psu.hasVoutOVFault(), false); 694 } 695