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