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 
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 
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 
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 mock services
170     MockServices services{};
171 
172     // Expect Sensors service to be called 5+5=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 3+3=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 1+1=2 times to log a DBus error
185     MockErrorLogging& errorLogging = services.getMockErrorLogging();
186     EXPECT_CALL(errorLogging, logDBusError).Times(2);
187 
188     // Monitor sensors 5 times.  Should fail every time, write to journal 3
189     // times, and log one error.
190     for (int i = 1; i <= 5; ++i)
191     {
192         system.monitorSensors(services);
193     }
194 
195     // Clear error history
196     system.clearErrorHistory();
197 
198     // Monitor sensors 5 times again.  Should fail every time, write to journal
199     // 3 times, and log one error.
200     for (int i = 1; i <= 5; ++i)
201     {
202         system.monitorSensors(services);
203     }
204 }
205 
206 TEST(SystemTests, CloseDevices)
207 {
208     // Specify an empty rules vector
209     std::vector<std::unique_ptr<Rule>> rules{};
210 
211     // Create mock services.  Expect logDebug() to be called.
212     MockServices services{};
213     MockJournal& journal = services.getMockJournal();
214     EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
215     EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1);
216     EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0);
217     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
218 
219     // Create Chassis
220     std::vector<std::unique_ptr<Chassis>> chassis{};
221     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
222     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
223 
224     // Create System
225     System system{std::move(rules), std::move(chassis)};
226 
227     // Call closeDevices()
228     system.closeDevices(services);
229 }
230 
231 TEST(SystemTests, Configure)
232 {
233     // Create mock services.  Expect logInfo() to be called.
234     MockServices services{};
235     MockJournal& journal = services.getMockJournal();
236     EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
237     EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1);
238     EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
239     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
240 
241     // Specify an empty rules vector
242     std::vector<std::unique_ptr<Rule>> rules{};
243 
244     // Create Chassis
245     std::vector<std::unique_ptr<Chassis>> chassis{};
246     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
247     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
248 
249     // Create System
250     System system{std::move(rules), std::move(chassis)};
251 
252     // Call configure()
253     system.configure(services);
254 }
255 
256 TEST(SystemTests, DetectPhaseFaults)
257 {
258     // Create mock services with the following expectations:
259     // - 2 error messages in journal for N phase fault detected in reg0
260     // - 2 error messages in journal for N phase fault detected in reg1
261     // - 1 N phase fault error logged for reg0
262     // - 1 N phase fault error logged for reg1
263     MockServices services{};
264     MockJournal& journal = services.getMockJournal();
265     EXPECT_CALL(journal,
266                 logError("n phase fault detected in regulator reg0: count=1"))
267         .Times(1);
268     EXPECT_CALL(journal,
269                 logError("n phase fault detected in regulator reg0: count=2"))
270         .Times(1);
271     EXPECT_CALL(journal,
272                 logError("n phase fault detected in regulator reg1: count=1"))
273         .Times(1);
274     EXPECT_CALL(journal,
275                 logError("n phase fault detected in regulator reg1: count=2"))
276         .Times(1);
277     MockErrorLogging& errorLogging = services.getMockErrorLogging();
278     EXPECT_CALL(errorLogging, logPhaseFault).Times(2);
279 
280     std::vector<std::unique_ptr<Chassis>> chassisVec{};
281 
282     // Create Chassis 1 with regulator reg0
283     {
284         // Create PhaseFaultDetection
285         auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
286         std::vector<std::unique_ptr<Action>> actions{};
287         actions.push_back(std::move(action));
288         auto phaseFaultDetection =
289             std::make_unique<PhaseFaultDetection>(std::move(actions));
290 
291         // Create Device
292         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
293         std::unique_ptr<PresenceDetection> presenceDetection{};
294         std::unique_ptr<Configuration> configuration{};
295         auto device = std::make_unique<Device>(
296             "reg0", true,
297             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
298             "reg0",
299             std::move(i2cInterface), std::move(presenceDetection),
300             std::move(configuration), std::move(phaseFaultDetection));
301 
302         // Create Chassis
303         std::vector<std::unique_ptr<Device>> devices{};
304         devices.emplace_back(std::move(device));
305         auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1',
306                                                  std::move(devices));
307         chassisVec.emplace_back(std::move(chassis));
308     }
309 
310     // Create Chassis 2 with regulator reg1
311     {
312         // Create PhaseFaultDetection
313         auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
314         std::vector<std::unique_ptr<Action>> actions{};
315         actions.push_back(std::move(action));
316         auto phaseFaultDetection =
317             std::make_unique<PhaseFaultDetection>(std::move(actions));
318 
319         // Create Device
320         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
321         std::unique_ptr<PresenceDetection> presenceDetection{};
322         std::unique_ptr<Configuration> configuration{};
323         auto device = std::make_unique<Device>(
324             "reg1", true,
325             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
326             "reg1",
327             std::move(i2cInterface), std::move(presenceDetection),
328             std::move(configuration), std::move(phaseFaultDetection));
329 
330         // Create Chassis
331         std::vector<std::unique_ptr<Device>> devices{};
332         devices.emplace_back(std::move(device));
333         auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2',
334                                                  std::move(devices));
335         chassisVec.emplace_back(std::move(chassis));
336     }
337 
338     // Create System that contains Chassis
339     std::vector<std::unique_ptr<Rule>> rules{};
340     System system{std::move(rules), std::move(chassisVec)};
341 
342     // Call detectPhaseFaults() 5 times
343     for (int i = 1; i <= 5; ++i)
344     {
345         system.detectPhaseFaults(services);
346     }
347 }
348 
349 TEST(SystemTests, GetChassis)
350 {
351     // Specify an empty rules vector
352     std::vector<std::unique_ptr<Rule>> rules{};
353 
354     // Create Chassis
355     std::vector<std::unique_ptr<Chassis>> chassis{};
356     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1'));
357     chassis.emplace_back(std::make_unique<Chassis>(3, chassisInvPath + '3'));
358 
359     // Create System
360     System system{std::move(rules), std::move(chassis)};
361     EXPECT_EQ(system.getChassis().size(), 2);
362     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
363     EXPECT_EQ(system.getChassis()[1]->getNumber(), 3);
364 }
365 
366 TEST(SystemTests, GetIDMap)
367 {
368     // Create Rules
369     std::vector<std::unique_ptr<Rule>> rules{};
370     rules.emplace_back(createRule("set_voltage_rule"));
371     rules.emplace_back(createRule("read_sensors_rule"));
372 
373     // Create Chassis
374     std::vector<std::unique_ptr<Chassis>> chassis{};
375     {
376         // Chassis 1
377         std::vector<std::unique_ptr<Device>> devices{};
378         devices.emplace_back(createDevice("reg1", {"rail1"}));
379         devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
380         chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath + '1',
381                                                        std::move(devices)));
382     }
383     {
384         // Chassis 2
385         std::vector<std::unique_ptr<Device>> devices{};
386         devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"}));
387         devices.emplace_back(createDevice("reg4"));
388         chassis.emplace_back(std::make_unique<Chassis>(2, chassisInvPath + '2',
389                                                        std::move(devices)));
390     }
391 
392     // Create System
393     System system{std::move(rules), std::move(chassis)};
394     const IDMap& idMap = system.getIDMap();
395 
396     // Verify all Rules are in the IDMap
397     EXPECT_NO_THROW(idMap.getRule("set_voltage_rule"));
398     EXPECT_NO_THROW(idMap.getRule("read_sensors_rule"));
399     EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument);
400 
401     // Verify all Devices are in the IDMap
402     EXPECT_NO_THROW(idMap.getDevice("reg1"));
403     EXPECT_NO_THROW(idMap.getDevice("reg2"));
404     EXPECT_NO_THROW(idMap.getDevice("reg3"));
405     EXPECT_NO_THROW(idMap.getDevice("reg4"));
406     EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument);
407 
408     // Verify all Rails are in the IDMap
409     EXPECT_NO_THROW(idMap.getRail("rail1"));
410     EXPECT_NO_THROW(idMap.getRail("rail2a"));
411     EXPECT_NO_THROW(idMap.getRail("rail2b"));
412     EXPECT_NO_THROW(idMap.getRail("rail3a"));
413     EXPECT_NO_THROW(idMap.getRail("rail3b"));
414     EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument);
415 }
416 
417 TEST(SystemTests, GetRules)
418 {
419     // Create Rules
420     std::vector<std::unique_ptr<Rule>> rules{};
421     rules.emplace_back(createRule("set_voltage_rule"));
422     rules.emplace_back(createRule("read_sensors_rule"));
423 
424     // Create Chassis
425     std::vector<std::unique_ptr<Chassis>> chassis{};
426     chassis.emplace_back(std::make_unique<Chassis>(1, chassisInvPath));
427 
428     // Create System
429     System system{std::move(rules), std::move(chassis)};
430     EXPECT_EQ(system.getRules().size(), 2);
431     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
432     EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule");
433 }
434 
435 TEST(SystemTests, MonitorSensors)
436 {
437     // Create mock services.  Set Sensors service expectations.
438     MockServices services{};
439     MockSensors& sensors = services.getMockSensors();
440     EXPECT_CALL(sensors, startRail("c1_vdd0",
441                                    "/xyz/openbmc_project/inventory/system/"
442                                    "chassis1/motherboard/vdd0_reg",
443                                    chassisInvPath + '1'))
444         .Times(1);
445     EXPECT_CALL(sensors, startRail("c2_vdd0",
446                                    "/xyz/openbmc_project/inventory/system/"
447                                    "chassis2/motherboard/vdd0_reg",
448                                    chassisInvPath + '2'))
449         .Times(1);
450     EXPECT_CALL(sensors, setValue).Times(0);
451     EXPECT_CALL(sensors, endRail(false)).Times(2);
452 
453     std::vector<std::unique_ptr<Chassis>> chassisVec{};
454 
455     // Create Chassis 1
456     {
457         // Create SensorMonitoring for Rail
458         auto action = std::make_unique<MockAction>();
459         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
460         std::vector<std::unique_ptr<Action>> actions{};
461         actions.emplace_back(std::move(action));
462         auto sensorMonitoring =
463             std::make_unique<SensorMonitoring>(std::move(actions));
464 
465         // Create Rail
466         std::unique_ptr<Configuration> configuration{};
467         auto rail = std::make_unique<Rail>("c1_vdd0", std::move(configuration),
468                                            std::move(sensorMonitoring));
469 
470         // Create Device
471         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
472         std::unique_ptr<PresenceDetection> presenceDetection{};
473         std::unique_ptr<Configuration> deviceConfiguration{};
474         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
475         std::vector<std::unique_ptr<Rail>> rails{};
476         rails.emplace_back(std::move(rail));
477         auto device = std::make_unique<Device>(
478             "c1_vdd0_reg", true,
479             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
480             "vdd0_reg",
481             std::move(i2cInterface), std::move(presenceDetection),
482             std::move(deviceConfiguration), std::move(phaseFaultDetection),
483             std::move(rails));
484 
485         // Create Chassis
486         std::vector<std::unique_ptr<Device>> devices{};
487         devices.emplace_back(std::move(device));
488         auto chassis = std::make_unique<Chassis>(1, chassisInvPath + '1',
489                                                  std::move(devices));
490         chassisVec.emplace_back(std::move(chassis));
491     }
492 
493     // Create Chassis 2
494     {
495         // Create SensorMonitoring for Rail
496         auto action = std::make_unique<MockAction>();
497         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
498         std::vector<std::unique_ptr<Action>> actions{};
499         actions.emplace_back(std::move(action));
500         auto sensorMonitoring =
501             std::make_unique<SensorMonitoring>(std::move(actions));
502 
503         // Create Rail
504         std::unique_ptr<Configuration> configuration{};
505         auto rail = std::make_unique<Rail>("c2_vdd0", std::move(configuration),
506                                            std::move(sensorMonitoring));
507 
508         // Create Device
509         auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
510         std::unique_ptr<PresenceDetection> presenceDetection{};
511         std::unique_ptr<Configuration> deviceConfiguration{};
512         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
513         std::vector<std::unique_ptr<Rail>> rails{};
514         rails.emplace_back(std::move(rail));
515         auto device = std::make_unique<Device>(
516             "c2_vdd0_reg", true,
517             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
518             "vdd0_reg",
519             std::move(i2cInterface), std::move(presenceDetection),
520             std::move(deviceConfiguration), std::move(phaseFaultDetection),
521             std::move(rails));
522 
523         // Create Chassis
524         std::vector<std::unique_ptr<Device>> devices{};
525         devices.emplace_back(std::move(device));
526         auto chassis = std::make_unique<Chassis>(2, chassisInvPath + '2',
527                                                  std::move(devices));
528         chassisVec.emplace_back(std::move(chassis));
529     }
530 
531     // Create System that contains Chassis
532     std::vector<std::unique_ptr<Rule>> rules{};
533     System system{std::move(rules), std::move(chassisVec)};
534 
535     // Call monitorSensors()
536     system.monitorSensors(services);
537 }
538