blob: c6d481425bc67d7144fe4d576f5d28b6e868bb44 [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::_;
14using ::testing::Assign;
15using ::testing::DoAll;
16using ::testing::Return;
17using ::testing::StrEq;
18
19static auto PSUInventoryPath = "/xyz/bmc/inv/sys/chassis/board/powersupply0";
20
21class PowerSupplyTests : public ::testing::Test
22{
23 public:
24 PowerSupplyTests() :
25 mockedUtil(reinterpret_cast<const MockedUtil&>(getUtils()))
26 {
27 ON_CALL(mockedUtil, getPresence(_, _)).WillByDefault(Return(false));
28 }
29
30 ~PowerSupplyTests() override
31 {
32 freeUtils();
33 }
34
35 const MockedUtil& mockedUtil;
36};
37
38TEST_F(PowerSupplyTests, Constructor)
39{
40 /**
41 * @param[in] invpath - String for inventory path to use
42 * @param[in] i2cbus - The bus number this power supply is on
43 * @param[in] i2caddr - The 16-bit I2C address of the power supply
44 */
45 auto bus = sdbusplus::bus::new_default();
46 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
47 auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, "0068");
48
49 EXPECT_EQ(psu->isPresent(), false);
50 EXPECT_EQ(psu->isFaulted(), false);
51 EXPECT_EQ(psu->hasInputFault(), false);
52 EXPECT_EQ(psu->hasMFRFault(), false);
53 EXPECT_EQ(psu->hasVINUVFault(), false);
54}
55
56TEST_F(PowerSupplyTests, Analyze)
57{
58 auto bus = sdbusplus::bus::new_default();
59
60 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
61 PowerSupply psu{bus, PSUInventoryPath, 4, "0069"};
62 psu.analyze();
63 // By default, nothing should change.
64 EXPECT_EQ(psu.isPresent(), false);
65 EXPECT_EQ(psu.isFaulted(), false);
66 EXPECT_EQ(psu.hasInputFault(), false);
67 EXPECT_EQ(psu.hasMFRFault(), false);
68 EXPECT_EQ(psu.hasVINUVFault(), false);
69
70 // In order to get the various faults tested, the power supply needs to be
71 // present in order to read from the PMBus device(s).
72 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
73 .Times(1)
74 .WillOnce(Return(true)); // present
75 PowerSupply psu2{bus, PSUInventoryPath, 5, "006a"};
76 EXPECT_EQ(psu2.isPresent(), true);
77
78 // STATUS_WORD 0x0000 is powered on, no faults.
79 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu2.getPMBus());
80 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
81 psu2.analyze();
82 EXPECT_EQ(psu2.isPresent(), true);
83 EXPECT_EQ(psu2.isFaulted(), false);
84 EXPECT_EQ(psu2.hasInputFault(), false);
85 EXPECT_EQ(psu2.hasMFRFault(), false);
86 EXPECT_EQ(psu2.hasVINUVFault(), false);
87
88 // STATUS_WORD input fault/warn
89 EXPECT_CALL(mockPMBus, read(_, _))
90 .Times(1)
91 .WillOnce(Return(status_word::INPUT_FAULT_WARN));
92 psu2.analyze();
93 EXPECT_EQ(psu2.isPresent(), true);
94 EXPECT_EQ(psu2.isFaulted(), true);
95 EXPECT_EQ(psu2.hasInputFault(), true);
96 EXPECT_EQ(psu2.hasMFRFault(), false);
97 EXPECT_EQ(psu2.hasVINUVFault(), false);
98
99 // STATUS_WORD INPUT/UV fault.
100 // First need it to return good status, then the fault
101 EXPECT_CALL(mockPMBus, read(_, _))
102 .WillOnce(Return(0x0000))
103 .WillOnce(Return(status_word::VIN_UV_FAULT));
104 psu2.analyze();
105 psu2.analyze();
106 EXPECT_EQ(psu2.isPresent(), true);
107 EXPECT_EQ(psu2.isFaulted(), true);
108 EXPECT_EQ(psu2.hasInputFault(), false);
109 EXPECT_EQ(psu2.hasMFRFault(), false);
110 EXPECT_EQ(psu2.hasVINUVFault(), true);
111
112 // STATUS_WORD MFR fault.
113 EXPECT_CALL(mockPMBus, read(_, _))
114 .WillOnce(Return(0x0000))
115 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
116 psu2.analyze();
117 psu2.analyze();
118 EXPECT_EQ(psu2.isPresent(), true);
119 EXPECT_EQ(psu2.isFaulted(), true);
120 EXPECT_EQ(psu2.hasInputFault(), false);
121 EXPECT_EQ(psu2.hasMFRFault(), true);
122 EXPECT_EQ(psu2.hasVINUVFault(), false);
123
124 // Ignore Temperature fault.
125 EXPECT_CALL(mockPMBus, read(_, _))
126 .WillOnce(Return(0x0000))
127 .WillOnce(Return(status_word::TEMPERATURE_FAULT_WARN));
128 psu2.analyze();
129 psu2.analyze();
130 EXPECT_EQ(psu2.isPresent(), true);
131 EXPECT_EQ(psu2.isFaulted(), false);
132 EXPECT_EQ(psu2.hasInputFault(), false);
133 EXPECT_EQ(psu2.hasMFRFault(), false);
134 EXPECT_EQ(psu2.hasVINUVFault(), false);
135
136 // Ignore fan fault
137 EXPECT_CALL(mockPMBus, read(_, _))
138 .WillOnce(Return(0x0000))
139 .WillOnce(Return(status_word::FAN_FAULT));
140 psu2.analyze();
141 psu2.analyze();
142 EXPECT_EQ(psu2.isPresent(), true);
143 EXPECT_EQ(psu2.isFaulted(), false);
144 EXPECT_EQ(psu2.hasInputFault(), false);
145 EXPECT_EQ(psu2.hasMFRFault(), false);
146 EXPECT_EQ(psu2.hasVINUVFault(), false);
147
148 // TODO: ReadFailure
149}
150
151TEST_F(PowerSupplyTests, ClearFaults)
152{
153 auto bus = sdbusplus::bus::new_default();
154 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
155 .Times(1)
156 .WillOnce(Return(true)); // present
157 PowerSupply psu{bus, PSUInventoryPath, 13, "0068"};
158 EXPECT_EQ(psu.isPresent(), true);
159 EXPECT_EQ(psu.isFaulted(), false);
160 EXPECT_EQ(psu.hasInputFault(), false);
161 EXPECT_EQ(psu.hasMFRFault(), false);
162 EXPECT_EQ(psu.hasVINUVFault(), false);
163 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
164 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
165 psu.analyze();
166 EXPECT_EQ(psu.isPresent(), true);
167 EXPECT_EQ(psu.isFaulted(), true);
168 EXPECT_EQ(psu.hasInputFault(), true);
169 EXPECT_EQ(psu.hasMFRFault(), true);
170 EXPECT_EQ(psu.hasVINUVFault(), true);
Brandon Wyman3c208462020-05-13 16:25:58 -0500171 EXPECT_CALL(mockPMBus, read("in1_input", _))
172 .Times(1)
173 .WillOnce(Return(209000));
Brandon Wyman3f1242f2020-01-28 13:11:25 -0600174 psu.clearFaults();
175 EXPECT_EQ(psu.isPresent(), true);
176 EXPECT_EQ(psu.isFaulted(), false);
177 EXPECT_EQ(psu.hasInputFault(), false);
178 EXPECT_EQ(psu.hasMFRFault(), false);
179 EXPECT_EQ(psu.hasVINUVFault(), false);
180}
181
182TEST_F(PowerSupplyTests, UpdateInventory)
183{
184 auto bus = sdbusplus::bus::new_default();
185 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
186 .Times(1)
187 .WillOnce(Return(true)); // present
188 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
189 psu.updateInventory();
190 // TODO: Checks / Story #921
191}
192
193TEST_F(PowerSupplyTests, IsPresent)
194{
195 auto bus = sdbusplus::bus::new_default();
196 EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
197 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
198 EXPECT_EQ(psu.isPresent(), false);
199
200 EXPECT_CALL(mockedUtil, getPresence(_, _))
201 .WillOnce(Return(true)); // present
202 PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"};
203 EXPECT_EQ(psu2.isPresent(), true);
204}
205
206TEST_F(PowerSupplyTests, IsFaulted)
207{
208 auto bus = sdbusplus::bus::new_default();
209 EXPECT_CALL(mockedUtil, getPresence(_, _))
210 .WillOnce(Return(true)); // present
211 PowerSupply psu{bus, PSUInventoryPath, 11, "006f"};
212 EXPECT_EQ(psu.isFaulted(), false);
213 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
214 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
215 psu.analyze();
216 EXPECT_EQ(psu.isFaulted(), true);
217}
218
219TEST_F(PowerSupplyTests, HasInputFault)
220{
221 auto bus = sdbusplus::bus::new_default();
222 EXPECT_CALL(mockedUtil, getPresence(_, _))
223 .WillOnce(Return(true)); // present
224 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
225 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
226 EXPECT_EQ(psu.hasInputFault(), false);
227 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
228 psu.analyze();
229 EXPECT_EQ(psu.hasInputFault(), false);
230 EXPECT_CALL(mockPMBus, read(_, _))
231 .Times(1)
232 .WillOnce(Return(status_word::INPUT_FAULT_WARN));
233 psu.analyze();
234 EXPECT_EQ(psu.hasInputFault(), true);
235 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
236 psu.analyze();
237 EXPECT_EQ(psu.hasInputFault(), false);
238}
239
240TEST_F(PowerSupplyTests, HasMFRFault)
241{
242 auto bus = sdbusplus::bus::new_default();
243 EXPECT_CALL(mockedUtil, getPresence(_, _))
244 .WillOnce(Return(true)); // present
245 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
246 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
247 EXPECT_EQ(psu.hasMFRFault(), false);
248 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
249 psu.analyze();
250 EXPECT_EQ(psu.hasMFRFault(), false);
251 EXPECT_CALL(mockPMBus, read(_, _))
252 .Times(1)
253 .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
254 psu.analyze();
255 EXPECT_EQ(psu.hasMFRFault(), true);
256 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
257 psu.analyze();
258 EXPECT_EQ(psu.hasMFRFault(), false);
259}
260
261TEST_F(PowerSupplyTests, HasVINUVFault)
262{
263 auto bus = sdbusplus::bus::new_default();
264 EXPECT_CALL(mockedUtil, getPresence(_, _))
265 .WillOnce(Return(true)); // present
266 PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
267 MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
268 EXPECT_EQ(psu.hasVINUVFault(), false);
269 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
270 psu.analyze();
271 EXPECT_EQ(psu.hasVINUVFault(), false);
272 EXPECT_CALL(mockPMBus, read(_, _))
273 .Times(1)
274 .WillOnce(Return(status_word::VIN_UV_FAULT));
275 psu.analyze();
276 EXPECT_EQ(psu.hasVINUVFault(), true);
277 EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
278 psu.analyze();
279 EXPECT_EQ(psu.hasVINUVFault(), false);
280}