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     auto presenceDetection =
89         std::make_unique<PresenceDetection>(std::move(actions));
90     PresenceDetection* presenceDetectionPtr = presenceDetection.get();
91 
92     // Create Device that contains PresenceDetection
93     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
94     auto 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     auto 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     auto 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     auto sensorMonitoring =
134         std::make_unique<SensorMonitoring>(std::move(actions));
135 
136     // Create Rail
137     std::unique_ptr<Configuration> configuration{};
138     auto rail = std::make_unique<Rail>("vddr1", std::move(configuration),
139                                        std::move(sensorMonitoring));
140 
141     // Create Device that contains Rail
142     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
143     std::unique_ptr<PresenceDetection> presenceDetection{};
144     std::unique_ptr<Configuration> deviceConfiguration{};
145     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
146     std::vector<std::unique_ptr<Rail>> rails{};
147     rails.emplace_back(std::move(rail));
148     auto device = std::make_unique<Device>(
149         "reg1", true,
150         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
151         std::move(i2cInterface), std::move(presenceDetection),
152         std::move(deviceConfiguration), std::move(phaseFaultDetection),
153         std::move(rails));
154 
155     // Create Chassis that contains Device
156     std::vector<std::unique_ptr<Device>> devices{};
157     devices.emplace_back(std::move(device));
158     auto chassis =
159         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
160 
161     // Create System that contains Chassis
162     std::vector<std::unique_ptr<Rule>> rules{};
163     std::vector<std::unique_ptr<Chassis>> chassisVec{};
164     chassisVec.emplace_back(std::move(chassis));
165     System system{std::move(rules), std::move(chassisVec)};
166 
167     // Create mock services
168     MockServices services{};
169 
170     // Expect Sensors service to be called 5+5=10 times
171     MockSensors& sensors = services.getMockSensors();
172     EXPECT_CALL(sensors, startRail).Times(10);
173     EXPECT_CALL(sensors, setValue).Times(0);
174     EXPECT_CALL(sensors, endRail).Times(10);
175 
176     // Expect Journal service to be called 3+3=6 times to log error messages
177     MockJournal& journal = services.getMockJournal();
178     EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
179         .Times(6);
180     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
181 
182     // Expect ErrorLogging service to be called 1+1=2 times to log a DBus error
183     MockErrorLogging& errorLogging = services.getMockErrorLogging();
184     EXPECT_CALL(errorLogging, logDBusError).Times(2);
185 
186     // Monitor sensors 5 times.  Should fail every time, write to journal 3
187     // times, and log one error.
188     for (int i = 1; i <= 5; ++i)
189     {
190         system.monitorSensors(services);
191     }
192 
193     // Clear error history
194     system.clearErrorHistory();
195 
196     // Monitor sensors 5 times again.  Should fail every time, write to journal
197     // 3 times, and log one error.
198     for (int i = 1; i <= 5; ++i)
199     {
200         system.monitorSensors(services);
201     }
202 }
203 
204 TEST(SystemTests, CloseDevices)
205 {
206     // Specify an empty rules vector
207     std::vector<std::unique_ptr<Rule>> rules{};
208 
209     // Create mock services.  Expect logDebug() to be called.
210     MockServices services{};
211     MockJournal& journal = services.getMockJournal();
212     EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
213     EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1);
214     EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0);
215     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
216 
217     // Create Chassis
218     std::vector<std::unique_ptr<Chassis>> chassis{};
219     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
220     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
221 
222     // Create System
223     System system{std::move(rules), std::move(chassis)};
224 
225     // Call closeDevices()
226     system.closeDevices(services);
227 }
228 
229 TEST(SystemTests, Configure)
230 {
231     // Create mock services.  Expect logInfo() to be called.
232     MockServices services{};
233     MockJournal& journal = services.getMockJournal();
234     EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
235     EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1);
236     EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
237     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
238 
239     // Specify an empty rules vector
240     std::vector<std::unique_ptr<Rule>> rules{};
241 
242     // Create Chassis
243     std::vector<std::unique_ptr<Chassis>> chassis{};
244     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
245     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
246 
247     // Create System
248     System system{std::move(rules), std::move(chassis)};
249 
250     // Call configure()
251     system.configure(services);
252 }
253 
254 TEST(SystemTests, GetChassis)
255 {
256     // Specify an empty rules vector
257     std::vector<std::unique_ptr<Rule>> rules{};
258 
259     // Create Chassis
260     std::vector<std::unique_ptr<Chassis>> chassis{};
261     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
262     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
263 
264     // Create System
265     System system{std::move(rules), std::move(chassis)};
266     EXPECT_EQ(system.getChassis().size(), 2);
267     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
268     EXPECT_EQ(system.getChassis()[1]->getNumber(), 3);
269 }
270 
271 TEST(SystemTests, GetIDMap)
272 {
273     // Create Rules
274     std::vector<std::unique_ptr<Rule>> rules{};
275     rules.emplace_back(createRule("set_voltage_rule"));
276     rules.emplace_back(createRule("read_sensors_rule"));
277 
278     // Create Chassis
279     std::vector<std::unique_ptr<Chassis>> chassis{};
280     {
281         // Chassis 1
282         std::vector<std::unique_ptr<Device>> devices{};
283         devices.emplace_back(createDevice("reg1", {"rail1"}));
284         devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
285         chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1',
286                                                        std::move(devices)));
287     }
288     {
289         // Chassis 2
290         std::vector<std::unique_ptr<Device>> devices{};
291         devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"}));
292         devices.emplace_back(createDevice("reg4"));
293         chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2',
294                                                        std::move(devices)));
295     }
296 
297     // Create System
298     System system{std::move(rules), std::move(chassis)};
299     const IDMap& idMap = system.getIDMap();
300 
301     // Verify all Rules are in the IDMap
302     EXPECT_NO_THROW(idMap.getRule("set_voltage_rule"));
303     EXPECT_NO_THROW(idMap.getRule("read_sensors_rule"));
304     EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument);
305 
306     // Verify all Devices are in the IDMap
307     EXPECT_NO_THROW(idMap.getDevice("reg1"));
308     EXPECT_NO_THROW(idMap.getDevice("reg2"));
309     EXPECT_NO_THROW(idMap.getDevice("reg3"));
310     EXPECT_NO_THROW(idMap.getDevice("reg4"));
311     EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument);
312 
313     // Verify all Rails are in the IDMap
314     EXPECT_NO_THROW(idMap.getRail("rail1"));
315     EXPECT_NO_THROW(idMap.getRail("rail2a"));
316     EXPECT_NO_THROW(idMap.getRail("rail2b"));
317     EXPECT_NO_THROW(idMap.getRail("rail3a"));
318     EXPECT_NO_THROW(idMap.getRail("rail3b"));
319     EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument);
320 }
321 
322 TEST(SystemTests, GetRules)
323 {
324     // Create Rules
325     std::vector<std::unique_ptr<Rule>> rules{};
326     rules.emplace_back(createRule("set_voltage_rule"));
327     rules.emplace_back(createRule("read_sensors_rule"));
328 
329     // Create Chassis
330     std::vector<std::unique_ptr<Chassis>> chassis{};
331     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath));
332 
333     // Create System
334     System system{std::move(rules), std::move(chassis)};
335     EXPECT_EQ(system.getRules().size(), 2);
336     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
337     EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule");
338 }
339 
340 TEST(SystemTests, MonitorSensors)
341 {
342     // Create mock services.  Set Sensors service expectations.
343     MockServices services{};
344     MockSensors& sensors = services.getMockSensors();
345     EXPECT_CALL(sensors, startRail("c1_vdd0",
346                                    "/xyz/openbmc_project/inventory/system/"
347                                    "chassis1/motherboard/vdd0_reg",
348                                    chassisInvPath + '1'))
349         .Times(1);
350     EXPECT_CALL(sensors, startRail("c2_vdd0",
351                                    "/xyz/openbmc_project/inventory/system/"
352                                    "chassis2/motherboard/vdd0_reg",
353                                    chassisInvPath + '2'))
354         .Times(1);
355     EXPECT_CALL(sensors, setValue).Times(0);
356     EXPECT_CALL(sensors, endRail(false)).Times(2);
357 
358     std::vector<std::unique_ptr<Chassis>> chassisVec{};
359 
360     // Create Chassis 1
361     {
362         // Create SensorMonitoring for Rail
363         auto action = std::make_unique<MockAction>();
364         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
365         std::vector<std::unique_ptr<Action>> actions{};
366         actions.emplace_back(std::move(action));
367         auto sensorMonitoring =
368             std::make_unique<SensorMonitoring>(std::move(actions));
369 
370         // Create Rail
371         std::unique_ptr<Configuration> configuration{};
372         auto rail = std::make_unique<Rail>("c1_vdd0", std::move(configuration),
373                                            std::move(sensorMonitoring));
374 
375         // Create Device
376         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
377         std::unique_ptr<PresenceDetection> presenceDetection{};
378         std::unique_ptr<Configuration> deviceConfiguration{};
379         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
380         std::vector<std::unique_ptr<Rail>> rails{};
381         rails.emplace_back(std::move(rail));
382         auto device = std::make_unique<Device>(
383             "c1_vdd0_reg", true,
384             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
385             "vdd0_reg",
386             std::move(i2cInterface), std::move(presenceDetection),
387             std::move(deviceConfiguration), std::move(phaseFaultDetection),
388             std::move(rails));
389 
390         // Create Chassis
391         std::vector<std::unique_ptr<Device>> devices{};
392         devices.emplace_back(std::move(device));
393         auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1',
394                                                  std::move(devices));
395         chassisVec.emplace_back(std::move(chassis));
396     }
397 
398     // Create Chassis 2
399     {
400         // Create SensorMonitoring for Rail
401         auto action = std::make_unique<MockAction>();
402         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
403         std::vector<std::unique_ptr<Action>> actions{};
404         actions.emplace_back(std::move(action));
405         auto sensorMonitoring =
406             std::make_unique<SensorMonitoring>(std::move(actions));
407 
408         // Create Rail
409         std::unique_ptr<Configuration> configuration{};
410         auto rail = std::make_unique<Rail>("c2_vdd0", std::move(configuration),
411                                            std::move(sensorMonitoring));
412 
413         // Create Device
414         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
415         std::unique_ptr<PresenceDetection> presenceDetection{};
416         std::unique_ptr<Configuration> deviceConfiguration{};
417         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
418         std::vector<std::unique_ptr<Rail>> rails{};
419         rails.emplace_back(std::move(rail));
420         auto device = std::make_unique<Device>(
421             "c2_vdd0_reg", true,
422             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
423             "vdd0_reg",
424             std::move(i2cInterface), std::move(presenceDetection),
425             std::move(deviceConfiguration), std::move(phaseFaultDetection),
426             std::move(rails));
427 
428         // Create Chassis
429         std::vector<std::unique_ptr<Device>> devices{};
430         devices.emplace_back(std::move(device));
431         auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2',
432                                                  std::move(devices));
433         chassisVec.emplace_back(std::move(chassis));
434     }
435 
436     // Create System that contains Chassis
437     std::vector<std::unique_ptr<Rule>> rules{};
438     System system{std::move(rules), std::move(chassisVec)};
439 
440     // Call monitorSensors()
441     system.monitorSensors(services);
442 }
443