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