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