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 "id_map.hpp"
22 #include "log_phase_fault_action.hpp"
23 #include "mock_action.hpp"
24 #include "mock_error_logging.hpp"
25 #include "mock_journal.hpp"
26 #include "mock_sensors.hpp"
27 #include "mock_services.hpp"
28 #include "mocked_i2c_interface.hpp"
29 #include "phase_fault.hpp"
30 #include "phase_fault_detection.hpp"
31 #include "presence_detection.hpp"
32 #include "rail.hpp"
33 #include "rule.hpp"
34 #include "sensor_monitoring.hpp"
35 #include "sensors.hpp"
36 #include "system.hpp"
37 #include "test_sdbus_error.hpp"
38 #include "test_utils.hpp"
39
40 #include <memory>
41 #include <optional>
42 #include <string>
43 #include <utility>
44 #include <vector>
45
46 #include <gmock/gmock.h>
47 #include <gtest/gtest.h>
48
49 using namespace phosphor::power::regulators;
50 using namespace phosphor::power::regulators::test_utils;
51
52 using ::testing::A;
53 using ::testing::Ref;
54 using ::testing::Return;
55 using ::testing::Throw;
56 using ::testing::TypedEq;
57
58 class DeviceTests : public ::testing::Test
59 {
60 public:
61 /**
62 * Constructor.
63 *
64 * Creates the Chassis and System objects needed for calling some Device
65 * methods.
66 */
DeviceTests()67 DeviceTests() : ::testing::Test{}
68 {
69 // Create Chassis
70 auto chassis = std::make_unique<Chassis>(1, chassisInvPath);
71 this->chassis = chassis.get();
72
73 // Create System
74 std::vector<std::unique_ptr<Rule>> rules{};
75 std::vector<std::unique_ptr<Chassis>> chassisVec{};
76 chassisVec.emplace_back(std::move(chassis));
77 this->system =
78 std::make_unique<System>(std::move(rules), std::move(chassisVec));
79 }
80
81 protected:
82 const std::string deviceInvPath{
83 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2"};
84 const std::string chassisInvPath{
85 "/xyz/openbmc_project/inventory/system/chassis"};
86
87 // Note: This pointer does NOT need to be explicitly deleted. The Chassis
88 // object is owned by the System object and will be automatically deleted.
89 Chassis* chassis{nullptr};
90
91 std::unique_ptr<System> system{};
92 };
93
TEST_F(DeviceTests,Constructor)94 TEST_F(DeviceTests, Constructor)
95 {
96 // Test where only required parameters are specified
97 {
98 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
99 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
100 Device device{"vdd_reg", true, deviceInvPath, std::move(i2cInterface)};
101 EXPECT_EQ(device.getID(), "vdd_reg");
102 EXPECT_EQ(device.isRegulator(), true);
103 EXPECT_EQ(device.getFRU(), deviceInvPath);
104 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
105 EXPECT_EQ(device.getPresenceDetection(), nullptr);
106 EXPECT_EQ(device.getConfiguration(), nullptr);
107 EXPECT_EQ(device.getPhaseFaultDetection(), nullptr);
108 EXPECT_EQ(device.getRails().size(), 0);
109 }
110
111 // Test where all parameters are specified
112 {
113 // Create I2CInterface
114 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
115 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
116
117 // Create PresenceDetection
118 std::vector<std::unique_ptr<Action>> actions{};
119 actions.push_back(std::make_unique<MockAction>());
120 auto presenceDetection =
121 std::make_unique<PresenceDetection>(std::move(actions));
122
123 // Create Configuration
124 std::optional<double> volts{};
125 actions.clear();
126 actions.push_back(std::make_unique<MockAction>());
127 actions.push_back(std::make_unique<MockAction>());
128 auto configuration =
129 std::make_unique<Configuration>(volts, std::move(actions));
130
131 // Create PhaseFaultDetection
132 actions.clear();
133 actions.push_back(std::make_unique<MockAction>());
134 actions.push_back(std::make_unique<MockAction>());
135 actions.push_back(std::make_unique<MockAction>());
136 auto phaseFaultDetection =
137 std::make_unique<PhaseFaultDetection>(std::move(actions));
138
139 // Create vector of Rail objects
140 std::vector<std::unique_ptr<Rail>> rails{};
141 rails.push_back(std::make_unique<Rail>("vdd0"));
142 rails.push_back(std::make_unique<Rail>("vdd1"));
143
144 // Create Device
145 Device device{"vdd_reg",
146 false,
147 deviceInvPath,
148 std::move(i2cInterface),
149 std::move(presenceDetection),
150 std::move(configuration),
151 std::move(phaseFaultDetection),
152 std::move(rails)};
153 EXPECT_EQ(device.getID(), "vdd_reg");
154 EXPECT_EQ(device.isRegulator(), false);
155 EXPECT_EQ(device.getFRU(), deviceInvPath);
156 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
157 EXPECT_NE(device.getPresenceDetection(), nullptr);
158 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
159 EXPECT_NE(device.getConfiguration(), nullptr);
160 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
161 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
162 EXPECT_NE(device.getPhaseFaultDetection(), nullptr);
163 EXPECT_EQ(device.getPhaseFaultDetection()->getActions().size(), 3);
164 EXPECT_EQ(device.getRails().size(), 2);
165 }
166 }
167
TEST_F(DeviceTests,AddToIDMap)168 TEST_F(DeviceTests, AddToIDMap)
169 {
170 std::unique_ptr<PresenceDetection> presenceDetection{};
171 std::unique_ptr<Configuration> configuration{};
172 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
173
174 // Create vector of Rail objects
175 std::vector<std::unique_ptr<Rail>> rails{};
176 rails.push_back(std::make_unique<Rail>("vdd0"));
177 rails.push_back(std::make_unique<Rail>("vdd1"));
178
179 // Create Device
180 Device device{"vdd_reg",
181 false,
182 deviceInvPath,
183 createI2CInterface(),
184 std::move(presenceDetection),
185 std::move(configuration),
186 std::move(phaseFaultDetection),
187 std::move(rails)};
188
189 // Add Device and Rail objects to an IDMap
190 IDMap idMap{};
191 device.addToIDMap(idMap);
192
193 // Verify Device is in the IDMap
194 EXPECT_NO_THROW(idMap.getDevice("vdd_reg"));
195 EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument);
196
197 // Verify all Rails are in the IDMap
198 EXPECT_NO_THROW(idMap.getRail("vdd0"));
199 EXPECT_NO_THROW(idMap.getRail("vdd1"));
200 EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
201 }
202
TEST_F(DeviceTests,ClearCache)203 TEST_F(DeviceTests, ClearCache)
204 {
205 // Test where Device does not contain a PresenceDetection object
206 try
207 {
208 Device device{"vdd_reg", false, deviceInvPath, createI2CInterface()};
209 device.clearCache();
210 }
211 catch (...)
212 {
213 ADD_FAILURE() << "Should not have caught exception.";
214 }
215
216 // Test where Device contains a PresenceDetection object
217 {
218 // Create PresenceDetection
219 std::vector<std::unique_ptr<Action>> actions{};
220 auto presenceDetection =
221 std::make_unique<PresenceDetection>(std::move(actions));
222 PresenceDetection* presenceDetectionPtr = presenceDetection.get();
223
224 // Create Device
225 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
226 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface),
227 std::move(presenceDetection)};
228
229 // Cache presence value in PresenceDetection
230 MockServices services{};
231 presenceDetectionPtr->execute(services, *system, *chassis, device);
232 EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
233
234 // Clear cached data in Device
235 device.clearCache();
236
237 // Verify presence value no longer cached in PresenceDetection
238 EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
239 }
240 }
241
TEST_F(DeviceTests,ClearErrorHistory)242 TEST_F(DeviceTests, ClearErrorHistory)
243 {
244 // Create SensorMonitoring. Will fail with a DBus exception.
245 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
246 {
247 auto action = std::make_unique<MockAction>();
248 EXPECT_CALL(*action, execute)
249 .WillRepeatedly(Throw(TestSDBusError{"DBus Error"}));
250 std::vector<std::unique_ptr<Action>> actions{};
251 actions.emplace_back(std::move(action));
252 sensorMonitoring =
253 std::make_unique<SensorMonitoring>(std::move(actions));
254 }
255
256 // Create Rail
257 std::unique_ptr<Configuration> configuration{};
258 auto rail = std::make_unique<Rail>("vdd", std::move(configuration),
259 std::move(sensorMonitoring));
260
261 // Create PhaseFaultDetection. Will log an N phase fault.
262 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
263 {
264 auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
265 std::vector<std::unique_ptr<Action>> actions{};
266 actions.emplace_back(std::move(action));
267 phaseFaultDetection =
268 std::make_unique<PhaseFaultDetection>(std::move(actions));
269 }
270
271 // Create Device
272 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
273 std::unique_ptr<PresenceDetection> presenceDetection{};
274 std::unique_ptr<Configuration> deviceConfiguration{};
275 std::vector<std::unique_ptr<Rail>> rails{};
276 rails.emplace_back(std::move(rail));
277 Device device{"reg2",
278 true,
279 deviceInvPath,
280 std::move(i2cInterface),
281 std::move(presenceDetection),
282 std::move(deviceConfiguration),
283 std::move(phaseFaultDetection),
284 std::move(rails)};
285
286 // Create lambda that sets MockServices expectations. The lambda allows
287 // us to set expectations multiple times without duplicate code.
288 auto setExpectations = [](MockServices& services) {
289 // Set Journal service expectations:
290 // - 6 error messages for D-Bus errors
291 // - 6 error messages for inability to monitor sensors
292 // - 2 error messages for the N phase fault
293 MockJournal& journal = services.getMockJournal();
294 EXPECT_CALL(journal, logError(std::vector<std::string>{"DBus Error"}))
295 .Times(6);
296 EXPECT_CALL(journal, logError("Unable to monitor sensors for rail vdd"))
297 .Times(6);
298 EXPECT_CALL(
299 journal,
300 logError("n phase fault detected in regulator reg2: count=1"))
301 .Times(1);
302 EXPECT_CALL(
303 journal,
304 logError("n phase fault detected in regulator reg2: count=2"))
305 .Times(1);
306
307 // Set ErrorLogging service expectations:
308 // - D-Bus error should be logged once for the D-Bus exceptions
309 // - N phase fault error should be logged once
310 MockErrorLogging& errorLogging = services.getMockErrorLogging();
311 EXPECT_CALL(errorLogging, logDBusError).Times(1);
312 EXPECT_CALL(errorLogging, logPhaseFault).Times(1);
313
314 // Set Sensors service expections:
315 // - startRail() and endRail() called 10 times
316 MockSensors& sensors = services.getMockSensors();
317 EXPECT_CALL(sensors, startRail).Times(10);
318 EXPECT_CALL(sensors, endRail).Times(10);
319 };
320
321 // Monitor sensors and detect phase faults 10 times. Verify errors logged.
322 {
323 // Create mock services. Set expectations via lambda.
324 MockServices services{};
325 setExpectations(services);
326
327 for (int i = 1; i <= 10; ++i)
328 {
329 device.monitorSensors(services, *system, *chassis);
330 device.detectPhaseFaults(services, *system, *chassis);
331 }
332 }
333
334 // Clear error history
335 device.clearErrorHistory();
336
337 // Monitor sensors and detect phase faults 10 more times. Verify errors
338 // logged again.
339 {
340 // Create mock services. Set expectations via lambda.
341 MockServices services{};
342 setExpectations(services);
343
344 for (int i = 1; i <= 10; ++i)
345 {
346 device.monitorSensors(services, *system, *chassis);
347 device.detectPhaseFaults(services, *system, *chassis);
348 }
349 }
350 }
351
TEST_F(DeviceTests,Close)352 TEST_F(DeviceTests, Close)
353 {
354 // Test where works: I2C interface is not open
355 {
356 // Create mock I2CInterface
357 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
358 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
359 EXPECT_CALL(*i2cInterface, close).Times(0);
360
361 // Create mock services. No logError should occur.
362 MockServices services{};
363 MockJournal& journal = services.getMockJournal();
364 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
365 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
366 .Times(0);
367
368 // Create Device
369 Device device{"vdd_reg", true, deviceInvPath, std::move(i2cInterface)};
370
371 // Close Device
372 device.close(services);
373 }
374
375 // Test where works: I2C interface is open
376 {
377 // Create mock I2CInterface
378 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
379 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
380 EXPECT_CALL(*i2cInterface, close).Times(1);
381
382 // Create mock services. No logError should occur.
383 MockServices services{};
384 MockJournal& journal = services.getMockJournal();
385 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
386 EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
387 .Times(0);
388
389 // Create Device
390 Device device{"vdd_reg", true, deviceInvPath, std::move(i2cInterface)};
391
392 // Close Device
393 device.close(services);
394 }
395
396 // Test where fails: closing I2C interface fails
397 {
398 // Create mock I2CInterface
399 auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
400 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
401 EXPECT_CALL(*i2cInterface, close)
402 .Times(1)
403 .WillOnce(Throw(
404 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70}));
405
406 // Create mock services. Expect logError() and logI2CError() to be
407 // called.
408 MockServices services{};
409 MockErrorLogging& errorLogging = services.getMockErrorLogging();
410 MockJournal& journal = services.getMockJournal();
411 std::vector<std::string> expectedErrMessagesException{
412 "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70"};
413 EXPECT_CALL(journal, logError("Unable to close device vdd_reg"))
414 .Times(1);
415 EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1);
416 EXPECT_CALL(errorLogging,
417 logI2CError(Entry::Level::Notice, Ref(journal),
418 "/dev/i2c-1", 0x70, 0))
419 .Times(1);
420
421 // Create Device
422 Device device{"vdd_reg", true, deviceInvPath, std::move(i2cInterface)};
423
424 // Close Device
425 device.close(services);
426 }
427 }
428
TEST_F(DeviceTests,Configure)429 TEST_F(DeviceTests, Configure)
430 {
431 // Test where device is not present
432 {
433 // Create mock services. No logging should occur.
434 MockServices services{};
435 MockJournal& journal = services.getMockJournal();
436 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
437 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
438
439 // Create PresenceDetection. Indicates device is not present.
440 std::unique_ptr<PresenceDetection> presenceDetection{};
441 {
442 auto action = std::make_unique<MockAction>();
443 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
444 std::vector<std::unique_ptr<Action>> actions{};
445 actions.emplace_back(std::move(action));
446 presenceDetection =
447 std::make_unique<PresenceDetection>(std::move(actions));
448 }
449
450 // Create Configuration. Action inside it should not be executed.
451 std::unique_ptr<Configuration> configuration{};
452 {
453 std::optional<double> volts{};
454 auto action = std::make_unique<MockAction>();
455 EXPECT_CALL(*action, execute).Times(0);
456 std::vector<std::unique_ptr<Action>> actions{};
457 actions.emplace_back(std::move(action));
458 configuration =
459 std::make_unique<Configuration>(volts, std::move(actions));
460 }
461
462 // Create Device
463 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
464 Device device{"reg2",
465 true,
466 deviceInvPath,
467 std::move(i2cInterface),
468 std::move(presenceDetection),
469 std::move(configuration)};
470
471 // Call configure(). Should do nothing.
472 device.configure(services, *system, *chassis);
473 }
474
475 // Test where Configuration and Rails were not specified in constructor
476 {
477 // Create mock services. No logging should occur.
478 MockServices services{};
479 MockJournal& journal = services.getMockJournal();
480 EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
481 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
482
483 // Create Device
484 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
485 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface)};
486
487 // Call configure().
488 device.configure(services, *system, *chassis);
489 }
490
491 // Test where Configuration and Rails were specified in constructor
492 {
493 std::vector<std::unique_ptr<Rail>> rails{};
494
495 // Create mock services. Expect logDebug() to be called.
496 // For the Device and both Rails, should execute the Configuration
497 // and log a debug message.
498 MockServices services{};
499 MockJournal& journal = services.getMockJournal();
500 EXPECT_CALL(journal, logDebug("Configuring reg2")).Times(1);
501 EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000"))
502 .Times(1);
503 EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000"))
504 .Times(1);
505 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
506
507 // Create Rail vdd0
508 {
509 // Create Configuration for Rail
510 std::optional<double> volts{1.3};
511 auto action = std::make_unique<MockAction>();
512 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
513 std::vector<std::unique_ptr<Action>> actions{};
514 actions.emplace_back(std::move(action));
515 auto configuration =
516 std::make_unique<Configuration>(volts, std::move(actions));
517
518 // Create Rail
519 auto rail =
520 std::make_unique<Rail>("vdd0", std::move(configuration));
521 rails.emplace_back(std::move(rail));
522 }
523
524 // Create Rail vio0
525 {
526 // Create Configuration for Rail
527 std::optional<double> volts{3.2};
528 auto action = std::make_unique<MockAction>();
529 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
530 std::vector<std::unique_ptr<Action>> actions{};
531 actions.emplace_back(std::move(action));
532 auto configuration =
533 std::make_unique<Configuration>(volts, std::move(actions));
534
535 // Create Rail
536 auto rail =
537 std::make_unique<Rail>("vio0", std::move(configuration));
538 rails.emplace_back(std::move(rail));
539 }
540
541 // Create Configuration for Device
542 std::optional<double> volts{};
543 auto action = std::make_unique<MockAction>();
544 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
545 std::vector<std::unique_ptr<Action>> actions{};
546 actions.emplace_back(std::move(action));
547 auto configuration =
548 std::make_unique<Configuration>(volts, std::move(actions));
549
550 // Create Device
551 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
552 std::unique_ptr<PresenceDetection> presenceDetection{};
553 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
554 Device device{"reg2",
555 true,
556 deviceInvPath,
557 std::move(i2cInterface),
558 std::move(presenceDetection),
559 std::move(configuration),
560 std::move(phaseFaultDetection),
561 std::move(rails)};
562
563 // Call configure().
564 device.configure(services, *system, *chassis);
565 }
566 }
567
TEST_F(DeviceTests,DetectPhaseFaults)568 TEST_F(DeviceTests, DetectPhaseFaults)
569 {
570 // Test where device is not present
571 {
572 // Create mock services. No errors should be logged.
573 MockServices services{};
574 MockJournal& journal = services.getMockJournal();
575 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
576 MockErrorLogging& errorLogging = services.getMockErrorLogging();
577 EXPECT_CALL(errorLogging, logPhaseFault).Times(0);
578
579 // Create PresenceDetection. Indicates device is not present.
580 std::unique_ptr<PresenceDetection> presenceDetection{};
581 {
582 auto action = std::make_unique<MockAction>();
583 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
584 std::vector<std::unique_ptr<Action>> actions{};
585 actions.emplace_back(std::move(action));
586 presenceDetection =
587 std::make_unique<PresenceDetection>(std::move(actions));
588 }
589
590 // Create PhaseFaultDetection. Action inside it should not be executed.
591 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
592 {
593 auto action = std::make_unique<MockAction>();
594 EXPECT_CALL(*action, execute).Times(0);
595 std::vector<std::unique_ptr<Action>> actions{};
596 actions.emplace_back(std::move(action));
597 phaseFaultDetection =
598 std::make_unique<PhaseFaultDetection>(std::move(actions));
599 }
600
601 // Create Device
602 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
603 std::unique_ptr<Configuration> configuration{};
604 Device device{"reg2",
605 true,
606 deviceInvPath,
607 std::move(i2cInterface),
608 std::move(presenceDetection),
609 std::move(configuration),
610 std::move(phaseFaultDetection)};
611
612 // Call detectPhaseFaults() 5 times. Should do nothing.
613 for (int i = 1; i <= 5; ++i)
614 {
615 device.detectPhaseFaults(services, *system, *chassis);
616 }
617 }
618
619 // Test where PhaseFaultDetection was not specified in constructor
620 {
621 // Create mock services. No errors should be logged.
622 MockServices services{};
623 MockJournal& journal = services.getMockJournal();
624 EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
625 MockErrorLogging& errorLogging = services.getMockErrorLogging();
626 EXPECT_CALL(errorLogging, logPhaseFault).Times(0);
627
628 // Create Device
629 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
630 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface)};
631
632 // Call detectPhaseFaults() 5 times. Should do nothing.
633 for (int i = 1; i <= 5; ++i)
634 {
635 device.detectPhaseFaults(services, *system, *chassis);
636 }
637 }
638
639 // Test where PhaseFaultDetection was specified in constructor
640 {
641 // Create mock services with the following expectations:
642 // - 2 error messages in journal for N phase fault detected
643 // - 1 N phase fault error logged
644 MockServices services{};
645 MockJournal& journal = services.getMockJournal();
646 EXPECT_CALL(
647 journal,
648 logError("n phase fault detected in regulator reg2: count=1"))
649 .Times(1);
650 EXPECT_CALL(
651 journal,
652 logError("n phase fault detected in regulator reg2: count=2"))
653 .Times(1);
654 MockErrorLogging& errorLogging = services.getMockErrorLogging();
655 EXPECT_CALL(errorLogging, logPhaseFault).Times(1);
656
657 // Create PhaseFaultDetection
658 auto action = std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
659 std::vector<std::unique_ptr<Action>> actions{};
660 actions.push_back(std::move(action));
661 auto phaseFaultDetection =
662 std::make_unique<PhaseFaultDetection>(std::move(actions));
663
664 // Create Device
665 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
666 std::unique_ptr<PresenceDetection> presenceDetection{};
667 std::unique_ptr<Configuration> configuration{};
668 Device device{"reg2",
669 true,
670 deviceInvPath,
671 std::move(i2cInterface),
672 std::move(presenceDetection),
673 std::move(configuration),
674 std::move(phaseFaultDetection)};
675
676 // Call detectPhaseFaults() 5 times
677 for (int i = 1; i <= 5; ++i)
678 {
679 device.detectPhaseFaults(services, *system, *chassis);
680 }
681 }
682 }
683
TEST_F(DeviceTests,GetConfiguration)684 TEST_F(DeviceTests, GetConfiguration)
685 {
686 // Test where Configuration was not specified in constructor
687 {
688 Device device{"vdd_reg", true, deviceInvPath, createI2CInterface()};
689 EXPECT_EQ(device.getConfiguration(), nullptr);
690 }
691
692 // Test where Configuration was specified in constructor
693 {
694 std::unique_ptr<PresenceDetection> presenceDetection{};
695
696 // Create Configuration
697 std::optional<double> volts{3.2};
698 std::vector<std::unique_ptr<Action>> actions{};
699 actions.push_back(std::make_unique<MockAction>());
700 actions.push_back(std::make_unique<MockAction>());
701 auto configuration =
702 std::make_unique<Configuration>(volts, std::move(actions));
703
704 // Create Device
705 Device device{"vdd_reg",
706 true,
707 deviceInvPath,
708 createI2CInterface(),
709 std::move(presenceDetection),
710 std::move(configuration)};
711 EXPECT_NE(device.getConfiguration(), nullptr);
712 EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
713 EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
714 EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
715 }
716 }
717
TEST_F(DeviceTests,GetFRU)718 TEST_F(DeviceTests, GetFRU)
719 {
720 Device device{"vdd_reg", true, deviceInvPath, createI2CInterface()};
721 EXPECT_EQ(device.getFRU(), deviceInvPath);
722 }
723
TEST_F(DeviceTests,GetI2CInterface)724 TEST_F(DeviceTests, GetI2CInterface)
725 {
726 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
727 i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
728 Device device{"vdd_reg", true, deviceInvPath, std::move(i2cInterface)};
729 EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
730 }
731
TEST_F(DeviceTests,GetID)732 TEST_F(DeviceTests, GetID)
733 {
734 Device device{"vdd_reg", false, deviceInvPath, createI2CInterface()};
735 EXPECT_EQ(device.getID(), "vdd_reg");
736 }
737
TEST_F(DeviceTests,GetPhaseFaultDetection)738 TEST_F(DeviceTests, GetPhaseFaultDetection)
739 {
740 // Test where PhaseFaultDetection was not specified in constructor
741 {
742 Device device{"vdd_reg", true, deviceInvPath, createI2CInterface()};
743 EXPECT_EQ(device.getPhaseFaultDetection(), nullptr);
744 }
745
746 // Test where PhaseFaultDetection was specified in constructor
747 {
748 // Create PhaseFaultDetection
749 std::vector<std::unique_ptr<Action>> actions{};
750 actions.push_back(std::make_unique<MockAction>());
751 auto phaseFaultDetection =
752 std::make_unique<PhaseFaultDetection>(std::move(actions));
753
754 // Create Device
755 std::unique_ptr<PresenceDetection> presenceDetection{};
756 std::unique_ptr<Configuration> configuration{};
757 Device device{"vdd_reg",
758 false,
759 deviceInvPath,
760 createI2CInterface(),
761 std::move(presenceDetection),
762 std::move(configuration),
763 std::move(phaseFaultDetection)};
764 EXPECT_NE(device.getPhaseFaultDetection(), nullptr);
765 EXPECT_EQ(device.getPhaseFaultDetection()->getActions().size(), 1);
766 }
767 }
768
TEST_F(DeviceTests,GetPresenceDetection)769 TEST_F(DeviceTests, GetPresenceDetection)
770 {
771 // Test where PresenceDetection was not specified in constructor
772 {
773 Device device{"vdd_reg", true, deviceInvPath, createI2CInterface()};
774 EXPECT_EQ(device.getPresenceDetection(), nullptr);
775 }
776
777 // Test where PresenceDetection was specified in constructor
778 {
779 // Create PresenceDetection
780 std::vector<std::unique_ptr<Action>> actions{};
781 actions.push_back(std::make_unique<MockAction>());
782 auto presenceDetection =
783 std::make_unique<PresenceDetection>(std::move(actions));
784
785 // Create Device
786 Device device{"vdd_reg", false, deviceInvPath, createI2CInterface(),
787 std::move(presenceDetection)};
788 EXPECT_NE(device.getPresenceDetection(), nullptr);
789 EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
790 }
791 }
792
TEST_F(DeviceTests,GetRails)793 TEST_F(DeviceTests, GetRails)
794 {
795 // Test where no rails were specified in constructor
796 {
797 Device device{"vdd_reg", true, deviceInvPath, createI2CInterface()};
798 EXPECT_EQ(device.getRails().size(), 0);
799 }
800
801 // Test where rails were specified in constructor
802 {
803 std::unique_ptr<PresenceDetection> presenceDetection{};
804 std::unique_ptr<Configuration> configuration{};
805 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
806
807 // Create vector of Rail objects
808 std::vector<std::unique_ptr<Rail>> rails{};
809 rails.push_back(std::make_unique<Rail>("vdd0"));
810 rails.push_back(std::make_unique<Rail>("vdd1"));
811
812 // Create Device
813 Device device{"vdd_reg",
814 false,
815 deviceInvPath,
816 createI2CInterface(),
817 std::move(presenceDetection),
818 std::move(configuration),
819 std::move(phaseFaultDetection),
820 std::move(rails)};
821 EXPECT_EQ(device.getRails().size(), 2);
822 EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
823 EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
824 }
825 }
826
TEST_F(DeviceTests,IsPresent)827 TEST_F(DeviceTests, IsPresent)
828 {
829 // Test where PresenceDetection not specified in constructor
830 {
831 // Create Device
832 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
833 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface)};
834
835 // Create MockServices
836 MockServices services{};
837
838 // Since no PresenceDetection defined, isPresent() should return true
839 EXPECT_TRUE(device.isPresent(services, *system, *chassis));
840 }
841
842 // Test where PresenceDetection was specified in constructor: Is present
843 {
844 // Create PresenceDetection. Indicates device is present.
845 auto action = std::make_unique<MockAction>();
846 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
847 std::vector<std::unique_ptr<Action>> actions{};
848 actions.emplace_back(std::move(action));
849 auto presenceDetection =
850 std::make_unique<PresenceDetection>(std::move(actions));
851
852 // Create Device
853 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
854 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface),
855 std::move(presenceDetection)};
856
857 // Create MockServices
858 MockServices services{};
859
860 // PresenceDetection::execute() and isPresent() should return true
861 EXPECT_TRUE(device.isPresent(services, *system, *chassis));
862 }
863
864 // Test where PresenceDetection was specified in constructor: Is not present
865 {
866 // Create PresenceDetection. Indicates device is not present.
867 auto action = std::make_unique<MockAction>();
868 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
869 std::vector<std::unique_ptr<Action>> actions{};
870 actions.emplace_back(std::move(action));
871 auto presenceDetection =
872 std::make_unique<PresenceDetection>(std::move(actions));
873
874 // Create Device
875 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
876 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface),
877 std::move(presenceDetection)};
878
879 // Create MockServices
880 MockServices services{};
881
882 // PresenceDetection::execute() and isPresent() should return false
883 EXPECT_FALSE(device.isPresent(services, *system, *chassis));
884 }
885 }
886
TEST_F(DeviceTests,IsRegulator)887 TEST_F(DeviceTests, IsRegulator)
888 {
889 Device device{"vdd_reg", false, deviceInvPath, createI2CInterface()};
890 EXPECT_EQ(device.isRegulator(), false);
891 }
892
TEST_F(DeviceTests,MonitorSensors)893 TEST_F(DeviceTests, MonitorSensors)
894 {
895 // Test where device is not present
896 {
897 // Create mock services. No Sensors methods should be called.
898 MockServices services{};
899 MockSensors& sensors = services.getMockSensors();
900 EXPECT_CALL(sensors, startRail).Times(0);
901 EXPECT_CALL(sensors, setValue).Times(0);
902 EXPECT_CALL(sensors, endRail).Times(0);
903
904 // Create SensorMonitoring. Action inside it should not be executed.
905 std::unique_ptr<SensorMonitoring> sensorMonitoring{};
906 {
907 auto action = std::make_unique<MockAction>();
908 EXPECT_CALL(*action, execute).Times(0);
909 std::vector<std::unique_ptr<Action>> actions{};
910 actions.emplace_back(std::move(action));
911 sensorMonitoring =
912 std::make_unique<SensorMonitoring>(std::move(actions));
913 }
914
915 // Create Rail
916 std::unique_ptr<Configuration> configuration{};
917 auto rail = std::make_unique<Rail>("vddr1", std::move(configuration),
918 std::move(sensorMonitoring));
919
920 // Create PresenceDetection. Indicates device is not present.
921 std::unique_ptr<PresenceDetection> presenceDetection{};
922 {
923 auto action = std::make_unique<MockAction>();
924 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
925 std::vector<std::unique_ptr<Action>> actions{};
926 actions.emplace_back(std::move(action));
927 presenceDetection =
928 std::make_unique<PresenceDetection>(std::move(actions));
929 }
930
931 // Create Device
932 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
933 std::unique_ptr<Configuration> deviceConfiguration{};
934 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
935 std::vector<std::unique_ptr<Rail>> rails{};
936 rails.emplace_back(std::move(rail));
937 Device device{"reg2",
938 true,
939 deviceInvPath,
940 std::move(i2cInterface),
941 std::move(presenceDetection),
942 std::move(deviceConfiguration),
943 std::move(phaseFaultDetection),
944 std::move(rails)};
945
946 // Call monitorSensors(). Should do nothing.
947 device.monitorSensors(services, *system, *chassis);
948 }
949
950 // Test where Rails were not specified in constructor
951 {
952 // Create mock services. No Sensors methods should be called.
953 MockServices services{};
954 MockSensors& sensors = services.getMockSensors();
955 EXPECT_CALL(sensors, startRail).Times(0);
956 EXPECT_CALL(sensors, setValue).Times(0);
957 EXPECT_CALL(sensors, endRail).Times(0);
958
959 // Create Device
960 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
961 Device device{"reg2", true, deviceInvPath, std::move(i2cInterface)};
962
963 // Call monitorSensors(). Should do nothing.
964 device.monitorSensors(services, *system, *chassis);
965 }
966
967 // Test where Rails were specified in constructor
968 {
969 // Create mock services. Set Sensors service expectations.
970 MockServices services{};
971 MockSensors& sensors = services.getMockSensors();
972 EXPECT_CALL(sensors, startRail("vdd0", deviceInvPath, chassisInvPath))
973 .Times(1);
974 EXPECT_CALL(sensors, startRail("vio0", deviceInvPath, chassisInvPath))
975 .Times(1);
976 EXPECT_CALL(sensors, setValue).Times(0);
977 EXPECT_CALL(sensors, endRail(false)).Times(2);
978
979 std::vector<std::unique_ptr<Rail>> rails{};
980
981 // Create Rail vdd0
982 {
983 // Create SensorMonitoring for Rail
984 auto action = std::make_unique<MockAction>();
985 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
986 std::vector<std::unique_ptr<Action>> actions{};
987 actions.emplace_back(std::move(action));
988 auto sensorMonitoring =
989 std::make_unique<SensorMonitoring>(std::move(actions));
990
991 // Create Rail
992 std::unique_ptr<Configuration> configuration{};
993 auto rail = std::make_unique<Rail>("vdd0", std::move(configuration),
994 std::move(sensorMonitoring));
995 rails.emplace_back(std::move(rail));
996 }
997
998 // Create Rail vio0
999 {
1000 // Create SensorMonitoring for Rail
1001 auto action = std::make_unique<MockAction>();
1002 EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
1003 std::vector<std::unique_ptr<Action>> actions{};
1004 actions.emplace_back(std::move(action));
1005 auto sensorMonitoring =
1006 std::make_unique<SensorMonitoring>(std::move(actions));
1007
1008 // Create Rail
1009 std::unique_ptr<Configuration> configuration{};
1010 auto rail = std::make_unique<Rail>("vio0", std::move(configuration),
1011 std::move(sensorMonitoring));
1012 rails.emplace_back(std::move(rail));
1013 }
1014
1015 // Create Device that contains Rails
1016 std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
1017 std::unique_ptr<PresenceDetection> presenceDetection{};
1018 std::unique_ptr<Configuration> configuration{};
1019 std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
1020 Device device{"reg2",
1021 true,
1022 deviceInvPath,
1023 std::move(i2cInterface),
1024 std::move(presenceDetection),
1025 std::move(configuration),
1026 std::move(phaseFaultDetection),
1027 std::move(rails)};
1028
1029 // Call monitorSensors(). Should monitor sensors in both rails.
1030 device.monitorSensors(services, *system, *chassis);
1031 }
1032 }
1033