blob: 74d98c1a4e6cdba0715242ef814f046ba99370c5 [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";
23
24class PowerSupplyTests : public ::testing::Test
25{
26 public:
27 PowerSupplyTests() :
28 mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils()))
29 {
30 ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false));
31 }
32
33 ~PowerSupplyTests() override
34 {
35 freeUtils();
36 }
37
38 const MockedUtil& mockedUtil;
39};
40
41TEST_F(PowerSupplyTests, Constructor)
42{
43 /**
44 * @param[in] invpath - String for inventory path to use
45 * @param[in] i2cbus - The bus number this power supply is on
46 * @param[in] i2caddr - The 16-bit I2C address of the power supply
47 */
48 auto bus = sdbusplus::bus::new_default();
Brandon Wyman3f1242f2020-01-28 13:11:25 -060049
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050050 // Try where inventory path is empty, constructor should fail.
51 try
52 {
Brandon Wyman510acaa2020-11-05 18:32:04 -060053 auto psu = std::make_unique<PowerSupply>(bus, "", 3, 0x68);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050054 ADD_FAILURE() << "Should not have reached this line.";
55 }
56 catch (const std::invalid_argument& e)
57 {
58 EXPECT_STREQ(e.what(), "Invalid empty inventoryPath");
59 }
60 catch (...)
61 {
62 ADD_FAILURE() << "Should not have caught exception.";
63 }
64
65 // Test with valid arguments
66 try
67 {
68 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
69 .Times(1);
70 auto psu =
Brandon Wyman510acaa2020-11-05 18:32:04 -060071 std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68);
Brandon Wyman1d7a7df2020-03-26 10:14:05 -050072
73 EXPECT_EQ(psu->isPresent(), false);
74 EXPECT_EQ(psu->isFaulted(), false);
75 EXPECT_EQ(psu->hasInputFault(), false);
76 EXPECT_EQ(psu->hasMFRFault(), false);
77 EXPECT_EQ(psu->hasVINUVFault(), false);
78 }
79 catch (...)
80 {
81 ADD_FAILURE() << "Should not have caught exception.";
82 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -060083}
84
85TEST_F(PowerSupplyTests, Analyze)
86{
87 auto bus = sdbusplus::bus::new_default();
88
89 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
Brandon Wyman510acaa2020-11-05 18:32:04 -060090 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69};
Brandon Wyman3f1242f2020-01-28 13:11:25 -060091 psu.analyze();
92 // By default, nothing should change.
93 EXPECT_EQ(psu.isPresent(), false);
94 EXPECT_EQ(psu.isFaulted(), false);
95 EXPECT_EQ(psu.hasInputFault(), false);
96 EXPECT_EQ(psu.hasMFRFault(), false);
97 EXPECT_EQ(psu.hasVINUVFault(), false);
98
99 // In order to get the various faults tested, the power supply needs to be
100 // present in order to read from the PMBus device(s).
101 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
102 .Times(1)
103 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600104 PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600105 EXPECT_EQ(psu2.isPresent(), true);
106
107 // STATUS_WORD 0x0000 is powered on, no faults.
108 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
109 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
110 psu2.analyze();
111 EXPECT_EQ(psu2.isPresent(), true);
112 EXPECT_EQ(psu2.isFaulted(), false);
113 EXPECT_EQ(psu2.hasInputFault(), false);
114 EXPECT_EQ(psu2.hasMFRFault(), false);
115 EXPECT_EQ(psu2.hasVINUVFault(), false);
116
117 // STATUS_WORD input fault/warn
118 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600119 .Times(2)
120 .WillOnce(Return(status_word::INPUT_FAULT_WARN))
121 .WillOnce(Return(0x0000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600122 psu2.analyze();
123 EXPECT_EQ(psu2.isPresent(), true);
124 EXPECT_EQ(psu2.isFaulted(), true);
125 EXPECT_EQ(psu2.hasInputFault(), true);
126 EXPECT_EQ(psu2.hasMFRFault(), false);
127 EXPECT_EQ(psu2.hasVINUVFault(), false);
128
129 // STATUS_WORD INPUT/UV fault.
130 // First need it to return good status, then the fault
131 EXPECT_CALL(mockPMBus, read(_, _))
132 .WillOnce(Return(0x0000))
Jay Meyer10d94052020-11-30 14:41:21 -0600133 .WillOnce(Return(status_word::VIN_UV_FAULT))
134 .WillOnce(Return(0x0000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600135 psu2.analyze();
136 psu2.analyze();
137 EXPECT_EQ(psu2.isPresent(), true);
138 EXPECT_EQ(psu2.isFaulted(), true);
139 EXPECT_EQ(psu2.hasInputFault(), false);
140 EXPECT_EQ(psu2.hasMFRFault(), false);
141 EXPECT_EQ(psu2.hasVINUVFault(), true);
142
143 // STATUS_WORD MFR fault.
144 EXPECT_CALL(mockPMBus, read(_, _))
145 .WillOnce(Return(0x0000))
Jay Meyer10d94052020-11-30 14:41:21 -0600146 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT))
147 .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600148 psu2.analyze();
149 psu2.analyze();
150 EXPECT_EQ(psu2.isPresent(), true);
151 EXPECT_EQ(psu2.isFaulted(), true);
152 EXPECT_EQ(psu2.hasInputFault(), false);
153 EXPECT_EQ(psu2.hasMFRFault(), true);
154 EXPECT_EQ(psu2.hasVINUVFault(), false);
155
156 // Ignore Temperature fault.
157 EXPECT_CALL(mockPMBus, read(_, _))
158 .WillOnce(Return(0x0000))
Jay Meyer10d94052020-11-30 14:41:21 -0600159 .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN))
160 .WillOnce(Return(0x0000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600161 psu2.analyze();
162 psu2.analyze();
163 EXPECT_EQ(psu2.isPresent(), true);
164 EXPECT_EQ(psu2.isFaulted(), false);
165 EXPECT_EQ(psu2.hasInputFault(), false);
166 EXPECT_EQ(psu2.hasMFRFault(), false);
167 EXPECT_EQ(psu2.hasVINUVFault(), false);
168
169 // Ignore fan fault
170 EXPECT_CALL(mockPMBus, read(_, _))
171 .WillOnce(Return(0x0000))
Jay Meyer10d94052020-11-30 14:41:21 -0600172 .WillOnce(Return(status_word::FAN_FAULT))
173 .WillOnce(Return(0x0000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600174 psu2.analyze();
175 psu2.analyze();
176 EXPECT_EQ(psu2.isPresent(), true);
177 EXPECT_EQ(psu2.isFaulted(), false);
178 EXPECT_EQ(psu2.hasInputFault(), false);
179 EXPECT_EQ(psu2.hasMFRFault(), false);
180 EXPECT_EQ(psu2.hasVINUVFault(), false);
181
182 // TODO: ReadFailure
183}
184
Brandon Wyman59a35792020-06-04 12:37:40 -0500185TEST_F(PowerSupplyTests, OnOffConfig)
186{
187 auto bus = sdbusplus::bus::new_default();
188 uint8_t data = 0x15;
189
190 // Test where PSU is NOT present
191 try
192 {
193 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
194 .Times(1)
195 .WillOnce(Return(false));
Brandon Wyman510acaa2020-11-05 18:32:04 -0600196 PowerSupply psu{bus, PSUInventoryPath, 4, 0x69};
Brandon Wyman59a35792020-06-04 12:37:40 -0500197 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
198 // If it is not present, I should not be trying to write to it.
199 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0);
200 psu.onOffConfig(data);
201 }
202 catch (...)
203 {
204 }
205
206 // Test where PSU is present
207 try
208 {
209 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
210 .Times(1)
211 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600212 PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a};
Brandon Wyman59a35792020-06-04 12:37:40 -0500213 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
214 // TODO: ???should I check the filename?
215 EXPECT_CALL(mockPMBus,
216 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug))
217 .Times(1);
218 psu.onOffConfig(data);
219 }
220 catch (...)
221 {
222 }
223}
224
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600225TEST_F(PowerSupplyTests, ClearFaults)
226{
227 auto bus = sdbusplus::bus::new_default();
228 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
229 .Times(1)
230 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600231 PowerSupply psu{bus, PSUInventoryPath, 13, 0x68};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600232 EXPECT_EQ(psu.isPresent(), true);
233 EXPECT_EQ(psu.isFaulted(), false);
234 EXPECT_EQ(psu.hasInputFault(), false);
235 EXPECT_EQ(psu.hasMFRFault(), false);
236 EXPECT_EQ(psu.hasVINUVFault(), false);
237 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Jay Meyer10d94052020-11-30 14:41:21 -0600238 EXPECT_CALL(mockPMBus, read(_, _))
239 .Times(2)
240 .WillOnce(Return(0xFFFF))
241 .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600242 psu.analyze();
243 EXPECT_EQ(psu.isPresent(), true);
244 EXPECT_EQ(psu.isFaulted(), true);
245 EXPECT_EQ(psu.hasInputFault(), true);
246 EXPECT_EQ(psu.hasMFRFault(), true);
247 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wyman3c208462020-05-13 16:25:58 -0500248 EXPECT_CALL(mockPMBus, read("in1_input", _))
249 .Times(1)
250 .WillOnce(Return(209000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600251 psu.clearFaults();
252 EXPECT_EQ(psu.isPresent(), true);
253 EXPECT_EQ(psu.isFaulted(), false);
254 EXPECT_EQ(psu.hasInputFault(), false);
255 EXPECT_EQ(psu.hasMFRFault(), false);
256 EXPECT_EQ(psu.hasVINUVFault(), false);
257}
258
259TEST_F(PowerSupplyTests, UpdateInventory)
260{
261 auto bus = sdbusplus::bus::new_default();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500262
263 try
264 {
265 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
266 .Times(1)
267 .WillOnce(Return(false)); // missing
Brandon Wyman510acaa2020-11-05 18:32:04 -0600268 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68};
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500269 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
270 // If it is not present, I should not be trying to read a string
271 EXPECT_CALL(mockPMBus, readString(_, _)).Times(0);
272 psu.updateInventory();
273 }
274 catch (...)
275 {
276 ADD_FAILURE() << "Should not have caught exception.";
277 }
278
279 try
280 {
281 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
282 .Times(1)
283 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600284 PowerSupply psu{bus, PSUInventoryPath, 13, 0x69};
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500285 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
286 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
287 psu.updateInventory();
288
Brandon Wyman3c530fb2021-04-13 13:13:22 -0500289#if IBM_VPD
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500290 EXPECT_CALL(mockPMBus, readString(_, _))
291 .WillOnce(Return("CCIN"))
292 .WillOnce(Return("PN3456"))
293 .WillOnce(Return("FN3456"))
294 .WillOnce(Return("HEADER"))
295 .WillOnce(Return("SN3456"))
296 .WillOnce(Return("FW3456"));
Brandon Wyman3c530fb2021-04-13 13:13:22 -0500297#endif
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500298 psu.updateInventory();
299 // TODO: D-Bus mocking to verify values stored on D-Bus (???)
300 }
301 catch (...)
302 {
303 ADD_FAILURE() << "Should not have caught exception.";
304 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600305}
306
307TEST_F(PowerSupplyTests, IsPresent)
308{
309 auto bus = sdbusplus::bus::new_default();
310 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
Brandon Wyman510acaa2020-11-05 18:32:04 -0600311 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600312 EXPECT_EQ(psu.isPresent(), false);
313
314 EXPECT_CALL(mockedUtil, getPresence(_, _))
315 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600316 PowerSupply psu2{bus, PSUInventoryPath, 10, 0x6b};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600317 EXPECT_EQ(psu2.isPresent(), true);
318}
319
320TEST_F(PowerSupplyTests, IsFaulted)
321{
322 auto bus = sdbusplus::bus::new_default();
323 EXPECT_CALL(mockedUtil, getPresence(_, _))
324 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600325 PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600326 EXPECT_EQ(psu.isFaulted(), false);
327 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Jay Meyer10d94052020-11-30 14:41:21 -0600328 EXPECT_CALL(mockPMBus, read(_, _))
329 .Times(2)
330 .WillOnce(Return(0xFFFF))
331 .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600332 psu.analyze();
333 EXPECT_EQ(psu.isFaulted(), true);
334}
335
336TEST_F(PowerSupplyTests, HasInputFault)
337{
338 auto bus = sdbusplus::bus::new_default();
339 EXPECT_CALL(mockedUtil, getPresence(_, _))
340 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600341 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600342 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
343 EXPECT_EQ(psu.hasInputFault(), false);
344 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
345 psu.analyze();
346 EXPECT_EQ(psu.hasInputFault(), false);
347 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600348 .Times(2)
349 .WillOnce(Return(status_word::INPUT_FAULT_WARN))
350 .WillOnce(Return(0));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600351 psu.analyze();
352 EXPECT_EQ(psu.hasInputFault(), true);
353 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
354 psu.analyze();
355 EXPECT_EQ(psu.hasInputFault(), false);
356}
357
358TEST_F(PowerSupplyTests, HasMFRFault)
359{
360 auto bus = sdbusplus::bus::new_default();
361 EXPECT_CALL(mockedUtil, getPresence(_, _))
362 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600363 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600364 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
365 EXPECT_EQ(psu.hasMFRFault(), false);
366 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
367 psu.analyze();
368 EXPECT_EQ(psu.hasMFRFault(), false);
369 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600370 .Times(2)
371 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT))
372 .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600373 psu.analyze();
374 EXPECT_EQ(psu.hasMFRFault(), true);
375 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
376 psu.analyze();
377 EXPECT_EQ(psu.hasMFRFault(), false);
378}
379
380TEST_F(PowerSupplyTests, HasVINUVFault)
381{
382 auto bus = sdbusplus::bus::new_default();
383 EXPECT_CALL(mockedUtil, getPresence(_, _))
384 .WillOnce(Return(true)); // present
Brandon Wyman510acaa2020-11-05 18:32:04 -0600385 PowerSupply psu{bus, PSUInventoryPath, 3, 0x68};
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600386 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
387 EXPECT_EQ(psu.hasVINUVFault(), false);
388 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
389 psu.analyze();
390 EXPECT_EQ(psu.hasVINUVFault(), false);
391 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600392 .Times(2)
393 .WillOnce(Return(status_word::VIN_UV_FAULT))
394 .WillOnce(Return(0));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600395 psu.analyze();
396 EXPECT_EQ(psu.hasVINUVFault(), true);
397 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
398 psu.analyze();
399 EXPECT_EQ(psu.hasVINUVFault(), false);
400}