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