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 145 PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName}; 146 // In order to get the various faults tested, the power supply needs to 147 // be present in order to read from the PMBus device(s). 148 MockedGPIOInterface* mockPresenceGPIO2 = 149 static_cast<MockedGPIOInterface*>(psu2.getPresenceGPIO()); 150 ON_CALL(*mockPresenceGPIO2, read()).WillByDefault(Return(1)); 151 152 EXPECT_EQ(psu2.isPresent(), false); 153 154 // STATUS_WORD 0x0000 is powered on, no faults (0x0000). 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 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 160 .Times(1) 161 .WillOnce(Return(0x0000)); 162 psu2.analyze(); 163 EXPECT_EQ(psu2.isPresent(), true); 164 EXPECT_EQ(psu2.isFaulted(), false); 165 EXPECT_EQ(psu2.hasInputFault(), false); 166 EXPECT_EQ(psu2.hasMFRFault(), false); 167 EXPECT_EQ(psu2.hasVINUVFault(), false); 168 169 // STATUS_WORD input fault/warn 170 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 171 .Times(1) 172 .WillOnce(Return(status_word::INPUT_FAULT_WARN)); 173 // Due to the fault bit on in STATUS_WORD, there will also be a read of 174 // STATUS_INPUT and STATUS_MFR, so there should be 3 reads total expected. 175 // STATUS_INPUT fault bits ... on. 176 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 177 .Times(1) 178 .WillOnce(Return(0x38)); 179 // STATUS_MFR don't care 180 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0)); 181 182 psu2.analyze(); 183 EXPECT_EQ(psu2.isPresent(), true); 184 EXPECT_EQ(psu2.isFaulted(), true); 185 EXPECT_EQ(psu2.hasInputFault(), true); 186 EXPECT_EQ(psu2.hasMFRFault(), false); 187 EXPECT_EQ(psu2.hasVINUVFault(), false); 188 189 // STATUS_WORD INPUT/UV fault. 190 // First need it to return good status, then the fault 191 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 192 .Times(2) 193 .WillOnce(Return(0x0000)) 194 .WillOnce(Return( 195 (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT))); 196 // STATUS_INPUT fault bits ... on. 197 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 198 .Times(1) 199 .WillOnce(Return(0x38)); 200 // STATUS_MFR don't care 201 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0)); 202 203 psu2.analyze(); 204 psu2.analyze(); 205 EXPECT_EQ(psu2.isPresent(), true); 206 EXPECT_EQ(psu2.isFaulted(), true); 207 EXPECT_EQ(psu2.hasInputFault(), true); 208 EXPECT_EQ(psu2.hasMFRFault(), false); 209 EXPECT_EQ(psu2.hasVINUVFault(), true); 210 211 // STATUS_WORD MFR fault. 212 // First need it to return good status, then the fault 213 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 214 .Times(2) 215 .WillOnce(Return(0x0000)) 216 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT)); 217 // STATUS_INPUT fault bits ... don't care. 218 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 219 .Times(1) 220 .WillOnce(Return(0x00)); 221 // STATUS_MFR bits on. 222 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF)); 223 224 psu2.analyze(); 225 psu2.analyze(); 226 EXPECT_EQ(psu2.isPresent(), true); 227 EXPECT_EQ(psu2.isFaulted(), true); 228 EXPECT_EQ(psu2.hasInputFault(), false); 229 EXPECT_EQ(psu2.hasMFRFault(), true); 230 EXPECT_EQ(psu2.hasVINUVFault(), false); 231 232 // Ignore Temperature fault. 233 // First STATUS_WORD with no bits set, then with temperature fault. 234 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 235 .Times(2) 236 .WillOnce(Return(0x0000)) 237 .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN)); 238 // If STATUS_WORD bits set, should read STATUS_MFR_SPECIFIC and STATUS_INPUT 239 // STATUS_INPUT fault bits ... don't care. 240 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 241 .Times(1) 242 .WillOnce(Return(0x00)); 243 // STATUS_MFR don't care 244 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0)); 245 246 psu2.analyze(); 247 psu2.analyze(); 248 EXPECT_EQ(psu2.isPresent(), true); 249 EXPECT_EQ(psu2.isFaulted(), false); 250 EXPECT_EQ(psu2.hasInputFault(), false); 251 EXPECT_EQ(psu2.hasMFRFault(), false); 252 EXPECT_EQ(psu2.hasVINUVFault(), false); 253 254 // Ignore fan fault 255 // First STATUS_WORD with no bits set, then with fan fault. 256 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 257 .Times(2) 258 .WillOnce(Return(0x0000)) 259 .WillOnce(Return(status_word::FAN_FAULT)); 260 // STATUS_WORD bits set causes read STATUS_MFR_SPECIFIC and STATUS_INPUT. 261 // Don't care if bits set or not. 262 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 263 .Times(1) 264 .WillOnce(Return(0x00)); 265 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0)); 266 267 psu2.analyze(); 268 psu2.analyze(); 269 EXPECT_EQ(psu2.isPresent(), true); 270 EXPECT_EQ(psu2.isFaulted(), false); 271 EXPECT_EQ(psu2.hasInputFault(), false); 272 EXPECT_EQ(psu2.hasMFRFault(), false); 273 EXPECT_EQ(psu2.hasVINUVFault(), false); 274 275 // TODO: ReadFailure 276 } 277 278 TEST_F(PowerSupplyTests, OnOffConfig) 279 { 280 auto bus = sdbusplus::bus::new_default(); 281 uint8_t data = 0x15; 282 283 // Test where PSU is NOT present 284 try 285 { 286 // Assume GPIO presence, not inventory presence? 287 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName}; 288 289 MockedGPIOInterface* mockPresenceGPIO = 290 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 291 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(0)); 292 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 293 // Constructor should set initial presence, default read returns 0. 294 // If it is not present, I should not be trying to write to it. 295 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0); 296 psu.onOffConfig(data); 297 } 298 catch (...) 299 {} 300 301 // Test where PSU is present 302 try 303 { 304 // Assume GPIO presence, not inventory presence? 305 PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName}; 306 MockedGPIOInterface* mockPresenceGPIO = 307 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 308 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1)); 309 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 310 // TODO: expect setPresence call? 311 // updatePresence() private function reads gpio, called by analyze(). 312 psu.analyze(); 313 // TODO: ???should I check the filename? 314 EXPECT_CALL(mockPMBus, 315 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug)) 316 .Times(1); 317 psu.onOffConfig(data); 318 } 319 catch (...) 320 {} 321 } 322 323 TEST_F(PowerSupplyTests, ClearFaults) 324 { 325 auto bus = sdbusplus::bus::new_default(); 326 PowerSupply psu{bus, PSUInventoryPath, 13, 0x68, PSUGPIOLineName}; 327 MockedGPIOInterface* mockPresenceGPIO = 328 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 329 // GPIO read return 1 to indicate present. 330 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1)); 331 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 332 ON_CALL(mockPMBus, read(STATUS_WORD, _)).WillByDefault(Return(0)); 333 psu.analyze(); 334 EXPECT_EQ(psu.isPresent(), true); 335 EXPECT_EQ(psu.isFaulted(), false); 336 EXPECT_EQ(psu.hasInputFault(), false); 337 EXPECT_EQ(psu.hasMFRFault(), false); 338 EXPECT_EQ(psu.hasVINUVFault(), false); 339 // STATUS_WORD with fault bits galore! 340 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 341 .Times(1) 342 .WillOnce(Return(0xFFFF)); 343 // If STATUS_WORD has any fault bits on, STATUS_MFR_SPECIFIC and 344 // STATUS_INPUT will be read. 345 // STATUS_INPUT with fault bits on. 346 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 347 .Times(1) 348 .WillOnce(Return(0xFF)); 349 // STATUS_MFR_SPEFIC with bits on. 350 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF)); 351 psu.analyze(); 352 EXPECT_EQ(psu.isPresent(), true); 353 EXPECT_EQ(psu.isFaulted(), true); 354 EXPECT_EQ(psu.hasInputFault(), true); 355 EXPECT_EQ(psu.hasMFRFault(), true); 356 EXPECT_EQ(psu.hasVINUVFault(), true); 357 EXPECT_CALL(mockPMBus, read("in1_input", _)) 358 .Times(1) 359 .WillOnce(Return(209000)); 360 psu.clearFaults(); 361 EXPECT_EQ(psu.isPresent(), true); 362 EXPECT_EQ(psu.isFaulted(), false); 363 EXPECT_EQ(psu.hasInputFault(), false); 364 EXPECT_EQ(psu.hasMFRFault(), false); 365 EXPECT_EQ(psu.hasVINUVFault(), false); 366 367 // TODO: Faults clear on missing/present? 368 } 369 370 TEST_F(PowerSupplyTests, UpdateInventory) 371 { 372 auto bus = sdbusplus::bus::new_default(); 373 374 try 375 { 376 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 377 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 378 // If it is not present, I should not be trying to read a string 379 EXPECT_CALL(mockPMBus, readString(_, _)).Times(0); 380 psu.updateInventory(); 381 } 382 catch (...) 383 { 384 ADD_FAILURE() << "Should not have caught exception."; 385 } 386 387 try 388 { 389 PowerSupply psu{bus, PSUInventoryPath, 13, 0x69, PSUGPIOLineName}; 390 MockedGPIOInterface* mockPresenceGPIO = 391 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 392 // GPIO read return 1 to indicate present. 393 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1)); 394 psu.analyze(); 395 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 396 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return("")); 397 psu.updateInventory(); 398 399 #if IBM_VPD 400 EXPECT_CALL(mockPMBus, readString(_, _)) 401 .WillOnce(Return("CCIN")) 402 .WillOnce(Return("PN3456")) 403 .WillOnce(Return("FN3456")) 404 .WillOnce(Return("HEADER")) 405 .WillOnce(Return("SN3456")) 406 .WillOnce(Return("FW3456")); 407 #endif 408 psu.updateInventory(); 409 // TODO: D-Bus mocking to verify values stored on D-Bus (???) 410 } 411 catch (...) 412 { 413 ADD_FAILURE() << "Should not have caught exception."; 414 } 415 } 416 417 TEST_F(PowerSupplyTests, IsPresent) 418 { 419 auto bus = sdbusplus::bus::new_default(); 420 421 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 422 MockedGPIOInterface* mockPresenceGPIO = 423 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 424 EXPECT_EQ(psu.isPresent(), false); 425 426 // Change GPIO read to return 1 to indicate present. 427 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1)); 428 psu.analyze(); 429 EXPECT_EQ(psu.isPresent(), true); 430 } 431 432 TEST_F(PowerSupplyTests, IsFaulted) 433 { 434 auto bus = sdbusplus::bus::new_default(); 435 436 PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f, PSUGPIOLineName}; 437 MockedGPIOInterface* mockPresenceGPIO = 438 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 439 // Always return 1 to indicate present. 440 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 441 psu.analyze(); 442 EXPECT_EQ(psu.isFaulted(), false); 443 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 444 // STATUS_WORD with fault bits on. 445 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 446 .Times(1) 447 .WillOnce(Return(0xFFFF)); 448 // If STATUS_WORD has bit(s) on, STATUS_MFR_SPECIFIC and STATUS_INPUT read. 449 // STATUS_INPUT with fault bits on. 450 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 451 .Times(1) 452 .WillOnce(Return(0xFF)); 453 // STATUS_MFR_SPECIFIC with faults bits on. 454 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF)); 455 psu.analyze(); 456 EXPECT_EQ(psu.isFaulted(), true); 457 } 458 459 TEST_F(PowerSupplyTests, HasInputFault) 460 { 461 auto bus = sdbusplus::bus::new_default(); 462 463 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 464 MockedGPIOInterface* mockPresenceGPIO = 465 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 466 // Always return 1 to indicate present. 467 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 468 psu.analyze(); 469 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 470 EXPECT_EQ(psu.hasInputFault(), false); 471 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 472 psu.analyze(); 473 EXPECT_EQ(psu.hasInputFault(), false); 474 // STATUS_WORD with input fault/warn on. 475 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 476 .Times(1) 477 .WillOnce(Return(status_word::INPUT_FAULT_WARN)); 478 // If STATUS_WORD has bit(s) on, STATUS_MFR_SPECIFIC and STATUS_INPUT read. 479 // STATUS_INPUT with an input fault bit on. 480 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 481 .Times(1) 482 .WillOnce(Return(0x80)); 483 // STATUS_MFR don't care. 484 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0x00)); 485 psu.analyze(); 486 EXPECT_EQ(psu.hasInputFault(), true); 487 // STATUS_WORD with no bits on. 488 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 489 .Times(1) 490 .WillOnce(Return(0x0000)); 491 psu.analyze(); 492 EXPECT_EQ(psu.hasInputFault(), false); 493 } 494 495 TEST_F(PowerSupplyTests, HasMFRFault) 496 { 497 auto bus = sdbusplus::bus::new_default(); 498 499 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 500 MockedGPIOInterface* mockPresenceGPIO = 501 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 502 // Always return 1 to indicate present. 503 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 504 psu.analyze(); 505 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 506 EXPECT_EQ(psu.hasMFRFault(), false); 507 // First return STATUS_WORD with no bits on. 508 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 509 .Times(1) 510 .WillOnce(Return(0x0000)); 511 psu.analyze(); 512 EXPECT_EQ(psu.hasMFRFault(), false); 513 // Next return STATUS_WORD with MFR fault bit on. 514 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 515 .Times(1) 516 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT)); 517 // If STATUS_WORD has bits on, STATUS_MFR_SPECIFIC and STATUS_INPUT read. 518 // STATUS_INPUT don't care 519 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 520 .Times(1) 521 .WillOnce(Return(0x00)); 522 // STATUS_MFR_SPEFIC with bit(s) on. 523 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0xFF)); 524 psu.analyze(); 525 EXPECT_EQ(psu.hasMFRFault(), true); 526 // Back to no bits on in STATUS_WORD 527 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 528 .Times(1) 529 .WillOnce(Return(0x0000)); 530 psu.analyze(); 531 EXPECT_EQ(psu.hasMFRFault(), false); 532 } 533 534 TEST_F(PowerSupplyTests, HasVINUVFault) 535 { 536 auto bus = sdbusplus::bus::new_default(); 537 538 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName}; 539 MockedGPIOInterface* mockPresenceGPIO = 540 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO()); 541 // Always return 1 to indicate present. 542 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1)); 543 psu.analyze(); 544 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 545 EXPECT_EQ(psu.hasVINUVFault(), false); 546 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 547 .Times(1) 548 .WillOnce(Return(0x0000)); 549 psu.analyze(); 550 EXPECT_EQ(psu.hasVINUVFault(), false); 551 // Turn fault on. 552 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 553 .Times(1) 554 .WillOnce(Return(status_word::VIN_UV_FAULT)); 555 // Fault bits on in STATUS_WORD causes read of STATUS_MFR_SPECIFIC and 556 // STATUS_INPUT. 557 // Curious disagreement between PMBus Spec. Part II Figure 16 and 33. 558 // Go by Figure 16, and assume bits on in STATUS_INPUT. 559 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _)) 560 .Times(1) 561 .WillOnce(Return(0x18)); 562 // STATUS_MFR don't care. 563 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _)).Times(1).WillOnce(Return(0x00)); 564 565 psu.analyze(); 566 EXPECT_EQ(psu.hasVINUVFault(), true); 567 // Back to no fault bits on in STATUS_WORD 568 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _)) 569 .Times(1) 570 .WillOnce(Return(0x0000)); 571 psu.analyze(); 572 EXPECT_EQ(psu.hasVINUVFault(), false); 573 } 574