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 24 class PowerSupplyTests : public ::testing::Test 25 { 26 public: 27 PowerSupplyTests() : 28 mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils())) 29 { 30 ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false)); 31 } 32 33 ~PowerSupplyTests() override 34 { 35 freeUtils(); 36 } 37 38 const MockedUtil& mockedUtil; 39 }; 40 41 TEST_F(PowerSupplyTests, Constructor) 42 { 43 /** 44 * @param[in] invpath - String for inventory path to use 45 * @param[in] i2cbus - The bus number this power supply is on 46 * @param[in] i2caddr - The 16-bit I2C address of the power supply 47 */ 48 auto bus = sdbusplus::bus::new_default(); 49 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1); 50 auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, "0068"); 51 52 EXPECT_EQ(psu->isPresent(), false); 53 EXPECT_EQ(psu->isFaulted(), false); 54 EXPECT_EQ(psu->hasInputFault(), false); 55 EXPECT_EQ(psu->hasMFRFault(), false); 56 EXPECT_EQ(psu->hasVINUVFault(), false); 57 } 58 59 TEST_F(PowerSupplyTests, Analyze) 60 { 61 auto bus = sdbusplus::bus::new_default(); 62 63 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1); 64 PowerSupply psu{bus, PSUInventoryPath, 4, "0069"}; 65 psu.analyze(); 66 // By default, nothing should change. 67 EXPECT_EQ(psu.isPresent(), false); 68 EXPECT_EQ(psu.isFaulted(), false); 69 EXPECT_EQ(psu.hasInputFault(), false); 70 EXPECT_EQ(psu.hasMFRFault(), false); 71 EXPECT_EQ(psu.hasVINUVFault(), false); 72 73 // In order to get the various faults tested, the power supply needs to be 74 // present in order to read from the PMBus device(s). 75 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))) 76 .Times(1) 77 .WillOnce(Return(true)); // present 78 PowerSupply psu2{bus, PSUInventoryPath, 5, "006a"}; 79 EXPECT_EQ(psu2.isPresent(), true); 80 81 // STATUS_WORD 0x0000 is powered on, no faults. 82 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus()); 83 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 84 psu2.analyze(); 85 EXPECT_EQ(psu2.isPresent(), true); 86 EXPECT_EQ(psu2.isFaulted(), false); 87 EXPECT_EQ(psu2.hasInputFault(), false); 88 EXPECT_EQ(psu2.hasMFRFault(), false); 89 EXPECT_EQ(psu2.hasVINUVFault(), false); 90 91 // STATUS_WORD input fault/warn 92 EXPECT_CALL(mockPMBus, read(_, _)) 93 .Times(1) 94 .WillOnce(Return(status_word::INPUT_FAULT_WARN)); 95 psu2.analyze(); 96 EXPECT_EQ(psu2.isPresent(), true); 97 EXPECT_EQ(psu2.isFaulted(), true); 98 EXPECT_EQ(psu2.hasInputFault(), true); 99 EXPECT_EQ(psu2.hasMFRFault(), false); 100 EXPECT_EQ(psu2.hasVINUVFault(), false); 101 102 // STATUS_WORD INPUT/UV fault. 103 // First need it to return good status, then the fault 104 EXPECT_CALL(mockPMBus, read(_, _)) 105 .WillOnce(Return(0x0000)) 106 .WillOnce(Return(status_word::VIN_UV_FAULT)); 107 psu2.analyze(); 108 psu2.analyze(); 109 EXPECT_EQ(psu2.isPresent(), true); 110 EXPECT_EQ(psu2.isFaulted(), true); 111 EXPECT_EQ(psu2.hasInputFault(), false); 112 EXPECT_EQ(psu2.hasMFRFault(), false); 113 EXPECT_EQ(psu2.hasVINUVFault(), true); 114 115 // STATUS_WORD MFR fault. 116 EXPECT_CALL(mockPMBus, read(_, _)) 117 .WillOnce(Return(0x0000)) 118 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT)); 119 psu2.analyze(); 120 psu2.analyze(); 121 EXPECT_EQ(psu2.isPresent(), true); 122 EXPECT_EQ(psu2.isFaulted(), true); 123 EXPECT_EQ(psu2.hasInputFault(), false); 124 EXPECT_EQ(psu2.hasMFRFault(), true); 125 EXPECT_EQ(psu2.hasVINUVFault(), false); 126 127 // Ignore Temperature fault. 128 EXPECT_CALL(mockPMBus, read(_, _)) 129 .WillOnce(Return(0x0000)) 130 .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN)); 131 psu2.analyze(); 132 psu2.analyze(); 133 EXPECT_EQ(psu2.isPresent(), true); 134 EXPECT_EQ(psu2.isFaulted(), false); 135 EXPECT_EQ(psu2.hasInputFault(), false); 136 EXPECT_EQ(psu2.hasMFRFault(), false); 137 EXPECT_EQ(psu2.hasVINUVFault(), false); 138 139 // Ignore fan fault 140 EXPECT_CALL(mockPMBus, read(_, _)) 141 .WillOnce(Return(0x0000)) 142 .WillOnce(Return(status_word::FAN_FAULT)); 143 psu2.analyze(); 144 psu2.analyze(); 145 EXPECT_EQ(psu2.isPresent(), true); 146 EXPECT_EQ(psu2.isFaulted(), false); 147 EXPECT_EQ(psu2.hasInputFault(), false); 148 EXPECT_EQ(psu2.hasMFRFault(), false); 149 EXPECT_EQ(psu2.hasVINUVFault(), false); 150 151 // TODO: ReadFailure 152 } 153 154 TEST_F(PowerSupplyTests, OnOffConfig) 155 { 156 auto bus = sdbusplus::bus::new_default(); 157 uint8_t data = 0x15; 158 159 // Test where PSU is NOT present 160 try 161 { 162 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))) 163 .Times(1) 164 .WillOnce(Return(false)); 165 PowerSupply psu{bus, PSUInventoryPath, 4, "0069"}; 166 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 167 // If it is not present, I should not be trying to write to it. 168 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0); 169 psu.onOffConfig(data); 170 } 171 catch (...) 172 { 173 } 174 175 // Test where PSU is present 176 try 177 { 178 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))) 179 .Times(1) 180 .WillOnce(Return(true)); // present 181 PowerSupply psu{bus, PSUInventoryPath, 5, "006a"}; 182 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 183 // TODO: ???should I check the filename? 184 EXPECT_CALL(mockPMBus, 185 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug)) 186 .Times(1); 187 psu.onOffConfig(data); 188 } 189 catch (...) 190 { 191 } 192 } 193 194 TEST_F(PowerSupplyTests, ClearFaults) 195 { 196 auto bus = sdbusplus::bus::new_default(); 197 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))) 198 .Times(1) 199 .WillOnce(Return(true)); // present 200 PowerSupply psu{bus, PSUInventoryPath, 13, "0068"}; 201 EXPECT_EQ(psu.isPresent(), true); 202 EXPECT_EQ(psu.isFaulted(), false); 203 EXPECT_EQ(psu.hasInputFault(), false); 204 EXPECT_EQ(psu.hasMFRFault(), false); 205 EXPECT_EQ(psu.hasVINUVFault(), false); 206 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 207 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF)); 208 psu.analyze(); 209 EXPECT_EQ(psu.isPresent(), true); 210 EXPECT_EQ(psu.isFaulted(), true); 211 EXPECT_EQ(psu.hasInputFault(), true); 212 EXPECT_EQ(psu.hasMFRFault(), true); 213 EXPECT_EQ(psu.hasVINUVFault(), true); 214 EXPECT_CALL(mockPMBus, read("in1_input", _)) 215 .Times(1) 216 .WillOnce(Return(209000)); 217 psu.clearFaults(); 218 EXPECT_EQ(psu.isPresent(), true); 219 EXPECT_EQ(psu.isFaulted(), false); 220 EXPECT_EQ(psu.hasInputFault(), false); 221 EXPECT_EQ(psu.hasMFRFault(), false); 222 EXPECT_EQ(psu.hasVINUVFault(), false); 223 } 224 225 TEST_F(PowerSupplyTests, UpdateInventory) 226 { 227 auto bus = sdbusplus::bus::new_default(); 228 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))) 229 .Times(1) 230 .WillOnce(Return(true)); // present 231 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 232 psu.updateInventory(); 233 // TODO: Checks / Story #921 234 } 235 236 TEST_F(PowerSupplyTests, IsPresent) 237 { 238 auto bus = sdbusplus::bus::new_default(); 239 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1); 240 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 241 EXPECT_EQ(psu.isPresent(), false); 242 243 EXPECT_CALL(mockedUtil, getPresence(_, _)) 244 .WillOnce(Return(true)); // present 245 PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"}; 246 EXPECT_EQ(psu2.isPresent(), true); 247 } 248 249 TEST_F(PowerSupplyTests, IsFaulted) 250 { 251 auto bus = sdbusplus::bus::new_default(); 252 EXPECT_CALL(mockedUtil, getPresence(_, _)) 253 .WillOnce(Return(true)); // present 254 PowerSupply psu{bus, PSUInventoryPath, 11, "006f"}; 255 EXPECT_EQ(psu.isFaulted(), false); 256 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 257 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF)); 258 psu.analyze(); 259 EXPECT_EQ(psu.isFaulted(), true); 260 } 261 262 TEST_F(PowerSupplyTests, HasInputFault) 263 { 264 auto bus = sdbusplus::bus::new_default(); 265 EXPECT_CALL(mockedUtil, getPresence(_, _)) 266 .WillOnce(Return(true)); // present 267 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 268 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 269 EXPECT_EQ(psu.hasInputFault(), false); 270 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 271 psu.analyze(); 272 EXPECT_EQ(psu.hasInputFault(), false); 273 EXPECT_CALL(mockPMBus, read(_, _)) 274 .Times(1) 275 .WillOnce(Return(status_word::INPUT_FAULT_WARN)); 276 psu.analyze(); 277 EXPECT_EQ(psu.hasInputFault(), true); 278 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 279 psu.analyze(); 280 EXPECT_EQ(psu.hasInputFault(), false); 281 } 282 283 TEST_F(PowerSupplyTests, HasMFRFault) 284 { 285 auto bus = sdbusplus::bus::new_default(); 286 EXPECT_CALL(mockedUtil, getPresence(_, _)) 287 .WillOnce(Return(true)); // present 288 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 289 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 290 EXPECT_EQ(psu.hasMFRFault(), false); 291 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 292 psu.analyze(); 293 EXPECT_EQ(psu.hasMFRFault(), false); 294 EXPECT_CALL(mockPMBus, read(_, _)) 295 .Times(1) 296 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT)); 297 psu.analyze(); 298 EXPECT_EQ(psu.hasMFRFault(), true); 299 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 300 psu.analyze(); 301 EXPECT_EQ(psu.hasMFRFault(), false); 302 } 303 304 TEST_F(PowerSupplyTests, HasVINUVFault) 305 { 306 auto bus = sdbusplus::bus::new_default(); 307 EXPECT_CALL(mockedUtil, getPresence(_, _)) 308 .WillOnce(Return(true)); // present 309 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 310 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 311 EXPECT_EQ(psu.hasVINUVFault(), false); 312 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 313 psu.analyze(); 314 EXPECT_EQ(psu.hasVINUVFault(), false); 315 EXPECT_CALL(mockPMBus, read(_, _)) 316 .Times(1) 317 .WillOnce(Return(status_word::VIN_UV_FAULT)); 318 psu.analyze(); 319 EXPECT_EQ(psu.hasVINUVFault(), true); 320 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 321 psu.analyze(); 322 EXPECT_EQ(psu.hasVINUVFault(), false); 323 } 324