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 "journal.hpp"
23 #include "mock_journal.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 "system.hpp"
30 #include "test_utils.hpp"
31 
32 #include <memory>
33 #include <stdexcept>
34 #include <string>
35 #include <utility>
36 #include <vector>
37 
38 #include <gmock/gmock.h>
39 #include <gtest/gtest.h>
40 
41 using namespace phosphor::power::regulators;
42 using namespace phosphor::power::regulators::test_utils;
43 
44 using ::testing::A;
45 using ::testing::Return;
46 using ::testing::TypedEq;
47 
48 TEST(ChassisTests, Constructor)
49 {
50     // Test where works: Only required parameters are specified
51     {
52         Chassis chassis{2};
53         EXPECT_EQ(chassis.getNumber(), 2);
54         EXPECT_EQ(chassis.getDevices().size(), 0);
55     }
56 
57     // Test where works: All parameters are specified
58     {
59         // Create vector of Device objects
60         std::vector<std::unique_ptr<Device>> devices{};
61         devices.emplace_back(createDevice("vdd_reg1"));
62         devices.emplace_back(createDevice("vdd_reg2"));
63 
64         // Create Chassis
65         Chassis chassis{1, std::move(devices)};
66         EXPECT_EQ(chassis.getNumber(), 1);
67         EXPECT_EQ(chassis.getDevices().size(), 2);
68     }
69 
70     // Test where fails: Invalid chassis number < 1
71     try
72     {
73         Chassis chassis{0};
74         ADD_FAILURE() << "Should not have reached this line.";
75     }
76     catch (const std::invalid_argument& e)
77     {
78         EXPECT_STREQ(e.what(), "Invalid chassis number: 0");
79     }
80     catch (...)
81     {
82         ADD_FAILURE() << "Should not have caught exception.";
83     }
84 }
85 
86 TEST(ChassisTests, AddToIDMap)
87 {
88     // Create vector of Device objects
89     std::vector<std::unique_ptr<Device>> devices{};
90     devices.emplace_back(createDevice("reg1", {"rail1"}));
91     devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
92     devices.emplace_back(createDevice("reg3"));
93 
94     // Create Chassis
95     Chassis chassis{1, std::move(devices)};
96 
97     // Add Device and Rail objects within the Chassis to an IDMap
98     IDMap idMap{};
99     chassis.addToIDMap(idMap);
100 
101     // Verify all Devices are in the IDMap
102     EXPECT_NO_THROW(idMap.getDevice("reg1"));
103     EXPECT_NO_THROW(idMap.getDevice("reg2"));
104     EXPECT_NO_THROW(idMap.getDevice("reg3"));
105     EXPECT_THROW(idMap.getDevice("reg4"), std::invalid_argument);
106 
107     // Verify all Rails are in the IDMap
108     EXPECT_NO_THROW(idMap.getRail("rail1"));
109     EXPECT_NO_THROW(idMap.getRail("rail2a"));
110     EXPECT_NO_THROW(idMap.getRail("rail2b"));
111     EXPECT_THROW(idMap.getRail("rail3"), std::invalid_argument);
112 }
113 
114 TEST(ChassisTests, CloseDevices)
115 {
116     // Test where no devices were specified in constructor
117     {
118         // Create Chassis
119         Chassis chassis{2};
120 
121         // Call closeDevices()
122         journal::clear();
123         chassis.closeDevices();
124         EXPECT_EQ(journal::getErrMessages().size(), 0);
125         EXPECT_EQ(journal::getInfoMessages().size(), 0);
126         std::vector<std::string> expectedDebugMessages{
127             "Closing devices in chassis 2"};
128         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
129     }
130 
131     // Test where devices were specified in constructor
132     {
133         std::vector<std::unique_ptr<Device>> devices{};
134 
135         // Create Device vdd0_reg
136         {
137             // Create mock I2CInterface: isOpen() and close() should be called
138             std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
139                 std::make_unique<i2c::MockedI2CInterface>();
140             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
141             EXPECT_CALL(*i2cInterface, close).Times(1);
142 
143             // Create Device
144             std::unique_ptr<Device> device = std::make_unique<Device>(
145                 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg",
146                 std::move(i2cInterface));
147             devices.emplace_back(std::move(device));
148         }
149 
150         // Create Device vdd1_reg
151         {
152             // Create mock I2CInterface: isOpen() and close() should be called
153             std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
154                 std::make_unique<i2c::MockedI2CInterface>();
155             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
156             EXPECT_CALL(*i2cInterface, close).Times(1);
157 
158             // Create Device
159             std::unique_ptr<Device> device = std::make_unique<Device>(
160                 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg",
161                 std::move(i2cInterface));
162             devices.emplace_back(std::move(device));
163         }
164 
165         // Create Chassis
166         Chassis chassis{1, std::move(devices)};
167 
168         // Call closeDevices()
169         journal::clear();
170         chassis.closeDevices();
171         EXPECT_EQ(journal::getErrMessages().size(), 0);
172         EXPECT_EQ(journal::getInfoMessages().size(), 0);
173         std::vector<std::string> expectedDebugMessages{
174             "Closing devices in chassis 1"};
175         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
176     }
177 }
178 
179 TEST(ChassisTests, Configure)
180 {
181     // Test where no devices were specified in constructor
182     {
183         // Create Chassis
184         std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(1);
185         Chassis* chassisPtr = chassis.get();
186 
187         // Create System that contains Chassis
188         std::vector<std::unique_ptr<Rule>> rules{};
189         std::vector<std::unique_ptr<Chassis>> chassisVec{};
190         chassisVec.emplace_back(std::move(chassis));
191         System system{std::move(rules), std::move(chassisVec)};
192 
193         // Call configure()
194         journal::clear();
195         chassisPtr->configure(system);
196         EXPECT_EQ(journal::getDebugMessages().size(), 0);
197         EXPECT_EQ(journal::getErrMessages().size(), 0);
198         std::vector<std::string> expectedInfoMessages{"Configuring chassis 1"};
199         EXPECT_EQ(journal::getInfoMessages(), expectedInfoMessages);
200     }
201 
202     // Test where devices were specified in constructor
203     {
204         std::vector<std::unique_ptr<Device>> devices{};
205 
206         // Create Device vdd0_reg
207         {
208             // Create Configuration
209             std::vector<std::unique_ptr<Action>> actions{};
210             std::unique_ptr<Configuration> configuration =
211                 std::make_unique<Configuration>(1.3, std::move(actions));
212 
213             // Create Device
214             std::unique_ptr<i2c::I2CInterface> i2cInterface =
215                 createI2CInterface();
216             std::unique_ptr<PresenceDetection> presenceDetection{};
217             std::unique_ptr<Device> device = std::make_unique<Device>(
218                 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg",
219                 std::move(i2cInterface), std::move(presenceDetection),
220                 std::move(configuration));
221             devices.emplace_back(std::move(device));
222         }
223 
224         // Create Device vdd1_reg
225         {
226             // Create Configuration
227             std::vector<std::unique_ptr<Action>> actions{};
228             std::unique_ptr<Configuration> configuration =
229                 std::make_unique<Configuration>(1.2, std::move(actions));
230 
231             // Create Device
232             std::unique_ptr<i2c::I2CInterface> i2cInterface =
233                 createI2CInterface();
234             std::unique_ptr<PresenceDetection> presenceDetection{};
235             std::unique_ptr<Device> device = std::make_unique<Device>(
236                 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg",
237                 std::move(i2cInterface), std::move(presenceDetection),
238                 std::move(configuration));
239             devices.emplace_back(std::move(device));
240         }
241 
242         // Create Chassis
243         std::unique_ptr<Chassis> chassis =
244             std::make_unique<Chassis>(2, std::move(devices));
245         Chassis* chassisPtr = chassis.get();
246 
247         // Create System that contains Chassis
248         std::vector<std::unique_ptr<Rule>> rules{};
249         std::vector<std::unique_ptr<Chassis>> chassisVec{};
250         chassisVec.emplace_back(std::move(chassis));
251         System system{std::move(rules), std::move(chassisVec)};
252 
253         // Call configure()
254         journal::clear();
255         chassisPtr->configure(system);
256         std::vector<std::string> expectedDebugMessages{
257             "Configuring vdd0_reg: volts=1.300000",
258             "Configuring vdd1_reg: volts=1.200000"};
259         EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
260         EXPECT_EQ(journal::getErrMessages().size(), 0);
261         std::vector<std::string> expectedInfoMessages{"Configuring chassis 2"};
262         EXPECT_EQ(journal::getInfoMessages(), expectedInfoMessages);
263     }
264 }
265 
266 TEST(ChassisTests, GetDevices)
267 {
268     // Test where no devices were specified in constructor
269     {
270         Chassis chassis{2};
271         EXPECT_EQ(chassis.getDevices().size(), 0);
272     }
273 
274     // Test where devices were specified in constructor
275     {
276         // Create vector of Device objects
277         std::vector<std::unique_ptr<Device>> devices{};
278         devices.emplace_back(createDevice("vdd_reg1"));
279         devices.emplace_back(createDevice("vdd_reg2"));
280 
281         // Create Chassis
282         Chassis chassis{1, std::move(devices)};
283         EXPECT_EQ(chassis.getDevices().size(), 2);
284         EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
285         EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
286     }
287 }
288 
289 TEST(ChassisTests, GetNumber)
290 {
291     Chassis chassis{3};
292     EXPECT_EQ(chassis.getNumber(), 3);
293 }
294 
295 TEST(ChassisTests, MonitorSensors)
296 {
297     // Test where no devices were specified in constructor
298     {
299         // Create Chassis
300         std::vector<std::unique_ptr<Device>> devices{};
301         std::unique_ptr<Chassis> chassis =
302             std::make_unique<Chassis>(1, std::move(devices));
303         Chassis* chassisPtr = chassis.get();
304 
305         // Create System that contains Chassis
306         std::vector<std::unique_ptr<Rule>> rules{};
307         std::vector<std::unique_ptr<Chassis>> chassisVec{};
308         chassisVec.emplace_back(std::move(chassis));
309         System system{std::move(rules), std::move(chassisVec)};
310 
311         // Call monitorSensors().  Should do nothing.
312         journal::clear();
313         chassisPtr->monitorSensors(system);
314         EXPECT_EQ(journal::getDebugMessages().size(), 0);
315         EXPECT_EQ(journal::getErrMessages().size(), 0);
316     }
317 
318     // Test where devices were specified in constructor
319     {
320         std::vector<std::unique_ptr<Device>> devices{};
321 
322         // Create PMBusReadSensorAction
323         pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
324         uint8_t command = 0x8C;
325         pmbus_utils::SensorDataFormat format{
326             pmbus_utils::SensorDataFormat::linear_11};
327         std::optional<int8_t> exponent{};
328         std::unique_ptr<PMBusReadSensorAction> action =
329             std::make_unique<PMBusReadSensorAction>(type, command, format,
330                                                     exponent);
331 
332         // Create mock I2CInterface.  A two-byte read should occur.
333         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
334             std::make_unique<i2c::MockedI2CInterface>();
335         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
336         EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
337             .Times(1);
338 
339         // Create SensorMonitoring
340         std::vector<std::unique_ptr<Action>> actions{};
341         actions.emplace_back(std::move(action));
342         std::unique_ptr<SensorMonitoring> sensorMonitoring =
343             std::make_unique<SensorMonitoring>(std::move(actions));
344 
345         // Create Rail
346         std::vector<std::unique_ptr<Rail>> rails{};
347         std::unique_ptr<Configuration> configuration{};
348         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
349             "vdd0", std::move(configuration), std::move(sensorMonitoring));
350         rails.emplace_back(std::move(rail));
351 
352         // Create Device
353         std::unique_ptr<PresenceDetection> presenceDetection{};
354         std::unique_ptr<Configuration> deviceConfiguration{};
355         std::unique_ptr<Device> device = std::make_unique<Device>(
356             "reg1", true, "/system/chassis/motherboard/reg1",
357             std::move(i2cInterface), std::move(presenceDetection),
358             std::move(deviceConfiguration), std::move(rails));
359 
360         // Create Chassis
361         devices.emplace_back(std::move(device));
362         std::unique_ptr<Chassis> chassis =
363             std::make_unique<Chassis>(1, std::move(devices));
364         Chassis* chassisPtr = chassis.get();
365 
366         // Create System that contains Chassis
367         std::vector<std::unique_ptr<Rule>> rules{};
368         std::vector<std::unique_ptr<Chassis>> chassisVec{};
369         chassisVec.emplace_back(std::move(chassis));
370         System system{std::move(rules), std::move(chassisVec)};
371 
372         // Call monitorSensors()
373         journal::clear();
374         chassisPtr->monitorSensors(system);
375         EXPECT_EQ(journal::getDebugMessages().size(), 0);
376         EXPECT_EQ(journal::getErrMessages().size(), 0);
377     }
378 }
379