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 psu.clearFaults(); 172 EXPECT_EQ(psu.isPresent(), true); 173 EXPECT_EQ(psu.isFaulted(), false); 174 EXPECT_EQ(psu.hasInputFault(), false); 175 EXPECT_EQ(psu.hasMFRFault(), false); 176 EXPECT_EQ(psu.hasVINUVFault(), false); 177 } 178 179 TEST_F(PowerSupplyTests, UpdateInventory) 180 { 181 auto bus = sdbusplus::bus::new_default(); 182 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))) 183 .Times(1) 184 .WillOnce(Return(true)); // present 185 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 186 psu.updateInventory(); 187 // TODO: Checks / Story #921 188 } 189 190 TEST_F(PowerSupplyTests, IsPresent) 191 { 192 auto bus = sdbusplus::bus::new_default(); 193 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1); 194 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 195 EXPECT_EQ(psu.isPresent(), false); 196 197 EXPECT_CALL(mockedUtil, getPresence(_, _)) 198 .WillOnce(Return(true)); // present 199 PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"}; 200 EXPECT_EQ(psu2.isPresent(), true); 201 } 202 203 TEST_F(PowerSupplyTests, IsFaulted) 204 { 205 auto bus = sdbusplus::bus::new_default(); 206 EXPECT_CALL(mockedUtil, getPresence(_, _)) 207 .WillOnce(Return(true)); // present 208 PowerSupply psu{bus, PSUInventoryPath, 11, "006f"}; 209 EXPECT_EQ(psu.isFaulted(), false); 210 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 211 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF)); 212 psu.analyze(); 213 EXPECT_EQ(psu.isFaulted(), true); 214 } 215 216 TEST_F(PowerSupplyTests, HasInputFault) 217 { 218 auto bus = sdbusplus::bus::new_default(); 219 EXPECT_CALL(mockedUtil, getPresence(_, _)) 220 .WillOnce(Return(true)); // present 221 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 222 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 223 EXPECT_EQ(psu.hasInputFault(), false); 224 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 225 psu.analyze(); 226 EXPECT_EQ(psu.hasInputFault(), false); 227 EXPECT_CALL(mockPMBus, read(_, _)) 228 .Times(1) 229 .WillOnce(Return(status_word::INPUT_FAULT_WARN)); 230 psu.analyze(); 231 EXPECT_EQ(psu.hasInputFault(), true); 232 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 233 psu.analyze(); 234 EXPECT_EQ(psu.hasInputFault(), false); 235 } 236 237 TEST_F(PowerSupplyTests, HasMFRFault) 238 { 239 auto bus = sdbusplus::bus::new_default(); 240 EXPECT_CALL(mockedUtil, getPresence(_, _)) 241 .WillOnce(Return(true)); // present 242 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 243 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 244 EXPECT_EQ(psu.hasMFRFault(), false); 245 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 246 psu.analyze(); 247 EXPECT_EQ(psu.hasMFRFault(), false); 248 EXPECT_CALL(mockPMBus, read(_, _)) 249 .Times(1) 250 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT)); 251 psu.analyze(); 252 EXPECT_EQ(psu.hasMFRFault(), true); 253 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 254 psu.analyze(); 255 EXPECT_EQ(psu.hasMFRFault(), false); 256 } 257 258 TEST_F(PowerSupplyTests, HasVINUVFault) 259 { 260 auto bus = sdbusplus::bus::new_default(); 261 EXPECT_CALL(mockedUtil, getPresence(_, _)) 262 .WillOnce(Return(true)); // present 263 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"}; 264 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus()); 265 EXPECT_EQ(psu.hasVINUVFault(), false); 266 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 267 psu.analyze(); 268 EXPECT_EQ(psu.hasVINUVFault(), false); 269 EXPECT_CALL(mockPMBus, read(_, _)) 270 .Times(1) 271 .WillOnce(Return(status_word::VIN_UV_FAULT)); 272 psu.analyze(); 273 EXPECT_EQ(psu.hasVINUVFault(), true); 274 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000)); 275 psu.analyze(); 276 EXPECT_EQ(psu.hasVINUVFault(), false); 277 } 278