blob: 04c0fc706cd605c59c47ea415c3ea2ecad7a1725 [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 Wyman8da35c52021-10-28 22:45:08 +000025// Helper function to setup expectations for various STATUS_* commands
26void setPMBusExpectations(MockedPMBus& mockPMBus, uint16_t statusWordValue,
27 uint8_t statusInputValue = 0,
28 uint8_t statusMFRValue = 0,
29 uint8_t statusCMLValue = 0)
30{
31 EXPECT_CALL(mockPMBus, read(STATUS_WORD, _))
32 .Times(1)
33 .WillOnce(Return(statusWordValue));
34
35 if (statusWordValue != 0)
36 {
37 // If fault bits are on in STATUS_WORD, there will also be a read of
38 // STATUS_INPUT, STATUS_MFR, and STATUS_CML.
39 EXPECT_CALL(mockPMBus, read(STATUS_INPUT, _))
40 .Times(1)
41 .WillOnce(Return(statusInputValue));
42 EXPECT_CALL(mockPMBus, read(STATUS_MFR, _))
43 .Times(1)
44 .WillOnce(Return(statusMFRValue));
45 EXPECT_CALL(mockPMBus, read(STATUS_CML, _))
46 .Times(1)
47 .WillOnce(Return(statusCMLValue));
48 }
49}
50
Brandon Wyman3f1242f2020-01-28 13:11:25 -060051class PowerSupplyTests : public ::testing::Test
52{
53 public:
54 PowerSupplyTests() :
55 mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils()))
56 {
57 ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false));
58 }
59
60 ~PowerSupplyTests() override
61 {
62 freeUtils();
63 }
64
65 const MockedUtil& mockedUtil;
66};
67
68TEST_F(PowerSupplyTests, Constructor)
69{
70 /**
71 * @param[in] invpath - String for inventory path to use
72 * @param[in] i2cbus - The bus number this power supply is on
73 * @param[in] i2caddr - The 16-bit I2C address of the power supply
B. J. Wyman681b2a32021-04-20 22:31:22 +000074 * @param[in] gpioLineName - The string for the gpio-line-name to read for
75 * presence.
76 * @param[in] bindDelay - Time in milliseconds to delay binding the device
77 * driver after seeing the presence line go active.
Brandon Wyman3f1242f2020-01-28 13:11:25 -060078 */
79 auto bus = sdbusplus::bus::new_default();
Brandon Wyman3f1242f2020-01-28 13:11:25 -060080
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050081 // Try where inventory path is empty, constructor should fail.
82 try
83 {
B. J. Wyman681b2a32021-04-20 22:31:22 +000084 auto psu =
85 std::make_unique<PowerSupply>(bus, "", 3, 0x68, PSUGPIOLineName);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050086 ADD_FAILURE() << "Should not have reached this line.";
87 }
88 catch (const std::invalid_argument& e)
89 {
90 EXPECT_STREQ(e.what(), "Invalid empty inventoryPath");
91 }
92 catch (...)
93 {
94 ADD_FAILURE() << "Should not have caught exception.";
95 }
96
B. J. Wyman681b2a32021-04-20 22:31:22 +000097 // TODO: Try invalid i2c address?
98
99 // Try where gpioLineName is empty.
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500100 try
101 {
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500102 auto psu =
B. J. Wyman681b2a32021-04-20 22:31:22 +0000103 std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68, "");
104 ADD_FAILURE()
105 << "Should not have reached this line. Invalid gpioLineName.";
106 }
107 catch (const std::invalid_argument& e)
108 {
109 EXPECT_STREQ(e.what(), "Invalid empty gpioLineName");
110 }
111 catch (...)
112 {
113 ADD_FAILURE() << "Should not have caught exception.";
114 }
115
116 // Test with valid arguments
117 // NOT using D-Bus inventory path for presence.
118 try
119 {
120 auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68,
121 PSUGPIOLineName);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500122
123 EXPECT_EQ(psu->isPresent(), false);
124 EXPECT_EQ(psu->isFaulted(), false);
Brandon Wyman8da35c52021-10-28 22:45:08 +0000125 EXPECT_EQ(psu->hasCommFault(), false);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500126 EXPECT_EQ(psu->hasInputFault(), false);
127 EXPECT_EQ(psu->hasMFRFault(), false);
128 EXPECT_EQ(psu->hasVINUVFault(), false);
129 }
130 catch (...)
131 {
132 ADD_FAILURE() << "Should not have caught exception.";
133 }
B. J. Wyman681b2a32021-04-20 22:31:22 +0000134
135 // Test with valid arguments
136 // TODO: Using D-Bus inventory path for presence.
137 try
138 {
139 // FIXME: How do I get that presenceGPIO.read() in the startup to throw
140 // an exception?
141
142 // EXPECT_CALL(mockedUtil, getPresence(_,
143 // StrEq(PSUInventoryPath)))
144 // .Times(1);
145 }
146 catch (...)
147 {
148 ADD_FAILURE() << "Should not have caught exception.";
149 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600150}
151
152TEST_F(PowerSupplyTests, Analyze)
153{
154 auto bus = sdbusplus::bus::new_default();
155
B. J. Wyman681b2a32021-04-20 22:31:22 +0000156 // If I default to reading the GPIO, I will NOT expect a call to
157 // getPresence().
158
159 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000160 MockedGPIOInterface* mockPresenceGPIO =
161 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000162 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(0));
163
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600164 psu.analyze();
165 // By default, nothing should change.
166 EXPECT_EQ(psu.isPresent(), false);
167 EXPECT_EQ(psu.isFaulted(), false);
168 EXPECT_EQ(psu.hasInputFault(), false);
169 EXPECT_EQ(psu.hasMFRFault(), false);
170 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000171 EXPECT_EQ(psu.hasCommFault(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600172
B. J. Wyman681b2a32021-04-20 22:31:22 +0000173 PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
174 // In order to get the various faults tested, the power supply needs to
175 // be present in order to read from the PMBus device(s).
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000176 MockedGPIOInterface* mockPresenceGPIO2 =
177 static_cast<MockedGPIOInterface*>(psu2.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000178 ON_CALL(*mockPresenceGPIO2, read()).WillByDefault(Return(1));
179
180 EXPECT_EQ(psu2.isPresent(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600181
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600182 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
Brandon Wyman8da35c52021-10-28 22:45:08 +0000183 // Presence change from missing to present will trigger write to
184 // ON_OFF_CONFIG.
185 EXPECT_CALL(mockPMBus, writeBinary(ON_OFF_CONFIG, _, _));
Brandon Wymanf07bc792021-10-12 19:00:35 +0000186 // Presence change from missing to present will trigger in1_input read in
187 // an attempt to get CLEAR_FAULTS called.
188 EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000189 // STATUS_WORD 0x0000 is powered on, no faults.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000190 uint16_t statusWordValue = 0;
191 uint8_t statusInputValue = 0;
192 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600193 psu2.analyze();
194 EXPECT_EQ(psu2.isPresent(), true);
195 EXPECT_EQ(psu2.isFaulted(), false);
196 EXPECT_EQ(psu2.hasInputFault(), false);
197 EXPECT_EQ(psu2.hasMFRFault(), false);
198 EXPECT_EQ(psu2.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000199 EXPECT_EQ(psu2.hasCommFault(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600200
201 // STATUS_WORD input fault/warn
Brandon Wyman8da35c52021-10-28 22:45:08 +0000202 statusWordValue = (status_word::INPUT_FAULT_WARN);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000203 // STATUS_INPUT fault bits ... on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000204 statusInputValue = 0x38;
205 // STATUS_MFR and STATUS_CML don't care
206 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600207 psu2.analyze();
208 EXPECT_EQ(psu2.isPresent(), true);
209 EXPECT_EQ(psu2.isFaulted(), true);
210 EXPECT_EQ(psu2.hasInputFault(), true);
211 EXPECT_EQ(psu2.hasMFRFault(), false);
212 EXPECT_EQ(psu2.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000213 EXPECT_EQ(psu2.hasCommFault(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600214
215 // STATUS_WORD INPUT/UV fault.
216 // First need it to return good status, then the fault
Brandon Wyman8da35c52021-10-28 22:45:08 +0000217 statusWordValue = 0;
218 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600219 psu2.analyze();
Brandon Wyman8da35c52021-10-28 22:45:08 +0000220 // Now set fault bits in STATUS_WORD
221 statusWordValue =
222 (status_word::INPUT_FAULT_WARN | status_word::VIN_UV_FAULT);
223 // STATUS_INPUT fault bits ... on.
224 statusInputValue = 0x38;
225 // STATUS_MFR and STATUS_CML don't care
226 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600227 psu2.analyze();
228 EXPECT_EQ(psu2.isPresent(), true);
229 EXPECT_EQ(psu2.isFaulted(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000230 EXPECT_EQ(psu2.hasInputFault(), true);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600231 EXPECT_EQ(psu2.hasMFRFault(), false);
232 EXPECT_EQ(psu2.hasVINUVFault(), true);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000233 EXPECT_EQ(psu2.hasCommFault(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600234
235 // STATUS_WORD MFR fault.
Brandon Wymanf07bc792021-10-12 19:00:35 +0000236 // First need it to return good status, then the fault
Brandon Wyman8da35c52021-10-28 22:45:08 +0000237 statusWordValue = 0;
238 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600239 psu2.analyze();
Brandon Wyman8da35c52021-10-28 22:45:08 +0000240 // Now STATUS_WORD with MFR fault bit on.
241 statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
242 // STATUS_INPUT fault bits ... don't care.
243 statusInputValue = 0;
244 // STATUS_MFR bits on.
245 uint8_t statusMFRValue = 0xFF;
246 // STATUS_CML don't care
247 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue,
248 statusMFRValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600249 psu2.analyze();
250 EXPECT_EQ(psu2.isPresent(), true);
251 EXPECT_EQ(psu2.isFaulted(), true);
252 EXPECT_EQ(psu2.hasInputFault(), false);
253 EXPECT_EQ(psu2.hasMFRFault(), true);
254 EXPECT_EQ(psu2.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000255 EXPECT_EQ(psu2.hasCommFault(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600256
257 // Ignore Temperature fault.
Brandon Wymanf07bc792021-10-12 19:00:35 +0000258 // First STATUS_WORD with no bits set, then with temperature fault.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000259 statusWordValue = 0;
260 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600261 psu2.analyze();
Brandon Wyman8da35c52021-10-28 22:45:08 +0000262 // STATUS_WORD with temperature fault bit on.
263 statusWordValue = (status_word::TEMPERATURE_FAULT_WARN);
264 // STATUS_INPUT, STATUS_MFR, and STATUS_CML fault bits ... don't care.
265 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600266 psu2.analyze();
267 EXPECT_EQ(psu2.isPresent(), true);
268 EXPECT_EQ(psu2.isFaulted(), false);
269 EXPECT_EQ(psu2.hasInputFault(), false);
270 EXPECT_EQ(psu2.hasMFRFault(), false);
271 EXPECT_EQ(psu2.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000272 EXPECT_EQ(psu2.hasCommFault(), false);
273
274 // CML fault
275 // First STATUS_WORD wit no bits set, then with CML fault.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000276 statusWordValue = 0;
277 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000278 psu2.analyze();
Brandon Wyman8da35c52021-10-28 22:45:08 +0000279 // STATUS_WORD with CML fault bit on.
280 statusWordValue = (status_word::CML_FAULT);
281 // STATUS_INPUT fault bits ... don't care.
282 statusInputValue = 0;
283 // STATUS_MFR don't care
284 statusMFRValue = 0;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000285 // Turn on STATUS_CML fault bit(s)
Brandon Wyman8da35c52021-10-28 22:45:08 +0000286 uint8_t statusCMLValue = 0xFF;
287 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue,
288 statusMFRValue, statusCMLValue);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000289 psu2.analyze();
290 EXPECT_EQ(psu2.isPresent(), true);
291 EXPECT_EQ(psu2.isFaulted(), true);
292 EXPECT_EQ(psu2.hasInputFault(), false);
293 EXPECT_EQ(psu2.hasMFRFault(), false);
294 EXPECT_EQ(psu2.hasVINUVFault(), false);
295 EXPECT_EQ(psu2.hasCommFault(), true);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600296
297 // Ignore fan fault
Brandon Wyman8da35c52021-10-28 22:45:08 +0000298 // First STATUS_WORD with no bits set, then with fan
299 // fault.
300 statusWordValue = 0;
301 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600302 psu2.analyze();
Brandon Wyman8da35c52021-10-28 22:45:08 +0000303 statusWordValue = (status_word::FAN_FAULT);
304 // STATUS_INPUT, STATUS_MFR, and STATUS_CML: Don't care if bits set or not.
305 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600306 psu2.analyze();
307 EXPECT_EQ(psu2.isPresent(), true);
308 EXPECT_EQ(psu2.isFaulted(), false);
309 EXPECT_EQ(psu2.hasInputFault(), false);
310 EXPECT_EQ(psu2.hasMFRFault(), false);
311 EXPECT_EQ(psu2.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000312 EXPECT_EQ(psu2.hasCommFault(), false);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600313
314 // TODO: ReadFailure
315}
316
Brandon Wyman59a35792020-06-04 12:37:40 -0500317TEST_F(PowerSupplyTests, OnOffConfig)
318{
319 auto bus = sdbusplus::bus::new_default();
320 uint8_t data = 0x15;
321
322 // Test where PSU is NOT present
323 try
324 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000325 // Assume GPIO presence, not inventory presence?
326 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
327
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000328 MockedGPIOInterface* mockPresenceGPIO =
329 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000330 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(0));
Brandon Wyman59a35792020-06-04 12:37:40 -0500331 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000332 // Constructor should set initial presence, default read returns 0.
Brandon Wyman59a35792020-06-04 12:37:40 -0500333 // If it is not present, I should not be trying to write to it.
334 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0);
335 psu.onOffConfig(data);
336 }
337 catch (...)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +0000338 {}
Brandon Wyman59a35792020-06-04 12:37:40 -0500339
340 // Test where PSU is present
341 try
342 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000343 // Assume GPIO presence, not inventory presence?
344 PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000345 MockedGPIOInterface* mockPresenceGPIO =
346 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000347 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
Brandon Wyman59a35792020-06-04 12:37:40 -0500348 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000349 // TODO: expect setPresence call?
350 // updatePresence() private function reads gpio, called by analyze().
351 psu.analyze();
Brandon Wyman59a35792020-06-04 12:37:40 -0500352 // TODO: ???should I check the filename?
353 EXPECT_CALL(mockPMBus,
354 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug))
355 .Times(1);
356 psu.onOffConfig(data);
357 }
358 catch (...)
Adriana Kobylak0c9a33d2021-09-13 18:05:09 +0000359 {}
Brandon Wyman59a35792020-06-04 12:37:40 -0500360}
361
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600362TEST_F(PowerSupplyTests, ClearFaults)
363{
364 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000365 PowerSupply psu{bus, PSUInventoryPath, 13, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000366 MockedGPIOInterface* mockPresenceGPIO =
367 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000368 // GPIO read return 1 to indicate present.
369 ON_CALL(*mockPresenceGPIO, read()).WillByDefault(Return(1));
370 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Brandon Wyman8da35c52021-10-28 22:45:08 +0000371 // Presence change from missing to present will trigger in1_input read in
372 // an attempt to get CLEAR_FAULTS called.
373 EXPECT_CALL(mockPMBus, read(READ_VIN, _)).Times(1).WillOnce(Return(206000));
374 // STATUS_WORD 0x0000 is powered on, no faults.
375 uint16_t statusWordValue = 0;
376 setPMBusExpectations(mockPMBus, statusWordValue);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000377 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600378 EXPECT_EQ(psu.isPresent(), true);
379 EXPECT_EQ(psu.isFaulted(), false);
380 EXPECT_EQ(psu.hasInputFault(), false);
381 EXPECT_EQ(psu.hasMFRFault(), false);
382 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000383 EXPECT_EQ(psu.hasCommFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000384 // STATUS_WORD with fault bits galore!
Brandon Wyman8da35c52021-10-28 22:45:08 +0000385 statusWordValue = 0xFFFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000386 // STATUS_INPUT with fault bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000387 uint8_t statusInputValue = 0xFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000388 // STATUS_MFR_SPEFIC with bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000389 uint8_t statusMFRValue = 0xFF;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000390 // STATUS_CML with bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000391 uint8_t statusCMLValue = 0xFF;
392 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue,
393 statusMFRValue, statusCMLValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600394 psu.analyze();
395 EXPECT_EQ(psu.isPresent(), true);
396 EXPECT_EQ(psu.isFaulted(), true);
397 EXPECT_EQ(psu.hasInputFault(), true);
398 EXPECT_EQ(psu.hasMFRFault(), true);
399 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000400 EXPECT_EQ(psu.hasCommFault(), true);
Brandon Wyman3c208462020-05-13 16:25:58 -0500401 EXPECT_CALL(mockPMBus, read("in1_input", _))
402 .Times(1)
403 .WillOnce(Return(209000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600404 psu.clearFaults();
405 EXPECT_EQ(psu.isPresent(), true);
406 EXPECT_EQ(psu.isFaulted(), false);
407 EXPECT_EQ(psu.hasInputFault(), false);
408 EXPECT_EQ(psu.hasMFRFault(), false);
409 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000410 EXPECT_EQ(psu.hasCommFault(), false);
B. J. Wyman681b2a32021-04-20 22:31:22 +0000411
412 // TODO: Faults clear on missing/present?
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600413}
414
415TEST_F(PowerSupplyTests, UpdateInventory)
416{
417 auto bus = sdbusplus::bus::new_default();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500418
419 try
420 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000421 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500422 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
423 // If it is not present, I should not be trying to read a string
424 EXPECT_CALL(mockPMBus, readString(_, _)).Times(0);
425 psu.updateInventory();
426 }
427 catch (...)
428 {
429 ADD_FAILURE() << "Should not have caught exception.";
430 }
431
432 try
433 {
B. J. Wyman681b2a32021-04-20 22:31:22 +0000434 PowerSupply psu{bus, PSUInventoryPath, 13, 0x69, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000435 MockedGPIOInterface* mockPresenceGPIO =
436 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000437 // GPIO read return 1 to indicate present.
438 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1));
439 psu.analyze();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500440 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
441 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
442 psu.updateInventory();
443
Brandon Wyman3c530fb2021-04-13 13:13:22 -0500444#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500445 EXPECT_CALL(mockPMBus, readString(_, _))
446 .WillOnce(Return("CCIN"))
447 .WillOnce(Return("PN3456"))
448 .WillOnce(Return("FN3456"))
449 .WillOnce(Return("HEADER"))
450 .WillOnce(Return("SN3456"))
451 .WillOnce(Return("FW3456"));
Brandon Wyman3c530fb2021-04-13 13:13:22 -0500452#endif
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500453 psu.updateInventory();
454 // TODO: D-Bus mocking to verify values stored on D-Bus (???)
455 }
456 catch (...)
457 {
458 ADD_FAILURE() << "Should not have caught exception.";
459 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600460}
461
462TEST_F(PowerSupplyTests, IsPresent)
463{
464 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000465
466 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000467 MockedGPIOInterface* mockPresenceGPIO =
468 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600469 EXPECT_EQ(psu.isPresent(), false);
470
B. J. Wyman681b2a32021-04-20 22:31:22 +0000471 // Change GPIO read to return 1 to indicate present.
472 EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(1));
473 psu.analyze();
474 EXPECT_EQ(psu.isPresent(), true);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600475}
476
477TEST_F(PowerSupplyTests, IsFaulted)
478{
479 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000480
481 PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000482 MockedGPIOInterface* mockPresenceGPIO =
483 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000484 // Always return 1 to indicate present.
485 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
486 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600487 EXPECT_EQ(psu.isFaulted(), false);
488 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Brandon Wymanf07bc792021-10-12 19:00:35 +0000489 // STATUS_WORD with fault bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000490 uint16_t statusWordValue = 0xFFFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000491 // STATUS_INPUT with fault bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000492 uint8_t statusInputValue = 0xFF;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000493 // STATUS_MFR_SPECIFIC with faults bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000494 uint8_t statusMFRValue = 0xFF;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000495 // STATUS_CML with faults bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000496 uint8_t statusCMLValue = 0xFF;
497 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue,
498 statusMFRValue, statusCMLValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600499 psu.analyze();
500 EXPECT_EQ(psu.isFaulted(), true);
501}
502
503TEST_F(PowerSupplyTests, HasInputFault)
504{
505 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000506
507 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000508 MockedGPIOInterface* mockPresenceGPIO =
509 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000510 // Always return 1 to indicate present.
511 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
512 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600513 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
514 EXPECT_EQ(psu.hasInputFault(), false);
Brandon Wyman8da35c52021-10-28 22:45:08 +0000515 // STATUS_WORD 0x0000 is powered on, no faults.
516 uint16_t statusWordValue = 0;
517 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600518 psu.analyze();
519 EXPECT_EQ(psu.hasInputFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000520 // STATUS_WORD with input fault/warn on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000521 statusWordValue = (status_word::INPUT_FAULT_WARN);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000522 // STATUS_INPUT with an input fault bit on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000523 uint8_t statusInputValue = 0x80;
524 // STATUS_MFR and STATUS_CML don't care.
525 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600526 psu.analyze();
527 EXPECT_EQ(psu.hasInputFault(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000528 // STATUS_WORD with no bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000529 statusWordValue = 0;
530 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600531 psu.analyze();
532 EXPECT_EQ(psu.hasInputFault(), false);
533}
534
535TEST_F(PowerSupplyTests, HasMFRFault)
536{
537 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000538
539 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000540 MockedGPIOInterface* mockPresenceGPIO =
541 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000542 // Always return 1 to indicate present.
543 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
544 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600545 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
546 EXPECT_EQ(psu.hasMFRFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000547 // First return STATUS_WORD with no bits on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000548 // STATUS_WORD 0x0000 is powered on, no faults.
549 uint16_t statusWordValue = 0;
550 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600551 psu.analyze();
552 EXPECT_EQ(psu.hasMFRFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000553 // Next return STATUS_WORD with MFR fault bit on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000554 statusWordValue = (status_word::MFR_SPECIFIC_FAULT);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000555 // STATUS_INPUT don't care
Brandon Wyman8da35c52021-10-28 22:45:08 +0000556 uint8_t statusInputValue = 0;
Brandon Wymanf07bc792021-10-12 19:00:35 +0000557 // STATUS_MFR_SPEFIC with bit(s) on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000558 uint8_t statusMFRValue = 0xFF;
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000559 // STATUS_CML don't care.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000560 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue,
561 statusMFRValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600562 psu.analyze();
563 EXPECT_EQ(psu.hasMFRFault(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000564 // Back to no bits on in STATUS_WORD
Brandon Wyman8da35c52021-10-28 22:45:08 +0000565 statusWordValue = 0;
566 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600567 psu.analyze();
568 EXPECT_EQ(psu.hasMFRFault(), false);
569}
570
571TEST_F(PowerSupplyTests, HasVINUVFault)
572{
573 auto bus = sdbusplus::bus::new_default();
B. J. Wyman681b2a32021-04-20 22:31:22 +0000574
575 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
Adriana Kobylak3ca062a2021-10-20 15:27:23 +0000576 MockedGPIOInterface* mockPresenceGPIO =
577 static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
B. J. Wyman681b2a32021-04-20 22:31:22 +0000578 // Always return 1 to indicate present.
579 EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
580 psu.analyze();
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600581 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
582 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wyman8da35c52021-10-28 22:45:08 +0000583 // STATUS_WORD 0x0000 is powered on, no faults.
584 uint16_t statusWordValue = 0;
585 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600586 psu.analyze();
587 EXPECT_EQ(psu.hasVINUVFault(), false);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000588 // Turn fault on.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000589 statusWordValue = (status_word::VIN_UV_FAULT);
Brandon Wyman85c7bf42021-10-19 22:28:48 +0000590 // Curious disagreement between PMBus Spec. Part II Figure 16 and 33. Go by
591 // Figure 16, and assume bits on in STATUS_INPUT.
Brandon Wyman8da35c52021-10-28 22:45:08 +0000592 uint8_t statusInputValue = 0x18;
593 // STATUS_MFR and STATUS_CML don't care.
594 setPMBusExpectations(mockPMBus, statusWordValue, statusInputValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600595 psu.analyze();
596 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wymanf07bc792021-10-12 19:00:35 +0000597 // Back to no fault bits on in STATUS_WORD
Brandon Wyman8da35c52021-10-28 22:45:08 +0000598 statusWordValue = 0;
599 setPMBusExpectations(mockPMBus, statusWordValue);
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600600 psu.analyze();
601 EXPECT_EQ(psu.hasVINUVFault(), false);
602}