1 /**
2  * Copyright © 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "action.hpp"
17 #include "chassis.hpp"
18 #include "configuration.hpp"
19 #include "device.hpp"
20 #include "i2c_interface.hpp"
21 #include "id_map.hpp"
22 #include "mock_action.hpp"
23 #include "mock_error_logging.hpp"
24 #include "mock_journal.hpp"
25 #include "mock_sensors.hpp"
26 #include "mock_services.hpp"
27 #include "mocked_i2c_interface.hpp"
28 #include "phase_fault_detection.hpp"
29 #include "presence_detection.hpp"
30 #include "rail.hpp"
31 #include "rule.hpp"
32 #include "sensor_monitoring.hpp"
33 #include "sensors.hpp"
34 #include "services.hpp"
35 #include "system.hpp"
36 #include "test_sdbus_error.hpp"
37 #include "test_utils.hpp"
38 
39 #include <memory>
40 #include <stdexcept>
41 #include <string>
42 #include <utility>
43 #include <vector>
44 
45 #include <gmock/gmock.h>
46 #include <gtest/gtest.h>
47 
48 using namespace phosphor::power::regulators;
49 using namespace phosphor::power::regulators::test_utils;
50 
51 using ::testing::A;
52 using ::testing::Return;
53 using ::testing::Throw;
54 using ::testing::TypedEq;
55 
56 static const std::string chassisInvPath{
57     "/xyz/openbmc_project/inventory/system/chassis"};
58 
59 TEST(SystemTests, Constructor)
60 {
61     // Create Rules
62     std::vector<std::unique_ptr<Rule>> rules{};
63     rules.emplace_back(createRule("set_voltage_rule"));
64 
65     // Create Chassis
66     std::vector<std::unique_ptr<Chassis>> chassis{};
67     std::vector<std::unique_ptr<Device>> devices{};
68     devices.emplace_back(createDevice("reg1", {"rail1"}));
69     chassis.emplace_back(
70         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)));
71 
72     // Create System
73     System system{std::move(rules), std::move(chassis)};
74     EXPECT_EQ(system.getChassis().size(), 1);
75     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
76     EXPECT_NO_THROW(system.getIDMap().getRule("set_voltage_rule"));
77     EXPECT_NO_THROW(system.getIDMap().getDevice("reg1"));
78     EXPECT_NO_THROW(system.getIDMap().getRail("rail1"));
79     EXPECT_THROW(system.getIDMap().getRail("rail2"), std::invalid_argument);
80     EXPECT_EQ(system.getRules().size(), 1);
81     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
82 }
83 
84 TEST(SystemTests, ClearCache)
85 {
86     // Create PresenceDetection
87     std::vector<std::unique_ptr<Action>> actions{};
88     std::unique_ptr<PresenceDetection> presenceDetection =
89         std::make_unique<PresenceDetection>(std::move(actions));
90     PresenceDetection* presenceDetectionPtr = presenceDetection.get();
91 
92     // Create Device that contains PresenceDetection
93     std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
94     std::unique_ptr<Device> device = std::make_unique<Device>(
95         "reg1", true,
96         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
97         std::move(i2cInterface), std::move(presenceDetection));
98     Device* devicePtr = device.get();
99 
100     // Create Chassis that contains Device
101     std::vector<std::unique_ptr<Device>> devices{};
102     devices.emplace_back(std::move(device));
103     std::unique_ptr<Chassis> chassis =
104         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
105     Chassis* chassisPtr = chassis.get();
106 
107     // Create System that contains Chassis
108     std::vector<std::unique_ptr<Rule>> rules{};
109     std::vector<std::unique_ptr<Chassis>> chassisVec{};
110     chassisVec.emplace_back(std::move(chassis));
111     System system{std::move(rules), std::move(chassisVec)};
112 
113     // Cache presence value in PresenceDetection
114     MockServices services{};
115     presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr);
116     EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
117 
118     // Clear cached data in System
119     system.clearCache();
120 
121     // Verify presence value no longer cached in PresenceDetection
122     EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
123 }
124 
125 TEST(SystemTests, ClearErrorHistory)
126 {
127     // Create SensorMonitoring.  Will fail with a DBus exception.
128     std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
129     EXPECT_CALL(*action, execute)
130         .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"}));
131     std::vector<std::unique_ptr<Action>> actions{};
132     actions.emplace_back(std::move(action));
133     std::unique_ptr<SensorMonitoring> sensorMonitoring =
134         std::make_unique<SensorMonitoring>(std::move(actions));
135 
136     // Create Rail
137     std::unique_ptr<Configuration> configuration{};
138     std::unique_ptr<Rail> rail = std::make_unique<Rail>(
139         "vddr1", std::move(configuration), std::move(sensorMonitoring));
140 
141     // Create Device that contains Rail
142     std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
143         std::make_unique<i2c::MockedI2CInterface>();
144     std::unique_ptr<PresenceDetection> presenceDetection{};
145     std::unique_ptr<Configuration> deviceConfiguration{};
146     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
147     std::vector<std::unique_ptr<Rail>> rails{};
148     rails.emplace_back(std::move(rail));
149     std::unique_ptr<Device> device = std::make_unique<Device>(
150         "reg1", true,
151         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
152         std::move(i2cInterface), std::move(presenceDetection),
153         std::move(deviceConfiguration), std::move(phaseFaultDetection),
154         std::move(rails));
155 
156     // Create Chassis that contains Device
157     std::vector<std::unique_ptr<Device>> devices{};
158     devices.emplace_back(std::move(device));
159     std::unique_ptr<Chassis> chassis =
160         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
161 
162     // Create System that contains Chassis
163     std::vector<std::unique_ptr<Rule>> rules{};
164     std::vector<std::unique_ptr<Chassis>> chassisVec{};
165     chassisVec.emplace_back(std::move(chassis));
166     System system{std::move(rules), std::move(chassisVec)};
167 
168     // Create mock services
169     MockServices services{};
170 
171     // Expect Sensors service to be called 5+5=10 times
172     MockSensors& sensors = services.getMockSensors();
173     EXPECT_CALL(sensors, startRail).Times(10);
174     EXPECT_CALL(sensors, setValue).Times(0);
175     EXPECT_CALL(sensors, endRail).Times(10);
176 
177     // Expect Journal service to be called 3+3=6 times to log error messages
178     MockJournal& journal = services.getMockJournal();
179     EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
180         .Times(6);
181     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
182 
183     // Expect ErrorLogging service to be called 1+1=2 times to log a DBus error
184     MockErrorLogging& errorLogging = services.getMockErrorLogging();
185     EXPECT_CALL(errorLogging, logDBusError).Times(2);
186 
187     // Monitor sensors 5 times.  Should fail every time, write to journal 3
188     // times, and log one error.
189     for (int i = 1; i <= 5; ++i)
190     {
191         system.monitorSensors(services);
192     }
193 
194     // Clear error history
195     system.clearErrorHistory();
196 
197     // Monitor sensors 5 times again.  Should fail every time, write to journal
198     // 3 times, and log one error.
199     for (int i = 1; i <= 5; ++i)
200     {
201         system.monitorSensors(services);
202     }
203 }
204 
205 TEST(SystemTests, CloseDevices)
206 {
207     // Specify an empty rules vector
208     std::vector<std::unique_ptr<Rule>> rules{};
209 
210     // Create mock services.  Expect logDebug() to be called.
211     MockServices services{};
212     MockJournal& journal = services.getMockJournal();
213     EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
214     EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1);
215     EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0);
216     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
217 
218     // Create Chassis
219     std::vector<std::unique_ptr<Chassis>> chassis{};
220     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
221     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
222 
223     // Create System
224     System system{std::move(rules), std::move(chassis)};
225 
226     // Call closeDevices()
227     system.closeDevices(services);
228 }
229 
230 TEST(SystemTests, Configure)
231 {
232     // Create mock services.  Expect logInfo() to be called.
233     MockServices services{};
234     MockJournal& journal = services.getMockJournal();
235     EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
236     EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1);
237     EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
238     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
239 
240     // Specify an empty rules vector
241     std::vector<std::unique_ptr<Rule>> rules{};
242 
243     // Create Chassis
244     std::vector<std::unique_ptr<Chassis>> chassis{};
245     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
246     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
247 
248     // Create System
249     System system{std::move(rules), std::move(chassis)};
250 
251     // Call configure()
252     system.configure(services);
253 }
254 
255 TEST(SystemTests, GetChassis)
256 {
257     // Specify an empty rules vector
258     std::vector<std::unique_ptr<Rule>> rules{};
259 
260     // Create Chassis
261     std::vector<std::unique_ptr<Chassis>> chassis{};
262     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
263     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
264 
265     // Create System
266     System system{std::move(rules), std::move(chassis)};
267     EXPECT_EQ(system.getChassis().size(), 2);
268     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
269     EXPECT_EQ(system.getChassis()[1]->getNumber(), 3);
270 }
271 
272 TEST(SystemTests, GetIDMap)
273 {
274     // Create Rules
275     std::vector<std::unique_ptr<Rule>> rules{};
276     rules.emplace_back(createRule("set_voltage_rule"));
277     rules.emplace_back(createRule("read_sensors_rule"));
278 
279     // Create Chassis
280     std::vector<std::unique_ptr<Chassis>> chassis{};
281     {
282         // Chassis 1
283         std::vector<std::unique_ptr<Device>> devices{};
284         devices.emplace_back(createDevice("reg1", {"rail1"}));
285         devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
286         chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1',
287                                                        std::move(devices)));
288     }
289     {
290         // Chassis 2
291         std::vector<std::unique_ptr<Device>> devices{};
292         devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"}));
293         devices.emplace_back(createDevice("reg4"));
294         chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2',
295                                                        std::move(devices)));
296     }
297 
298     // Create System
299     System system{std::move(rules), std::move(chassis)};
300     const IDMap& idMap = system.getIDMap();
301 
302     // Verify all Rules are in the IDMap
303     EXPECT_NO_THROW(idMap.getRule("set_voltage_rule"));
304     EXPECT_NO_THROW(idMap.getRule("read_sensors_rule"));
305     EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument);
306 
307     // Verify all Devices are in the IDMap
308     EXPECT_NO_THROW(idMap.getDevice("reg1"));
309     EXPECT_NO_THROW(idMap.getDevice("reg2"));
310     EXPECT_NO_THROW(idMap.getDevice("reg3"));
311     EXPECT_NO_THROW(idMap.getDevice("reg4"));
312     EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument);
313 
314     // Verify all Rails are in the IDMap
315     EXPECT_NO_THROW(idMap.getRail("rail1"));
316     EXPECT_NO_THROW(idMap.getRail("rail2a"));
317     EXPECT_NO_THROW(idMap.getRail("rail2b"));
318     EXPECT_NO_THROW(idMap.getRail("rail3a"));
319     EXPECT_NO_THROW(idMap.getRail("rail3b"));
320     EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument);
321 }
322 
323 TEST(SystemTests, GetRules)
324 {
325     // Create Rules
326     std::vector<std::unique_ptr<Rule>> rules{};
327     rules.emplace_back(createRule("set_voltage_rule"));
328     rules.emplace_back(createRule("read_sensors_rule"));
329 
330     // Create Chassis
331     std::vector<std::unique_ptr<Chassis>> chassis{};
332     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath));
333 
334     // Create System
335     System system{std::move(rules), std::move(chassis)};
336     EXPECT_EQ(system.getRules().size(), 2);
337     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
338     EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule");
339 }
340 
341 TEST(SystemTests, MonitorSensors)
342 {
343     // Create mock services.  Set Sensors service expectations.
344     MockServices services{};
345     MockSensors& sensors = services.getMockSensors();
346     EXPECT_CALL(sensors, startRail("c1_vdd0",
347                                    "/xyz/openbmc_project/inventory/system/"
348                                    "chassis1/motherboard/vdd0_reg",
349                                    chassisInvPath + '1'))
350         .Times(1);
351     EXPECT_CALL(sensors, startRail("c2_vdd0",
352                                    "/xyz/openbmc_project/inventory/system/"
353                                    "chassis2/motherboard/vdd0_reg",
354                                    chassisInvPath + '2'))
355         .Times(1);
356     EXPECT_CALL(sensors, setValue).Times(0);
357     EXPECT_CALL(sensors, endRail(false)).Times(2);
358 
359     std::vector<std::unique_ptr<Chassis>> chassisVec{};
360 
361     // Create Chassis 1
362     {
363         // Create SensorMonitoring for Rail
364         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
365         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
366         std::vector<std::unique_ptr<Action>> actions{};
367         actions.emplace_back(std::move(action));
368         std::unique_ptr<SensorMonitoring> sensorMonitoring =
369             std::make_unique<SensorMonitoring>(std::move(actions));
370 
371         // Create Rail
372         std::unique_ptr<Configuration> configuration{};
373         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
374             "c1_vdd0", std::move(configuration), std::move(sensorMonitoring));
375 
376         // Create Device
377         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
378         std::unique_ptr<PresenceDetection> presenceDetection{};
379         std::unique_ptr<Configuration> deviceConfiguration{};
380         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
381         std::vector<std::unique_ptr<Rail>> rails{};
382         rails.emplace_back(std::move(rail));
383         std::unique_ptr<Device> device = std::make_unique<Device>(
384             "c1_vdd0_reg", true,
385             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
386             "vdd0_reg",
387             std::move(i2cInterface), std::move(presenceDetection),
388             std::move(deviceConfiguration), std::move(phaseFaultDetection),
389             std::move(rails));
390 
391         // Create Chassis
392         std::vector<std::unique_ptr<Device>> devices{};
393         devices.emplace_back(std::move(device));
394         std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(
395             1, chassisInvPath + '1', std::move(devices));
396         chassisVec.emplace_back(std::move(chassis));
397     }
398 
399     // Create Chassis 2
400     {
401         // Create SensorMonitoring for Rail
402         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
403         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
404         std::vector<std::unique_ptr<Action>> actions{};
405         actions.emplace_back(std::move(action));
406         std::unique_ptr<SensorMonitoring> sensorMonitoring =
407             std::make_unique<SensorMonitoring>(std::move(actions));
408 
409         // Create Rail
410         std::unique_ptr<Configuration> configuration{};
411         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
412             "c2_vdd0", std::move(configuration), std::move(sensorMonitoring));
413 
414         // Create Device
415         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
416         std::unique_ptr<PresenceDetection> presenceDetection{};
417         std::unique_ptr<Configuration> deviceConfiguration{};
418         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
419         std::vector<std::unique_ptr<Rail>> rails{};
420         rails.emplace_back(std::move(rail));
421         std::unique_ptr<Device> device = std::make_unique<Device>(
422             "c2_vdd0_reg", true,
423             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
424             "vdd0_reg",
425             std::move(i2cInterface), std::move(presenceDetection),
426             std::move(deviceConfiguration), std::move(phaseFaultDetection),
427             std::move(rails));
428 
429         // Create Chassis
430         std::vector<std::unique_ptr<Device>> devices{};
431         devices.emplace_back(std::move(device));
432         std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(
433             2, chassisInvPath + '2', std::move(devices));
434         chassisVec.emplace_back(std::move(chassis));
435     }
436 
437     // Create System that contains Chassis
438     std::vector<std::unique_ptr<Rule>> rules{};
439     System system{std::move(rules), std::move(chassisVec)};
440 
441     // Call monitorSensors()
442     system.monitorSensors(services);
443 }
444