blob: 55dc2a74518be2a9cea6866e5a71f048b83cbf03 [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(_, _))
119 .Times(1)
120 .WillOnce(Return(status_word::INPUT_FAULT_WARN));
121 psu2.analyze();
122 EXPECT_EQ(psu2.isPresent(), true);
123 EXPECT_EQ(psu2.isFaulted(), true);
124 EXPECT_EQ(psu2.hasInputFault(), true);
125 EXPECT_EQ(psu2.hasMFRFault(), false);
126 EXPECT_EQ(psu2.hasVINUVFault(), false);
127
128 // STATUS_WORD INPUT/UV fault.
129 // First need it to return good status, then the fault
130 EXPECT_CALL(mockPMBus, read(_, _))
131 .WillOnce(Return(0x0000))
132 .WillOnce(Return(status_word::VIN_UV_FAULT));
133 psu2.analyze();
134 psu2.analyze();
135 EXPECT_EQ(psu2.isPresent(), true);
136 EXPECT_EQ(psu2.isFaulted(), true);
137 EXPECT_EQ(psu2.hasInputFault(), false);
138 EXPECT_EQ(psu2.hasMFRFault(), false);
139 EXPECT_EQ(psu2.hasVINUVFault(), true);
140
141 // STATUS_WORD MFR fault.
142 EXPECT_CALL(mockPMBus, read(_, _))
143 .WillOnce(Return(0x0000))
144 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
145 psu2.analyze();
146 psu2.analyze();
147 EXPECT_EQ(psu2.isPresent(), true);
148 EXPECT_EQ(psu2.isFaulted(), true);
149 EXPECT_EQ(psu2.hasInputFault(), false);
150 EXPECT_EQ(psu2.hasMFRFault(), true);
151 EXPECT_EQ(psu2.hasVINUVFault(), false);
152
153 // Ignore Temperature fault.
154 EXPECT_CALL(mockPMBus, read(_, _))
155 .WillOnce(Return(0x0000))
156 .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN));
157 psu2.analyze();
158 psu2.analyze();
159 EXPECT_EQ(psu2.isPresent(), true);
160 EXPECT_EQ(psu2.isFaulted(), false);
161 EXPECT_EQ(psu2.hasInputFault(), false);
162 EXPECT_EQ(psu2.hasMFRFault(), false);
163 EXPECT_EQ(psu2.hasVINUVFault(), false);
164
165 // Ignore fan fault
166 EXPECT_CALL(mockPMBus, read(_, _))
167 .WillOnce(Return(0x0000))
168 .WillOnce(Return(status_word::FAN_FAULT));
169 psu2.analyze();
170 psu2.analyze();
171 EXPECT_EQ(psu2.isPresent(), true);
172 EXPECT_EQ(psu2.isFaulted(), false);
173 EXPECT_EQ(psu2.hasInputFault(), false);
174 EXPECT_EQ(psu2.hasMFRFault(), false);
175 EXPECT_EQ(psu2.hasVINUVFault(), false);
176
177 // TODO: ReadFailure
178}
179
Brandon Wyman59a35792020-06-04 12:37:40 -0500180TEST_F(PowerSupplyTests, OnOffConfig)
181{
182 auto bus = sdbusplus::bus::new_default();
183 uint8_t data = 0x15;
184
185 // Test where PSU is NOT present
186 try
187 {
188 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
189 .Times(1)
190 .WillOnce(Return(false));
191 PowerSupply psu{bus, PSUInventoryPath, 4, "0069"};
192 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
193 // If it is not present, I should not be trying to write to it.
194 EXPECT_CALL(mockPMBus, writeBinary(_, _, _)).Times(0);
195 psu.onOffConfig(data);
196 }
197 catch (...)
198 {
199 }
200
201 // Test where PSU is present
202 try
203 {
204 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
205 .Times(1)
206 .WillOnce(Return(true)); // present
207 PowerSupply psu{bus, PSUInventoryPath, 5, "006a"};
208 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
209 // TODO: ???should I check the filename?
210 EXPECT_CALL(mockPMBus,
211 writeBinary(_, ElementsAre(0x15), Type::HwmonDeviceDebug))
212 .Times(1);
213 psu.onOffConfig(data);
214 }
215 catch (...)
216 {
217 }
218}
219
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600220TEST_F(PowerSupplyTests, ClearFaults)
221{
222 auto bus = sdbusplus::bus::new_default();
223 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
224 .Times(1)
225 .WillOnce(Return(true)); // present
226 PowerSupply psu{bus, PSUInventoryPath, 13, "0068"};
227 EXPECT_EQ(psu.isPresent(), true);
228 EXPECT_EQ(psu.isFaulted(), false);
229 EXPECT_EQ(psu.hasInputFault(), false);
230 EXPECT_EQ(psu.hasMFRFault(), false);
231 EXPECT_EQ(psu.hasVINUVFault(), false);
232 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
233 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
234 psu.analyze();
235 EXPECT_EQ(psu.isPresent(), true);
236 EXPECT_EQ(psu.isFaulted(), true);
237 EXPECT_EQ(psu.hasInputFault(), true);
238 EXPECT_EQ(psu.hasMFRFault(), true);
239 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wyman3c208462020-05-13 16:25:58 -0500240 EXPECT_CALL(mockPMBus, read("in1_input", _))
241 .Times(1)
242 .WillOnce(Return(209000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600243 psu.clearFaults();
244 EXPECT_EQ(psu.isPresent(), true);
245 EXPECT_EQ(psu.isFaulted(), false);
246 EXPECT_EQ(psu.hasInputFault(), false);
247 EXPECT_EQ(psu.hasMFRFault(), false);
248 EXPECT_EQ(psu.hasVINUVFault(), false);
249}
250
251TEST_F(PowerSupplyTests, UpdateInventory)
252{
253 auto bus = sdbusplus::bus::new_default();
Brandon Wyman1d7a7df2020-03-26 10:14:05 -0500254
255 try
256 {
257 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
258 .Times(1)
259 .WillOnce(Return(false)); // missing
260 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
261 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
262 // If it is not present, I should not be trying to read a string
263 EXPECT_CALL(mockPMBus, readString(_, _)).Times(0);
264 psu.updateInventory();
265 }
266 catch (...)
267 {
268 ADD_FAILURE() << "Should not have caught exception.";
269 }
270
271 try
272 {
273 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
274 .Times(1)
275 .WillOnce(Return(true)); // present
276 PowerSupply psu{bus, PSUInventoryPath, 13, "0069"};
277 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
278 EXPECT_CALL(mockPMBus, readString(_, _)).WillRepeatedly(Return(""));
279 psu.updateInventory();
280
281 EXPECT_CALL(mockPMBus, readString(_, _))
282 .WillOnce(Return("CCIN"))
283 .WillOnce(Return("PN3456"))
284 .WillOnce(Return("FN3456"))
285 .WillOnce(Return("HEADER"))
286 .WillOnce(Return("SN3456"))
287 .WillOnce(Return("FW3456"));
288 psu.updateInventory();
289 // TODO: D-Bus mocking to verify values stored on D-Bus (???)
290 }
291 catch (...)
292 {
293 ADD_FAILURE() << "Should not have caught exception.";
294 }
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600295}
296
297TEST_F(PowerSupplyTests, IsPresent)
298{
299 auto bus = sdbusplus::bus::new_default();
300 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
301 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
302 EXPECT_EQ(psu.isPresent(), false);
303
304 EXPECT_CALL(mockedUtil, getPresence(_, _))
305 .WillOnce(Return(true)); // present
306 PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"};
307 EXPECT_EQ(psu2.isPresent(), true);
308}
309
310TEST_F(PowerSupplyTests, IsFaulted)
311{
312 auto bus = sdbusplus::bus::new_default();
313 EXPECT_CALL(mockedUtil, getPresence(_, _))
314 .WillOnce(Return(true)); // present
315 PowerSupply psu{bus, PSUInventoryPath, 11, "006f"};
316 EXPECT_EQ(psu.isFaulted(), false);
317 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
318 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
319 psu.analyze();
320 EXPECT_EQ(psu.isFaulted(), true);
321}
322
323TEST_F(PowerSupplyTests, HasInputFault)
324{
325 auto bus = sdbusplus::bus::new_default();
326 EXPECT_CALL(mockedUtil, getPresence(_, _))
327 .WillOnce(Return(true)); // present
328 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
329 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
330 EXPECT_EQ(psu.hasInputFault(), false);
331 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
332 psu.analyze();
333 EXPECT_EQ(psu.hasInputFault(), false);
334 EXPECT_CALL(mockPMBus, read(_, _))
335 .Times(1)
336 .WillOnce(Return(status_word::INPUT_FAULT_WARN));
337 psu.analyze();
338 EXPECT_EQ(psu.hasInputFault(), true);
339 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
340 psu.analyze();
341 EXPECT_EQ(psu.hasInputFault(), false);
342}
343
344TEST_F(PowerSupplyTests, HasMFRFault)
345{
346 auto bus = sdbusplus::bus::new_default();
347 EXPECT_CALL(mockedUtil, getPresence(_, _))
348 .WillOnce(Return(true)); // present
349 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
350 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
351 EXPECT_EQ(psu.hasMFRFault(), false);
352 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
353 psu.analyze();
354 EXPECT_EQ(psu.hasMFRFault(), false);
355 EXPECT_CALL(mockPMBus, read(_, _))
356 .Times(1)
357 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
358 psu.analyze();
359 EXPECT_EQ(psu.hasMFRFault(), true);
360 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
361 psu.analyze();
362 EXPECT_EQ(psu.hasMFRFault(), false);
363}
364
365TEST_F(PowerSupplyTests, HasVINUVFault)
366{
367 auto bus = sdbusplus::bus::new_default();
368 EXPECT_CALL(mockedUtil, getPresence(_, _))
369 .WillOnce(Return(true)); // present
370 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
371 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
372 EXPECT_EQ(psu.hasVINUVFault(), false);
373 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
374 psu.analyze();
375 EXPECT_EQ(psu.hasVINUVFault(), false);
376 EXPECT_CALL(mockPMBus, read(_, _))
377 .Times(1)
378 .WillOnce(Return(status_word::VIN_UV_FAULT));
379 psu.analyze();
380 EXPECT_EQ(psu.hasVINUVFault(), true);
381 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
382 psu.analyze();
383 EXPECT_EQ(psu.hasVINUVFault(), false);
384}