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 static auto PSUGPIOLineName = "presence-ps0";
24 
25 struct 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     uint8_t statusTempValue{0x00};
33 };
34 
35 // Helper function to setup expectations for various STATUS_* commands
36 void setPMBusExpectations(MockedPMBus& mockPMBus,
37                           const PMBusExpectations& expectations)
38 {
39     EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
40         .Times(1)
41         .WillOnce(Return(expectations.statusWordValue));
42 
43     if (expectations.statusWordValue != 0)
44     {
45         // If fault bits are on in STATUS_WORD, there will also be a read of
46         // STATUS_INPUT, STATUS_MFR, STATUS_CML, STATUS_VOUT (page 0), and
47         // STATUS_TEMPERATURE.
48         EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
49             .Times(1)
50             .WillOnce(Return(expectations.statusInputValue));
51         EXPECT_CALL(mockPMBus, read(STATUS_MFR, _))
52             .Times(1)
53             .WillOnce(Return(expectations.statusMFRValue));
54         EXPECT_CALL(mockPMBus, read(STATUS_CML, _))
55             .Times(1)
56             .WillOnce(Return(expectations.statusCMLValue));
57         // Page will need to be set to 0 to read STATUS_VOUT.
58         EXPECT_CALL(mockPMBus, insertPageNum(STATUS_VOUT, 0))
59             .Times(1)
60             .WillOnce(Return("status0_vout"));
61         EXPECT_CALL(mockPMBus, read("status0_vout", _))
62             .Times(1)
63             .WillOnce(Return(expectations.statusVOUTValue));
64         EXPECT_CALL(mockPMBus, read(STATUS_TEMPERATURE, _))
65             .Times(1)
66             .WillOnce(Return(expectations.statusTempValue));
67     }
68 }
69 
70 class PowerSupplyTests : public ::testing::Test
71 {
72   public:
73     PowerSupplyTests() :
74         mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils()))
75     {
76         ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false));
77     }
78 
79     ~PowerSupplyTests() override
80     {
81         freeUtils();
82     }
83 
84     const MockedUtil& mockedUtil;
85 };
86 
87 TEST_F(PowerSupplyTests, Constructor)
88 {
89     /**
90      * @param[in] invpath - String for inventory path to use
91      * @param[in] i2cbus - The bus number this power supply is on
92      * @param[in] i2caddr - The 16-bit I2C address of the power supply
93      * @param[in] gpioLineName - The string for the gpio-line-name to read for
94      * presence.
95      * @param[in] bindDelay - Time in milliseconds to delay binding the device
96      * driver after seeing the presence line go active.
97      */
98     auto bus = sdbusplus::bus::new_default();
99 
100     // Try where inventory path is empty, constructor should fail.
101     try
102     {
103         auto psu =
104             std::make_unique<PowerSupply>(bus, "", 3, 0x68, PSUGPIOLineName);
105         ADD_FAILURE() << "Should not have reached this line.";
106     }
107     catch (const std::invalid_argument& e)
108     {
109         EXPECT_STREQ(e.what(), "Invalid empty inventoryPath");
110     }
111     catch (...)
112     {
113         ADD_FAILURE() << "Should not have caught exception.";
114     }
115 
116     // TODO: Try invalid i2c address?
117 
118     // Try where gpioLineName is empty.
119     try
120     {
121         auto psu =
122             std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68, "");
123         ADD_FAILURE()
124             << "Should not have reached this line. Invalid gpioLineName.";
125     }
126     catch (const std::invalid_argument& e)
127     {
128         EXPECT_STREQ(e.what(), "Invalid empty gpioLineName");
129     }
130     catch (...)
131     {
132         ADD_FAILURE() << "Should not have caught exception.";
133     }
134 
135     // Test with valid arguments
136     // NOT using D-Bus inventory path for presence.
137     try
138     {
139         auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68,
140                                                  PSUGPIOLineName);
141 
142         EXPECT_EQ(psu->isPresent(), false);
143         EXPECT_EQ(psu->isFaulted(), false);
144         EXPECT_EQ(psu->hasCommFault(), false);
145         EXPECT_EQ(psu->hasInputFault(), false);
146         EXPECT_EQ(psu->hasMFRFault(), false);
147         EXPECT_EQ(psu->hasVINUVFault(), false);
148         EXPECT_EQ(psu->hasVoutOVFault(), false);
149         EXPECT_EQ(psu->hasTempFault(), false);
150         EXPECT_EQ(psu->hasPgoodFault(), false);
151     }
152     catch (...)
153     {
154         ADD_FAILURE() << "Should not have caught exception.";
155     }
156 
157     // Test with valid arguments
158     // TODO: Using D-Bus inventory path for presence.
159     try
160     {
161         // FIXME: How do I get that presenceGPIO.read() in the startup to throw
162         // an exception?
163 
164         // EXPECT_CALL(mockedUtil, getPresence(_,
165         // StrEq(PSUInventoryPath)))
166         //    .Times(1);
167     }
168     catch (...)
169     {
170         ADD_FAILURE() << "Should not have caught exception.";
171     }
172 }
173 
174 TEST_F(PowerSupplyTests, Analyze)
175 {
176     auto bus = sdbusplus::bus::new_default();
177 
178     {
179         // If I default to reading the GPIO, I will NOT expect a call to
180         // getPresence().
181 
182         PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
183         MockedGPIOInterface* mockPresenceGPIO =
184             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
185         EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(0));
186 
187         psu.analyze();
188         // By default, nothing should change.
189         EXPECT_EQ(psu.isPresent(), false);
190         EXPECT_EQ(psu.isFaulted(), false);
191         EXPECT_EQ(psu.hasInputFault(), false);
192         EXPECT_EQ(psu.hasMFRFault(), false);
193         EXPECT_EQ(psu.hasVINUVFault(), false);
194         EXPECT_EQ(psu.hasCommFault(), false);
195         EXPECT_EQ(psu.hasVoutOVFault(), false);
196         EXPECT_EQ(psu.hasTempFault(), false);
197         EXPECT_EQ(psu.hasPgoodFault(), false);
198     }
199 
200     PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
201     // In order to get the various faults tested, the power supply needs to
202     // be present in order to read from the PMBus device(s).
203     MockedGPIOInterface* mockPresenceGPIO2 =
204         static_cast<MockedGPIOInterface*>(psu2.getPresenceGPIO());
205     ON_CALL(*mockPresenceGPIO2, read()).WillByDefault(Return(1));
206     EXPECT_EQ(psu2.isPresent(), false);
207 
208     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
209     // Presence change from missing to present will trigger write to
210     // ON_OFF_CONFIG.
211     EXPECT_CALL(mockPMBus, writeBinary(ON_OFF_CONFIG, _, _));
212     // Presence change from missing to present will trigger in1_input read
213     // in an attempt to get CLEAR_FAULTS called.
214     EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
215 
216     // STATUS_WORD INPUT fault.
217     {
218         // Start with STATUS_WORD 0x0000. Powered on, no faults.
219         // Set expectations for a no fault
220         PMBusExpectations expectations;
221         setPMBusExpectations(mockPMBus, expectations);
222         psu2.analyze();
223         EXPECT_EQ(psu2.isPresent(), true);
224         EXPECT_EQ(psu2.isFaulted(), false);
225         EXPECT_EQ(psu2.hasInputFault(), false);
226         EXPECT_EQ(psu2.hasMFRFault(), false);
227         EXPECT_EQ(psu2.hasVINUVFault(), false);
228         EXPECT_EQ(psu2.hasCommFault(), false);
229         EXPECT_EQ(psu2.hasVoutOVFault(), false);
230         EXPECT_EQ(psu2.hasTempFault(), false);
231         EXPECT_EQ(psu2.hasPgoodFault(), false);
232 
233         // Update expectations for STATUS_WORD input fault/warn
234         // STATUS_INPUT fault bits ... on.
235         expectations.statusWordValue = (status_word::INPUT_FAULT_WARN);
236         expectations.statusInputValue = 0x38;
237         setPMBusExpectations(mockPMBus, expectations);
238         psu2.analyze();
239         EXPECT_EQ(psu2.isPresent(), true);
240         EXPECT_EQ(psu2.isFaulted(), true);
241         EXPECT_EQ(psu2.hasInputFault(), true);
242         EXPECT_EQ(psu2.hasMFRFault(), false);
243         EXPECT_EQ(psu2.hasVINUVFault(), false);
244         EXPECT_EQ(psu2.hasCommFault(), false);
245         EXPECT_EQ(psu2.hasVoutOVFault(), false);
246         EXPECT_EQ(psu2.hasTempFault(), false);
247         EXPECT_EQ(psu2.hasPgoodFault(), false);
248     }
249 
250     // STATUS_WORD INPUT/UV fault.
251     {
252         // First need it to return good status, then the fault
253         PMBusExpectations expectations;
254         setPMBusExpectations(mockPMBus, expectations);
255         psu2.analyze();
256         // Now set fault bits in STATUS_WORD
257         expectations.statusWordValue =
258             (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT);
259         // STATUS_INPUT fault bits ... on.
260         expectations.statusInputValue = 0x38;
261         setPMBusExpectations(mockPMBus, expectations);
262         psu2.analyze();
263         EXPECT_EQ(psu2.isPresent(), true);
264         EXPECT_EQ(psu2.isFaulted(), true);
265         EXPECT_EQ(psu2.hasInputFault(), true);
266         EXPECT_EQ(psu2.hasMFRFault(), false);
267         EXPECT_EQ(psu2.hasVINUVFault(), true);
268         EXPECT_EQ(psu2.hasCommFault(), false);
269         EXPECT_EQ(psu2.hasVoutOVFault(), false);
270         EXPECT_EQ(psu2.hasTempFault(), false);
271         EXPECT_EQ(psu2.hasPgoodFault(), false);
272     }
273 
274     // STATUS_WORD MFR fault.
275     {
276         // First need it to return good status, then the fault
277         PMBusExpectations expectations;
278         setPMBusExpectations(mockPMBus, expectations);
279         psu2.analyze();
280         // Now STATUS_WORD with MFR fault bit on.
281         expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
282         // STATUS_MFR bits on.
283         expectations.statusMFRValue = 0xFF;
284         setPMBusExpectations(mockPMBus, expectations);
285         psu2.analyze();
286         EXPECT_EQ(psu2.isPresent(), true);
287         EXPECT_EQ(psu2.isFaulted(), true);
288         EXPECT_EQ(psu2.hasInputFault(), false);
289         EXPECT_EQ(psu2.hasMFRFault(), true);
290         EXPECT_EQ(psu2.hasVINUVFault(), false);
291         EXPECT_EQ(psu2.hasCommFault(), false);
292         EXPECT_EQ(psu2.hasVoutOVFault(), false);
293         EXPECT_EQ(psu2.hasTempFault(), false);
294         EXPECT_EQ(psu2.hasPgoodFault(), false);
295     }
296 
297     // Temperature fault.
298     {
299         // First STATUS_WORD with no bits set, then with temperature fault.
300         PMBusExpectations expectations;
301         setPMBusExpectations(mockPMBus, expectations);
302         psu2.analyze();
303         // STATUS_WORD with temperature fault bit on.
304         expectations.statusWordValue = (status_word::TEMPERATURE_FAULT_WARN);
305         // STATUS_TEMPERATURE with fault bit(s) on.
306         expectations.statusTempValue = 0x10;
307         setPMBusExpectations(mockPMBus, expectations);
308         psu2.analyze();
309         EXPECT_EQ(psu2.isPresent(), true);
310         EXPECT_EQ(psu2.isFaulted(), true);
311         EXPECT_EQ(psu2.hasInputFault(), false);
312         EXPECT_EQ(psu2.hasMFRFault(), false);
313         EXPECT_EQ(psu2.hasVINUVFault(), false);
314         EXPECT_EQ(psu2.hasCommFault(), false);
315         EXPECT_EQ(psu2.hasVoutOVFault(), false);
316         EXPECT_EQ(psu2.hasTempFault(), true);
317         EXPECT_EQ(psu2.hasPgoodFault(), false);
318     }
319 
320     // CML fault
321     {
322         // First STATUS_WORD wit no bits set, then with CML fault.
323         PMBusExpectations expectations;
324         setPMBusExpectations(mockPMBus, expectations);
325         psu2.analyze();
326         // STATUS_WORD with CML fault bit on.
327         expectations.statusWordValue = (status_word::CML_FAULT);
328         // Turn on STATUS_CML fault bit(s)
329         expectations.statusCMLValue = 0xFF;
330         setPMBusExpectations(mockPMBus, expectations);
331         psu2.analyze();
332         EXPECT_EQ(psu2.isPresent(), true);
333         EXPECT_EQ(psu2.isFaulted(), true);
334         EXPECT_EQ(psu2.hasInputFault(), false);
335         EXPECT_EQ(psu2.hasMFRFault(), false);
336         EXPECT_EQ(psu2.hasVINUVFault(), false);
337         EXPECT_EQ(psu2.hasCommFault(), true);
338         EXPECT_EQ(psu2.hasVoutOVFault(), false);
339         EXPECT_EQ(psu2.hasTempFault(), false);
340         EXPECT_EQ(psu2.hasPgoodFault(), false);
341     }
342 
343     // VOUT_OV_FAULT fault
344     {
345         // First STATUS_WORD with no bits set, then with VOUT/VOUT_OV fault.
346         PMBusExpectations expectations;
347         setPMBusExpectations(mockPMBus, expectations);
348         psu2.analyze();
349         // STATUS_WORD with VOUT/VOUT_OV fault.
350         expectations.statusWordValue =
351             ((status_word::VOUT_FAULT) | (status_word::VOUT_OV_FAULT));
352         // Turn on STATUS_VOUT fault bit(s)
353         expectations.statusVOUTValue = 0xA0;
354         // STATUS_TEMPERATURE don't care (default)
355         setPMBusExpectations(mockPMBus, expectations);
356         psu2.analyze();
357         EXPECT_EQ(psu2.isPresent(), true);
358         EXPECT_EQ(psu2.isFaulted(), true);
359         EXPECT_EQ(psu2.hasInputFault(), false);
360         EXPECT_EQ(psu2.hasMFRFault(), false);
361         EXPECT_EQ(psu2.hasVINUVFault(), false);
362         EXPECT_EQ(psu2.hasCommFault(), false);
363         EXPECT_EQ(psu2.hasVoutOVFault(), true);
364         EXPECT_EQ(psu2.hasTempFault(), false);
365         EXPECT_EQ(psu2.hasPgoodFault(), false);
366     }
367 
368     // Ignore fan fault
369     {
370         // First STATUS_WORD with no bits set, then with fan fault.
371         PMBusExpectations expectations;
372         setPMBusExpectations(mockPMBus, expectations);
373         psu2.analyze();
374         expectations.statusWordValue = (status_word::FAN_FAULT);
375         setPMBusExpectations(mockPMBus, expectations);
376         psu2.analyze();
377         EXPECT_EQ(psu2.isPresent(), true);
378         EXPECT_EQ(psu2.isFaulted(), false);
379         EXPECT_EQ(psu2.hasInputFault(), false);
380         EXPECT_EQ(psu2.hasMFRFault(), false);
381         EXPECT_EQ(psu2.hasVINUVFault(), false);
382         EXPECT_EQ(psu2.hasCommFault(), false);
383         EXPECT_EQ(psu2.hasVoutOVFault(), false);
384         EXPECT_EQ(psu2.hasTempFault(), false);
385         EXPECT_EQ(psu2.hasPgoodFault(), false);
386     }
387 
388     {
389         // PGOOD/OFF fault.
390         // First STATUS_WORD with no bits set.
391         PMBusExpectations expectations;
392         setPMBusExpectations(mockPMBus, expectations);
393         psu2.analyze();
394         EXPECT_EQ(psu2.isFaulted(), false);
395         // POWER_GOOD# inactive, and OFF bit on.
396         expectations.statusWordValue =
397             ((status_word::POWER_GOOD_NEGATED) | (status_word::UNIT_IS_OFF));
398         // STATUS_INPUT, STATUS_MFR, STATUS_CML, STATUS_VOUT, and
399         // STATUS_TEMPERATURE: Don't care if bits set or not (defaults).
400         setPMBusExpectations(mockPMBus, expectations);
401         psu2.analyze();
402         EXPECT_EQ(psu2.isPresent(), true);
403         EXPECT_EQ(psu2.isFaulted(), true);
404         EXPECT_EQ(psu2.hasInputFault(), false);
405         EXPECT_EQ(psu2.hasMFRFault(), false);
406         EXPECT_EQ(psu2.hasVINUVFault(), false);
407         EXPECT_EQ(psu2.hasCommFault(), false);
408         EXPECT_EQ(psu2.hasVoutOVFault(), false);
409         EXPECT_EQ(psu2.hasTempFault(), false);
410         EXPECT_EQ(psu2.hasPgoodFault(), true);
411     }
412 
413     // TODO: ReadFailure
414 }
415 
416 TEST_F(PowerSupplyTests, OnOffConfig)
417 {
418     auto bus = sdbusplus::bus::new_default();
419     uint8_t data = 0x15;
420 
421     // Test where PSU is NOT present
422     try
423     {
424         // Assume GPIO presence, not inventory presence?
425         PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
426 
427         MockedGPIOInterface* mockPresenceGPIO =
428             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
429         ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(0));
430         MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
431         // Constructor should set initial presence, default read returns 0.
432         // If it is not present, I should not be trying to write to it.
433         EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0);
434         psu.onOffConfig(data);
435     }
436     catch (...)
437     {}
438 
439     // Test where PSU is present
440     try
441     {
442         // Assume GPIO presence, not inventory presence?
443         PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
444         MockedGPIOInterface* mockPresenceGPIO =
445             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
446         ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
447         MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
448         // TODO: expect setPresence call?
449         // updatePresence() private function reads gpio, called by analyze().
450         psu.analyze();
451         // TODO: ???should I check the filename?
452         EXPECT_CALL(mockPMBus,
453                     writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug))
454             .Times(1);
455         psu.onOffConfig(data);
456     }
457     catch (...)
458     {}
459 }
460 
461 TEST_F(PowerSupplyTests, ClearFaults)
462 {
463     auto bus = sdbusplus::bus::new_default();
464     PowerSupply psu{bus, PSUInventoryPath, 13, 0x68, PSUGPIOLineName};
465     MockedGPIOInterface* mockPresenceGPIO =
466         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
467     // GPIO read return 1 to indicate present.
468     ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
469     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
470     // Presence change from missing to present will trigger in1_input read in
471     // an attempt to get CLEAR_FAULTS called.
472     EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
473     // STATUS_WORD 0x0000 is powered on, no faults.
474     PMBusExpectations expectations;
475     setPMBusExpectations(mockPMBus, expectations);
476     psu.analyze();
477     EXPECT_EQ(psu.isPresent(), true);
478     EXPECT_EQ(psu.isFaulted(), false);
479     EXPECT_EQ(psu.hasInputFault(), false);
480     EXPECT_EQ(psu.hasMFRFault(), false);
481     EXPECT_EQ(psu.hasVINUVFault(), false);
482     EXPECT_EQ(psu.hasCommFault(), false);
483     EXPECT_EQ(psu.hasVoutOVFault(), false);
484     EXPECT_EQ(psu.hasTempFault(), false);
485     EXPECT_EQ(psu.hasPgoodFault(), false);
486 
487     // STATUS_WORD with fault bits galore!
488     expectations.statusWordValue = 0xFFFF;
489     // STATUS_INPUT with fault bits on.
490     expectations.statusInputValue = 0xFF;
491     // STATUS_MFR_SPEFIC with bits on.
492     expectations.statusMFRValue = 0xFF;
493     // STATUS_CML with bits on.
494     expectations.statusCMLValue = 0xFF;
495     // STATUS_VOUT with bits on.
496     expectations.statusVOUTValue = 0xFF;
497     // STATUS_TEMPERATURE with bits on.
498     expectations.statusTempValue = 0xFF;
499     setPMBusExpectations(mockPMBus, expectations);
500     psu.analyze();
501     EXPECT_EQ(psu.isPresent(), true);
502     EXPECT_EQ(psu.isFaulted(), true);
503     EXPECT_EQ(psu.hasInputFault(), true);
504     EXPECT_EQ(psu.hasMFRFault(), true);
505     EXPECT_EQ(psu.hasVINUVFault(), true);
506     EXPECT_EQ(psu.hasCommFault(), true);
507     EXPECT_EQ(psu.hasVoutOVFault(), true);
508     EXPECT_EQ(psu.hasTempFault(), true);
509     EXPECT_EQ(psu.hasPgoodFault(), true);
510     EXPECT_CALL(mockPMBus, read("in1_input", _))
511         .Times(1)
512         .WillOnce(Return(209000));
513     psu.clearFaults();
514     EXPECT_EQ(psu.isPresent(), true);
515     EXPECT_EQ(psu.isFaulted(), false);
516     EXPECT_EQ(psu.hasInputFault(), false);
517     EXPECT_EQ(psu.hasMFRFault(), false);
518     EXPECT_EQ(psu.hasVINUVFault(), false);
519     EXPECT_EQ(psu.hasCommFault(), false);
520     EXPECT_EQ(psu.hasVoutOVFault(), false);
521     EXPECT_EQ(psu.hasTempFault(), false);
522     EXPECT_EQ(psu.hasPgoodFault(), false);
523 
524     // TODO: Faults clear on missing/present?
525 }
526 
527 TEST_F(PowerSupplyTests, UpdateInventory)
528 {
529     auto bus = sdbusplus::bus::new_default();
530 
531     try
532     {
533         PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
534         MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
535         // If it is not present, I should not be trying to read a string
536         EXPECT_CALL(mockPMBus, readString(_, _)).Times(0);
537         psu.updateInventory();
538     }
539     catch (...)
540     {
541         ADD_FAILURE() << "Should not have caught exception.";
542     }
543 
544     try
545     {
546         PowerSupply psu{bus, PSUInventoryPath, 13, 0x69, PSUGPIOLineName};
547         MockedGPIOInterface* mockPresenceGPIO =
548             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
549         // GPIO read return 1 to indicate present.
550         EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1));
551         psu.analyze();
552         MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
553         EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
554         psu.updateInventory();
555 
556 #if IBM_VPD
557         EXPECT_CALL(mockPMBus, readString(_, _))
558             .WillOnce(Return("CCIN"))
559             .WillOnce(Return("PN3456"))
560             .WillOnce(Return("FN3456"))
561             .WillOnce(Return("HEADER"))
562             .WillOnce(Return("SN3456"))
563             .WillOnce(Return("FW3456"));
564 #endif
565         psu.updateInventory();
566         // TODO: D-Bus mocking to verify values stored on D-Bus (???)
567     }
568     catch (...)
569     {
570         ADD_FAILURE() << "Should not have caught exception.";
571     }
572 }
573 
574 TEST_F(PowerSupplyTests, IsPresent)
575 {
576     auto bus = sdbusplus::bus::new_default();
577 
578     PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
579     MockedGPIOInterface* mockPresenceGPIO =
580         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
581     EXPECT_EQ(psu.isPresent(), false);
582 
583     // Change GPIO read to return 1 to indicate present.
584     EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1));
585     psu.analyze();
586     EXPECT_EQ(psu.isPresent(), true);
587 }
588 
589 TEST_F(PowerSupplyTests, IsFaulted)
590 {
591     auto bus = sdbusplus::bus::new_default();
592 
593     PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f, PSUGPIOLineName};
594     MockedGPIOInterface* mockPresenceGPIO =
595         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
596     // Always return 1 to indicate present.
597     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
598     psu.analyze();
599     EXPECT_EQ(psu.isFaulted(), false);
600     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
601     PMBusExpectations expectations;
602     // STATUS_WORD with fault bits on.
603     expectations.statusWordValue = 0xFFFF;
604     // STATUS_INPUT with fault bits on.
605     expectations.statusInputValue = 0xFF;
606     // STATUS_MFR_SPECIFIC with faults bits on.
607     expectations.statusMFRValue = 0xFF;
608     // STATUS_CML with faults bits on.
609     expectations.statusCMLValue = 0xFF;
610     // STATUS_VOUT with fault bits on.
611     expectations.statusVOUTValue = 0xFF;
612     // STATUS_TEMPERATURE with fault bits on.
613     expectations.statusTempValue = 0xFF;
614     setPMBusExpectations(mockPMBus, expectations);
615     psu.analyze();
616     EXPECT_EQ(psu.isFaulted(), true);
617 }
618 
619 TEST_F(PowerSupplyTests, HasInputFault)
620 {
621     auto bus = sdbusplus::bus::new_default();
622 
623     PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
624     MockedGPIOInterface* mockPresenceGPIO =
625         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
626     // Always return 1 to indicate present.
627     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
628     psu.analyze();
629     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
630     EXPECT_EQ(psu.hasInputFault(), false);
631     // STATUS_WORD 0x0000 is powered on, no faults.
632     PMBusExpectations expectations;
633     setPMBusExpectations(mockPMBus, expectations);
634     psu.analyze();
635     EXPECT_EQ(psu.hasInputFault(), false);
636     // STATUS_WORD with input fault/warn on.
637     expectations.statusWordValue = (status_word::INPUT_FAULT_WARN);
638     // STATUS_INPUT with an input fault bit on.
639     expectations.statusInputValue = 0x80;
640     setPMBusExpectations(mockPMBus, expectations);
641     psu.analyze();
642     EXPECT_EQ(psu.hasInputFault(), true);
643     // STATUS_WORD with no bits on.
644     expectations.statusWordValue = 0;
645     setPMBusExpectations(mockPMBus, expectations);
646     psu.analyze();
647     EXPECT_EQ(psu.hasInputFault(), false);
648 }
649 
650 TEST_F(PowerSupplyTests, HasMFRFault)
651 {
652     auto bus = sdbusplus::bus::new_default();
653 
654     PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
655     MockedGPIOInterface* mockPresenceGPIO =
656         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
657     // Always return 1 to indicate present.
658     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
659     psu.analyze();
660     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
661     EXPECT_EQ(psu.hasMFRFault(), false);
662     // First return STATUS_WORD with no bits on.
663     // STATUS_WORD 0x0000 is powered on, no faults.
664     PMBusExpectations expectations;
665     setPMBusExpectations(mockPMBus, expectations);
666     psu.analyze();
667     EXPECT_EQ(psu.hasMFRFault(), false);
668     // Next return STATUS_WORD with MFR fault bit on.
669     expectations.statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
670     // STATUS_MFR_SPEFIC with bit(s) on.
671     expectations.statusMFRValue = 0xFF;
672     setPMBusExpectations(mockPMBus, expectations);
673     psu.analyze();
674     EXPECT_EQ(psu.hasMFRFault(), true);
675     // Back to no bits on in STATUS_WORD
676     expectations.statusWordValue = 0;
677     setPMBusExpectations(mockPMBus, expectations);
678     psu.analyze();
679     EXPECT_EQ(psu.hasMFRFault(), false);
680 }
681 
682 TEST_F(PowerSupplyTests, HasVINUVFault)
683 {
684     auto bus = sdbusplus::bus::new_default();
685 
686     PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
687     MockedGPIOInterface* mockPresenceGPIO =
688         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
689     // Always return 1 to indicate present.
690     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
691     psu.analyze();
692     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
693     EXPECT_EQ(psu.hasVINUVFault(), false);
694     // STATUS_WORD 0x0000 is powered on, no faults.
695     PMBusExpectations expectations;
696     setPMBusExpectations(mockPMBus, expectations);
697     psu.analyze();
698     EXPECT_EQ(psu.hasVINUVFault(), false);
699     // Turn fault on.
700     expectations.statusWordValue = (status_word::VIN_UV_FAULT);
701     // Curious disagreement between PMBus Spec. Part II Figure 16 and 33. Go by
702     // Figure 16, and assume bits on in STATUS_INPUT.
703     expectations.statusInputValue = 0x18;
704     setPMBusExpectations(mockPMBus, expectations);
705     psu.analyze();
706     EXPECT_EQ(psu.hasVINUVFault(), true);
707     // Back to no fault bits on in STATUS_WORD
708     expectations.statusWordValue = 0;
709     setPMBusExpectations(mockPMBus, expectations);
710     psu.analyze();
711     EXPECT_EQ(psu.hasVINUVFault(), false);
712 }
713 
714 TEST_F(PowerSupplyTests, HasVoutOVFault)
715 {
716     auto bus = sdbusplus::bus::new_default();
717 
718     PowerSupply psu{bus, PSUInventoryPath, 3, 0x69, PSUGPIOLineName};
719     MockedGPIOInterface* mockPresenceGPIO =
720         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
721     // Always return 1 to indicate present.
722     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
723     psu.analyze();
724     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
725     EXPECT_EQ(psu.hasVoutOVFault(), false);
726     // STATUS_WORD 0x0000 is powered on, no faults.
727     PMBusExpectations expectations;
728     setPMBusExpectations(mockPMBus, expectations);
729     psu.analyze();
730     EXPECT_EQ(psu.hasVoutOVFault(), false);
731     // Turn fault on.
732     expectations.statusWordValue = (status_word::VOUT_OV_FAULT);
733     // STATUS_VOUT fault bit(s)
734     expectations.statusVOUTValue = 0x80;
735     // STATUS_TEMPERATURE default.
736     setPMBusExpectations(mockPMBus, expectations);
737     psu.analyze();
738     EXPECT_EQ(psu.hasVoutOVFault(), true);
739     // Back to no fault bits on in STATUS_WORD
740     expectations.statusWordValue = 0;
741     setPMBusExpectations(mockPMBus, expectations);
742     psu.analyze();
743     EXPECT_EQ(psu.hasVoutOVFault(), false);
744 }
745 
746 TEST_F(PowerSupplyTests, HasTempFault)
747 {
748     auto bus = sdbusplus::bus::new_default();
749 
750     PowerSupply psu{bus, PSUInventoryPath, 3, 0x6a, PSUGPIOLineName};
751     MockedGPIOInterface* mockPresenceGPIO =
752         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
753     // Always return 1 to indicate present.
754     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
755     psu.analyze();
756     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
757     EXPECT_EQ(psu.hasTempFault(), false);
758     // STATUS_WORD 0x0000 is powered on, no faults.
759     PMBusExpectations expectations;
760     setPMBusExpectations(mockPMBus, expectations);
761     psu.analyze();
762     EXPECT_EQ(psu.hasTempFault(), false);
763     // Turn fault on.
764     expectations.statusWordValue = (status_word::TEMPERATURE_FAULT_WARN);
765     // STATUS_TEMPERATURE fault bit on (OT Fault)
766     expectations.statusTempValue = 0x80;
767     setPMBusExpectations(mockPMBus, expectations);
768     psu.analyze();
769     EXPECT_EQ(psu.hasTempFault(), true);
770     // Back to no fault bits on in STATUS_WORD
771     expectations.statusWordValue = 0;
772     setPMBusExpectations(mockPMBus, expectations);
773     psu.analyze();
774     EXPECT_EQ(psu.hasTempFault(), false);
775 }
776 
777 TEST_F(PowerSupplyTests, HasPgoodFault)
778 {
779     auto bus = sdbusplus::bus::new_default();
780 
781     PowerSupply psu{bus, PSUInventoryPath, 3, 0x6b, PSUGPIOLineName};
782     MockedGPIOInterface* mockPresenceGPIO =
783         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
784     // Always return 1 to indicate present.
785     EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
786     psu.analyze();
787     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
788     EXPECT_EQ(psu.hasPgoodFault(), false);
789     // STATUS_WORD 0x0000 is powered on, no faults.
790     PMBusExpectations expectations;
791     setPMBusExpectations(mockPMBus, expectations);
792     psu.analyze();
793     EXPECT_EQ(psu.hasPgoodFault(), false);
794     // Turn PGOOD# off (fault on).
795     expectations.statusWordValue = (status_word::POWER_GOOD_NEGATED);
796     setPMBusExpectations(mockPMBus, expectations);
797     psu.analyze();
798     EXPECT_EQ(psu.hasPgoodFault(), true);
799     // Back to no fault bits on in STATUS_WORD
800     expectations.statusWordValue = 0;
801     setPMBusExpectations(mockPMBus, expectations);
802     psu.analyze();
803     EXPECT_EQ(psu.hasPgoodFault(), false);
804     // Turn OFF bit on
805     expectations.statusWordValue = (status_word::UNIT_IS_OFF);
806     setPMBusExpectations(mockPMBus, expectations);
807     psu.analyze();
808     EXPECT_EQ(psu.hasPgoodFault(), true);
809     // Back to no fault bits on in STATUS_WORD
810     expectations.statusWordValue = 0;
811     setPMBusExpectations(mockPMBus, expectations);
812     psu.analyze();
813     EXPECT_EQ(psu.hasPgoodFault(), false);
814 }
815