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_journal.hpp"
23 #include "mock_services.hpp"
24 #include "mocked_i2c_interface.hpp"
25 #include "pmbus_read_sensor_action.hpp"
26 #include "presence_detection.hpp"
27 #include "rail.hpp"
28 #include "rule.hpp"
29 #include "sensor_monitoring.hpp"
30 #include "system.hpp"
31 
32 #include <memory>
33 #include <optional>
34 #include <utility>
35 #include <vector>
36 
37 #include <gmock/gmock.h>
38 #include <gtest/gtest.h>
39 
40 using namespace phosphor::power::regulators;
41 
42 using ::testing::A;
43 using ::testing::Return;
44 using ::testing::TypedEq;
45 
46 TEST(RailTests, Constructor)
47 {
48     // Test where only required parameters are specified
49     {
50         Rail rail{"vdd0"};
51         EXPECT_EQ(rail.getID(), "vdd0");
52         EXPECT_EQ(rail.getConfiguration(), nullptr);
53         EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
54     }
55 
56     // Test where all parameters are specified
57     {
58         // Create Configuration
59         std::optional<double> volts{1.3};
60         std::vector<std::unique_ptr<Action>> actions{};
61         actions.push_back(std::make_unique<MockAction>());
62         actions.push_back(std::make_unique<MockAction>());
63         std::unique_ptr<Configuration> configuration =
64             std::make_unique<Configuration>(volts, std::move(actions));
65 
66         // Create SensorMonitoring
67         actions.clear();
68         actions.push_back(std::make_unique<MockAction>());
69         std::unique_ptr<SensorMonitoring> sensorMonitoring =
70             std::make_unique<SensorMonitoring>(std::move(actions));
71 
72         // Create Rail
73         Rail rail{"vddr1", std::move(configuration),
74                   std::move(sensorMonitoring)};
75         EXPECT_EQ(rail.getID(), "vddr1");
76         EXPECT_NE(rail.getConfiguration(), nullptr);
77         EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
78         EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 1.3);
79         EXPECT_EQ(rail.getConfiguration()->getActions().size(), 2);
80         EXPECT_NE(rail.getSensorMonitoring(), nullptr);
81         EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 1);
82     }
83 }
84 
85 TEST(RailTests, Configure)
86 {
87     // Test where Configuration was not specified in constructor
88     {
89         // Create mock services.  No logging should occur.
90         MockServices services{};
91         MockJournal& journal = services.getMockJournal();
92         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
93         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
94 
95         // Create Rail
96         std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0");
97         Rail* railPtr = rail.get();
98 
99         // Create Device that contains Rail
100         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
101             std::make_unique<i2c::MockedI2CInterface>();
102         std::unique_ptr<PresenceDetection> presenceDetection{};
103         std::unique_ptr<Configuration> deviceConfiguration{};
104         std::vector<std::unique_ptr<Rail>> rails{};
105         rails.emplace_back(std::move(rail));
106         std::unique_ptr<Device> device = std::make_unique<Device>(
107             "reg1", true,
108             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
109             std::move(i2cInterface), std::move(presenceDetection),
110             std::move(deviceConfiguration), std::move(rails));
111         Device* devicePtr = device.get();
112 
113         // Create Chassis that contains Device
114         std::vector<std::unique_ptr<Device>> devices{};
115         devices.emplace_back(std::move(device));
116         std::unique_ptr<Chassis> chassis =
117             std::make_unique<Chassis>(1, std::move(devices));
118         Chassis* chassisPtr = chassis.get();
119 
120         // Create System that contains Chassis
121         std::vector<std::unique_ptr<Rule>> rules{};
122         std::vector<std::unique_ptr<Chassis>> chassisVec{};
123         chassisVec.emplace_back(std::move(chassis));
124         System system{std::move(rules), std::move(chassisVec)};
125 
126         // Call configure().
127         railPtr->configure(services, system, *chassisPtr, *devicePtr);
128     }
129 
130     // Test where Configuration was specified in constructor
131     {
132         // Create mock services.  Expect logDebug() to be called.
133         MockServices services{};
134         MockJournal& journal = services.getMockJournal();
135         EXPECT_CALL(journal, logDebug("Configuring vddr1: volts=1.300000"))
136             .Times(1);
137         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
138 
139         // Create Configuration
140         std::optional<double> volts{1.3};
141         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
142         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
143         std::vector<std::unique_ptr<Action>> actions{};
144         actions.emplace_back(std::move(action));
145         std::unique_ptr<Configuration> configuration =
146             std::make_unique<Configuration>(volts, std::move(actions));
147 
148         // Create Rail
149         std::unique_ptr<Rail> rail =
150             std::make_unique<Rail>("vddr1", std::move(configuration));
151         Rail* railPtr = rail.get();
152 
153         // Create Device that contains Rail
154         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
155             std::make_unique<i2c::MockedI2CInterface>();
156         std::unique_ptr<PresenceDetection> presenceDetection{};
157         std::unique_ptr<Configuration> deviceConfiguration{};
158         std::vector<std::unique_ptr<Rail>> rails{};
159         rails.emplace_back(std::move(rail));
160         std::unique_ptr<Device> device = std::make_unique<Device>(
161             "reg1", true,
162             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
163             std::move(i2cInterface), std::move(presenceDetection),
164             std::move(deviceConfiguration), std::move(rails));
165         Device* devicePtr = device.get();
166 
167         // Create Chassis that contains Device
168         std::vector<std::unique_ptr<Device>> devices{};
169         devices.emplace_back(std::move(device));
170         std::unique_ptr<Chassis> chassis =
171             std::make_unique<Chassis>(1, std::move(devices));
172         Chassis* chassisPtr = chassis.get();
173 
174         // Create System that contains Chassis
175         std::vector<std::unique_ptr<Rule>> rules{};
176         std::vector<std::unique_ptr<Chassis>> chassisVec{};
177         chassisVec.emplace_back(std::move(chassis));
178         System system{std::move(rules), std::move(chassisVec)};
179 
180         // Call configure().
181         railPtr->configure(services, system, *chassisPtr, *devicePtr);
182     }
183 }
184 
185 TEST(RailTests, GetConfiguration)
186 {
187     // Test where Configuration was not specified in constructor
188     {
189         Rail rail{"vdd0"};
190         EXPECT_EQ(rail.getConfiguration(), nullptr);
191     }
192 
193     // Test where Configuration was specified in constructor
194     {
195         // Create Configuration
196         std::optional<double> volts{3.2};
197         std::vector<std::unique_ptr<Action>> actions{};
198         actions.push_back(std::make_unique<MockAction>());
199         std::unique_ptr<Configuration> configuration =
200             std::make_unique<Configuration>(volts, std::move(actions));
201 
202         // Create Rail
203         Rail rail{"vddr1", std::move(configuration)};
204         EXPECT_NE(rail.getConfiguration(), nullptr);
205         EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
206         EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2);
207         EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1);
208     }
209 }
210 
211 TEST(RailTests, GetID)
212 {
213     Rail rail{"vio2"};
214     EXPECT_EQ(rail.getID(), "vio2");
215 }
216 
217 TEST(RailTests, MonitorSensors)
218 {
219     // Test where SensorMonitoring was not specified in constructor
220     {
221         // Create mock services.  No logging should occur.
222         MockServices services{};
223         MockJournal& journal = services.getMockJournal();
224         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
225         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
226 
227         // Create mock I2CInterface.  A two-byte read should NOT occur.
228         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
229             std::make_unique<i2c::MockedI2CInterface>();
230         EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0);
231 
232         // Create Rail
233         std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0");
234         Rail* railPtr = rail.get();
235 
236         // Create Device that contains Rail
237         std::unique_ptr<PresenceDetection> presenceDetection{};
238         std::unique_ptr<Configuration> deviceConfiguration{};
239         std::vector<std::unique_ptr<Rail>> rails{};
240         rails.emplace_back(std::move(rail));
241         std::unique_ptr<Device> device = std::make_unique<Device>(
242             "reg1", true,
243             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
244             std::move(i2cInterface), std::move(presenceDetection),
245             std::move(deviceConfiguration), std::move(rails));
246         Device* devicePtr = device.get();
247 
248         // Create Chassis that contains Device
249         std::vector<std::unique_ptr<Device>> devices{};
250         devices.emplace_back(std::move(device));
251         std::unique_ptr<Chassis> chassis =
252             std::make_unique<Chassis>(1, std::move(devices));
253         Chassis* chassisPtr = chassis.get();
254 
255         // Create System that contains Chassis
256         std::vector<std::unique_ptr<Rule>> rules{};
257         std::vector<std::unique_ptr<Chassis>> chassisVec{};
258         chassisVec.emplace_back(std::move(chassis));
259         System system{std::move(rules), std::move(chassisVec)};
260 
261         // Call monitorSensors().
262         railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
263     }
264 
265     // Test where SensorMonitoring was specified in constructor
266     {
267         // Create mock services.  No logging should occur.
268         MockServices services{};
269         MockJournal& journal = services.getMockJournal();
270         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
271         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
272 
273         // Create PMBusReadSensorAction
274         pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
275         uint8_t command = 0x8C;
276         pmbus_utils::SensorDataFormat format{
277             pmbus_utils::SensorDataFormat::linear_11};
278         std::optional<int8_t> exponent{};
279         std::unique_ptr<PMBusReadSensorAction> action =
280             std::make_unique<PMBusReadSensorAction>(type, command, format,
281                                                     exponent);
282 
283         // Create mock I2CInterface.  A two-byte read should occur.
284         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
285             std::make_unique<i2c::MockedI2CInterface>();
286         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
287         EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
288             .Times(1);
289 
290         // Create SensorMonitoring
291         std::vector<std::unique_ptr<Action>> actions{};
292         actions.emplace_back(std::move(action));
293         std::unique_ptr<SensorMonitoring> sensorMonitoring =
294             std::make_unique<SensorMonitoring>(std::move(actions));
295 
296         // Create Rail
297         std::unique_ptr<Configuration> configuration{};
298         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
299             "vddr1", std::move(configuration), std::move(sensorMonitoring));
300         Rail* railPtr = rail.get();
301 
302         // Create Device that contains Rail
303         std::unique_ptr<PresenceDetection> presenceDetection{};
304         std::unique_ptr<Configuration> deviceConfiguration{};
305         std::vector<std::unique_ptr<Rail>> rails{};
306         rails.emplace_back(std::move(rail));
307         std::unique_ptr<Device> device = std::make_unique<Device>(
308             "reg1", true,
309             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
310             std::move(i2cInterface), std::move(presenceDetection),
311             std::move(deviceConfiguration), std::move(rails));
312         Device* devicePtr = device.get();
313 
314         // Create Chassis that contains Device
315         std::vector<std::unique_ptr<Device>> devices{};
316         devices.emplace_back(std::move(device));
317         std::unique_ptr<Chassis> chassis =
318             std::make_unique<Chassis>(1, std::move(devices));
319         Chassis* chassisPtr = chassis.get();
320 
321         // Create System that contains Chassis
322         std::vector<std::unique_ptr<Rule>> rules{};
323         std::vector<std::unique_ptr<Chassis>> chassisVec{};
324         chassisVec.emplace_back(std::move(chassis));
325         System system{std::move(rules), std::move(chassisVec)};
326 
327         // Call monitorSensors().
328         railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
329     }
330 }
331 
332 TEST(RailTests, GetSensorMonitoring)
333 {
334     // Test where SensorMonitoring was not specified in constructor
335     {
336         Rail rail{"vdd0", nullptr, nullptr};
337         EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
338     }
339 
340     // Test where SensorMonitoring was specified in constructor
341     {
342         std::unique_ptr<Configuration> configuration{};
343 
344         // Create SensorMonitoring
345         std::vector<std::unique_ptr<Action>> actions{};
346         actions.push_back(std::make_unique<MockAction>());
347         actions.push_back(std::make_unique<MockAction>());
348         std::unique_ptr<SensorMonitoring> sensorMonitoring =
349             std::make_unique<SensorMonitoring>(std::move(actions));
350 
351         // Create Rail
352         Rail rail{"vddr1", std::move(configuration),
353                   std::move(sensorMonitoring)};
354         EXPECT_NE(rail.getSensorMonitoring(), nullptr);
355         EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2);
356     }
357 }
358