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 "id_map.hpp"
22 #include "journal.hpp"
23 #include "mock_action.hpp"
24 #include "mock_journal.hpp"
25 #include "presence_detection.hpp"
26 #include "rail.hpp"
27 #include "rule.hpp"
28 #include "system.hpp"
29 #include "test_utils.hpp"
30 
31 #include <memory>
32 #include <optional>
33 #include <string>
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 using namespace phosphor::power::regulators::test_utils;
42 
43 using ::testing::Return;
44 
45 TEST(DeviceTests, Constructor)
46 {
47     // Test where only required parameters are specified
48     {
49         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
50         i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
51         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
52                       std::move(i2cInterface)};
53         EXPECT_EQ(device.getID(), "vdd_reg");
54         EXPECT_EQ(device.isRegulator(), true);
55         EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
56         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
57         EXPECT_EQ(device.getPresenceDetection(), nullptr);
58         EXPECT_EQ(device.getConfiguration(), nullptr);
59         EXPECT_EQ(device.getRails().size(), 0);
60     }
61 
62     // Test where all parameters are specified
63     {
64         // Create I2CInterface
65         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
66         i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
67 
68         // Create PresenceDetection
69         std::vector<std::unique_ptr<Action>> actions{};
70         actions.push_back(std::make_unique<MockAction>());
71         std::unique_ptr<PresenceDetection> presenceDetection =
72             std::make_unique<PresenceDetection>(std::move(actions));
73 
74         // Create Configuration
75         std::optional<double> volts{};
76         actions.clear();
77         actions.push_back(std::make_unique<MockAction>());
78         actions.push_back(std::make_unique<MockAction>());
79         std::unique_ptr<Configuration> configuration =
80             std::make_unique<Configuration>(volts, std::move(actions));
81 
82         // Create vector of Rail objects
83         std::vector<std::unique_ptr<Rail>> rails{};
84         rails.push_back(std::make_unique<Rail>("vdd0"));
85         rails.push_back(std::make_unique<Rail>("vdd1"));
86 
87         // Create Device
88         Device device{"vdd_reg",
89                       false,
90                       "/system/chassis/motherboard/reg1",
91                       std::move(i2cInterface),
92                       std::move(presenceDetection),
93                       std::move(configuration),
94                       std::move(rails)};
95         EXPECT_EQ(device.getID(), "vdd_reg");
96         EXPECT_EQ(device.isRegulator(), false);
97         EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg1");
98         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
99         EXPECT_NE(device.getPresenceDetection(), nullptr);
100         EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
101         EXPECT_NE(device.getConfiguration(), nullptr);
102         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
103         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
104         EXPECT_EQ(device.getRails().size(), 2);
105     }
106 }
107 
108 TEST(DeviceTests, AddToIDMap)
109 {
110     std::unique_ptr<PresenceDetection> presenceDetection{};
111     std::unique_ptr<Configuration> configuration{};
112 
113     // Create vector of Rail objects
114     std::vector<std::unique_ptr<Rail>> rails{};
115     rails.push_back(std::make_unique<Rail>("vdd0"));
116     rails.push_back(std::make_unique<Rail>("vdd1"));
117 
118     // Create Device
119     Device device{"vdd_reg",
120                   false,
121                   "/system/chassis/motherboard/reg2",
122                   std::move(createI2CInterface()),
123                   std::move(presenceDetection),
124                   std::move(configuration),
125                   std::move(rails)};
126 
127     // Add Device and Rail objects to an IDMap
128     IDMap idMap{};
129     device.addToIDMap(idMap);
130 
131     // Verify Device is in the IDMap
132     EXPECT_NO_THROW(idMap.getDevice("vdd_reg"));
133     EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument);
134 
135     // Verify all Rails are in the IDMap
136     EXPECT_NO_THROW(idMap.getRail("vdd0"));
137     EXPECT_NO_THROW(idMap.getRail("vdd1"));
138     EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
139 }
140 
141 TEST(DeviceTests, Configure)
142 {
143     // Test where Configuration and Rails were not specified in constructor
144     {
145         // Create Device
146         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
147         std::unique_ptr<Device> device = std::make_unique<Device>(
148             "reg1", true, "/system/chassis/motherboard/reg1",
149             std::move(i2cInterface));
150         Device* devicePtr = device.get();
151 
152         // Create Chassis that contains Device
153         std::vector<std::unique_ptr<Device>> devices{};
154         devices.emplace_back(std::move(device));
155         std::unique_ptr<Chassis> chassis =
156             std::make_unique<Chassis>(1, std::move(devices));
157         Chassis* chassisPtr = chassis.get();
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         // Call configure().  Should do nothing.
166         journal::clear();
167         devicePtr->configure(system, *chassisPtr);
168         EXPECT_EQ(journal::getDebugMessages().size(), 0);
169         EXPECT_EQ(journal::getErrMessages().size(), 0);
170     }
171 
172     // Test where Configuration and Rails were specified in constructor
173     {
174         std::vector<std::unique_ptr<Rail>> rails{};
175 
176         // Create Rail vdd0
177         {
178             // Create Configuration for Rail
179             std::optional<double> volts{1.3};
180             std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
181             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
182             std::vector<std::unique_ptr<Action>> actions{};
183             actions.emplace_back(std::move(action));
184             std::unique_ptr<Configuration> configuration =
185                 std::make_unique<Configuration>(volts, std::move(actions));
186 
187             // Create Rail
188             std::unique_ptr<Rail> rail =
189                 std::make_unique<Rail>("vdd0", std::move(configuration));
190             rails.emplace_back(std::move(rail));
191         }
192 
193         // Create Rail vio0
194         {
195             // Create Configuration for Rail
196             std::optional<double> volts{3.2};
197             std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
198             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
199             std::vector<std::unique_ptr<Action>> actions{};
200             actions.emplace_back(std::move(action));
201             std::unique_ptr<Configuration> configuration =
202                 std::make_unique<Configuration>(volts, std::move(actions));
203 
204             // Create Rail
205             std::unique_ptr<Rail> rail =
206                 std::make_unique<Rail>("vio0", std::move(configuration));
207             rails.emplace_back(std::move(rail));
208         }
209 
210         // Create Configuration for Device
211         std::optional<double> volts{};
212         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
213         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
214         std::vector<std::unique_ptr<Action>> actions{};
215         actions.emplace_back(std::move(action));
216         std::unique_ptr<Configuration> configuration =
217             std::make_unique<Configuration>(volts, std::move(actions));
218 
219         // Create Device
220         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
221         std::unique_ptr<PresenceDetection> presenceDetection{};
222         std::unique_ptr<Device> device = std::make_unique<Device>(
223             "reg1", true, "/system/chassis/motherboard/reg1",
224             std::move(i2cInterface), std::move(presenceDetection),
225             std::move(configuration), std::move(rails));
226         Device* devicePtr = device.get();
227 
228         // Create Chassis that contains Device
229         std::vector<std::unique_ptr<Device>> devices{};
230         devices.emplace_back(std::move(device));
231         std::unique_ptr<Chassis> chassis =
232             std::make_unique<Chassis>(1, std::move(devices));
233         Chassis* chassisPtr = chassis.get();
234 
235         // Create System that contains Chassis
236         std::vector<std::unique_ptr<Rule>> rules{};
237         std::vector<std::unique_ptr<Chassis>> chassisVec{};
238         chassisVec.emplace_back(std::move(chassis));
239         System system{std::move(rules), std::move(chassisVec)};
240 
241         // Call configure().  For the Device and both Rails, should execute the
242         // Configuration and log a debug message.
243         journal::clear();
244         devicePtr->configure(system, *chassisPtr);
245         std::vector<std::string> expectedDebugMessages{
246             "Configuring reg1", "Configuring vdd0: volts=1.300000",
247             "Configuring vio0: volts=3.200000"};
248         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
249         EXPECT_EQ(journal::getErrMessages().size(), 0);
250     }
251 }
252 
253 TEST(DeviceTests, GetConfiguration)
254 {
255     // Test where Configuration was not specified in constructor
256     {
257         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
258                       std::move(createI2CInterface())};
259         EXPECT_EQ(device.getConfiguration(), nullptr);
260     }
261 
262     // Test where Configuration was specified in constructor
263     {
264         std::unique_ptr<PresenceDetection> presenceDetection{};
265 
266         // Create Configuration
267         std::optional<double> volts{3.2};
268         std::vector<std::unique_ptr<Action>> actions{};
269         actions.push_back(std::make_unique<MockAction>());
270         actions.push_back(std::make_unique<MockAction>());
271         std::unique_ptr<Configuration> configuration =
272             std::make_unique<Configuration>(volts, std::move(actions));
273 
274         // Create Device
275         Device device{"vdd_reg",
276                       true,
277                       "/system/chassis/motherboard/reg2",
278                       std::move(createI2CInterface()),
279                       std::move(presenceDetection),
280                       std::move(configuration)};
281         EXPECT_NE(device.getConfiguration(), nullptr);
282         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
283         EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
284         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
285     }
286 }
287 
288 TEST(DeviceTests, GetFRU)
289 {
290     Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
291                   std::move(createI2CInterface())};
292     EXPECT_EQ(device.getFRU(), "/system/chassis/motherboard/reg2");
293 }
294 
295 TEST(DeviceTests, GetI2CInterface)
296 {
297     std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
298     i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
299     Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
300                   std::move(i2cInterface)};
301     EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
302 }
303 
304 TEST(DeviceTests, GetID)
305 {
306     Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
307                   std::move(createI2CInterface())};
308     EXPECT_EQ(device.getID(), "vdd_reg");
309 }
310 
311 TEST(DeviceTests, GetPresenceDetection)
312 {
313     // Test where PresenceDetection was not specified in constructor
314     {
315         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
316                       std::move(createI2CInterface())};
317         EXPECT_EQ(device.getPresenceDetection(), nullptr);
318     }
319 
320     // Test where PresenceDetection was specified in constructor
321     {
322         // Create PresenceDetection
323         std::vector<std::unique_ptr<Action>> actions{};
324         actions.push_back(std::make_unique<MockAction>());
325         std::unique_ptr<PresenceDetection> presenceDetection =
326             std::make_unique<PresenceDetection>(std::move(actions));
327 
328         // Create Device
329         Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
330                       std::move(createI2CInterface()),
331                       std::move(presenceDetection)};
332         EXPECT_NE(device.getPresenceDetection(), nullptr);
333         EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
334     }
335 }
336 
337 TEST(DeviceTests, GetRails)
338 {
339     // Test where no rails were specified in constructor
340     {
341         Device device{"vdd_reg", true, "/system/chassis/motherboard/reg2",
342                       std::move(createI2CInterface())};
343         EXPECT_EQ(device.getRails().size(), 0);
344     }
345 
346     // Test where rails were specified in constructor
347     {
348         std::unique_ptr<PresenceDetection> presenceDetection{};
349         std::unique_ptr<Configuration> configuration{};
350 
351         // Create vector of Rail objects
352         std::vector<std::unique_ptr<Rail>> rails{};
353         rails.push_back(std::make_unique<Rail>("vdd0"));
354         rails.push_back(std::make_unique<Rail>("vdd1"));
355 
356         // Create Device
357         Device device{"vdd_reg",
358                       false,
359                       "/system/chassis/motherboard/reg2",
360                       std::move(createI2CInterface()),
361                       std::move(presenceDetection),
362                       std::move(configuration),
363                       std::move(rails)};
364         EXPECT_EQ(device.getRails().size(), 2);
365         EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
366         EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
367     }
368 }
369 
370 TEST(DeviceTests, IsRegulator)
371 {
372     Device device{"vdd_reg", false, "/system/chassis/motherboard/reg2",
373                   std::move(createI2CInterface())};
374     EXPECT_EQ(device.isRegulator(), false);
375 }
376