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