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