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      */
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 
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 
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 
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 
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 mock services
216     MockServices services{};
217 
218     // Expect Sensors service to be called 5+5=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 3+3=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 1+1=2 times to log a DBus error
231     MockErrorLogging& errorLogging = services.getMockErrorLogging();
232     EXPECT_CALL(errorLogging, logDBusError).Times(2);
233 
234     // Monitor sensors 5 times.  Should fail every time, write to journal 3
235     // times, and log one error.
236     for (int i = 1; i <= 5; ++i)
237     {
238         chassis.monitorSensors(services, *system);
239     }
240 
241     // Clear error history
242     chassis.clearErrorHistory();
243 
244     // Monitor sensors 5 times again.  Should fail every time, write to journal
245     // 3 times, and log one error.
246     for (int i = 1; i <= 5; ++i)
247     {
248         chassis.monitorSensors(services, *system);
249     }
250 }
251 
252 TEST_F(ChassisTests, CloseDevices)
253 {
254     // Test where no devices were specified in constructor
255     {
256         // Create mock services.  Expect logDebug() to be called.
257         MockServices services{};
258         MockJournal& journal = services.getMockJournal();
259         EXPECT_CALL(journal, logDebug("Closing devices in chassis 2")).Times(1);
260 
261         // Create Chassis
262         Chassis chassis{2, defaultInventoryPath};
263 
264         // Call closeDevices()
265         chassis.closeDevices(services);
266     }
267 
268     // Test where devices were specified in constructor
269     {
270         std::vector<std::unique_ptr<Device>> devices{};
271 
272         // Create mock services.  Expect logDebug() to be called.
273         MockServices services{};
274         MockJournal& journal = services.getMockJournal();
275         EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
276 
277         // Create Device vdd0_reg
278         {
279             // Create mock I2CInterface: isOpen() and close() should be called
280             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
281             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
282             EXPECT_CALL(*i2cInterface, close).Times(1);
283 
284             // Create Device
285             auto device =
286                 std::make_unique<Device>("vdd0_reg", true,
287                                          "/xyz/openbmc_project/inventory/"
288                                          "system/chassis/motherboard/vdd0_reg",
289                                          std::move(i2cInterface));
290             devices.emplace_back(std::move(device));
291         }
292 
293         // Create Device vdd1_reg
294         {
295             // Create mock I2CInterface: isOpen() and close() should be called
296             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
297             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
298             EXPECT_CALL(*i2cInterface, close).Times(1);
299 
300             // Create Device
301             auto device =
302                 std::make_unique<Device>("vdd1_reg", true,
303                                          "/xyz/openbmc_project/inventory/"
304                                          "system/chassis/motherboard/vdd1_reg",
305                                          std::move(i2cInterface));
306             devices.emplace_back(std::move(device));
307         }
308 
309         // Create Chassis
310         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
311 
312         // Call closeDevices()
313         chassis.closeDevices(services);
314     }
315 }
316 
317 TEST_F(ChassisTests, Configure)
318 {
319     // Test where no devices were specified in constructor
320     {
321         // Create mock services.  Expect logInfo() to be called.
322         MockServices services{};
323         MockJournal& journal = services.getMockJournal();
324         EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
325         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
326         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
327 
328         // Create Chassis
329         Chassis chassis{1, defaultInventoryPath};
330 
331         // Call configure()
332         chassis.configure(services, *system);
333     }
334 
335     // Test where devices were specified in constructor
336     {
337         std::vector<std::unique_ptr<Device>> devices{};
338 
339         // Create mock services.  Expect logInfo() and logDebug() to be called.
340         MockServices services{};
341         MockJournal& journal = services.getMockJournal();
342         EXPECT_CALL(journal, logInfo("Configuring chassis 2")).Times(1);
343         EXPECT_CALL(journal, logDebug("Configuring vdd0_reg: volts=1.300000"))
344             .Times(1);
345         EXPECT_CALL(journal, logDebug("Configuring vdd1_reg: volts=1.200000"))
346             .Times(1);
347         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
348 
349         // Create Device vdd0_reg
350         {
351             // Create Configuration
352             std::vector<std::unique_ptr<Action>> actions{};
353             auto configuration =
354                 std::make_unique<Configuration>(1.3, std::move(actions));
355 
356             // Create Device
357             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
358             std::unique_ptr<PresenceDetection> presenceDetection{};
359             auto device = std::make_unique<Device>(
360                 "vdd0_reg", true,
361                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
362                 "vdd0_reg",
363                 std::move(i2cInterface), std::move(presenceDetection),
364                 std::move(configuration));
365             devices.emplace_back(std::move(device));
366         }
367 
368         // Create Device vdd1_reg
369         {
370             // Create Configuration
371             std::vector<std::unique_ptr<Action>> actions{};
372             auto configuration =
373                 std::make_unique<Configuration>(1.2, std::move(actions));
374 
375             // Create Device
376             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
377             std::unique_ptr<PresenceDetection> presenceDetection{};
378             auto device = std::make_unique<Device>(
379                 "vdd1_reg", true,
380                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
381                 "vdd1_reg",
382                 std::move(i2cInterface), std::move(presenceDetection),
383                 std::move(configuration));
384             devices.emplace_back(std::move(device));
385         }
386 
387         // Create Chassis
388         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
389 
390         // Call configure()
391         chassis.configure(services, *system);
392     }
393 }
394 
395 TEST_F(ChassisTests, DetectPhaseFaults)
396 {
397     // Test where no devices were specified in constructor
398     {
399         // Create mock services.  No errors should be logged.
400         MockServices services{};
401         MockJournal& journal = services.getMockJournal();
402         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
403         MockErrorLogging& errorLogging = services.getMockErrorLogging();
404         EXPECT_CALL(errorLogging, logPhaseFault).Times(0);
405 
406         // Create Chassis
407         Chassis chassis{1, defaultInventoryPath};
408 
409         // Call detectPhaseFaults() 5 times.  Should do nothing.
410         for (int i = 1; i <= 5; ++i)
411         {
412             chassis.detectPhaseFaults(services, *system);
413         }
414     }
415 
416     // Test where devices were specified in constructor
417     {
418         // Create mock services with the following expectations:
419         // - 2 error messages in journal for N phase fault detected in reg0
420         // - 2 error messages in journal for N phase fault detected in reg1
421         // - 1 N phase fault error logged for reg0
422         // - 1 N phase fault error logged for reg1
423         MockServices services{};
424         MockJournal& journal = services.getMockJournal();
425         EXPECT_CALL(
426             journal,
427             logError("n phase fault detected in regulator reg0: count=1"))
428             .Times(1);
429         EXPECT_CALL(
430             journal,
431             logError("n phase fault detected in regulator reg0: count=2"))
432             .Times(1);
433         EXPECT_CALL(
434             journal,
435             logError("n phase fault detected in regulator reg1: count=1"))
436             .Times(1);
437         EXPECT_CALL(
438             journal,
439             logError("n phase fault detected in regulator reg1: count=2"))
440             .Times(1);
441         MockErrorLogging& errorLogging = services.getMockErrorLogging();
442         EXPECT_CALL(errorLogging, logPhaseFault).Times(2);
443 
444         std::vector<std::unique_ptr<Device>> devices{};
445 
446         // Create Device reg0
447         {
448             // Create PhaseFaultDetection
449             auto action =
450                 std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
451             std::vector<std::unique_ptr<Action>> actions{};
452             actions.push_back(std::move(action));
453             auto phaseFaultDetection =
454                 std::make_unique<PhaseFaultDetection>(std::move(actions));
455 
456             // Create Device
457             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
458             std::unique_ptr<PresenceDetection> presenceDetection{};
459             std::unique_ptr<Configuration> configuration{};
460             auto device = std::make_unique<Device>(
461                 "reg0", true,
462                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
463                 "reg0",
464                 std::move(i2cInterface), std::move(presenceDetection),
465                 std::move(configuration), std::move(phaseFaultDetection));
466             devices.emplace_back(std::move(device));
467         }
468 
469         // Create Device reg1
470         {
471             // Create PhaseFaultDetection
472             auto action =
473                 std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
474             std::vector<std::unique_ptr<Action>> actions{};
475             actions.push_back(std::move(action));
476             auto phaseFaultDetection =
477                 std::make_unique<PhaseFaultDetection>(std::move(actions));
478 
479             // Create Device
480             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
481             std::unique_ptr<PresenceDetection> presenceDetection{};
482             std::unique_ptr<Configuration> configuration{};
483             auto device = std::make_unique<Device>(
484                 "reg1", true,
485                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
486                 "reg1",
487                 std::move(i2cInterface), std::move(presenceDetection),
488                 std::move(configuration), std::move(phaseFaultDetection));
489             devices.emplace_back(std::move(device));
490         }
491 
492         // Create Chassis
493         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
494 
495         // Call detectPhaseFaults() 5 times
496         for (int i = 1; i <= 5; ++i)
497         {
498             chassis.detectPhaseFaults(services, *system);
499         }
500     }
501 }
502 
503 TEST_F(ChassisTests, GetDevices)
504 {
505     // Test where no devices were specified in constructor
506     {
507         Chassis chassis{2, defaultInventoryPath};
508         EXPECT_EQ(chassis.getDevices().size(), 0);
509     }
510 
511     // Test where devices were specified in constructor
512     {
513         // Create vector of Device objects
514         std::vector<std::unique_ptr<Device>> devices{};
515         devices.emplace_back(createDevice("vdd_reg1"));
516         devices.emplace_back(createDevice("vdd_reg2"));
517 
518         // Create Chassis
519         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
520         EXPECT_EQ(chassis.getDevices().size(), 2);
521         EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
522         EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
523     }
524 }
525 
526 TEST_F(ChassisTests, GetInventoryPath)
527 {
528     Chassis chassis{3, defaultInventoryPath};
529     EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
530 }
531 
532 TEST_F(ChassisTests, GetNumber)
533 {
534     Chassis chassis{3, defaultInventoryPath};
535     EXPECT_EQ(chassis.getNumber(), 3);
536 }
537 
538 TEST_F(ChassisTests, MonitorSensors)
539 {
540     // Test where no devices were specified in constructor
541     {
542         // Create mock services.  No Sensors methods should be called.
543         MockServices services{};
544         MockSensors& sensors = services.getMockSensors();
545         EXPECT_CALL(sensors, startRail).Times(0);
546         EXPECT_CALL(sensors, setValue).Times(0);
547         EXPECT_CALL(sensors, endRail).Times(0);
548 
549         // Create Chassis
550         Chassis chassis{1, defaultInventoryPath};
551 
552         // Call monitorSensors().  Should do nothing.
553         chassis.monitorSensors(services, *system);
554     }
555 
556     // Test where devices were specified in constructor
557     {
558         // Create mock services.  Set Sensors service expectations.
559         MockServices services{};
560         MockSensors& sensors = services.getMockSensors();
561         EXPECT_CALL(sensors, startRail("vdd0",
562                                        "/xyz/openbmc_project/inventory/system/"
563                                        "chassis/motherboard/vdd0_reg",
564                                        defaultInventoryPath))
565             .Times(1);
566         EXPECT_CALL(sensors, startRail("vdd1",
567                                        "/xyz/openbmc_project/inventory/system/"
568                                        "chassis/motherboard/vdd1_reg",
569                                        defaultInventoryPath))
570             .Times(1);
571         EXPECT_CALL(sensors, setValue).Times(0);
572         EXPECT_CALL(sensors, endRail(false)).Times(2);
573 
574         std::vector<std::unique_ptr<Device>> devices{};
575 
576         // Create Device vdd0_reg
577         {
578             // Create SensorMonitoring for Rail
579             auto action = std::make_unique<MockAction>();
580             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
581             std::vector<std::unique_ptr<Action>> actions{};
582             actions.emplace_back(std::move(action));
583             auto sensorMonitoring =
584                 std::make_unique<SensorMonitoring>(std::move(actions));
585 
586             // Create Rail
587             std::unique_ptr<Configuration> configuration{};
588             auto rail = std::make_unique<Rail>("vdd0", std::move(configuration),
589                                                std::move(sensorMonitoring));
590 
591             // Create Device
592             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
593             std::unique_ptr<PresenceDetection> presenceDetection{};
594             std::unique_ptr<Configuration> deviceConfiguration{};
595             std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
596             std::vector<std::unique_ptr<Rail>> rails{};
597             rails.emplace_back(std::move(rail));
598             auto device = std::make_unique<Device>(
599                 "vdd0_reg", true,
600                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
601                 "vdd0_reg",
602                 std::move(i2cInterface), std::move(presenceDetection),
603                 std::move(deviceConfiguration), std::move(phaseFaultDetection),
604                 std::move(rails));
605             devices.emplace_back(std::move(device));
606         }
607 
608         // Create Device vdd1_reg
609         {
610             // Create SensorMonitoring for Rail
611             auto action = std::make_unique<MockAction>();
612             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
613             std::vector<std::unique_ptr<Action>> actions{};
614             actions.emplace_back(std::move(action));
615             auto sensorMonitoring =
616                 std::make_unique<SensorMonitoring>(std::move(actions));
617 
618             // Create Rail
619             std::unique_ptr<Configuration> configuration{};
620             auto rail = std::make_unique<Rail>("vdd1", std::move(configuration),
621                                                std::move(sensorMonitoring));
622 
623             // Create Device
624             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
625             std::unique_ptr<PresenceDetection> presenceDetection{};
626             std::unique_ptr<Configuration> deviceConfiguration{};
627             std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
628             std::vector<std::unique_ptr<Rail>> rails{};
629             rails.emplace_back(std::move(rail));
630             auto device = std::make_unique<Device>(
631                 "vdd1_reg", true,
632                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
633                 "vdd1_reg",
634                 std::move(i2cInterface), std::move(presenceDetection),
635                 std::move(deviceConfiguration), std::move(phaseFaultDetection),
636                 std::move(rails));
637             devices.emplace_back(std::move(device));
638         }
639 
640         // Create Chassis that contains Devices
641         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
642 
643         // Call monitorSensors()
644         chassis.monitorSensors(services, *system);
645     }
646 }
647