xref: /openbmc/phosphor-power/phosphor-regulators/test/chassis_tests.cpp (revision b7552f0cbc6692693ef3430e0faa4f145f7b08c3)
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 "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 "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 mock services.  Expect logDebug() to be called.
119         MockServices services{};
120         MockJournal& journal = services.getMockJournal();
121         EXPECT_CALL(journal, logDebug("Closing devices in chassis 2")).Times(1);
122 
123         // Create Chassis
124         Chassis chassis{2};
125 
126         // Call closeDevices()
127         chassis.closeDevices(services);
128     }
129 
130     // Test where devices were specified in constructor
131     {
132         std::vector<std::unique_ptr<Device>> devices{};
133 
134         // Create mock services.  Expect logDebug() to be called.
135         MockServices services{};
136         MockJournal& journal = services.getMockJournal();
137         EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
138 
139         // Create Device vdd0_reg
140         {
141             // Create mock I2CInterface: isOpen() and close() should be called
142             std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
143                 std::make_unique<i2c::MockedI2CInterface>();
144             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
145             EXPECT_CALL(*i2cInterface, close).Times(1);
146 
147             // Create Device
148             std::unique_ptr<Device> device = std::make_unique<Device>(
149                 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg",
150                 std::move(i2cInterface));
151             devices.emplace_back(std::move(device));
152         }
153 
154         // Create Device vdd1_reg
155         {
156             // Create mock I2CInterface: isOpen() and close() should be called
157             std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
158                 std::make_unique<i2c::MockedI2CInterface>();
159             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
160             EXPECT_CALL(*i2cInterface, close).Times(1);
161 
162             // Create Device
163             std::unique_ptr<Device> device = std::make_unique<Device>(
164                 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg",
165                 std::move(i2cInterface));
166             devices.emplace_back(std::move(device));
167         }
168 
169         // Create Chassis
170         Chassis chassis{1, std::move(devices)};
171 
172         // Call closeDevices()
173         chassis.closeDevices(services);
174     }
175 }
176 
177 TEST(ChassisTests, Configure)
178 {
179     // Test where no devices were specified in constructor
180     {
181         // Create mock services.  Expect logInfo() to be called.
182         MockServices services{};
183         MockJournal& journal = services.getMockJournal();
184         EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
185         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
186         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
187 
188         // Create Chassis
189         std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(1);
190         Chassis* chassisPtr = chassis.get();
191 
192         // Create System that contains Chassis
193         std::vector<std::unique_ptr<Rule>> rules{};
194         std::vector<std::unique_ptr<Chassis>> chassisVec{};
195         chassisVec.emplace_back(std::move(chassis));
196         System system{std::move(rules), std::move(chassisVec)};
197 
198         // Call configure()
199         chassisPtr->configure(services, system);
200     }
201 
202     // Test where devices were specified in constructor
203     {
204         std::vector<std::unique_ptr<Device>> devices{};
205 
206         // Create mock services.  Expect logInfo() and logDebug() to be called.
207         MockServices services{};
208         MockJournal& journal = services.getMockJournal();
209         EXPECT_CALL(journal, logInfo("Configuring chassis 2")).Times(1);
210         EXPECT_CALL(journal, logDebug("Configuring vdd0_reg: volts=1.300000"))
211             .Times(1);
212         EXPECT_CALL(journal, logDebug("Configuring vdd1_reg: volts=1.200000"))
213             .Times(1);
214         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
215 
216         // Create Device vdd0_reg
217         {
218             // Create Configuration
219             std::vector<std::unique_ptr<Action>> actions{};
220             std::unique_ptr<Configuration> configuration =
221                 std::make_unique<Configuration>(1.3, std::move(actions));
222 
223             // Create Device
224             std::unique_ptr<i2c::I2CInterface> i2cInterface =
225                 createI2CInterface();
226             std::unique_ptr<PresenceDetection> presenceDetection{};
227             std::unique_ptr<Device> device = std::make_unique<Device>(
228                 "vdd0_reg", true, "/system/chassis/motherboard/vdd0_reg",
229                 std::move(i2cInterface), std::move(presenceDetection),
230                 std::move(configuration));
231             devices.emplace_back(std::move(device));
232         }
233 
234         // Create Device vdd1_reg
235         {
236             // Create Configuration
237             std::vector<std::unique_ptr<Action>> actions{};
238             std::unique_ptr<Configuration> configuration =
239                 std::make_unique<Configuration>(1.2, std::move(actions));
240 
241             // Create Device
242             std::unique_ptr<i2c::I2CInterface> i2cInterface =
243                 createI2CInterface();
244             std::unique_ptr<PresenceDetection> presenceDetection{};
245             std::unique_ptr<Device> device = std::make_unique<Device>(
246                 "vdd1_reg", true, "/system/chassis/motherboard/vdd1_reg",
247                 std::move(i2cInterface), std::move(presenceDetection),
248                 std::move(configuration));
249             devices.emplace_back(std::move(device));
250         }
251 
252         // Create Chassis
253         std::unique_ptr<Chassis> chassis =
254             std::make_unique<Chassis>(2, std::move(devices));
255         Chassis* chassisPtr = chassis.get();
256 
257         // Create System that contains Chassis
258         std::vector<std::unique_ptr<Rule>> rules{};
259         std::vector<std::unique_ptr<Chassis>> chassisVec{};
260         chassisVec.emplace_back(std::move(chassis));
261         System system{std::move(rules), std::move(chassisVec)};
262 
263         // Call configure()
264         chassisPtr->configure(services, system);
265     }
266 }
267 
268 TEST(ChassisTests, GetDevices)
269 {
270     // Test where no devices were specified in constructor
271     {
272         Chassis chassis{2};
273         EXPECT_EQ(chassis.getDevices().size(), 0);
274     }
275 
276     // Test where devices were specified in constructor
277     {
278         // Create vector of Device objects
279         std::vector<std::unique_ptr<Device>> devices{};
280         devices.emplace_back(createDevice("vdd_reg1"));
281         devices.emplace_back(createDevice("vdd_reg2"));
282 
283         // Create Chassis
284         Chassis chassis{1, std::move(devices)};
285         EXPECT_EQ(chassis.getDevices().size(), 2);
286         EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
287         EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
288     }
289 }
290 
291 TEST(ChassisTests, GetNumber)
292 {
293     Chassis chassis{3};
294     EXPECT_EQ(chassis.getNumber(), 3);
295 }
296 
297 TEST(ChassisTests, MonitorSensors)
298 {
299     // Test where no devices were specified in constructor
300     {
301         // Create mock services.  No logging should occur.
302         MockServices services{};
303         MockJournal& journal = services.getMockJournal();
304         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
305         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
306 
307         // Create Chassis
308         std::vector<std::unique_ptr<Device>> devices{};
309         std::unique_ptr<Chassis> chassis =
310             std::make_unique<Chassis>(1, std::move(devices));
311         Chassis* chassisPtr = chassis.get();
312 
313         // Create System that contains Chassis
314         std::vector<std::unique_ptr<Rule>> rules{};
315         std::vector<std::unique_ptr<Chassis>> chassisVec{};
316         chassisVec.emplace_back(std::move(chassis));
317         System system{std::move(rules), std::move(chassisVec)};
318 
319         // Call monitorSensors().  Should do nothing.
320         chassisPtr->monitorSensors(services, system);
321     }
322 
323     // Test where devices were specified in constructor
324     {
325         // Create mock services.  No logging should occur.
326         MockServices services{};
327         MockJournal& journal = services.getMockJournal();
328         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
329         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
330 
331         std::vector<std::unique_ptr<Device>> devices{};
332 
333         // Create PMBusReadSensorAction
334         pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
335         uint8_t command = 0x8C;
336         pmbus_utils::SensorDataFormat format{
337             pmbus_utils::SensorDataFormat::linear_11};
338         std::optional<int8_t> exponent{};
339         std::unique_ptr<PMBusReadSensorAction> action =
340             std::make_unique<PMBusReadSensorAction>(type, command, format,
341                                                     exponent);
342 
343         // Create mock I2CInterface.  A two-byte read should occur.
344         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
345             std::make_unique<i2c::MockedI2CInterface>();
346         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
347         EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
348             .Times(1);
349 
350         // Create SensorMonitoring
351         std::vector<std::unique_ptr<Action>> actions{};
352         actions.emplace_back(std::move(action));
353         std::unique_ptr<SensorMonitoring> sensorMonitoring =
354             std::make_unique<SensorMonitoring>(std::move(actions));
355 
356         // Create Rail
357         std::vector<std::unique_ptr<Rail>> rails{};
358         std::unique_ptr<Configuration> configuration{};
359         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
360             "vdd0", std::move(configuration), std::move(sensorMonitoring));
361         rails.emplace_back(std::move(rail));
362 
363         // Create Device
364         std::unique_ptr<PresenceDetection> presenceDetection{};
365         std::unique_ptr<Configuration> deviceConfiguration{};
366         std::unique_ptr<Device> device = std::make_unique<Device>(
367             "reg1", true, "/system/chassis/motherboard/reg1",
368             std::move(i2cInterface), std::move(presenceDetection),
369             std::move(deviceConfiguration), std::move(rails));
370 
371         // Create Chassis
372         devices.emplace_back(std::move(device));
373         std::unique_ptr<Chassis> chassis =
374             std::make_unique<Chassis>(1, std::move(devices));
375         Chassis* chassisPtr = chassis.get();
376 
377         // Create System that contains Chassis
378         std::vector<std::unique_ptr<Rule>> rules{};
379         std::vector<std::unique_ptr<Chassis>> chassisVec{};
380         chassisVec.emplace_back(std::move(chassis));
381         System system{std::move(rules), std::move(chassisVec)};
382 
383         // Call monitorSensors()
384         chassisPtr->monitorSensors(services, system);
385     }
386 }
387