blob: c131621c9d08e59b6269604f7cc645051f8b0aad [file] [log] [blame]
Brandon Wyman3f1242f2020-01-28 13:11:25 -06001#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
10using namespace phosphor::power::psu;
11using namespace phosphor::pmbus;
12
13using ::testing::_;
Brandon Wyman59a35792020-06-04 12:37:40 -050014using ::testing::Args;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060015using ::testing::Assign;
16using ::testing::DoAll;
Brandon Wyman59a35792020-06-04 12:37:40 -050017using ::testing::ElementsAre;
18using ::testing::NotNull;
Brandon Wyman3f1242f2020-01-28 13:11:25 -060019using ::testing::Return;
20using ::testing::StrEq;
21
22static auto PSUInventoryPath = "/xyz/bmc/inv/sys/chassis/board/powersupply0";
B. J. Wyman681b2a32021-04-20 22:31:22 +000023static auto PSUGPIOLineName = "presence-ps0";
Brandon Wyman3f1242f2020-01-28 13:11:25 -060024
Brandon Wymanb654c612021-11-05 23:24:51 +000025struct PMBusExpectations
26{
27 uint16_t statusWordValue{0x0000};
28 uint8_t statusInputValue{0x00};
29 uint8_t statusMFRValue{0x00};
30 uint8_t statusCMLValue{0x00};
31 uint8_t statusVOUTValue{0x00};
32};
33
Brandon Wyman8da35c52021-10-28 22:45:08 +000034// Helper function to setup expectations for various STATUS_* commands
Brandon Wymanb654c612021-11-05 23:24:51 +000035void setPMBusExpectations(MockedPMBus& mockPMBus,
36 const PMBusExpectations& expectations)
Brandon Wyman8da35c52021-10-28 22:45:08 +000037{
38 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
39 .Times(1)
Brandon Wymanb654c612021-11-05 23:24:51 +000040 .WillOnce(Return(expectations.statusWordValue));
Brandon Wyman8da35c52021-10-28 22:45:08 +000041
Brandon Wymanb654c612021-11-05 23:24:51 +000042 if (expectations.statusWordValue != 0)
Brandon Wyman8da35c52021-10-28 22:45:08 +000043 {
44 // If fault bits are on in STATUS_WORD, there will also be a read of
45 // STATUS_INPUT, STATUS_MFR, and STATUS_CML.
46 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
47 .Times(1)
Brandon Wymanb654c612021-11-05 23:24:51 +000048 .WillOnce(Return(expectations.statusInputValue));
Brandon Wyman8da35c52021-10-28 22:45:08 +000049 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _))
50 .Times(1)
Brandon Wymanb654c612021-11-05 23:24:51 +000051 .WillOnce(Return(expectations.statusMFRValue));
Brandon Wyman8da35c52021-10-28 22:45:08 +000052 EXPECT_CALL(mockPMBus, read(STATUS_CML, _))
53 .Times(1)
Brandon Wymanb654c612021-11-05 23:24:51 +000054 .WillOnce(Return(expectations.statusCMLValue));
Brandon Wyman6710ba22021-10-27 17:39:31 +000055 // Page will need to be set to 0 to read STATUS_VOUT.
56 EXPECT_CALL(mockPMBus, insertPageNum(STATUS_VOUT, 0))
57 .Times(1)
58 .WillOnce(Return("status0_vout"));
59 EXPECT_CALL(mockPMBus, read("status0_vout", _))
60 .Times(1)
Brandon Wymanb654c612021-11-05 23:24:51 +000061 .WillOnce(Return(expectations.statusVOUTValue));
Brandon Wyman8da35c52021-10-28 22:45:08 +000062 }
63}
64
Brandon Wyman3f1242f2020-01-28 13:11:25 -060065class PowerSupplyTests : public ::testing::Test
66{
67 public:
68 PowerSupplyTests() :
69 mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils()))
70 {
71 ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false));
72 }
73
74 ~PowerSupplyTests() override
75 {
76 freeUtils();
77 }
78
79 const MockedUtil& mockedUtil;
80};
81
82TEST_F(PowerSupplyTests, Constructor)
83{
84 /**
85 * @param[in] invpath - String for inventory path to use
86 * @param[in] i2cbus - The bus number this power supply is on
87 * @param[in] i2caddr - The 16-bit I2C address of the power supply
B. J. Wyman681b2a32021-04-20 22:31:22 +000088 * @param[in] gpioLineName - The string for the gpio-line-name to read for
89 * presence.
90 * @param[in] bindDelay - Time in milliseconds to delay binding the device
91 * driver after seeing the presence line go active.
Brandon Wyman3f1242f2020-01-28 13:11:25 -060092 */
93 auto bus = sdbusplus::bus::new_default();
Brandon Wyman3f1242f2020-01-28 13:11:25 -060094
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050095 // Try where inventory path is empty, constructor should fail.
96 try
97 {
B. J. Wyman681b2a32021-04-20 22:31:22 +000098 auto psu =
99 std::make_unique<PowerSupply>(bus, "", 3, 0x68, PSUGPIOLineName);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500100 ADD_FAILURE() << "Should not have reached this line.";
101 }
102 catch (const std::invalid_argument& e)
103 {
104 EXPECT_STREQ(e.what(), "Invalid empty inventoryPath");
105 }
106 catch (...)
107 {
108 ADD_FAILURE() << "Should not have caught exception.";
109 }
110
B. J. Wyman681b2a32021-04-20 22:31:22 +0000111 // TODO: Try invalid i2c address?
112
113 // Try where gpioLineName is empty.
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500114 try
115 {
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500116 auto psu =
B. J. Wyman681b2a32021-04-20 22:31:22 +0000117 std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68, "");
118 ADD_FAILURE()
119 << "Should not have reached this line. Invalid gpioLineName.";
120 }
121 catch (const std::invalid_argument& e)
122 {
123 EXPECT_STREQ(e.what(), "Invalid empty gpioLineName");
124 }
125 catch (...)
126 {
127 ADD_FAILURE() << "Should not have caught exception.";
128 }
129
130 // Test with valid arguments
131 // NOT using D-Bus inventory path for presence.
132 try
133 {
134 auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68,
135 PSUGPIOLineName);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500136
137 EXPECT_EQ(psu->isPresent(), false);
138 EXPECT_EQ(psu->isFaulted(), false);
Brandon Wyman8da35c52021-10-28 22:45:08 +0000139 EXPECT_EQ(psu->hasCommFault(), false);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500140 EXPECT_EQ(psu->hasInputFault(), false);
141 EXPECT_EQ(psu->hasMFRFault(), false);
142 EXPECT_EQ(psu->hasVINUVFault(), false);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000143 EXPECT_EQ(psu->hasVoutOVFault(), false);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500144 }
145 catch (...)
146 {
147 ADD_FAILURE() << "Should not have caught exception.";
148 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000149
150 // Test with valid arguments
151 // TODO: Using D-Bus inventory path for presence.
152 try
153 {
154 // FIXME: How do I get that presenceGPIO.read() in the startup to throw
155 // an exception?
156
157 // EXPECT_CALL(mockedUtil, getPresence(_,
158 // StrEq(PSUInventoryPath)))
159 // .Times(1);
160 }
161 catch (...)
162 {
163 ADD_FAILURE() << "Should not have caught exception.";
164 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600165}
166
167TEST_F(PowerSupplyTests, Analyze)
168{
169 auto bus = sdbusplus::bus::new_default();
170
Brandon Wymanb654c612021-11-05 23:24:51 +0000171 {
172 // If I default to reading the GPIO, I will NOT expect a call to
173 // getPresence().
B. J. Wyman681b2a32021-04-20 22:31:22 +0000174
Brandon Wymanb654c612021-11-05 23:24:51 +0000175 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
176 MockedGPIOInterface* mockPresenceGPIO =
177 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
178 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(0));
B. J. Wyman681b2a32021-04-20 22:31:22 +0000179
Brandon Wymanb654c612021-11-05 23:24:51 +0000180 psu.analyze();
181 // By default, nothing should change.
182 EXPECT_EQ(psu.isPresent(), false);
183 EXPECT_EQ(psu.isFaulted(), false);
184 EXPECT_EQ(psu.hasInputFault(), false);
185 EXPECT_EQ(psu.hasMFRFault(), false);
186 EXPECT_EQ(psu.hasVINUVFault(), false);
187 EXPECT_EQ(psu.hasCommFault(), false);
188 EXPECT_EQ(psu.hasVoutOVFault(), false);
189 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600190
B. J. Wyman681b2a32021-04-20 22:31:22 +0000191 PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
192 // In order to get the various faults tested, the power supply needs to
193 // be present in order to read from the PMBus device(s).
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000194 MockedGPIOInterface* mockPresenceGPIO2 =
195 static_cast<MockedGPIOInterface*>(psu2.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000196 ON_CALL(*mockPresenceGPIO2, read()).WillByDefault(Return(1));
B. J. Wyman681b2a32021-04-20 22:31:22 +0000197 EXPECT_EQ(psu2.isPresent(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600198
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600199 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
Brandon Wyman8da35c52021-10-28 22:45:08 +0000200 // Presence change from missing to present will trigger write to
201 // ON_OFF_CONFIG.
202 EXPECT_CALL(mockPMBus, writeBinary(ON_OFF_CONFIG, _, _));
Brandon Wymanb654c612021-11-05 23:24:51 +0000203 // Presence change from missing to present will trigger in1_input read
204 // in an attempt to get CLEAR_FAULTS called.
Brandon Wymanf07bc792021-10-12 19:00:35 +0000205 EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600206
Brandon Wymanb654c612021-11-05 23:24:51 +0000207 // STATUS_WORD INPUT fault.
208 {
209 // Start with STATUS_WORD 0x0000. Powered on, no faults.
210 // Set expectations for a no fault
211 PMBusExpectations expectations;
212 setPMBusExpectations(mockPMBus, expectations);
213 psu2.analyze();
214 EXPECT_EQ(psu2.isPresent(), true);
215 EXPECT_EQ(psu2.isFaulted(), false);
216 EXPECT_EQ(psu2.hasInputFault(), false);
217 EXPECT_EQ(psu2.hasMFRFault(), false);
218 EXPECT_EQ(psu2.hasVINUVFault(), false);
219 EXPECT_EQ(psu2.hasCommFault(), false);
220 EXPECT_EQ(psu2.hasVoutOVFault(), false);
221
222 // Update expectations for STATUS_WORD input fault/warn
223 expectations.statusWordValue = (status_word::INPUT_FAULT_WARN);
224 expectations.statusInputValue = 0x38;
225 setPMBusExpectations(mockPMBus, expectations);
226 psu2.analyze();
227 EXPECT_EQ(psu2.isPresent(), true);
228 EXPECT_EQ(psu2.isFaulted(), true);
229 EXPECT_EQ(psu2.hasInputFault(), true);
230 EXPECT_EQ(psu2.hasMFRFault(), false);
231 EXPECT_EQ(psu2.hasVINUVFault(), false);
232 EXPECT_EQ(psu2.hasCommFault(), false);
233 EXPECT_EQ(psu2.hasVoutOVFault(), false);
234 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600235
236 // STATUS_WORD INPUT/UV fault.
Brandon Wymanb654c612021-11-05 23:24:51 +0000237 {
238 // First need it to return good status, then the fault
239 PMBusExpectations expectations;
240 setPMBusExpectations(mockPMBus, expectations);
241 psu2.analyze();
242 // Now set fault bits in STATUS_WORD
243 expectations.statusWordValue =
244 (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT);
245 // STATUS_INPUT fault bits ... on.
246 expectations.statusInputValue = 0x38;
247 setPMBusExpectations(mockPMBus, expectations);
248 psu2.analyze();
249 EXPECT_EQ(psu2.isPresent(), true);
250 EXPECT_EQ(psu2.isFaulted(), true);
251 EXPECT_EQ(psu2.hasInputFault(), true);
252 EXPECT_EQ(psu2.hasMFRFault(), false);
253 EXPECT_EQ(psu2.hasVINUVFault(), true);
254 EXPECT_EQ(psu2.hasCommFault(), false);
255 EXPECT_EQ(psu2.hasVoutOVFault(), false);
256 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600257
258 // STATUS_WORD MFR fault.
Brandon Wymanb654c612021-11-05 23:24:51 +0000259 {
260 // First need it to return good status, then the fault
261 PMBusExpectations expectations;
262 setPMBusExpectations(mockPMBus, expectations);
263 psu2.analyze();
264 // Now STATUS_WORD with MFR fault bit on.
265 expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
266 // STATUS_MFR bits on.
267 expectations.statusMFRValue = 0xFF;
268 setPMBusExpectations(mockPMBus, expectations);
269 psu2.analyze();
270 EXPECT_EQ(psu2.isPresent(), true);
271 EXPECT_EQ(psu2.isFaulted(), true);
272 EXPECT_EQ(psu2.hasInputFault(), false);
273 EXPECT_EQ(psu2.hasMFRFault(), true);
274 EXPECT_EQ(psu2.hasVINUVFault(), false);
275 EXPECT_EQ(psu2.hasCommFault(), false);
276 EXPECT_EQ(psu2.hasVoutOVFault(), false);
277 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600278
279 // Ignore Temperature fault.
Brandon Wymanb654c612021-11-05 23:24:51 +0000280 {
281 // First STATUS_WORD with no bits set, then with temperature fault.
282 PMBusExpectations expectations;
283 setPMBusExpectations(mockPMBus, expectations);
284 psu2.analyze();
285 // STATUS_WORD with temperature fault bit on.
286 expectations.statusWordValue = (status_word::TEMPERATURE_FAULT_WARN);
287 // STATUS_INPUT, STATUS_MFR, STATUS_CML, and STATUS_VOUT fault bits ...
288 // don't care (defaults).
289 setPMBusExpectations(mockPMBus, expectations);
290 psu2.analyze();
291 EXPECT_EQ(psu2.isPresent(), true);
292 EXPECT_EQ(psu2.isFaulted(), false);
293 EXPECT_EQ(psu2.hasInputFault(), false);
294 EXPECT_EQ(psu2.hasMFRFault(), false);
295 EXPECT_EQ(psu2.hasVINUVFault(), false);
296 EXPECT_EQ(psu2.hasCommFault(), false);
297 EXPECT_EQ(psu2.hasVoutOVFault(), false);
298 }
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000299
300 // CML fault
Brandon Wymanb654c612021-11-05 23:24:51 +0000301 {
302 // First STATUS_WORD wit no bits set, then with CML fault.
303 PMBusExpectations expectations;
304 setPMBusExpectations(mockPMBus, expectations);
305 psu2.analyze();
306 // STATUS_WORD with CML fault bit on.
307 expectations.statusWordValue = (status_word::CML_FAULT);
308 // Turn on STATUS_CML fault bit(s)
309 expectations.statusCMLValue = 0xFF;
310 setPMBusExpectations(mockPMBus, expectations);
311 psu2.analyze();
312 EXPECT_EQ(psu2.isPresent(), true);
313 EXPECT_EQ(psu2.isFaulted(), true);
314 EXPECT_EQ(psu2.hasInputFault(), false);
315 EXPECT_EQ(psu2.hasMFRFault(), false);
316 EXPECT_EQ(psu2.hasVINUVFault(), false);
317 EXPECT_EQ(psu2.hasCommFault(), true);
318 EXPECT_EQ(psu2.hasVoutOVFault(), false);
319 }
Brandon Wyman6710ba22021-10-27 17:39:31 +0000320
321 // VOUT_OV_FAULT fault
Brandon Wymanb654c612021-11-05 23:24:51 +0000322 {
323 // First STATUS_WORD with no bits set, then with VOUT/VOUT_OV fault.
324 PMBusExpectations expectations;
325 setPMBusExpectations(mockPMBus, expectations);
326 psu2.analyze();
327 // STATUS_WORD with VOUT/VOUT_OV fault.
328 expectations.statusWordValue =
329 ((status_word::VOUT_FAULT) | (status_word::VOUT_OV_FAULT));
330 // Turn on STATUS_VOUT fault bit(s)
331 expectations.statusVOUTValue = 0xA0;
332 setPMBusExpectations(mockPMBus, expectations);
333 psu2.analyze();
334 EXPECT_EQ(psu2.isPresent(), true);
335 EXPECT_EQ(psu2.isFaulted(), true);
336 EXPECT_EQ(psu2.hasInputFault(), false);
337 EXPECT_EQ(psu2.hasMFRFault(), false);
338 EXPECT_EQ(psu2.hasVINUVFault(), false);
339 EXPECT_EQ(psu2.hasCommFault(), false);
340 EXPECT_EQ(psu2.hasVoutOVFault(), true);
341 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600342
343 // Ignore fan fault
Brandon Wymanb654c612021-11-05 23:24:51 +0000344 {
345 // First STATUS_WORD with no bits set, then with fan fault.
346 PMBusExpectations expectations;
347 setPMBusExpectations(mockPMBus, expectations);
348 psu2.analyze();
349 expectations.statusWordValue = (status_word::FAN_FAULT);
350 setPMBusExpectations(mockPMBus, expectations);
351 psu2.analyze();
352 EXPECT_EQ(psu2.isPresent(), true);
353 EXPECT_EQ(psu2.isFaulted(), false);
354 EXPECT_EQ(psu2.hasInputFault(), false);
355 EXPECT_EQ(psu2.hasMFRFault(), false);
356 EXPECT_EQ(psu2.hasVINUVFault(), false);
357 EXPECT_EQ(psu2.hasCommFault(), false);
358 EXPECT_EQ(psu2.hasVoutOVFault(), false);
359 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600360 // TODO: ReadFailure
361}
362
Brandon Wyman59a35792020-06-04 12:37:40 -0500363TEST_F(PowerSupplyTests, OnOffConfig)
364{
365 auto bus = sdbusplus::bus::new_default();
366 uint8_t data = 0x15;
367
368 // Test where PSU is NOT present
369 try
370 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000371 // Assume GPIO presence, not inventory presence?
372 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
373
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000374 MockedGPIOInterface* mockPresenceGPIO =
375 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000376 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(0));
Brandon Wyman59a35792020-06-04 12:37:40 -0500377 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000378 // Constructor should set initial presence, default read returns 0.
Brandon Wyman59a35792020-06-04 12:37:40 -0500379 // If it is not present, I should not be trying to write to it.
380 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0);
381 psu.onOffConfig(data);
382 }
383 catch (...)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +0000384 {}
Brandon Wyman59a35792020-06-04 12:37:40 -0500385
386 // Test where PSU is present
387 try
388 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000389 // Assume GPIO presence, not inventory presence?
390 PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000391 MockedGPIOInterface* mockPresenceGPIO =
392 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000393 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
Brandon Wyman59a35792020-06-04 12:37:40 -0500394 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000395 // TODO: expect setPresence call?
396 // updatePresence() private function reads gpio, called by analyze().
397 psu.analyze();
Brandon Wyman59a35792020-06-04 12:37:40 -0500398 // TODO: ???should I check the filename?
399 EXPECT_CALL(mockPMBus,
400 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug))
401 .Times(1);
402 psu.onOffConfig(data);
403 }
404 catch (...)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +0000405 {}
Brandon Wyman59a35792020-06-04 12:37:40 -0500406}
407
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600408TEST_F(PowerSupplyTests, ClearFaults)
409{
410 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000411 PowerSupply psu{bus, PSUInventoryPath, 13, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000412 MockedGPIOInterface* mockPresenceGPIO =
413 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000414 // GPIO read return 1 to indicate present.
415 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
416 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Brandon Wyman8da35c52021-10-28 22:45:08 +0000417 // Presence change from missing to present will trigger in1_input read in
418 // an attempt to get CLEAR_FAULTS called.
419 EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
420 // STATUS_WORD 0x0000 is powered on, no faults.
Brandon Wymanb654c612021-11-05 23:24:51 +0000421 PMBusExpectations expectations;
422 setPMBusExpectations(mockPMBus, expectations);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000423 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600424 EXPECT_EQ(psu.isPresent(), true);
425 EXPECT_EQ(psu.isFaulted(), false);
426 EXPECT_EQ(psu.hasInputFault(), false);
427 EXPECT_EQ(psu.hasMFRFault(), false);
428 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000429 EXPECT_EQ(psu.hasCommFault(), false);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000430 EXPECT_EQ(psu.hasVoutOVFault(), false);
Brandon Wymanb654c612021-11-05 23:24:51 +0000431
Brandon Wymanf07bc792021-10-12 19:00:35 +0000432 // STATUS_WORD with fault bits galore!
Brandon Wymanb654c612021-11-05 23:24:51 +0000433 expectations.statusWordValue = 0xFFFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000434 // STATUS_INPUT with fault bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000435 expectations.statusInputValue = 0xFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000436 // STATUS_MFR_SPEFIC with bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000437 expectations.statusMFRValue = 0xFF;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000438 // STATUS_CML with bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000439 expectations.statusCMLValue = 0xFF;
Brandon Wyman6710ba22021-10-27 17:39:31 +0000440 // STATUS_VOUT with bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000441 expectations.statusVOUTValue = 0xFF;
442 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600443 psu.analyze();
444 EXPECT_EQ(psu.isPresent(), true);
445 EXPECT_EQ(psu.isFaulted(), true);
446 EXPECT_EQ(psu.hasInputFault(), true);
447 EXPECT_EQ(psu.hasMFRFault(), true);
448 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000449 EXPECT_EQ(psu.hasCommFault(), true);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000450 EXPECT_EQ(psu.hasVoutOVFault(), true);
Brandon Wyman3c208462020-05-13 16:25:58 -0500451 EXPECT_CALL(mockPMBus, read("in1_input", _))
452 .Times(1)
453 .WillOnce(Return(209000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600454 psu.clearFaults();
455 EXPECT_EQ(psu.isPresent(), true);
456 EXPECT_EQ(psu.isFaulted(), false);
457 EXPECT_EQ(psu.hasInputFault(), false);
458 EXPECT_EQ(psu.hasMFRFault(), false);
459 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000460 EXPECT_EQ(psu.hasCommFault(), false);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000461 EXPECT_EQ(psu.hasVoutOVFault(), false);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000462
463 // TODO: Faults clear on missing/present?
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600464}
465
466TEST_F(PowerSupplyTests, UpdateInventory)
467{
468 auto bus = sdbusplus::bus::new_default();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500469
470 try
471 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000472 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500473 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
474 // If it is not present, I should not be trying to read a string
475 EXPECT_CALL(mockPMBus, readString(_, _)).Times(0);
476 psu.updateInventory();
477 }
478 catch (...)
479 {
480 ADD_FAILURE() << "Should not have caught exception.";
481 }
482
483 try
484 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000485 PowerSupply psu{bus, PSUInventoryPath, 13, 0x69, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000486 MockedGPIOInterface* mockPresenceGPIO =
487 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000488 // GPIO read return 1 to indicate present.
489 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1));
490 psu.analyze();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500491 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
492 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
493 psu.updateInventory();
494
Brandon Wyman3c530fb2021-04-13 13:13:22 -0500495#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500496 EXPECT_CALL(mockPMBus, readString(_, _))
497 .WillOnce(Return("CCIN"))
498 .WillOnce(Return("PN3456"))
499 .WillOnce(Return("FN3456"))
500 .WillOnce(Return("HEADER"))
501 .WillOnce(Return("SN3456"))
502 .WillOnce(Return("FW3456"));
Brandon Wyman3c530fb2021-04-13 13:13:22 -0500503#endif
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500504 psu.updateInventory();
505 // TODO: D-Bus mocking to verify values stored on D-Bus (???)
506 }
507 catch (...)
508 {
509 ADD_FAILURE() << "Should not have caught exception.";
510 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600511}
512
513TEST_F(PowerSupplyTests, IsPresent)
514{
515 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000516
517 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000518 MockedGPIOInterface* mockPresenceGPIO =
519 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600520 EXPECT_EQ(psu.isPresent(), false);
521
B. J. Wyman681b2a32021-04-20 22:31:22 +0000522 // Change GPIO read to return 1 to indicate present.
523 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1));
524 psu.analyze();
525 EXPECT_EQ(psu.isPresent(), true);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600526}
527
528TEST_F(PowerSupplyTests, IsFaulted)
529{
530 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000531
532 PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000533 MockedGPIOInterface* mockPresenceGPIO =
534 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000535 // Always return 1 to indicate present.
536 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
537 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600538 EXPECT_EQ(psu.isFaulted(), false);
539 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Brandon Wymanb654c612021-11-05 23:24:51 +0000540 PMBusExpectations expectations;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000541 // STATUS_WORD with fault bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000542 expectations.statusWordValue = 0xFFFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000543 // STATUS_INPUT with fault bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000544 expectations.statusInputValue = 0xFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000545 // STATUS_MFR_SPECIFIC with faults bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000546 expectations.statusMFRValue = 0xFF;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000547 // STATUS_CML with faults bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000548 expectations.statusCMLValue = 0xFF;
Brandon Wyman6710ba22021-10-27 17:39:31 +0000549 // STATUS_VOUT with fault bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000550 expectations.statusVOUTValue = 0xFF;
551 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600552 psu.analyze();
553 EXPECT_EQ(psu.isFaulted(), true);
554}
555
556TEST_F(PowerSupplyTests, HasInputFault)
557{
558 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000559
560 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000561 MockedGPIOInterface* mockPresenceGPIO =
562 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000563 // Always return 1 to indicate present.
564 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
565 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600566 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
567 EXPECT_EQ(psu.hasInputFault(), false);
Brandon Wyman8da35c52021-10-28 22:45:08 +0000568 // STATUS_WORD 0x0000 is powered on, no faults.
Brandon Wymanb654c612021-11-05 23:24:51 +0000569 PMBusExpectations expectations;
570 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600571 psu.analyze();
572 EXPECT_EQ(psu.hasInputFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000573 // STATUS_WORD with input fault/warn on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000574 expectations.statusWordValue = (status_word::INPUT_FAULT_WARN);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000575 // STATUS_INPUT with an input fault bit on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000576 expectations.statusInputValue = 0x80;
577 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600578 psu.analyze();
579 EXPECT_EQ(psu.hasInputFault(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000580 // STATUS_WORD with no bits on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000581 expectations.statusWordValue = 0;
582 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600583 psu.analyze();
584 EXPECT_EQ(psu.hasInputFault(), false);
585}
586
587TEST_F(PowerSupplyTests, HasMFRFault)
588{
589 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000590
591 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000592 MockedGPIOInterface* mockPresenceGPIO =
593 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000594 // Always return 1 to indicate present.
595 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
596 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600597 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
598 EXPECT_EQ(psu.hasMFRFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000599 // First return STATUS_WORD with no bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000600 // STATUS_WORD 0x0000 is powered on, no faults.
Brandon Wymanb654c612021-11-05 23:24:51 +0000601 PMBusExpectations expectations;
602 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600603 psu.analyze();
604 EXPECT_EQ(psu.hasMFRFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000605 // Next return STATUS_WORD with MFR fault bit on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000606 expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000607 // STATUS_MFR_SPEFIC with bit(s) on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000608 expectations.statusMFRValue = 0xFF;
609 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600610 psu.analyze();
611 EXPECT_EQ(psu.hasMFRFault(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000612 // Back to no bits on in STATUS_WORD
Brandon Wymanb654c612021-11-05 23:24:51 +0000613 expectations.statusWordValue = 0;
614 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600615 psu.analyze();
616 EXPECT_EQ(psu.hasMFRFault(), false);
617}
618
619TEST_F(PowerSupplyTests, HasVINUVFault)
620{
621 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000622
623 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000624 MockedGPIOInterface* mockPresenceGPIO =
625 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000626 // Always return 1 to indicate present.
627 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
628 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600629 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
630 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman8da35c52021-10-28 22:45:08 +0000631 // STATUS_WORD 0x0000 is powered on, no faults.
Brandon Wymanb654c612021-11-05 23:24:51 +0000632 PMBusExpectations expectations;
633 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600634 psu.analyze();
635 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000636 // Turn fault on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000637 expectations.statusWordValue = (status_word::VIN_UV_FAULT);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000638 // Curious disagreement between PMBus Spec. Part II Figure 16 and 33. Go by
639 // Figure 16, and assume bits on in STATUS_INPUT.
Brandon Wymanb654c612021-11-05 23:24:51 +0000640 expectations.statusInputValue = 0x18;
641 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600642 psu.analyze();
643 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000644 // Back to no fault bits on in STATUS_WORD
Brandon Wymanb654c612021-11-05 23:24:51 +0000645 expectations.statusWordValue = 0;
646 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600647 psu.analyze();
648 EXPECT_EQ(psu.hasVINUVFault(), false);
649}
Brandon Wyman6710ba22021-10-27 17:39:31 +0000650
651TEST_F(PowerSupplyTests, HasVoutOVFault)
652{
653 auto bus = sdbusplus::bus::new_default();
654
655 PowerSupply psu{bus, PSUInventoryPath, 3, 0x69, PSUGPIOLineName};
656 MockedGPIOInterface* mockPresenceGPIO =
657 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
658 // Always return 1 to indicate present.
659 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
660 psu.analyze();
661 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
662 EXPECT_EQ(psu.hasVoutOVFault(), false);
663 // STATUS_WORD 0x0000 is powered on, no faults.
Brandon Wymanb654c612021-11-05 23:24:51 +0000664 PMBusExpectations expectations;
665 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000666 psu.analyze();
667 EXPECT_EQ(psu.hasVoutOVFault(), false);
668 // Turn fault on.
Brandon Wymanb654c612021-11-05 23:24:51 +0000669 expectations.statusWordValue = (status_word::VOUT_OV_FAULT);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000670 // STATUS_VOUT fault bit(s)
Brandon Wymanb654c612021-11-05 23:24:51 +0000671 expectations.statusVOUTValue = 0x80;
672 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000673 psu.analyze();
674 EXPECT_EQ(psu.hasVoutOVFault(), true);
675 // Back to no fault bits on in STATUS_WORD
Brandon Wymanb654c612021-11-05 23:24:51 +0000676 expectations.statusWordValue = 0;
677 setPMBusExpectations(mockPMBus, expectations);
Brandon Wyman6710ba22021-10-27 17:39:31 +0000678 psu.analyze();
679 EXPECT_EQ(psu.hasVoutOVFault(), false);
680}