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 "chassis.hpp"
17 #include "device.hpp"
18 #include "id_map.hpp"
19 #include "mock_journal.hpp"
20 #include "mock_services.hpp"
21 #include "mocked_i2c_interface.hpp"
22 #include "pmbus_read_sensor_action.hpp"
23 #include "rail.hpp"
24 #include "rule.hpp"
25 #include "services.hpp"
26 #include "system.hpp"
27 #include "test_utils.hpp"
28 
29 #include <memory>
30 #include <stdexcept>
31 #include <string>
32 #include <utility>
33 #include <vector>
34 
35 #include <gmock/gmock.h>
36 #include <gtest/gtest.h>
37 
38 using namespace phosphor::power::regulators;
39 using namespace phosphor::power::regulators::test_utils;
40 
41 using ::testing::A;
42 using ::testing::Return;
43 using ::testing::TypedEq;
44 
45 TEST(SystemTests, Constructor)
46 {
47     // Create Rules
48     std::vector<std::unique_ptr<Rule>> rules{};
49     rules.emplace_back(createRule("set_voltage_rule"));
50 
51     // Create Chassis
52     std::vector<std::unique_ptr<Chassis>> chassis{};
53     std::vector<std::unique_ptr<Device>> devices{};
54     devices.emplace_back(createDevice("reg1", {"rail1"}));
55     chassis.emplace_back(std::make_unique<Chassis>(1, std::move(devices)));
56 
57     // Create System
58     System system{std::move(rules), std::move(chassis)};
59     EXPECT_EQ(system.getChassis().size(), 1);
60     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
61     EXPECT_NO_THROW(system.getIDMap().getRule("set_voltage_rule"));
62     EXPECT_NO_THROW(system.getIDMap().getDevice("reg1"));
63     EXPECT_NO_THROW(system.getIDMap().getRail("rail1"));
64     EXPECT_THROW(system.getIDMap().getRail("rail2"), std::invalid_argument);
65     EXPECT_EQ(system.getRules().size(), 1);
66     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
67 }
68 
69 TEST(SystemTests, ClearCache)
70 {
71     // Create PresenceDetection
72     std::vector<std::unique_ptr<Action>> actions{};
73     std::unique_ptr<PresenceDetection> presenceDetection =
74         std::make_unique<PresenceDetection>(std::move(actions));
75     PresenceDetection* presenceDetectionPtr = presenceDetection.get();
76 
77     // Create Device that contains PresenceDetection
78     std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
79     std::unique_ptr<Device> device = std::make_unique<Device>(
80         "reg1", true,
81         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
82         std::move(i2cInterface), std::move(presenceDetection));
83     Device* devicePtr = device.get();
84 
85     // Create Chassis that contains Device
86     std::vector<std::unique_ptr<Device>> devices{};
87     devices.emplace_back(std::move(device));
88     std::unique_ptr<Chassis> chassis =
89         std::make_unique<Chassis>(1, std::move(devices));
90     Chassis* chassisPtr = chassis.get();
91 
92     // Create System that contains Chassis
93     std::vector<std::unique_ptr<Rule>> rules{};
94     std::vector<std::unique_ptr<Chassis>> chassisVec{};
95     chassisVec.emplace_back(std::move(chassis));
96     System system{std::move(rules), std::move(chassisVec)};
97 
98     // Cache presence value in PresenceDetection
99     MockServices services{};
100     presenceDetectionPtr->execute(services, system, *chassisPtr, *devicePtr);
101     EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
102 
103     // Clear cached data in System
104     system.clearCache();
105 
106     // Verify presence value no longer cached in PresenceDetection
107     EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
108 }
109 
110 TEST(SystemTests, CloseDevices)
111 {
112     // Specify an empty rules vector
113     std::vector<std::unique_ptr<Rule>> rules{};
114 
115     // Create mock services.  Expect logDebug() to be called.
116     MockServices services{};
117     MockJournal& journal = services.getMockJournal();
118     EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
119     EXPECT_CALL(journal, logDebug("Closing devices in chassis 3")).Times(1);
120     EXPECT_CALL(journal, logInfo(A<const std::string&>())).Times(0);
121     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
122 
123     // Create Chassis
124     std::vector<std::unique_ptr<Chassis>> chassis{};
125     chassis.emplace_back(std::make_unique<Chassis>(1));
126     chassis.emplace_back(std::make_unique<Chassis>(3));
127 
128     // Create System
129     System system{std::move(rules), std::move(chassis)};
130 
131     // Call closeDevices()
132     system.closeDevices(services);
133 }
134 
135 TEST(SystemTests, Configure)
136 {
137     // Create mock services.  Expect logInfo() to be called.
138     MockServices services{};
139     MockJournal& journal = services.getMockJournal();
140     EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
141     EXPECT_CALL(journal, logInfo("Configuring chassis 3")).Times(1);
142     EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
143     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
144 
145     // Specify an empty rules vector
146     std::vector<std::unique_ptr<Rule>> rules{};
147 
148     // Create Chassis
149     std::vector<std::unique_ptr<Chassis>> chassis{};
150     chassis.emplace_back(std::make_unique<Chassis>(1));
151     chassis.emplace_back(std::make_unique<Chassis>(3));
152 
153     // Create System
154     System system{std::move(rules), std::move(chassis)};
155 
156     // Call configure()
157     system.configure(services);
158 }
159 
160 TEST(SystemTests, GetChassis)
161 {
162     // Specify an empty rules vector
163     std::vector<std::unique_ptr<Rule>> rules{};
164 
165     // Create Chassis
166     std::vector<std::unique_ptr<Chassis>> chassis{};
167     chassis.emplace_back(std::make_unique<Chassis>(1));
168     chassis.emplace_back(std::make_unique<Chassis>(3));
169 
170     // Create System
171     System system{std::move(rules), std::move(chassis)};
172     EXPECT_EQ(system.getChassis().size(), 2);
173     EXPECT_EQ(system.getChassis()[0]->getNumber(), 1);
174     EXPECT_EQ(system.getChassis()[1]->getNumber(), 3);
175 }
176 
177 TEST(SystemTests, GetIDMap)
178 {
179     // Create Rules
180     std::vector<std::unique_ptr<Rule>> rules{};
181     rules.emplace_back(createRule("set_voltage_rule"));
182     rules.emplace_back(createRule("read_sensors_rule"));
183 
184     // Create Chassis
185     std::vector<std::unique_ptr<Chassis>> chassis{};
186     {
187         // Chassis 1
188         std::vector<std::unique_ptr<Device>> devices{};
189         devices.emplace_back(createDevice("reg1", {"rail1"}));
190         devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
191         chassis.emplace_back(std::make_unique<Chassis>(1, std::move(devices)));
192     }
193     {
194         // Chassis 2
195         std::vector<std::unique_ptr<Device>> devices{};
196         devices.emplace_back(createDevice("reg3", {"rail3a", "rail3b"}));
197         devices.emplace_back(createDevice("reg4"));
198         chassis.emplace_back(std::make_unique<Chassis>(2, std::move(devices)));
199     }
200 
201     // Create System
202     System system{std::move(rules), std::move(chassis)};
203     const IDMap& idMap = system.getIDMap();
204 
205     // Verify all Rules are in the IDMap
206     EXPECT_NO_THROW(idMap.getRule("set_voltage_rule"));
207     EXPECT_NO_THROW(idMap.getRule("read_sensors_rule"));
208     EXPECT_THROW(idMap.getRule("set_voltage_rule2"), std::invalid_argument);
209 
210     // Verify all Devices are in the IDMap
211     EXPECT_NO_THROW(idMap.getDevice("reg1"));
212     EXPECT_NO_THROW(idMap.getDevice("reg2"));
213     EXPECT_NO_THROW(idMap.getDevice("reg3"));
214     EXPECT_NO_THROW(idMap.getDevice("reg4"));
215     EXPECT_THROW(idMap.getDevice("reg5"), std::invalid_argument);
216 
217     // Verify all Rails are in the IDMap
218     EXPECT_NO_THROW(idMap.getRail("rail1"));
219     EXPECT_NO_THROW(idMap.getRail("rail2a"));
220     EXPECT_NO_THROW(idMap.getRail("rail2b"));
221     EXPECT_NO_THROW(idMap.getRail("rail3a"));
222     EXPECT_NO_THROW(idMap.getRail("rail3b"));
223     EXPECT_THROW(idMap.getRail("rail4"), std::invalid_argument);
224 }
225 
226 TEST(SystemTests, GetRules)
227 {
228     // Create Rules
229     std::vector<std::unique_ptr<Rule>> rules{};
230     rules.emplace_back(createRule("set_voltage_rule"));
231     rules.emplace_back(createRule("read_sensors_rule"));
232 
233     // Create Chassis
234     std::vector<std::unique_ptr<Chassis>> chassis{};
235     chassis.emplace_back(std::make_unique<Chassis>(1));
236 
237     // Create System
238     System system{std::move(rules), std::move(chassis)};
239     EXPECT_EQ(system.getRules().size(), 2);
240     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
241     EXPECT_EQ(system.getRules()[1]->getID(), "read_sensors_rule");
242 }
243 
244 TEST(SystemTests, MonitorSensors)
245 {
246     // Create mock services.  No logging should occur.
247     MockServices services{};
248     MockJournal& journal = services.getMockJournal();
249     EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
250     EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
251 
252     // Create PMBusReadSensorAction
253     pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
254     uint8_t command = 0x8C;
255     pmbus_utils::SensorDataFormat format{
256         pmbus_utils::SensorDataFormat::linear_11};
257     std::optional<int8_t> exponent{};
258     std::unique_ptr<PMBusReadSensorAction> action =
259         std::make_unique<PMBusReadSensorAction>(type, command, format,
260                                                 exponent);
261 
262     // Create mock I2CInterface.  A two-byte read should occur.
263     std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
264         std::make_unique<i2c::MockedI2CInterface>();
265     EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
266     EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
267         .Times(1);
268 
269     // Create SensorMonitoring
270     std::vector<std::unique_ptr<Action>> actions{};
271     actions.emplace_back(std::move(action));
272     std::unique_ptr<SensorMonitoring> sensorMonitoring =
273         std::make_unique<SensorMonitoring>(std::move(actions));
274 
275     // Create Rail
276     std::vector<std::unique_ptr<Rail>> rails{};
277     std::unique_ptr<Configuration> configuration{};
278     std::unique_ptr<Rail> rail = std::make_unique<Rail>(
279         "vdd0", std::move(configuration), std::move(sensorMonitoring));
280     rails.emplace_back(std::move(rail));
281 
282     // Create Device
283     std::unique_ptr<PresenceDetection> presenceDetection{};
284     std::unique_ptr<Configuration> deviceConfiguration{};
285     std::unique_ptr<Device> device = std::make_unique<Device>(
286         "reg1", true,
287         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
288         std::move(i2cInterface), std::move(presenceDetection),
289         std::move(deviceConfiguration), std::move(rails));
290 
291     // Create Chassis
292     std::vector<std::unique_ptr<Device>> devices{};
293     devices.emplace_back(std::move(device));
294     std::unique_ptr<Chassis> chassis =
295         std::make_unique<Chassis>(1, std::move(devices));
296 
297     // Create System that contains Chassis
298     std::vector<std::unique_ptr<Rule>> rules{};
299     std::vector<std::unique_ptr<Chassis>> chassisVec{};
300     chassisVec.emplace_back(std::move(chassis));
301     System system{std::move(rules), std::move(chassisVec)};
302 
303     // Call monitorSensors()
304     system.monitorSensors(services);
305 }
306