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 "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 <stdexcept>
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::Return;
54 using ::testing::Throw;
55 using ::testing::TypedEq;
56 
57 class ChassisTests : public ::testing::Test
58 {
59   public:
60     /**
61      * Constructor.
62      *
63      * Creates the System object needed for calling some Chassis methods.
64      */
ChassisTests()65     ChassisTests() : ::testing::Test{}
66     {
67         std::vector<std::unique_ptr<Rule>> rules{};
68         std::vector<std::unique_ptr<Chassis>> chassis{};
69         system = std::make_unique<System>(std::move(rules), std::move(chassis));
70     }
71 
72   protected:
73     const std::string defaultInventoryPath{
74         "/xyz/openbmc_project/inventory/system/chassis"};
75 
76     std::unique_ptr<System> system{};
77 };
78 
TEST_F(ChassisTests,Constructor)79 TEST_F(ChassisTests, Constructor)
80 {
81     // Test where works: Only required parameters are specified
82     {
83         Chassis chassis{2, defaultInventoryPath};
84         EXPECT_EQ(chassis.getNumber(), 2);
85         EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
86         EXPECT_EQ(chassis.getDevices().size(), 0);
87     }
88 
89     // Test where works: All parameters are specified
90     {
91         // Create vector of Device objects
92         std::vector<std::unique_ptr<Device>> devices{};
93         devices.emplace_back(createDevice("vdd_reg1"));
94         devices.emplace_back(createDevice("vdd_reg2"));
95 
96         // Create Chassis
97         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
98         EXPECT_EQ(chassis.getNumber(), 1);
99         EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
100         EXPECT_EQ(chassis.getDevices().size(), 2);
101     }
102 
103     // Test where fails: Invalid chassis number < 1
104     try
105     {
106         Chassis chassis{0, defaultInventoryPath};
107         ADD_FAILURE() << "Should not have reached this line.";
108     }
109     catch (const std::invalid_argument& e)
110     {
111         EXPECT_STREQ(e.what(), "Invalid chassis number: 0");
112     }
113     catch (...)
114     {
115         ADD_FAILURE() << "Should not have caught exception.";
116     }
117 }
118 
TEST_F(ChassisTests,AddToIDMap)119 TEST_F(ChassisTests, AddToIDMap)
120 {
121     // Create vector of Device objects
122     std::vector<std::unique_ptr<Device>> devices{};
123     devices.emplace_back(createDevice("reg1", {"rail1"}));
124     devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
125     devices.emplace_back(createDevice("reg3"));
126 
127     // Create Chassis
128     Chassis chassis{1, defaultInventoryPath, std::move(devices)};
129 
130     // Add Device and Rail objects within the Chassis to an IDMap
131     IDMap idMap{};
132     chassis.addToIDMap(idMap);
133 
134     // Verify all Devices are in the IDMap
135     EXPECT_NO_THROW(idMap.getDevice("reg1"));
136     EXPECT_NO_THROW(idMap.getDevice("reg2"));
137     EXPECT_NO_THROW(idMap.getDevice("reg3"));
138     EXPECT_THROW(idMap.getDevice("reg4"), std::invalid_argument);
139 
140     // Verify all Rails are in the IDMap
141     EXPECT_NO_THROW(idMap.getRail("rail1"));
142     EXPECT_NO_THROW(idMap.getRail("rail2a"));
143     EXPECT_NO_THROW(idMap.getRail("rail2b"));
144     EXPECT_THROW(idMap.getRail("rail3"), std::invalid_argument);
145 }
146 
TEST_F(ChassisTests,ClearCache)147 TEST_F(ChassisTests, ClearCache)
148 {
149     // Create PresenceDetection
150     std::vector<std::unique_ptr<Action>> actions{};
151     auto presenceDetection =
152         std::make_unique<PresenceDetection>(std::move(actions));
153     PresenceDetection* presenceDetectionPtr = presenceDetection.get();
154 
155     // Create Device that contains PresenceDetection
156     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
157     auto device = std::make_unique<Device>(
158         "reg1", true,
159         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
160         std::move(i2cInterface), std::move(presenceDetection));
161     Device* devicePtr = device.get();
162 
163     // Create Chassis that contains Device
164     std::vector<std::unique_ptr<Device>> devices{};
165     devices.emplace_back(std::move(device));
166     Chassis chassis{1, defaultInventoryPath, std::move(devices)};
167 
168     // Cache presence value in PresenceDetection
169     MockServices services{};
170     presenceDetectionPtr->execute(services, *system, chassis, *devicePtr);
171     EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
172 
173     // Clear cached data in Chassis
174     chassis.clearCache();
175 
176     // Verify presence value no longer cached in PresenceDetection
177     EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
178 }
179 
TEST_F(ChassisTests,ClearErrorHistory)180 TEST_F(ChassisTests, ClearErrorHistory)
181 {
182     // Create SensorMonitoring.  Will fail with a DBus exception.
183     auto action = std::make_unique<MockAction>();
184     EXPECT_CALL(*action, execute)
185         .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"}));
186     std::vector<std::unique_ptr<Action>> actions{};
187     actions.emplace_back(std::move(action));
188     auto sensorMonitoring =
189         std::make_unique<SensorMonitoring>(std::move(actions));
190 
191     // Create Rail
192     std::unique_ptr<Configuration> configuration{};
193     auto rail = std::make_unique<Rail>("vddr1", std::move(configuration),
194                                        std::move(sensorMonitoring));
195 
196     // Create Device that contains Rail
197     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
198     std::unique_ptr<PresenceDetection> presenceDetection{};
199     std::unique_ptr<Configuration> deviceConfiguration{};
200     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
201     std::vector<std::unique_ptr<Rail>> rails{};
202     rails.emplace_back(std::move(rail));
203     auto device = std::make_unique<Device>(
204         "reg1", true,
205         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
206         std::move(i2cInterface), std::move(presenceDetection),
207         std::move(deviceConfiguration), std::move(phaseFaultDetection),
208         std::move(rails));
209 
210     // Create Chassis that contains Device
211     std::vector<std::unique_ptr<Device>> devices{};
212     devices.emplace_back(std::move(device));
213     Chassis chassis{1, defaultInventoryPath, std::move(devices)};
214 
215     // Create lambda that sets MockServices expectations.  The lambda allows
216     // us to set expectations multiple times without duplicate code.
217     auto setExpectations = [](MockServices& services) {
218         // Expect Sensors service to be called 10 times
219         MockSensors& sensors = services.getMockSensors();
220         EXPECT_CALL(sensors, startRail).Times(10);
221         EXPECT_CALL(sensors, setValue).Times(0);
222         EXPECT_CALL(sensors, endRail).Times(10);
223 
224         // Expect Journal service to be called 6 times to log error messages
225         MockJournal& journal = services.getMockJournal();
226         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
227             .Times(6);
228         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
229 
230         // Expect ErrorLogging service to be called once to log a DBus error
231         MockErrorLogging& errorLogging = services.getMockErrorLogging();
232         EXPECT_CALL(errorLogging, logDBusError).Times(1);
233     };
234 
235     // Monitor sensors 10 times.  Verify errors logged.
236     {
237         // Create mock services.  Set expectations via lambda.
238         MockServices services{};
239         setExpectations(services);
240 
241         for (int i = 1; i <= 10; ++i)
242         {
243             chassis.monitorSensors(services, *system);
244         }
245     }
246 
247     // Clear error history
248     chassis.clearErrorHistory();
249 
250     // Monitor sensors 10 more times.  Verify errors logged again.
251     {
252         // Create mock services.  Set expectations via lambda.
253         MockServices services{};
254         setExpectations(services);
255 
256         for (int i = 1; i <= 10; ++i)
257         {
258             chassis.monitorSensors(services, *system);
259         }
260     }
261 }
262 
TEST_F(ChassisTests,CloseDevices)263 TEST_F(ChassisTests, CloseDevices)
264 {
265     // Test where no devices were specified in constructor
266     {
267         // Create mock services.  Expect logDebug() to be called.
268         MockServices services{};
269         MockJournal& journal = services.getMockJournal();
270         EXPECT_CALL(journal, logDebug("Closing devices in chassis 2")).Times(1);
271 
272         // Create Chassis
273         Chassis chassis{2, defaultInventoryPath};
274 
275         // Call closeDevices()
276         chassis.closeDevices(services);
277     }
278 
279     // Test where devices were specified in constructor
280     {
281         std::vector<std::unique_ptr<Device>> devices{};
282 
283         // Create mock services.  Expect logDebug() to be called.
284         MockServices services{};
285         MockJournal& journal = services.getMockJournal();
286         EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
287 
288         // Create Device vdd0_reg
289         {
290             // Create mock I2CInterface: isOpen() and close() should be called
291             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
292             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
293             EXPECT_CALL(*i2cInterface, close).Times(1);
294 
295             // Create Device
296             auto device = std::make_unique<Device>(
297                 "vdd0_reg", true,
298                 "/xyz/openbmc_project/inventory/"
299                 "system/chassis/motherboard/vdd0_reg",
300                 std::move(i2cInterface));
301             devices.emplace_back(std::move(device));
302         }
303 
304         // Create Device vdd1_reg
305         {
306             // Create mock I2CInterface: isOpen() and close() should be called
307             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
308             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
309             EXPECT_CALL(*i2cInterface, close).Times(1);
310 
311             // Create Device
312             auto device = std::make_unique<Device>(
313                 "vdd1_reg", true,
314                 "/xyz/openbmc_project/inventory/"
315                 "system/chassis/motherboard/vdd1_reg",
316                 std::move(i2cInterface));
317             devices.emplace_back(std::move(device));
318         }
319 
320         // Create Chassis
321         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
322 
323         // Call closeDevices()
324         chassis.closeDevices(services);
325     }
326 }
327 
TEST_F(ChassisTests,Configure)328 TEST_F(ChassisTests, Configure)
329 {
330     // Test where no devices were specified in constructor
331     {
332         // Create mock services.  Expect logInfo() to be called.
333         MockServices services{};
334         MockJournal& journal = services.getMockJournal();
335         EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
336         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
337         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
338 
339         // Create Chassis
340         Chassis chassis{1, defaultInventoryPath};
341 
342         // Call configure()
343         chassis.configure(services, *system);
344     }
345 
346     // Test where devices were specified in constructor
347     {
348         std::vector<std::unique_ptr<Device>> devices{};
349 
350         // Create mock services.  Expect logInfo() and logDebug() to be called.
351         MockServices services{};
352         MockJournal& journal = services.getMockJournal();
353         EXPECT_CALL(journal, logInfo("Configuring chassis 2")).Times(1);
354         EXPECT_CALL(journal, logDebug("Configuring vdd0_reg: volts=1.300000"))
355             .Times(1);
356         EXPECT_CALL(journal, logDebug("Configuring vdd1_reg: volts=1.200000"))
357             .Times(1);
358         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
359 
360         // Create Device vdd0_reg
361         {
362             // Create Configuration
363             std::vector<std::unique_ptr<Action>> actions{};
364             auto configuration =
365                 std::make_unique<Configuration>(1.3, std::move(actions));
366 
367             // Create Device
368             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
369             std::unique_ptr<PresenceDetection> presenceDetection{};
370             auto device = std::make_unique<Device>(
371                 "vdd0_reg", true,
372                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
373                 "vdd0_reg",
374                 std::move(i2cInterface), std::move(presenceDetection),
375                 std::move(configuration));
376             devices.emplace_back(std::move(device));
377         }
378 
379         // Create Device vdd1_reg
380         {
381             // Create Configuration
382             std::vector<std::unique_ptr<Action>> actions{};
383             auto configuration =
384                 std::make_unique<Configuration>(1.2, std::move(actions));
385 
386             // Create Device
387             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
388             std::unique_ptr<PresenceDetection> presenceDetection{};
389             auto device = std::make_unique<Device>(
390                 "vdd1_reg", true,
391                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
392                 "vdd1_reg",
393                 std::move(i2cInterface), std::move(presenceDetection),
394                 std::move(configuration));
395             devices.emplace_back(std::move(device));
396         }
397 
398         // Create Chassis
399         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
400 
401         // Call configure()
402         chassis.configure(services, *system);
403     }
404 }
405 
TEST_F(ChassisTests,DetectPhaseFaults)406 TEST_F(ChassisTests, DetectPhaseFaults)
407 {
408     // Test where no devices were specified in constructor
409     {
410         // Create mock services.  No errors should be logged.
411         MockServices services{};
412         MockJournal& journal = services.getMockJournal();
413         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
414         MockErrorLogging& errorLogging = services.getMockErrorLogging();
415         EXPECT_CALL(errorLogging, logPhaseFault).Times(0);
416 
417         // Create Chassis
418         Chassis chassis{1, defaultInventoryPath};
419 
420         // Call detectPhaseFaults() 5 times.  Should do nothing.
421         for (int i = 1; i <= 5; ++i)
422         {
423             chassis.detectPhaseFaults(services, *system);
424         }
425     }
426 
427     // Test where devices were specified in constructor
428     {
429         // Create mock services with the following expectations:
430         // - 2 error messages in journal for N phase fault detected in reg0
431         // - 2 error messages in journal for N phase fault detected in reg1
432         // - 1 N phase fault error logged for reg0
433         // - 1 N phase fault error logged for reg1
434         MockServices services{};
435         MockJournal& journal = services.getMockJournal();
436         EXPECT_CALL(
437             journal,
438             logError("n phase fault detected in regulator reg0: count=1"))
439             .Times(1);
440         EXPECT_CALL(
441             journal,
442             logError("n phase fault detected in regulator reg0: count=2"))
443             .Times(1);
444         EXPECT_CALL(
445             journal,
446             logError("n phase fault detected in regulator reg1: count=1"))
447             .Times(1);
448         EXPECT_CALL(
449             journal,
450             logError("n phase fault detected in regulator reg1: count=2"))
451             .Times(1);
452         MockErrorLogging& errorLogging = services.getMockErrorLogging();
453         EXPECT_CALL(errorLogging, logPhaseFault).Times(2);
454 
455         std::vector<std::unique_ptr<Device>> devices{};
456 
457         // Create Device reg0
458         {
459             // Create PhaseFaultDetection
460             auto action =
461                 std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
462             std::vector<std::unique_ptr<Action>> actions{};
463             actions.push_back(std::move(action));
464             auto phaseFaultDetection =
465                 std::make_unique<PhaseFaultDetection>(std::move(actions));
466 
467             // Create Device
468             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
469             std::unique_ptr<PresenceDetection> presenceDetection{};
470             std::unique_ptr<Configuration> configuration{};
471             auto device = std::make_unique<Device>(
472                 "reg0", true,
473                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
474                 "reg0",
475                 std::move(i2cInterface), std::move(presenceDetection),
476                 std::move(configuration), std::move(phaseFaultDetection));
477             devices.emplace_back(std::move(device));
478         }
479 
480         // Create Device reg1
481         {
482             // Create PhaseFaultDetection
483             auto action =
484                 std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
485             std::vector<std::unique_ptr<Action>> actions{};
486             actions.push_back(std::move(action));
487             auto phaseFaultDetection =
488                 std::make_unique<PhaseFaultDetection>(std::move(actions));
489 
490             // Create Device
491             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
492             std::unique_ptr<PresenceDetection> presenceDetection{};
493             std::unique_ptr<Configuration> configuration{};
494             auto device = std::make_unique<Device>(
495                 "reg1", true,
496                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
497                 "reg1",
498                 std::move(i2cInterface), std::move(presenceDetection),
499                 std::move(configuration), std::move(phaseFaultDetection));
500             devices.emplace_back(std::move(device));
501         }
502 
503         // Create Chassis
504         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
505 
506         // Call detectPhaseFaults() 5 times
507         for (int i = 1; i <= 5; ++i)
508         {
509             chassis.detectPhaseFaults(services, *system);
510         }
511     }
512 }
513 
TEST_F(ChassisTests,GetDevices)514 TEST_F(ChassisTests, GetDevices)
515 {
516     // Test where no devices were specified in constructor
517     {
518         Chassis chassis{2, defaultInventoryPath};
519         EXPECT_EQ(chassis.getDevices().size(), 0);
520     }
521 
522     // Test where devices were specified in constructor
523     {
524         // Create vector of Device objects
525         std::vector<std::unique_ptr<Device>> devices{};
526         devices.emplace_back(createDevice("vdd_reg1"));
527         devices.emplace_back(createDevice("vdd_reg2"));
528 
529         // Create Chassis
530         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
531         EXPECT_EQ(chassis.getDevices().size(), 2);
532         EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
533         EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
534     }
535 }
536 
TEST_F(ChassisTests,GetInventoryPath)537 TEST_F(ChassisTests, GetInventoryPath)
538 {
539     Chassis chassis{3, defaultInventoryPath};
540     EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
541 }
542 
TEST_F(ChassisTests,GetNumber)543 TEST_F(ChassisTests, GetNumber)
544 {
545     Chassis chassis{3, defaultInventoryPath};
546     EXPECT_EQ(chassis.getNumber(), 3);
547 }
548 
TEST_F(ChassisTests,MonitorSensors)549 TEST_F(ChassisTests, MonitorSensors)
550 {
551     // Test where no devices were specified in constructor
552     {
553         // Create mock services.  No Sensors methods should be called.
554         MockServices services{};
555         MockSensors& sensors = services.getMockSensors();
556         EXPECT_CALL(sensors, startRail).Times(0);
557         EXPECT_CALL(sensors, setValue).Times(0);
558         EXPECT_CALL(sensors, endRail).Times(0);
559 
560         // Create Chassis
561         Chassis chassis{1, defaultInventoryPath};
562 
563         // Call monitorSensors().  Should do nothing.
564         chassis.monitorSensors(services, *system);
565     }
566 
567     // Test where devices were specified in constructor
568     {
569         // Create mock services.  Set Sensors service expectations.
570         MockServices services{};
571         MockSensors& sensors = services.getMockSensors();
572         EXPECT_CALL(sensors, startRail("vdd0",
573                                        "/xyz/openbmc_project/inventory/system/"
574                                        "chassis/motherboard/vdd0_reg",
575                                        defaultInventoryPath))
576             .Times(1);
577         EXPECT_CALL(sensors, startRail("vdd1",
578                                        "/xyz/openbmc_project/inventory/system/"
579                                        "chassis/motherboard/vdd1_reg",
580                                        defaultInventoryPath))
581             .Times(1);
582         EXPECT_CALL(sensors, setValue).Times(0);
583         EXPECT_CALL(sensors, endRail(false)).Times(2);
584 
585         std::vector<std::unique_ptr<Device>> devices{};
586 
587         // Create Device vdd0_reg
588         {
589             // Create SensorMonitoring for Rail
590             auto action = std::make_unique<MockAction>();
591             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
592             std::vector<std::unique_ptr<Action>> actions{};
593             actions.emplace_back(std::move(action));
594             auto sensorMonitoring =
595                 std::make_unique<SensorMonitoring>(std::move(actions));
596 
597             // Create Rail
598             std::unique_ptr<Configuration> configuration{};
599             auto rail = std::make_unique<Rail>("vdd0", std::move(configuration),
600                                                std::move(sensorMonitoring));
601 
602             // Create Device
603             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
604             std::unique_ptr<PresenceDetection> presenceDetection{};
605             std::unique_ptr<Configuration> deviceConfiguration{};
606             std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
607             std::vector<std::unique_ptr<Rail>> rails{};
608             rails.emplace_back(std::move(rail));
609             auto device = std::make_unique<Device>(
610                 "vdd0_reg", true,
611                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
612                 "vdd0_reg",
613                 std::move(i2cInterface), std::move(presenceDetection),
614                 std::move(deviceConfiguration), std::move(phaseFaultDetection),
615                 std::move(rails));
616             devices.emplace_back(std::move(device));
617         }
618 
619         // Create Device vdd1_reg
620         {
621             // Create SensorMonitoring for Rail
622             auto action = std::make_unique<MockAction>();
623             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
624             std::vector<std::unique_ptr<Action>> actions{};
625             actions.emplace_back(std::move(action));
626             auto sensorMonitoring =
627                 std::make_unique<SensorMonitoring>(std::move(actions));
628 
629             // Create Rail
630             std::unique_ptr<Configuration> configuration{};
631             auto rail = std::make_unique<Rail>("vdd1", std::move(configuration),
632                                                std::move(sensorMonitoring));
633 
634             // Create Device
635             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
636             std::unique_ptr<PresenceDetection> presenceDetection{};
637             std::unique_ptr<Configuration> deviceConfiguration{};
638             std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
639             std::vector<std::unique_ptr<Rail>> rails{};
640             rails.emplace_back(std::move(rail));
641             auto device = std::make_unique<Device>(
642                 "vdd1_reg", true,
643                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
644                 "vdd1_reg",
645                 std::move(i2cInterface), std::move(presenceDetection),
646                 std::move(deviceConfiguration), std::move(phaseFaultDetection),
647                 std::move(rails));
648             devices.emplace_back(std::move(device));
649         }
650 
651         // Create Chassis that contains Devices
652         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
653 
654         // Call monitorSensors()
655         chassis.monitorSensors(services, *system);
656     }
657 }
658