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