1 #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 
10 using namespace phosphor::power::psu;
11 using namespace phosphor::pmbus;
12 
13 using ::testing::_;
14 using ::testing::Assign;
15 using ::testing::DoAll;
16 using ::testing::Return;
17 using ::testing::StrEq;
18 
19 static auto PSUInventoryPath = "/xyz/bmc/inv/sys/chassis/board/powersupply0";
20 
21 class 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 
38 TEST_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 
56 TEST_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 
151 TEST_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);
171     EXPECT_CALL(mockPMBus, read("in1_input", _))
172         .Times(1)
173         .WillOnce(Return(209000));
174     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 
182 TEST_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 
193 TEST_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 
206 TEST_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 
219 TEST_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 
240 TEST_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 
261 TEST_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 }
281