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     psu.clearFaults();
172     EXPECT_EQ(psu.isPresent(), true);
173     EXPECT_EQ(psu.isFaulted(), false);
174     EXPECT_EQ(psu.hasInputFault(), false);
175     EXPECT_EQ(psu.hasMFRFault(), false);
176     EXPECT_EQ(psu.hasVINUVFault(), false);
177 }
178 
179 TEST_F(PowerSupplyTests, UpdateInventory)
180 {
181     auto bus = sdbusplus::bus::new_default();
182     EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath)))
183         .Times(1)
184         .WillOnce(Return(true)); // present
185     PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
186     psu.updateInventory();
187     // TODO: Checks / Story #921
188 }
189 
190 TEST_F(PowerSupplyTests, IsPresent)
191 {
192     auto bus = sdbusplus::bus::new_default();
193     EXPECT_CALL(mockedUtil, getPresence(_, StrEq(PSUInventoryPath))).Times(1);
194     PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
195     EXPECT_EQ(psu.isPresent(), false);
196 
197     EXPECT_CALL(mockedUtil, getPresence(_, _))
198         .WillOnce(Return(true)); // present
199     PowerSupply psu2{bus, PSUInventoryPath, 10, "006b"};
200     EXPECT_EQ(psu2.isPresent(), true);
201 }
202 
203 TEST_F(PowerSupplyTests, IsFaulted)
204 {
205     auto bus = sdbusplus::bus::new_default();
206     EXPECT_CALL(mockedUtil, getPresence(_, _))
207         .WillOnce(Return(true)); // present
208     PowerSupply psu{bus, PSUInventoryPath, 11, "006f"};
209     EXPECT_EQ(psu.isFaulted(), false);
210     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
211     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0xFFFF));
212     psu.analyze();
213     EXPECT_EQ(psu.isFaulted(), true);
214 }
215 
216 TEST_F(PowerSupplyTests, HasInputFault)
217 {
218     auto bus = sdbusplus::bus::new_default();
219     EXPECT_CALL(mockedUtil, getPresence(_, _))
220         .WillOnce(Return(true)); // present
221     PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
222     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
223     EXPECT_EQ(psu.hasInputFault(), false);
224     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
225     psu.analyze();
226     EXPECT_EQ(psu.hasInputFault(), false);
227     EXPECT_CALL(mockPMBus, read(_, _))
228         .Times(1)
229         .WillOnce(Return(status_word::INPUT_FAULT_WARN));
230     psu.analyze();
231     EXPECT_EQ(psu.hasInputFault(), true);
232     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
233     psu.analyze();
234     EXPECT_EQ(psu.hasInputFault(), false);
235 }
236 
237 TEST_F(PowerSupplyTests, HasMFRFault)
238 {
239     auto bus = sdbusplus::bus::new_default();
240     EXPECT_CALL(mockedUtil, getPresence(_, _))
241         .WillOnce(Return(true)); // present
242     PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
243     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
244     EXPECT_EQ(psu.hasMFRFault(), false);
245     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
246     psu.analyze();
247     EXPECT_EQ(psu.hasMFRFault(), false);
248     EXPECT_CALL(mockPMBus, read(_, _))
249         .Times(1)
250         .WillOnce(Return(status_word::MFR_SPECIFIC_FAULT));
251     psu.analyze();
252     EXPECT_EQ(psu.hasMFRFault(), true);
253     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
254     psu.analyze();
255     EXPECT_EQ(psu.hasMFRFault(), false);
256 }
257 
258 TEST_F(PowerSupplyTests, HasVINUVFault)
259 {
260     auto bus = sdbusplus::bus::new_default();
261     EXPECT_CALL(mockedUtil, getPresence(_, _))
262         .WillOnce(Return(true)); // present
263     PowerSupply psu{bus, PSUInventoryPath, 3, "0068"};
264     MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
265     EXPECT_EQ(psu.hasVINUVFault(), false);
266     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
267     psu.analyze();
268     EXPECT_EQ(psu.hasVINUVFault(), false);
269     EXPECT_CALL(mockPMBus, read(_, _))
270         .Times(1)
271         .WillOnce(Return(status_word::VIN_UV_FAULT));
272     psu.analyze();
273     EXPECT_EQ(psu.hasVINUVFault(), true);
274     EXPECT_CALL(mockPMBus, read(_, _)).Times(1).WillOnce(Return(0x0000));
275     psu.analyze();
276     EXPECT_EQ(psu.hasVINUVFault(), false);
277 }
278