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