1 /**
2  * Copyright © 2019 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 "mock_action.hpp"
22 #include "mock_error_logging.hpp"
23 #include "mock_journal.hpp"
24 #include "mock_sensors.hpp"
25 #include "mock_services.hpp"
26 #include "mocked_i2c_interface.hpp"
27 #include "phase_fault_detection.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 "system.hpp"
34 #include "test_sdbus_error.hpp"
35 
36 #include <memory>
37 #include <optional>
38 #include <utility>
39 #include <vector>
40 
41 #include <gmock/gmock.h>
42 #include <gtest/gtest.h>
43 
44 using namespace phosphor::power::regulators;
45 
46 using ::testing::A;
47 using ::testing::Return;
48 using ::testing::Throw;
49 using ::testing::TypedEq;
50 
51 static const std::string chassisInvPath{
52     "/xyz/openbmc_project/inventory/system/chassis"};
53 
54 TEST(RailTests, Constructor)
55 {
56     // Test where only required parameters are specified
57     {
58         Rail rail{"vdd0"};
59         EXPECT_EQ(rail.getID(), "vdd0");
60         EXPECT_EQ(rail.getConfiguration(), nullptr);
61         EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
62     }
63 
64     // Test where all parameters are specified
65     {
66         // Create Configuration
67         std::optional<double> volts{1.3};
68         std::vector<std::unique_ptr<Action>> actions{};
69         actions.push_back(std::make_unique<MockAction>());
70         actions.push_back(std::make_unique<MockAction>());
71         std::unique_ptr<Configuration> configuration =
72             std::make_unique<Configuration>(volts, std::move(actions));
73 
74         // Create SensorMonitoring
75         actions.clear();
76         actions.push_back(std::make_unique<MockAction>());
77         std::unique_ptr<SensorMonitoring> sensorMonitoring =
78             std::make_unique<SensorMonitoring>(std::move(actions));
79 
80         // Create Rail
81         Rail rail{"vddr1", std::move(configuration),
82                   std::move(sensorMonitoring)};
83         EXPECT_EQ(rail.getID(), "vddr1");
84         EXPECT_NE(rail.getConfiguration(), nullptr);
85         EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
86         EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 1.3);
87         EXPECT_EQ(rail.getConfiguration()->getActions().size(), 2);
88         EXPECT_NE(rail.getSensorMonitoring(), nullptr);
89         EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 1);
90     }
91 }
92 
93 TEST(RailTests, ClearErrorHistory)
94 {
95     // Create SensorMonitoring.  Will fail with a DBus exception.
96     std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
97     EXPECT_CALL(*action, execute)
98         .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"}));
99     std::vector<std::unique_ptr<Action>> actions{};
100     actions.emplace_back(std::move(action));
101     std::unique_ptr<SensorMonitoring> sensorMonitoring =
102         std::make_unique<SensorMonitoring>(std::move(actions));
103 
104     // Create Rail
105     std::unique_ptr<Configuration> configuration{};
106     std::unique_ptr<Rail> rail = std::make_unique<Rail>(
107         "vddr1", std::move(configuration), std::move(sensorMonitoring));
108     Rail* railPtr = rail.get();
109 
110     // Create Device that contains Rail
111     std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
112         std::make_unique<i2c::MockedI2CInterface>();
113     std::unique_ptr<PresenceDetection> presenceDetection{};
114     std::unique_ptr<Configuration> deviceConfiguration{};
115     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
116     std::vector<std::unique_ptr<Rail>> rails{};
117     rails.emplace_back(std::move(rail));
118     std::unique_ptr<Device> device = std::make_unique<Device>(
119         "reg1", true,
120         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
121         std::move(i2cInterface), std::move(presenceDetection),
122         std::move(deviceConfiguration), std::move(phaseFaultDetection),
123         std::move(rails));
124     Device* devicePtr = device.get();
125 
126     // Create Chassis that contains Device
127     std::vector<std::unique_ptr<Device>> devices{};
128     devices.emplace_back(std::move(device));
129     std::unique_ptr<Chassis> chassis =
130         std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
131     Chassis* chassisPtr = chassis.get();
132 
133     // Create System that contains Chassis
134     std::vector<std::unique_ptr<Rule>> rules{};
135     std::vector<std::unique_ptr<Chassis>> chassisVec{};
136     chassisVec.emplace_back(std::move(chassis));
137     System system{std::move(rules), std::move(chassisVec)};
138 
139     // Create lambda that sets MockServices expectations.  The lambda allows
140     // us to set expectations multiple times without duplicate code.
141     auto setExpectations = [](MockServices& services) {
142         // Expect Sensors service to be called 10 times
143         MockSensors& sensors = services.getMockSensors();
144         EXPECT_CALL(sensors, startRail).Times(10);
145         EXPECT_CALL(sensors, setValue).Times(0);
146         EXPECT_CALL(sensors, endRail(true)).Times(10);
147 
148         // Expect Journal service to be called 6 times to log error messages
149         MockJournal& journal = services.getMockJournal();
150         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
151             .Times(6);
152         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
153 
154         // Expect ErrorLogging service to be called once to log a DBus error
155         MockErrorLogging& errorLogging = services.getMockErrorLogging();
156         EXPECT_CALL(errorLogging, logDBusError).Times(1);
157     };
158 
159     // Monitor sensors 10 times.  Verify errors logged.
160     {
161         // Create mock services.  Set expectations via lambda.
162         MockServices services{};
163         setExpectations(services);
164 
165         for (int i = 1; i <= 10; ++i)
166         {
167             railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
168         }
169     }
170 
171     // Clear error history
172     railPtr->clearErrorHistory();
173 
174     // Monitor sensors 10 more times.  Verify errors logged again.
175     {
176         // Create mock services.  Set expectations via lambda.
177         MockServices services{};
178         setExpectations(services);
179 
180         for (int i = 1; i <= 10; ++i)
181         {
182             railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
183         }
184     }
185 }
186 
187 TEST(RailTests, Configure)
188 {
189     // Test where Configuration was not specified in constructor
190     {
191         // Create mock services.  No logging should occur.
192         MockServices services{};
193         MockJournal& journal = services.getMockJournal();
194         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
195         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
196 
197         // Create Rail
198         std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0");
199         Rail* railPtr = rail.get();
200 
201         // Create Device that contains Rail
202         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
203             std::make_unique<i2c::MockedI2CInterface>();
204         std::unique_ptr<PresenceDetection> presenceDetection{};
205         std::unique_ptr<Configuration> deviceConfiguration{};
206         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
207         std::vector<std::unique_ptr<Rail>> rails{};
208         rails.emplace_back(std::move(rail));
209         std::unique_ptr<Device> device = std::make_unique<Device>(
210             "reg1", true,
211             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
212             std::move(i2cInterface), std::move(presenceDetection),
213             std::move(deviceConfiguration), std::move(phaseFaultDetection),
214             std::move(rails));
215         Device* devicePtr = device.get();
216 
217         // Create Chassis that contains Device
218         std::vector<std::unique_ptr<Device>> devices{};
219         devices.emplace_back(std::move(device));
220         std::unique_ptr<Chassis> chassis =
221             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
222         Chassis* chassisPtr = chassis.get();
223 
224         // Create System that contains Chassis
225         std::vector<std::unique_ptr<Rule>> rules{};
226         std::vector<std::unique_ptr<Chassis>> chassisVec{};
227         chassisVec.emplace_back(std::move(chassis));
228         System system{std::move(rules), std::move(chassisVec)};
229 
230         // Call configure().
231         railPtr->configure(services, system, *chassisPtr, *devicePtr);
232     }
233 
234     // Test where Configuration was specified in constructor
235     {
236         // Create mock services.  Expect logDebug() to be called.
237         MockServices services{};
238         MockJournal& journal = services.getMockJournal();
239         EXPECT_CALL(journal, logDebug("Configuring vddr1: volts=1.300000"))
240             .Times(1);
241         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
242 
243         // Create Configuration
244         std::optional<double> volts{1.3};
245         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
246         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
247         std::vector<std::unique_ptr<Action>> actions{};
248         actions.emplace_back(std::move(action));
249         std::unique_ptr<Configuration> configuration =
250             std::make_unique<Configuration>(volts, std::move(actions));
251 
252         // Create Rail
253         std::unique_ptr<Rail> rail =
254             std::make_unique<Rail>("vddr1", std::move(configuration));
255         Rail* railPtr = rail.get();
256 
257         // Create Device that contains Rail
258         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
259             std::make_unique<i2c::MockedI2CInterface>();
260         std::unique_ptr<PresenceDetection> presenceDetection{};
261         std::unique_ptr<Configuration> deviceConfiguration{};
262         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
263         std::vector<std::unique_ptr<Rail>> rails{};
264         rails.emplace_back(std::move(rail));
265         std::unique_ptr<Device> device = std::make_unique<Device>(
266             "reg1", true,
267             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
268             std::move(i2cInterface), std::move(presenceDetection),
269             std::move(deviceConfiguration), std::move(phaseFaultDetection),
270             std::move(rails));
271         Device* devicePtr = device.get();
272 
273         // Create Chassis that contains Device
274         std::vector<std::unique_ptr<Device>> devices{};
275         devices.emplace_back(std::move(device));
276         std::unique_ptr<Chassis> chassis =
277             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
278         Chassis* chassisPtr = chassis.get();
279 
280         // Create System that contains Chassis
281         std::vector<std::unique_ptr<Rule>> rules{};
282         std::vector<std::unique_ptr<Chassis>> chassisVec{};
283         chassisVec.emplace_back(std::move(chassis));
284         System system{std::move(rules), std::move(chassisVec)};
285 
286         // Call configure().
287         railPtr->configure(services, system, *chassisPtr, *devicePtr);
288     }
289 }
290 
291 TEST(RailTests, GetConfiguration)
292 {
293     // Test where Configuration was not specified in constructor
294     {
295         Rail rail{"vdd0"};
296         EXPECT_EQ(rail.getConfiguration(), nullptr);
297     }
298 
299     // Test where Configuration was specified in constructor
300     {
301         // Create Configuration
302         std::optional<double> volts{3.2};
303         std::vector<std::unique_ptr<Action>> actions{};
304         actions.push_back(std::make_unique<MockAction>());
305         std::unique_ptr<Configuration> configuration =
306             std::make_unique<Configuration>(volts, std::move(actions));
307 
308         // Create Rail
309         Rail rail{"vddr1", std::move(configuration)};
310         EXPECT_NE(rail.getConfiguration(), nullptr);
311         EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
312         EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2);
313         EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1);
314     }
315 }
316 
317 TEST(RailTests, GetID)
318 {
319     Rail rail{"vio2"};
320     EXPECT_EQ(rail.getID(), "vio2");
321 }
322 
323 TEST(RailTests, MonitorSensors)
324 {
325     // Test where SensorMonitoring was not specified in constructor
326     {
327         // Create mock services.  No Sensors methods should be called.
328         MockServices services{};
329         MockSensors& sensors = services.getMockSensors();
330         EXPECT_CALL(sensors, startRail).Times(0);
331         EXPECT_CALL(sensors, setValue).Times(0);
332         EXPECT_CALL(sensors, endRail).Times(0);
333 
334         // Create Rail
335         std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0");
336         Rail* railPtr = rail.get();
337 
338         // Create Device that contains Rail
339         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
340             std::make_unique<i2c::MockedI2CInterface>();
341         std::unique_ptr<PresenceDetection> presenceDetection{};
342         std::unique_ptr<Configuration> deviceConfiguration{};
343         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
344         std::vector<std::unique_ptr<Rail>> rails{};
345         rails.emplace_back(std::move(rail));
346         std::unique_ptr<Device> device = std::make_unique<Device>(
347             "reg1", true,
348             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
349             std::move(i2cInterface), std::move(presenceDetection),
350             std::move(deviceConfiguration), std::move(phaseFaultDetection),
351             std::move(rails));
352         Device* devicePtr = device.get();
353 
354         // Create Chassis that contains Device
355         std::vector<std::unique_ptr<Device>> devices{};
356         devices.emplace_back(std::move(device));
357         std::unique_ptr<Chassis> chassis =
358             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
359         Chassis* chassisPtr = chassis.get();
360 
361         // Create System that contains Chassis
362         std::vector<std::unique_ptr<Rule>> rules{};
363         std::vector<std::unique_ptr<Chassis>> chassisVec{};
364         chassisVec.emplace_back(std::move(chassis));
365         System system{std::move(rules), std::move(chassisVec)};
366 
367         // Call monitorSensors()
368         railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
369     }
370 
371     // Test where SensorMonitoring was specified in constructor
372     {
373         // Create mock services.  Set Sensors service expectations.
374         MockServices services{};
375         MockSensors& sensors = services.getMockSensors();
376         EXPECT_CALL(sensors,
377                     startRail("vddr1",
378                               "/xyz/openbmc_project/inventory/system/chassis/"
379                               "motherboard/reg1",
380                               chassisInvPath))
381             .Times(1);
382         EXPECT_CALL(sensors, setValue).Times(0);
383         EXPECT_CALL(sensors, endRail(false)).Times(1);
384 
385         // Create SensorMonitoring
386         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
387         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
388         std::vector<std::unique_ptr<Action>> actions{};
389         actions.emplace_back(std::move(action));
390         std::unique_ptr<SensorMonitoring> sensorMonitoring =
391             std::make_unique<SensorMonitoring>(std::move(actions));
392 
393         // Create Rail
394         std::unique_ptr<Configuration> configuration{};
395         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
396             "vddr1", std::move(configuration), std::move(sensorMonitoring));
397         Rail* railPtr = rail.get();
398 
399         // Create Device that contains Rail
400         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
401             std::make_unique<i2c::MockedI2CInterface>();
402         std::unique_ptr<PresenceDetection> presenceDetection{};
403         std::unique_ptr<Configuration> deviceConfiguration{};
404         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
405         std::vector<std::unique_ptr<Rail>> rails{};
406         rails.emplace_back(std::move(rail));
407         std::unique_ptr<Device> device = std::make_unique<Device>(
408             "reg1", true,
409             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
410             std::move(i2cInterface), std::move(presenceDetection),
411             std::move(deviceConfiguration), std::move(phaseFaultDetection),
412             std::move(rails));
413         Device* devicePtr = device.get();
414 
415         // Create Chassis that contains Device
416         std::vector<std::unique_ptr<Device>> devices{};
417         devices.emplace_back(std::move(device));
418         std::unique_ptr<Chassis> chassis =
419             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
420         Chassis* chassisPtr = chassis.get();
421 
422         // Create System that contains Chassis
423         std::vector<std::unique_ptr<Rule>> rules{};
424         std::vector<std::unique_ptr<Chassis>> chassisVec{};
425         chassisVec.emplace_back(std::move(chassis));
426         System system{std::move(rules), std::move(chassisVec)};
427 
428         // Call monitorSensors()
429         railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
430     }
431 }
432 
433 TEST(RailTests, GetSensorMonitoring)
434 {
435     // Test where SensorMonitoring was not specified in constructor
436     {
437         Rail rail{"vdd0", nullptr, nullptr};
438         EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
439     }
440 
441     // Test where SensorMonitoring was specified in constructor
442     {
443         std::unique_ptr<Configuration> configuration{};
444 
445         // Create SensorMonitoring
446         std::vector<std::unique_ptr<Action>> actions{};
447         actions.push_back(std::make_unique<MockAction>());
448         actions.push_back(std::make_unique<MockAction>());
449         std::unique_ptr<SensorMonitoring> sensorMonitoring =
450             std::make_unique<SensorMonitoring>(std::move(actions));
451 
452         // Create Rail
453         Rail rail{"vddr1", std::move(configuration),
454                   std::move(sensorMonitoring)};
455         EXPECT_NE(rail.getSensorMonitoring(), nullptr);
456         EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2);
457     }
458 }
459