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