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