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 "log_phase_fault_action.hpp"
23 #include "mock_action.hpp"
24 #include "mock_error_logging.hpp"
25 #include "mock_journal.hpp"
26 #include "mock_sensors.hpp"
27 #include "mock_services.hpp"
28 #include "mocked_i2c_interface.hpp"
29 #include "phase_fault.hpp"
30 #include "phase_fault_detection.hpp"
31 #include "presence_detection.hpp"
32 #include "rail.hpp"
33 #include "rule.hpp"
34 #include "sensor_monitoring.hpp"
35 #include "sensors.hpp"
36 #include "services.hpp"
37 #include "system.hpp"
38 #include "test_sdbus_error.hpp"
39 #include "test_utils.hpp"
40 
41 #include <memory>
42 #include <stdexcept>
43 #include <string>
44 #include <utility>
45 #include <vector>
46 
47 #include <gmock/gmock.h>
48 #include <gtest/gtest.h>
49 
50 using namespace phosphor::power::regulators;
51 using namespace phosphor::power::regulators::test_utils;
52 
53 using ::testing::A;
54 using ::testing::Return;
55 using ::testing::Throw;
56 using ::testing::TypedEq;
57 
58 static const std::string chassisInvPath{
59     "/xyz/openbmc_project/inventory/system/chassis"};
60 
TEST(SystemTests,Constructor)61 TEST(SystemTests, Constructor)
62 {
63     // Create Rules
64     std::vector<std::unique_ptr<Rule>> rules{};
65     rules.emplace_back(createRule("set_voltage_rule"));
66 
67     // Create Chassis
68     std::vector<std::unique_ptr<Chassis>> chassis{};
69     std::vector<std::unique_ptr<Device>> devices{};
70     devices.emplace_back(createDevice("reg1", {"rail1"}));
71     chassis.emplace_back(
72         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices)));
73 
74     // Create System
75     System system{std::move(rules), std::move(chassis)};
76     EXPECT_EQ(system.getChassis().size(), 1);
77     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
78     EXPECT_NO_THROW(system.getIDMap().getRule("set_voltage_rule"));
79     EXPECT_NO_THROW(system.getIDMap().getDevice("reg1"));
80     EXPECT_NO_THROW(system.getIDMap().getRail("rail1"));
81     EXPECT_THROW(system.getIDMap().getRail("rail2"), std::invalid_argument);
82     EXPECT_EQ(system.getRules().size(), 1);
83     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
84 }
85 
TEST(SystemTests,ClearCache)86 TEST(SystemTests, ClearCache)
87 {
88     // Create PresenceDetection
89     std::vector<std::unique_ptr<Action>> actions{};
90     auto presenceDetection =
91         std::make_unique<PresenceDetection>(std::move(actions));
92     PresenceDetection* presenceDetectionPtr = presenceDetection.get();
93 
94     // Create Device that contains PresenceDetection
95     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
96     auto device = std::make_unique<Device>(
97         "reg1", true,
98         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
99         std::move(i2cInterface), std::move(presenceDetection));
100     Device* devicePtr = device.get();
101 
102     // Create Chassis that contains Device
103     std::vector<std::unique_ptr<Device>> devices{};
104     devices.emplace_back(std::move(device));
105     auto chassis =
106         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
107     Chassis* chassisPtr = chassis.get();
108 
109     // Create System that contains Chassis
110     std::vector<std::unique_ptr<Rule>> rules{};
111     std::vector<std::unique_ptr<Chassis>> chassisVec{};
112     chassisVec.emplace_back(std::move(chassis));
113     System system{std::move(rules), std::move(chassisVec)};
114 
115     // Cache presence value in PresenceDetection
116     MockServices services{};
117     presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr);
118     EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
119 
120     // Clear cached data in System
121     system.clearCache();
122 
123     // Verify presence value no longer cached in PresenceDetection
124     EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
125 }
126 
TEST(SystemTests,ClearErrorHistory)127 TEST(SystemTests, ClearErrorHistory)
128 {
129     // Create SensorMonitoring.  Will fail with a DBus exception.
130     auto action = std::make_unique<MockAction>();
131     EXPECT_CALL(*action, execute)
132         .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"}));
133     std::vector<std::unique_ptr<Action>> actions{};
134     actions.emplace_back(std::move(action));
135     auto sensorMonitoring =
136         std::make_unique<SensorMonitoring>(std::move(actions));
137 
138     // Create Rail
139     std::unique_ptr<Configuration> configuration{};
140     auto rail = std::make_unique<Rail>("vddr1", std::move(configuration),
141                                        std::move(sensorMonitoring));
142 
143     // Create Device that contains Rail
144     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
145     std::unique_ptr<PresenceDetection> presenceDetection{};
146     std::unique_ptr<Configuration> deviceConfiguration{};
147     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
148     std::vector<std::unique_ptr<Rail>> rails{};
149     rails.emplace_back(std::move(rail));
150     auto device = std::make_unique<Device>(
151         "reg1", true,
152         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
153         std::move(i2cInterface), std::move(presenceDetection),
154         std::move(deviceConfiguration), std::move(phaseFaultDetection),
155         std::move(rails));
156 
157     // Create Chassis that contains Device
158     std::vector<std::unique_ptr<Device>> devices{};
159     devices.emplace_back(std::move(device));
160     auto chassis =
161         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
162 
163     // Create System that contains Chassis
164     std::vector<std::unique_ptr<Rule>> rules{};
165     std::vector<std::unique_ptr<Chassis>> chassisVec{};
166     chassisVec.emplace_back(std::move(chassis));
167     System system{std::move(rules), std::move(chassisVec)};
168 
169     // Create lambda that sets MockServices expectations.  The lambda allows
170     // us to set expectations multiple times without duplicate code.
171     auto setExpectations = [](MockServices& services) {
172         // Expect Sensors service to be called 10 times
173         MockSensors& sensors = services.getMockSensors();
174         EXPECT_CALL(sensors, startRail).Times(10);
175         EXPECT_CALL(sensors, setValue).Times(0);
176         EXPECT_CALL(sensors, endRail).Times(10);
177 
178         // Expect Journal service to be called 6 times to log error messages
179         MockJournal& journal = services.getMockJournal();
180         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
181             .Times(6);
182         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
183 
184         // Expect ErrorLogging service to be called once to log a DBus error
185         MockErrorLogging& errorLogging = services.getMockErrorLogging();
186         EXPECT_CALL(errorLogging, logDBusError).Times(1);
187     };
188 
189     // Monitor sensors 10 times.  Verify errors logged.
190     {
191         // Create mock services.  Set expectations via lambda.
192         MockServices services{};
193         setExpectations(services);
194 
195         for (int i = 1; i <= 10; ++i)
196         {
197             system.monitorSensors(services);
198         }
199     }
200 
201     // Clear error history
202     system.clearErrorHistory();
203 
204     // Monitor sensors 10 more times.  Verify errors logged again.
205     {
206         // Create mock services.  Set expectations via lambda.
207         MockServices services{};
208         setExpectations(services);
209 
210         for (int i = 1; i <= 10; ++i)
211         {
212             system.monitorSensors(services);
213         }
214     }
215 }
216 
TEST(SystemTests,CloseDevices)217 TEST(SystemTests, CloseDevices)
218 {
219     // Specify an empty rules vector
220     std::vector<std::unique_ptr<Rule>> rules{};
221 
222     // Create mock services.  Expect logDebug() to be called.
223     MockServices services{};
224     MockJournal& journal = services.getMockJournal();
225     EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
226     EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1);
227     EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0);
228     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
229 
230     // Create Chassis
231     std::vector<std::unique_ptr<Chassis>> chassis{};
232     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
233     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
234 
235     // Create System
236     System system{std::move(rules), std::move(chassis)};
237 
238     // Call closeDevices()
239     system.closeDevices(services);
240 }
241 
TEST(SystemTests,Configure)242 TEST(SystemTests, Configure)
243 {
244     // Create mock services.  Expect logInfo() to be called.
245     MockServices services{};
246     MockJournal& journal = services.getMockJournal();
247     EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
248     EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1);
249     EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
250     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
251 
252     // Specify an empty rules vector
253     std::vector<std::unique_ptr<Rule>> rules{};
254 
255     // Create Chassis
256     std::vector<std::unique_ptr<Chassis>> chassis{};
257     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
258     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
259 
260     // Create System
261     System system{std::move(rules), std::move(chassis)};
262 
263     // Call configure()
264     system.configure(services);
265 }
266 
TEST(SystemTests,DetectPhaseFaults)267 TEST(SystemTests, DetectPhaseFaults)
268 {
269     // Create mock services with the following expectations:
270     // - 2 error messages in journal for N phase fault detected in reg0
271     // - 2 error messages in journal for N phase fault detected in reg1
272     // - 1 N phase fault error logged for reg0
273     // - 1 N phase fault error logged for reg1
274     MockServices services{};
275     MockJournal& journal = services.getMockJournal();
276     EXPECT_CALL(journal,
277                 logError("n phase fault detected in regulator reg0: count=1"))
278         .Times(1);
279     EXPECT_CALL(journal,
280                 logError("n phase fault detected in regulator reg0: count=2"))
281         .Times(1);
282     EXPECT_CALL(journal,
283                 logError("n phase fault detected in regulator reg1: count=1"))
284         .Times(1);
285     EXPECT_CALL(journal,
286                 logError("n phase fault detected in regulator reg1: count=2"))
287         .Times(1);
288     MockErrorLogging& errorLogging = services.getMockErrorLogging();
289     EXPECT_CALL(errorLogging, logPhaseFault).Times(2);
290 
291     std::vector<std::unique_ptr<Chassis>> chassisVec{};
292 
293     // Create Chassis 1 with regulator reg0
294     {
295         // Create PhaseFaultDetection
296         auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
297         std::vector<std::unique_ptr<Action>> actions{};
298         actions.push_back(std::move(action));
299         auto phaseFaultDetection =
300             std::make_unique<PhaseFaultDetection>(std::move(actions));
301 
302         // Create Device
303         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
304         std::unique_ptr<PresenceDetection> presenceDetection{};
305         std::unique_ptr<Configuration> configuration{};
306         auto device = std::make_unique<Device>(
307             "reg0", true,
308             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
309             "reg0",
310             std::move(i2cInterface), std::move(presenceDetection),
311             std::move(configuration), std::move(phaseFaultDetection));
312 
313         // Create Chassis
314         std::vector<std::unique_ptr<Device>> devices{};
315         devices.emplace_back(std::move(device));
316         auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1',
317                                                  std::move(devices));
318         chassisVec.emplace_back(std::move(chassis));
319     }
320 
321     // Create Chassis 2 with regulator reg1
322     {
323         // Create PhaseFaultDetection
324         auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
325         std::vector<std::unique_ptr<Action>> actions{};
326         actions.push_back(std::move(action));
327         auto phaseFaultDetection =
328             std::make_unique<PhaseFaultDetection>(std::move(actions));
329 
330         // Create Device
331         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
332         std::unique_ptr<PresenceDetection> presenceDetection{};
333         std::unique_ptr<Configuration> configuration{};
334         auto device = std::make_unique<Device>(
335             "reg1", true,
336             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
337             "reg1",
338             std::move(i2cInterface), std::move(presenceDetection),
339             std::move(configuration), std::move(phaseFaultDetection));
340 
341         // Create Chassis
342         std::vector<std::unique_ptr<Device>> devices{};
343         devices.emplace_back(std::move(device));
344         auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2',
345                                                  std::move(devices));
346         chassisVec.emplace_back(std::move(chassis));
347     }
348 
349     // Create System that contains Chassis
350     std::vector<std::unique_ptr<Rule>> rules{};
351     System system{std::move(rules), std::move(chassisVec)};
352 
353     // Call detectPhaseFaults() 5 times
354     for (int i = 1; i <= 5; ++i)
355     {
356         system.detectPhaseFaults(services);
357     }
358 }
359 
TEST(SystemTests,GetChassis)360 TEST(SystemTests, GetChassis)
361 {
362     // Specify an empty rules vector
363     std::vector<std::unique_ptr<Rule>> rules{};
364 
365     // Create Chassis
366     std::vector<std::unique_ptr<Chassis>> chassis{};
367     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
368     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
369 
370     // Create System
371     System system{std::move(rules), std::move(chassis)};
372     EXPECT_EQ(system.getChassis().size(), 2);
373     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
374     EXPECT_EQ(system.getChassis()[1]->getNumber(), 3);
375 }
376 
TEST(SystemTests,GetIDMap)377 TEST(SystemTests, GetIDMap)
378 {
379     // Create Rules
380     std::vector<std::unique_ptr<Rule>> rules{};
381     rules.emplace_back(createRule("set_voltage_rule"));
382     rules.emplace_back(createRule("read_sensors_rule"));
383 
384     // Create Chassis
385     std::vector<std::unique_ptr<Chassis>> chassis{};
386     {
387         // Chassis 1
388         std::vector<std::unique_ptr<Device>> devices{};
389         devices.emplace_back(createDevice("reg1", {"rail1"}));
390         devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
391         chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1',
392                                                        std::move(devices)));
393     }
394     {
395         // Chassis 2
396         std::vector<std::unique_ptr<Device>> devices{};
397         devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"}));
398         devices.emplace_back(createDevice("reg4"));
399         chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2',
400                                                        std::move(devices)));
401     }
402 
403     // Create System
404     System system{std::move(rules), std::move(chassis)};
405     const IDMap& idMap = system.getIDMap();
406 
407     // Verify all Rules are in the IDMap
408     EXPECT_NO_THROW(idMap.getRule("set_voltage_rule"));
409     EXPECT_NO_THROW(idMap.getRule("read_sensors_rule"));
410     EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument);
411 
412     // Verify all Devices are in the IDMap
413     EXPECT_NO_THROW(idMap.getDevice("reg1"));
414     EXPECT_NO_THROW(idMap.getDevice("reg2"));
415     EXPECT_NO_THROW(idMap.getDevice("reg3"));
416     EXPECT_NO_THROW(idMap.getDevice("reg4"));
417     EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument);
418 
419     // Verify all Rails are in the IDMap
420     EXPECT_NO_THROW(idMap.getRail("rail1"));
421     EXPECT_NO_THROW(idMap.getRail("rail2a"));
422     EXPECT_NO_THROW(idMap.getRail("rail2b"));
423     EXPECT_NO_THROW(idMap.getRail("rail3a"));
424     EXPECT_NO_THROW(idMap.getRail("rail3b"));
425     EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument);
426 }
427 
TEST(SystemTests,GetRules)428 TEST(SystemTests, GetRules)
429 {
430     // Create Rules
431     std::vector<std::unique_ptr<Rule>> rules{};
432     rules.emplace_back(createRule("set_voltage_rule"));
433     rules.emplace_back(createRule("read_sensors_rule"));
434 
435     // Create Chassis
436     std::vector<std::unique_ptr<Chassis>> chassis{};
437     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath));
438 
439     // Create System
440     System system{std::move(rules), std::move(chassis)};
441     EXPECT_EQ(system.getRules().size(), 2);
442     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
443     EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule");
444 }
445 
TEST(SystemTests,MonitorSensors)446 TEST(SystemTests, MonitorSensors)
447 {
448     // Create mock services.  Set Sensors service expectations.
449     MockServices services{};
450     MockSensors& sensors = services.getMockSensors();
451     EXPECT_CALL(sensors, startRail("c1_vdd0",
452                                    "/xyz/openbmc_project/inventory/system/"
453                                    "chassis1/motherboard/vdd0_reg",
454                                    chassisInvPath + '1'))
455         .Times(1);
456     EXPECT_CALL(sensors, startRail("c2_vdd0",
457                                    "/xyz/openbmc_project/inventory/system/"
458                                    "chassis2/motherboard/vdd0_reg",
459                                    chassisInvPath + '2'))
460         .Times(1);
461     EXPECT_CALL(sensors, setValue).Times(0);
462     EXPECT_CALL(sensors, endRail(false)).Times(2);
463 
464     std::vector<std::unique_ptr<Chassis>> chassisVec{};
465 
466     // Create Chassis 1
467     {
468         // Create SensorMonitoring for Rail
469         auto action = std::make_unique<MockAction>();
470         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
471         std::vector<std::unique_ptr<Action>> actions{};
472         actions.emplace_back(std::move(action));
473         auto sensorMonitoring =
474             std::make_unique<SensorMonitoring>(std::move(actions));
475 
476         // Create Rail
477         std::unique_ptr<Configuration> configuration{};
478         auto rail = std::make_unique<Rail>("c1_vdd0", std::move(configuration),
479                                            std::move(sensorMonitoring));
480 
481         // Create Device
482         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
483         std::unique_ptr<PresenceDetection> presenceDetection{};
484         std::unique_ptr<Configuration> deviceConfiguration{};
485         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
486         std::vector<std::unique_ptr<Rail>> rails{};
487         rails.emplace_back(std::move(rail));
488         auto device = std::make_unique<Device>(
489             "c1_vdd0_reg", true,
490             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
491             "vdd0_reg",
492             std::move(i2cInterface), std::move(presenceDetection),
493             std::move(deviceConfiguration), std::move(phaseFaultDetection),
494             std::move(rails));
495 
496         // Create Chassis
497         std::vector<std::unique_ptr<Device>> devices{};
498         devices.emplace_back(std::move(device));
499         auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1',
500                                                  std::move(devices));
501         chassisVec.emplace_back(std::move(chassis));
502     }
503 
504     // Create Chassis 2
505     {
506         // Create SensorMonitoring for Rail
507         auto action = std::make_unique<MockAction>();
508         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
509         std::vector<std::unique_ptr<Action>> actions{};
510         actions.emplace_back(std::move(action));
511         auto sensorMonitoring =
512             std::make_unique<SensorMonitoring>(std::move(actions));
513 
514         // Create Rail
515         std::unique_ptr<Configuration> configuration{};
516         auto rail = std::make_unique<Rail>("c2_vdd0", std::move(configuration),
517                                            std::move(sensorMonitoring));
518 
519         // Create Device
520         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
521         std::unique_ptr<PresenceDetection> presenceDetection{};
522         std::unique_ptr<Configuration> deviceConfiguration{};
523         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
524         std::vector<std::unique_ptr<Rail>> rails{};
525         rails.emplace_back(std::move(rail));
526         auto device = std::make_unique<Device>(
527             "c2_vdd0_reg", true,
528             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
529             "vdd0_reg",
530             std::move(i2cInterface), std::move(presenceDetection),
531             std::move(deviceConfiguration), std::move(phaseFaultDetection),
532             std::move(rails));
533 
534         // Create Chassis
535         std::vector<std::unique_ptr<Device>> devices{};
536         devices.emplace_back(std::move(device));
537         auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2',
538                                                  std::move(devices));
539         chassisVec.emplace_back(std::move(chassis));
540     }
541 
542     // Create System that contains Chassis
543     std::vector<std::unique_ptr<Rule>> rules{};
544     System system{std::move(rules), std::move(chassisVec)};
545 
546     // Call monitorSensors()
547     system.monitorSensors(services);
548 }
549