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 "mock_action.hpp"
22 #include "mock_error_logging.hpp"
23 #include "mock_journal.hpp"
24 #include "mock_sensors.hpp"
25 #include "mock_services.hpp"
26 #include "mocked_i2c_interface.hpp"
27 #include "phase_fault_detection.hpp"
28 #include "presence_detection.hpp"
29 #include "rail.hpp"
30 #include "rule.hpp"
31 #include "sensor_monitoring.hpp"
32 #include "sensors.hpp"
33 #include "system.hpp"
34 #include "test_sdbus_error.hpp"
35
36 #include <memory>
37 #include <optional>
38 #include <utility>
39 #include <vector>
40
41 #include <gmock/gmock.h>
42 #include <gtest/gtest.h>
43
44 using namespace phosphor::power::regulators;
45
46 using ::testing::A;
47 using ::testing::Return;
48 using ::testing::Throw;
49 using ::testing::TypedEq;
50
51 static const std::string chassisInvPath{
52 "/xyz/openbmc_project/inventory/system/chassis"};
53
TEST(RailTests,Constructor)54 TEST(RailTests, Constructor)
55 {
56 // Test where only required parameters are specified
57 {
58 Rail rail{"vdd0"};
59 EXPECT_EQ(rail.getID(), "vdd0");
60 EXPECT_EQ(rail.getConfiguration(), nullptr);
61 EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
62 }
63
64 // Test where all parameters are specified
65 {
66 // Create Configuration
67 std::optional<double> volts{1.3};
68 std::vector<std::unique_ptr<Action>> actions{};
69 actions.push_back(std::make_unique<MockAction>());
70 actions.push_back(std::make_unique<MockAction>());
71 std::unique_ptr<Configuration> configuration =
72 std::make_unique<Configuration>(volts, std::move(actions));
73
74 // Create SensorMonitoring
75 actions.clear();
76 actions.push_back(std::make_unique<MockAction>());
77 std::unique_ptr<SensorMonitoring> sensorMonitoring =
78 std::make_unique<SensorMonitoring>(std::move(actions));
79
80 // Create Rail
81 Rail rail{"vddr1", std::move(configuration),
82 std::move(sensorMonitoring)};
83 EXPECT_EQ(rail.getID(), "vddr1");
84 EXPECT_NE(rail.getConfiguration(), nullptr);
85 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
86 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 1.3);
87 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 2);
88 EXPECT_NE(rail.getSensorMonitoring(), nullptr);
89 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 1);
90 }
91 }
92
TEST(RailTests,ClearErrorHistory)93 TEST(RailTests, ClearErrorHistory)
94 {
95 // Create SensorMonitoring. Will fail with a DBus exception.
96 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
97 EXPECT_CALL(*action, execute)
98 .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"}));
99 std::vector<std::unique_ptr<Action>> actions{};
100 actions.emplace_back(std::move(action));
101 std::unique_ptr<SensorMonitoring> sensorMonitoring =
102 std::make_unique<SensorMonitoring>(std::move(actions));
103
104 // Create Rail
105 std::unique_ptr<Configuration> configuration{};
106 std::unique_ptr<Rail> rail = std::make_unique<Rail>(
107 "vddr1", std::move(configuration), std::move(sensorMonitoring));
108 Rail* railPtr = rail.get();
109
110 // Create Device that contains Rail
111 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
112 std::make_unique<i2c::MockedI2CInterface>();
113 std::unique_ptr<PresenceDetection> presenceDetection{};
114 std::unique_ptr<Configuration> deviceConfiguration{};
115 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
116 std::vector<std::unique_ptr<Rail>> rails{};
117 rails.emplace_back(std::move(rail));
118 std::unique_ptr<Device> device = std::make_unique<Device>(
119 "reg1", true,
120 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
121 std::move(i2cInterface), std::move(presenceDetection),
122 std::move(deviceConfiguration), std::move(phaseFaultDetection),
123 std::move(rails));
124 Device* devicePtr = device.get();
125
126 // Create Chassis that contains Device
127 std::vector<std::unique_ptr<Device>> devices{};
128 devices.emplace_back(std::move(device));
129 std::unique_ptr<Chassis> chassis =
130 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
131 Chassis* chassisPtr = chassis.get();
132
133 // Create System that contains Chassis
134 std::vector<std::unique_ptr<Rule>> rules{};
135 std::vector<std::unique_ptr<Chassis>> chassisVec{};
136 chassisVec.emplace_back(std::move(chassis));
137 System system{std::move(rules), std::move(chassisVec)};
138
139 // Create lambda that sets MockServices expectations. The lambda allows
140 // us to set expectations multiple times without duplicate code.
141 auto setExpectations = [](MockServices& services) {
142 // Expect Sensors service to be called 10 times
143 MockSensors& sensors = services.getMockSensors();
144 EXPECT_CALL(sensors, startRail).Times(10);
145 EXPECT_CALL(sensors, setValue).Times(0);
146 EXPECT_CALL(sensors, endRail(true)).Times(10);
147
148 // Expect Journal service to be called 6 times to log error messages
149 MockJournal& journal = services.getMockJournal();
150 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
151 .Times(6);
152 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
153
154 // Expect ErrorLogging service to be called once to log a DBus error
155 MockErrorLogging& errorLogging = services.getMockErrorLogging();
156 EXPECT_CALL(errorLogging, logDBusError).Times(1);
157 };
158
159 // Monitor sensors 10 times. Verify errors logged.
160 {
161 // Create mock services. Set expectations via lambda.
162 MockServices services{};
163 setExpectations(services);
164
165 for (int i = 1; i <= 10; ++i)
166 {
167 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
168 }
169 }
170
171 // Clear error history
172 railPtr->clearErrorHistory();
173
174 // Monitor sensors 10 more times. Verify errors logged again.
175 {
176 // Create mock services. Set expectations via lambda.
177 MockServices services{};
178 setExpectations(services);
179
180 for (int i = 1; i <= 10; ++i)
181 {
182 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
183 }
184 }
185 }
186
TEST(RailTests,Configure)187 TEST(RailTests, Configure)
188 {
189 // Test where Configuration was not specified in constructor
190 {
191 // Create mock services. No logging should occur.
192 MockServices services{};
193 MockJournal& journal = services.getMockJournal();
194 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
195 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
196
197 // Create Rail
198 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0");
199 Rail* railPtr = rail.get();
200
201 // Create Device that contains Rail
202 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
203 std::make_unique<i2c::MockedI2CInterface>();
204 std::unique_ptr<PresenceDetection> presenceDetection{};
205 std::unique_ptr<Configuration> deviceConfiguration{};
206 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
207 std::vector<std::unique_ptr<Rail>> rails{};
208 rails.emplace_back(std::move(rail));
209 std::unique_ptr<Device> device = std::make_unique<Device>(
210 "reg1", true,
211 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
212 std::move(i2cInterface), std::move(presenceDetection),
213 std::move(deviceConfiguration), std::move(phaseFaultDetection),
214 std::move(rails));
215 Device* devicePtr = device.get();
216
217 // Create Chassis that contains Device
218 std::vector<std::unique_ptr<Device>> devices{};
219 devices.emplace_back(std::move(device));
220 std::unique_ptr<Chassis> chassis =
221 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
222 Chassis* chassisPtr = chassis.get();
223
224 // Create System that contains Chassis
225 std::vector<std::unique_ptr<Rule>> rules{};
226 std::vector<std::unique_ptr<Chassis>> chassisVec{};
227 chassisVec.emplace_back(std::move(chassis));
228 System system{std::move(rules), std::move(chassisVec)};
229
230 // Call configure().
231 railPtr->configure(services, system, *chassisPtr, *devicePtr);
232 }
233
234 // Test where Configuration was specified in constructor
235 {
236 // Create mock services. Expect logDebug() to be called.
237 MockServices services{};
238 MockJournal& journal = services.getMockJournal();
239 EXPECT_CALL(journal, logDebug("Configuring vddr1: volts=1.300000"))
240 .Times(1);
241 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
242
243 // Create Configuration
244 std::optional<double> volts{1.3};
245 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
246 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
247 std::vector<std::unique_ptr<Action>> actions{};
248 actions.emplace_back(std::move(action));
249 std::unique_ptr<Configuration> configuration =
250 std::make_unique<Configuration>(volts, std::move(actions));
251
252 // Create Rail
253 std::unique_ptr<Rail> rail =
254 std::make_unique<Rail>("vddr1", std::move(configuration));
255 Rail* railPtr = rail.get();
256
257 // Create Device that contains Rail
258 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
259 std::make_unique<i2c::MockedI2CInterface>();
260 std::unique_ptr<PresenceDetection> presenceDetection{};
261 std::unique_ptr<Configuration> deviceConfiguration{};
262 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
263 std::vector<std::unique_ptr<Rail>> rails{};
264 rails.emplace_back(std::move(rail));
265 std::unique_ptr<Device> device = std::make_unique<Device>(
266 "reg1", true,
267 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
268 std::move(i2cInterface), std::move(presenceDetection),
269 std::move(deviceConfiguration), std::move(phaseFaultDetection),
270 std::move(rails));
271 Device* devicePtr = device.get();
272
273 // Create Chassis that contains Device
274 std::vector<std::unique_ptr<Device>> devices{};
275 devices.emplace_back(std::move(device));
276 std::unique_ptr<Chassis> chassis =
277 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
278 Chassis* chassisPtr = chassis.get();
279
280 // Create System that contains Chassis
281 std::vector<std::unique_ptr<Rule>> rules{};
282 std::vector<std::unique_ptr<Chassis>> chassisVec{};
283 chassisVec.emplace_back(std::move(chassis));
284 System system{std::move(rules), std::move(chassisVec)};
285
286 // Call configure().
287 railPtr->configure(services, system, *chassisPtr, *devicePtr);
288 }
289 }
290
TEST(RailTests,GetConfiguration)291 TEST(RailTests, GetConfiguration)
292 {
293 // Test where Configuration was not specified in constructor
294 {
295 Rail rail{"vdd0"};
296 EXPECT_EQ(rail.getConfiguration(), nullptr);
297 }
298
299 // Test where Configuration was specified in constructor
300 {
301 // Create Configuration
302 std::optional<double> volts{3.2};
303 std::vector<std::unique_ptr<Action>> actions{};
304 actions.push_back(std::make_unique<MockAction>());
305 std::unique_ptr<Configuration> configuration =
306 std::make_unique<Configuration>(volts, std::move(actions));
307
308 // Create Rail
309 Rail rail{"vddr1", std::move(configuration)};
310 EXPECT_NE(rail.getConfiguration(), nullptr);
311 EXPECT_EQ(rail.getConfiguration()->getVolts().has_value(), true);
312 EXPECT_EQ(rail.getConfiguration()->getVolts().value(), 3.2);
313 EXPECT_EQ(rail.getConfiguration()->getActions().size(), 1);
314 }
315 }
316
TEST(RailTests,GetID)317 TEST(RailTests, GetID)
318 {
319 Rail rail{"vio2"};
320 EXPECT_EQ(rail.getID(), "vio2");
321 }
322
TEST(RailTests,MonitorSensors)323 TEST(RailTests, MonitorSensors)
324 {
325 // Test where SensorMonitoring was not specified in constructor
326 {
327 // Create mock services. No Sensors methods should be called.
328 MockServices services{};
329 MockSensors& sensors = services.getMockSensors();
330 EXPECT_CALL(sensors, startRail).Times(0);
331 EXPECT_CALL(sensors, setValue).Times(0);
332 EXPECT_CALL(sensors, endRail).Times(0);
333
334 // Create Rail
335 std::unique_ptr<Rail> rail = std::make_unique<Rail>("vdd0");
336 Rail* railPtr = rail.get();
337
338 // Create Device that contains Rail
339 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
340 std::make_unique<i2c::MockedI2CInterface>();
341 std::unique_ptr<PresenceDetection> presenceDetection{};
342 std::unique_ptr<Configuration> deviceConfiguration{};
343 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
344 std::vector<std::unique_ptr<Rail>> rails{};
345 rails.emplace_back(std::move(rail));
346 std::unique_ptr<Device> device = std::make_unique<Device>(
347 "reg1", true,
348 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
349 std::move(i2cInterface), std::move(presenceDetection),
350 std::move(deviceConfiguration), std::move(phaseFaultDetection),
351 std::move(rails));
352 Device* devicePtr = device.get();
353
354 // Create Chassis that contains Device
355 std::vector<std::unique_ptr<Device>> devices{};
356 devices.emplace_back(std::move(device));
357 std::unique_ptr<Chassis> chassis =
358 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
359 Chassis* chassisPtr = chassis.get();
360
361 // Create System that contains Chassis
362 std::vector<std::unique_ptr<Rule>> rules{};
363 std::vector<std::unique_ptr<Chassis>> chassisVec{};
364 chassisVec.emplace_back(std::move(chassis));
365 System system{std::move(rules), std::move(chassisVec)};
366
367 // Call monitorSensors()
368 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
369 }
370
371 // Test where SensorMonitoring was specified in constructor
372 {
373 // Create mock services. Set Sensors service expectations.
374 MockServices services{};
375 MockSensors& sensors = services.getMockSensors();
376 EXPECT_CALL(sensors,
377 startRail("vddr1",
378 "/xyz/openbmc_project/inventory/system/chassis/"
379 "motherboard/reg1",
380 chassisInvPath))
381 .Times(1);
382 EXPECT_CALL(sensors, setValue).Times(0);
383 EXPECT_CALL(sensors, endRail(false)).Times(1);
384
385 // Create SensorMonitoring
386 std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
387 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
388 std::vector<std::unique_ptr<Action>> actions{};
389 actions.emplace_back(std::move(action));
390 std::unique_ptr<SensorMonitoring> sensorMonitoring =
391 std::make_unique<SensorMonitoring>(std::move(actions));
392
393 // Create Rail
394 std::unique_ptr<Configuration> configuration{};
395 std::unique_ptr<Rail> rail = std::make_unique<Rail>(
396 "vddr1", std::move(configuration), std::move(sensorMonitoring));
397 Rail* railPtr = rail.get();
398
399 // Create Device that contains Rail
400 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
401 std::make_unique<i2c::MockedI2CInterface>();
402 std::unique_ptr<PresenceDetection> presenceDetection{};
403 std::unique_ptr<Configuration> deviceConfiguration{};
404 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
405 std::vector<std::unique_ptr<Rail>> rails{};
406 rails.emplace_back(std::move(rail));
407 std::unique_ptr<Device> device = std::make_unique<Device>(
408 "reg1", true,
409 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
410 std::move(i2cInterface), std::move(presenceDetection),
411 std::move(deviceConfiguration), std::move(phaseFaultDetection),
412 std::move(rails));
413 Device* devicePtr = device.get();
414
415 // Create Chassis that contains Device
416 std::vector<std::unique_ptr<Device>> devices{};
417 devices.emplace_back(std::move(device));
418 std::unique_ptr<Chassis> chassis =
419 std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
420 Chassis* chassisPtr = chassis.get();
421
422 // Create System that contains Chassis
423 std::vector<std::unique_ptr<Rule>> rules{};
424 std::vector<std::unique_ptr<Chassis>> chassisVec{};
425 chassisVec.emplace_back(std::move(chassis));
426 System system{std::move(rules), std::move(chassisVec)};
427
428 // Call monitorSensors()
429 railPtr->monitorSensors(services, system, *chassisPtr, *devicePtr);
430 }
431 }
432
TEST(RailTests,GetSensorMonitoring)433 TEST(RailTests, GetSensorMonitoring)
434 {
435 // Test where SensorMonitoring was not specified in constructor
436 {
437 Rail rail{"vdd0", nullptr, nullptr};
438 EXPECT_EQ(rail.getSensorMonitoring(), nullptr);
439 }
440
441 // Test where SensorMonitoring was specified in constructor
442 {
443 std::unique_ptr<Configuration> configuration{};
444
445 // Create SensorMonitoring
446 std::vector<std::unique_ptr<Action>> actions{};
447 actions.push_back(std::make_unique<MockAction>());
448 actions.push_back(std::make_unique<MockAction>());
449 std::unique_ptr<SensorMonitoring> sensorMonitoring =
450 std::make_unique<SensorMonitoring>(std::move(actions));
451
452 // Create Rail
453 Rail rail{"vddr1", std::move(configuration),
454 std::move(sensorMonitoring)};
455 EXPECT_NE(rail.getSensorMonitoring(), nullptr);
456 EXPECT_EQ(rail.getSensorMonitoring()->getActions().size(), 2);
457 }
458 }
459