blob: 07b4b9ef72647ecf60cd17978604a6905fc9b83f [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 {
53 auto psu = std::make_unique<PowerSupply>(bus, "", 3, "0068");
54 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 =
71 std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, "0068");
72
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);
90 PowerSupply psu{bus, PSUInventoryPath, 4, "0069"};
91 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
104 PowerSupply psu2{bus, PSUInventoryPath, 5, "006a"};
105 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));
196 PowerSupply psu{bus, PSUInventoryPath, 4, "0069"};
197 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
212 PowerSupply psu{bus, PSUInventoryPath, 5, "006a"};
213 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
231 PowerSupply psu{bus, PSUInventoryPath, 13, "0068"};
232 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
268 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
269 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
284 PowerSupply psu{bus, PSUInventoryPath, 13, "0069"};
285 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
286 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
287 psu.updateInventory();
288
289 EXPECT_CALL(mockPMBus, readString(_, _))
290 .WillOnce(Return("CCIN"))
291 .WillOnce(Return("PN3456"))
292 .WillOnce(Return("FN3456"))
293 .WillOnce(Return("HEADER"))
294 .WillOnce(Return("SN3456"))
295 .WillOnce(Return("FW3456"));
296 psu.updateInventory();
297 // TODO: D-Bus mocking to verify values stored on D-Bus (???)
298 }
299 catch (...)
300 {
301 ADD_FAILURE() << "Should not have caught exception.";
302 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600303}
304
305TEST_F(PowerSupplyTests, IsPresent)
306{
307 auto bus = sdbusplus::bus::new_default();
308 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
309 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
310 EXPECT_EQ(psu.isPresent(), false);
311
312 EXPECT_CALL(mockedUtil, getPresence(_, _))
313 .WillOnce(Return(true)); // present
314 PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"};
315 EXPECT_EQ(psu2.isPresent(), true);
316}
317
318TEST_F(PowerSupplyTests, IsFaulted)
319{
320 auto bus = sdbusplus::bus::new_default();
321 EXPECT_CALL(mockedUtil, getPresence(_, _))
322 .WillOnce(Return(true)); // present
323 PowerSupply psu{bus, PSUInventoryPath, 11, "006f"};
324 EXPECT_EQ(psu.isFaulted(), false);
325 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
Jay Meyer10d94052020-11-30 14:41:21 -0600326 EXPECT_CALL(mockPMBus, read(_, _))
327 .Times(2)
328 .WillOnce(Return(0xFFFF))
329 .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600330 psu.analyze();
331 EXPECT_EQ(psu.isFaulted(), true);
332}
333
334TEST_F(PowerSupplyTests, HasInputFault)
335{
336 auto bus = sdbusplus::bus::new_default();
337 EXPECT_CALL(mockedUtil, getPresence(_, _))
338 .WillOnce(Return(true)); // present
339 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
340 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
341 EXPECT_EQ(psu.hasInputFault(), false);
342 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
343 psu.analyze();
344 EXPECT_EQ(psu.hasInputFault(), false);
345 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600346 .Times(2)
347 .WillOnce(Return(status_word::INPUT_FAULT_WARN))
348 .WillOnce(Return(0));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600349 psu.analyze();
350 EXPECT_EQ(psu.hasInputFault(), true);
351 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
352 psu.analyze();
353 EXPECT_EQ(psu.hasInputFault(), false);
354}
355
356TEST_F(PowerSupplyTests, HasMFRFault)
357{
358 auto bus = sdbusplus::bus::new_default();
359 EXPECT_CALL(mockedUtil, getPresence(_, _))
360 .WillOnce(Return(true)); // present
361 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
362 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
363 EXPECT_EQ(psu.hasMFRFault(), false);
364 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
365 psu.analyze();
366 EXPECT_EQ(psu.hasMFRFault(), false);
367 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600368 .Times(2)
369 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT))
370 .WillOnce(Return(1)); // mock return for read(STATUS_MFR... )
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600371 psu.analyze();
372 EXPECT_EQ(psu.hasMFRFault(), true);
373 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
374 psu.analyze();
375 EXPECT_EQ(psu.hasMFRFault(), false);
376}
377
378TEST_F(PowerSupplyTests, HasVINUVFault)
379{
380 auto bus = sdbusplus::bus::new_default();
381 EXPECT_CALL(mockedUtil, getPresence(_, _))
382 .WillOnce(Return(true)); // present
383 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
384 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
385 EXPECT_EQ(psu.hasVINUVFault(), false);
386 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
387 psu.analyze();
388 EXPECT_EQ(psu.hasVINUVFault(), false);
389 EXPECT_CALL(mockPMBus, read(_, _))
Jay Meyer10d94052020-11-30 14:41:21 -0600390 .Times(2)
391 .WillOnce(Return(status_word::VIN_UV_FAULT))
392 .WillOnce(Return(0));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600393 psu.analyze();
394 EXPECT_EQ(psu.hasVINUVFault(), true);
395 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
396 psu.analyze();
397 EXPECT_EQ(psu.hasVINUVFault(), false);
398}