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_journal.hpp"
24 #include "mock_services.hpp"
25 #include "mocked_i2c_interface.hpp"
26 #include "pmbus_read_sensor_action.hpp"
27 #include "presence_detection.hpp"
28 #include "rail.hpp"
29 #include "rule.hpp"
30 #include "system.hpp"
31 #include "test_utils.hpp"
32 
33 #include <memory>
34 #include <optional>
35 #include <string>
36 #include <utility>
37 #include <vector>
38 
39 #include <gmock/gmock.h>
40 #include <gtest/gtest.h>
41 
42 using namespace phosphor::power::regulators;
43 using namespace phosphor::power::regulators::test_utils;
44 
45 using ::testing::A;
46 using ::testing::Return;
47 using ::testing::Throw;
48 using ::testing::TypedEq;
49 
50 TEST(DeviceTests, Constructor)
51 {
52     // Test where only required parameters are specified
53     {
54         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
55         i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
56         Device device{
57             "vdd_reg", true,
58             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
59             std::move(i2cInterface)};
60         EXPECT_EQ(device.getID(), "vdd_reg");
61         EXPECT_EQ(device.isRegulator(), true);
62         EXPECT_EQ(
63             device.getFRU(),
64             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2");
65         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
66         EXPECT_EQ(device.getPresenceDetection(), nullptr);
67         EXPECT_EQ(device.getConfiguration(), nullptr);
68         EXPECT_EQ(device.getRails().size(), 0);
69     }
70 
71     // Test where all parameters are specified
72     {
73         // Create I2CInterface
74         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
75         i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
76 
77         // Create PresenceDetection
78         std::vector<std::unique_ptr<Action>> actions{};
79         actions.push_back(std::make_unique<MockAction>());
80         std::unique_ptr<PresenceDetection> presenceDetection =
81             std::make_unique<PresenceDetection>(std::move(actions));
82 
83         // Create Configuration
84         std::optional<double> volts{};
85         actions.clear();
86         actions.push_back(std::make_unique<MockAction>());
87         actions.push_back(std::make_unique<MockAction>());
88         std::unique_ptr<Configuration> configuration =
89             std::make_unique<Configuration>(volts, std::move(actions));
90 
91         // Create vector of Rail objects
92         std::vector<std::unique_ptr<Rail>> rails{};
93         rails.push_back(std::make_unique<Rail>("vdd0"));
94         rails.push_back(std::make_unique<Rail>("vdd1"));
95 
96         // Create Device
97         Device device{
98             "vdd_reg",
99             false,
100             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
101             std::move(i2cInterface),
102             std::move(presenceDetection),
103             std::move(configuration),
104             std::move(rails)};
105         EXPECT_EQ(device.getID(), "vdd_reg");
106         EXPECT_EQ(device.isRegulator(), false);
107         EXPECT_EQ(
108             device.getFRU(),
109             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1");
110         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
111         EXPECT_NE(device.getPresenceDetection(), nullptr);
112         EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
113         EXPECT_NE(device.getConfiguration(), nullptr);
114         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
115         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
116         EXPECT_EQ(device.getRails().size(), 2);
117     }
118 }
119 
120 TEST(DeviceTests, AddToIDMap)
121 {
122     std::unique_ptr<PresenceDetection> presenceDetection{};
123     std::unique_ptr<Configuration> configuration{};
124 
125     // Create vector of Rail objects
126     std::vector<std::unique_ptr<Rail>> rails{};
127     rails.push_back(std::make_unique<Rail>("vdd0"));
128     rails.push_back(std::make_unique<Rail>("vdd1"));
129 
130     // Create Device
131     Device device{
132         "vdd_reg",
133         false,
134         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
135         std::move(createI2CInterface()),
136         std::move(presenceDetection),
137         std::move(configuration),
138         std::move(rails)};
139 
140     // Add Device and Rail objects to an IDMap
141     IDMap idMap{};
142     device.addToIDMap(idMap);
143 
144     // Verify Device is in the IDMap
145     EXPECT_NO_THROW(idMap.getDevice("vdd_reg"));
146     EXPECT_THROW(idMap.getDevice("vio_reg"), std::invalid_argument);
147 
148     // Verify all Rails are in the IDMap
149     EXPECT_NO_THROW(idMap.getRail("vdd0"));
150     EXPECT_NO_THROW(idMap.getRail("vdd1"));
151     EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
152 }
153 
154 TEST(DeviceTests, ClearCache)
155 {
156     // Test where Device does not contain a PresenceDetection object
157     try
158     {
159         Device device{
160             "vdd_reg", false,
161             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
162             std::move(createI2CInterface())};
163         device.clearCache();
164     }
165     catch (...)
166     {
167         ADD_FAILURE() << "Should not have caught exception.";
168     }
169 
170     // Test where Device contains a PresenceDetection object
171     {
172         // Create PresenceDetection
173         std::vector<std::unique_ptr<Action>> actions{};
174         std::unique_ptr<PresenceDetection> presenceDetection =
175             std::make_unique<PresenceDetection>(std::move(actions));
176         PresenceDetection* presenceDetectionPtr = presenceDetection.get();
177 
178         // Create Device
179         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
180         std::unique_ptr<Device> device = std::make_unique<Device>(
181             "reg1", true,
182             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
183             std::move(i2cInterface), std::move(presenceDetection));
184         Device* devicePtr = device.get();
185 
186         // Create Chassis that contains Device
187         std::vector<std::unique_ptr<Device>> devices{};
188         devices.emplace_back(std::move(device));
189         std::unique_ptr<Chassis> chassis =
190             std::make_unique<Chassis>(1, std::move(devices));
191         Chassis* chassisPtr = chassis.get();
192 
193         // Create System that contains Chassis
194         std::vector<std::unique_ptr<Rule>> rules{};
195         std::vector<std::unique_ptr<Chassis>> chassisVec{};
196         chassisVec.emplace_back(std::move(chassis));
197         System system{std::move(rules), std::move(chassisVec)};
198 
199         // Cache presence value in PresenceDetection
200         MockServices services{};
201         presenceDetectionPtr->execute(services, system, *chassisPtr,
202                                       *devicePtr);
203         EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
204 
205         // Clear cached data in Device
206         devicePtr->clearCache();
207 
208         // Verify presence value no longer cached in PresenceDetection
209         EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
210     }
211 }
212 
213 TEST(DeviceTests, Close)
214 {
215     // Test where works: I2C interface is not open
216     {
217         // Create mock I2CInterface
218         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
219             std::make_unique<i2c::MockedI2CInterface>();
220         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
221         EXPECT_CALL(*i2cInterface, close).Times(0);
222 
223         // Create mock services.  No logError should occur.
224         MockServices services{};
225         MockJournal& journal = services.getMockJournal();
226         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
227         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
228             .Times(0);
229 
230         // Create Device
231         Device device{
232             "vdd_reg", true,
233             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
234             std::move(i2cInterface)};
235 
236         // Close Device
237         device.close(services);
238     }
239 
240     // Test where works: I2C interface is open
241     {
242         // Create mock I2CInterface
243         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
244             std::make_unique<i2c::MockedI2CInterface>();
245         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
246         EXPECT_CALL(*i2cInterface, close).Times(1);
247 
248         // Create mock services.  No logError should occur.
249         MockServices services{};
250         MockJournal& journal = services.getMockJournal();
251         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
252         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
253             .Times(0);
254 
255         // Create Device
256         Device device{
257             "vdd_reg", true,
258             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
259             std::move(i2cInterface)};
260 
261         // Close Device
262         device.close(services);
263     }
264 
265     // Test where fails: closing I2C interface fails
266     {
267         // Create mock I2CInterface
268         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
269             std::make_unique<i2c::MockedI2CInterface>();
270         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
271         EXPECT_CALL(*i2cInterface, close)
272             .Times(1)
273             .WillOnce(Throw(
274                 i2c::I2CException{"Failed to close", "/dev/i2c-1", 0x70}));
275 
276         // Create mock services.  Expect logError() to be called.
277         MockServices services{};
278         MockJournal& journal = services.getMockJournal();
279         std::vector<std::string> expectedErrMessagesException{
280             "I2CException: Failed to close: bus /dev/i2c-1, addr 0x70"};
281         EXPECT_CALL(journal, logError("Unable to close device vdd_reg"))
282             .Times(1);
283         EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1);
284 
285         // Create Device
286         Device device{
287             "vdd_reg", true,
288             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
289             std::move(i2cInterface)};
290 
291         // Close Device
292         device.close(services);
293     }
294 }
295 
296 TEST(DeviceTests, Configure)
297 {
298     // Test where device is not present
299     {
300         // Create mock services.  No logging should occur.
301         MockServices services{};
302         MockJournal& journal = services.getMockJournal();
303         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
304         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
305 
306         // Create PresenceDetection.  Indicates device is not present.
307         std::unique_ptr<MockAction> presAction = std::make_unique<MockAction>();
308         EXPECT_CALL(*presAction, execute).Times(1).WillOnce(Return(false));
309         std::vector<std::unique_ptr<Action>> presActions{};
310         presActions.emplace_back(std::move(presAction));
311         std::unique_ptr<PresenceDetection> presenceDetection =
312             std::make_unique<PresenceDetection>(std::move(presActions));
313 
314         // Create Configuration.  Action inside it should not be executed.
315         std::optional<double> volts{};
316         std::unique_ptr<MockAction> confAction = std::make_unique<MockAction>();
317         EXPECT_CALL(*confAction, execute).Times(0);
318         std::vector<std::unique_ptr<Action>> confActions{};
319         confActions.emplace_back(std::move(confAction));
320         std::unique_ptr<Configuration> configuration =
321             std::make_unique<Configuration>(volts, std::move(confActions));
322 
323         // Create Device
324         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
325         std::unique_ptr<Device> device = std::make_unique<Device>(
326             "reg1", true,
327             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
328             std::move(i2cInterface), std::move(presenceDetection),
329             std::move(configuration));
330         Device* devicePtr = device.get();
331 
332         // Create Chassis that contains Device
333         std::vector<std::unique_ptr<Device>> devices{};
334         devices.emplace_back(std::move(device));
335         std::unique_ptr<Chassis> chassis =
336             std::make_unique<Chassis>(1, std::move(devices));
337         Chassis* chassisPtr = chassis.get();
338 
339         // Create System that contains Chassis
340         std::vector<std::unique_ptr<Rule>> rules{};
341         std::vector<std::unique_ptr<Chassis>> chassisVec{};
342         chassisVec.emplace_back(std::move(chassis));
343         System system{std::move(rules), std::move(chassisVec)};
344 
345         // Call configure().  Should do nothing.
346         devicePtr->configure(services, system, *chassisPtr);
347     }
348 
349     // Test where Configuration and Rails were not specified in constructor
350     {
351         // Create mock services.  No logging should occur.
352         MockServices services{};
353         MockJournal& journal = services.getMockJournal();
354         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
355         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
356 
357         // Create Device
358         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
359         std::unique_ptr<Device> device = std::make_unique<Device>(
360             "reg1", true,
361             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
362             std::move(i2cInterface));
363         Device* devicePtr = device.get();
364 
365         // Create Chassis that contains Device
366         std::vector<std::unique_ptr<Device>> devices{};
367         devices.emplace_back(std::move(device));
368         std::unique_ptr<Chassis> chassis =
369             std::make_unique<Chassis>(1, std::move(devices));
370         Chassis* chassisPtr = chassis.get();
371 
372         // Create System that contains Chassis
373         std::vector<std::unique_ptr<Rule>> rules{};
374         std::vector<std::unique_ptr<Chassis>> chassisVec{};
375         chassisVec.emplace_back(std::move(chassis));
376         System system{std::move(rules), std::move(chassisVec)};
377 
378         // Call configure().
379         devicePtr->configure(services, system, *chassisPtr);
380     }
381 
382     // Test where Configuration and Rails were specified in constructor
383     {
384         std::vector<std::unique_ptr<Rail>> rails{};
385 
386         // Create mock services.  Expect logDebug() to be called.
387         // For the Device and both Rails, should execute the Configuration
388         // and log a debug message.
389         MockServices services{};
390         MockJournal& journal = services.getMockJournal();
391         EXPECT_CALL(journal, logDebug("Configuring reg1")).Times(1);
392         EXPECT_CALL(journal, logDebug("Configuring vdd0: volts=1.300000"))
393             .Times(1);
394         EXPECT_CALL(journal, logDebug("Configuring vio0: volts=3.200000"))
395             .Times(1);
396         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
397 
398         // Create Rail vdd0
399         {
400             // Create Configuration for Rail
401             std::optional<double> volts{1.3};
402             std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
403             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
404             std::vector<std::unique_ptr<Action>> actions{};
405             actions.emplace_back(std::move(action));
406             std::unique_ptr<Configuration> configuration =
407                 std::make_unique<Configuration>(volts, std::move(actions));
408 
409             // Create Rail
410             std::unique_ptr<Rail> rail =
411                 std::make_unique<Rail>("vdd0", std::move(configuration));
412             rails.emplace_back(std::move(rail));
413         }
414 
415         // Create Rail vio0
416         {
417             // Create Configuration for Rail
418             std::optional<double> volts{3.2};
419             std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
420             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
421             std::vector<std::unique_ptr<Action>> actions{};
422             actions.emplace_back(std::move(action));
423             std::unique_ptr<Configuration> configuration =
424                 std::make_unique<Configuration>(volts, std::move(actions));
425 
426             // Create Rail
427             std::unique_ptr<Rail> rail =
428                 std::make_unique<Rail>("vio0", std::move(configuration));
429             rails.emplace_back(std::move(rail));
430         }
431 
432         // Create Configuration for Device
433         std::optional<double> volts{};
434         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
435         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
436         std::vector<std::unique_ptr<Action>> actions{};
437         actions.emplace_back(std::move(action));
438         std::unique_ptr<Configuration> configuration =
439             std::make_unique<Configuration>(volts, std::move(actions));
440 
441         // Create Device
442         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
443         std::unique_ptr<PresenceDetection> presenceDetection{};
444         std::unique_ptr<Device> device = std::make_unique<Device>(
445             "reg1", true,
446             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
447             std::move(i2cInterface), std::move(presenceDetection),
448             std::move(configuration), std::move(rails));
449         Device* devicePtr = device.get();
450 
451         // Create Chassis that contains Device
452         std::vector<std::unique_ptr<Device>> devices{};
453         devices.emplace_back(std::move(device));
454         std::unique_ptr<Chassis> chassis =
455             std::make_unique<Chassis>(1, std::move(devices));
456         Chassis* chassisPtr = chassis.get();
457 
458         // Create System that contains Chassis
459         std::vector<std::unique_ptr<Rule>> rules{};
460         std::vector<std::unique_ptr<Chassis>> chassisVec{};
461         chassisVec.emplace_back(std::move(chassis));
462         System system{std::move(rules), std::move(chassisVec)};
463 
464         // Call configure().
465         devicePtr->configure(services, system, *chassisPtr);
466     }
467 }
468 
469 TEST(DeviceTests, GetConfiguration)
470 {
471     // Test where Configuration was not specified in constructor
472     {
473         Device device{
474             "vdd_reg", true,
475             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
476             std::move(createI2CInterface())};
477         EXPECT_EQ(device.getConfiguration(), nullptr);
478     }
479 
480     // Test where Configuration was specified in constructor
481     {
482         std::unique_ptr<PresenceDetection> presenceDetection{};
483 
484         // Create Configuration
485         std::optional<double> volts{3.2};
486         std::vector<std::unique_ptr<Action>> actions{};
487         actions.push_back(std::make_unique<MockAction>());
488         actions.push_back(std::make_unique<MockAction>());
489         std::unique_ptr<Configuration> configuration =
490             std::make_unique<Configuration>(volts, std::move(actions));
491 
492         // Create Device
493         Device device{
494             "vdd_reg",
495             true,
496             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
497             std::move(createI2CInterface()),
498             std::move(presenceDetection),
499             std::move(configuration)};
500         EXPECT_NE(device.getConfiguration(), nullptr);
501         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), true);
502         EXPECT_EQ(device.getConfiguration()->getVolts().value(), 3.2);
503         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
504     }
505 }
506 
507 TEST(DeviceTests, GetFRU)
508 {
509     Device device{
510         "vdd_reg", true,
511         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
512         std::move(createI2CInterface())};
513     EXPECT_EQ(device.getFRU(),
514               "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2");
515 }
516 
517 TEST(DeviceTests, GetI2CInterface)
518 {
519     std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
520     i2c::I2CInterface* i2cInterfacePtr = i2cInterface.get();
521     Device device{
522         "vdd_reg", true,
523         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
524         std::move(i2cInterface)};
525     EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
526 }
527 
528 TEST(DeviceTests, GetID)
529 {
530     Device device{
531         "vdd_reg", false,
532         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
533         std::move(createI2CInterface())};
534     EXPECT_EQ(device.getID(), "vdd_reg");
535 }
536 
537 TEST(DeviceTests, GetPresenceDetection)
538 {
539     // Test where PresenceDetection was not specified in constructor
540     {
541         Device device{
542             "vdd_reg", true,
543             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
544             std::move(createI2CInterface())};
545         EXPECT_EQ(device.getPresenceDetection(), nullptr);
546     }
547 
548     // Test where PresenceDetection was specified in constructor
549     {
550         // Create PresenceDetection
551         std::vector<std::unique_ptr<Action>> actions{};
552         actions.push_back(std::make_unique<MockAction>());
553         std::unique_ptr<PresenceDetection> presenceDetection =
554             std::make_unique<PresenceDetection>(std::move(actions));
555 
556         // Create Device
557         Device device{
558             "vdd_reg", false,
559             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
560             std::move(createI2CInterface()), std::move(presenceDetection)};
561         EXPECT_NE(device.getPresenceDetection(), nullptr);
562         EXPECT_EQ(device.getPresenceDetection()->getActions().size(), 1);
563     }
564 }
565 
566 TEST(DeviceTests, GetRails)
567 {
568     // Test where no rails were specified in constructor
569     {
570         Device device{
571             "vdd_reg", true,
572             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
573             std::move(createI2CInterface())};
574         EXPECT_EQ(device.getRails().size(), 0);
575     }
576 
577     // Test where rails were specified in constructor
578     {
579         std::unique_ptr<PresenceDetection> presenceDetection{};
580         std::unique_ptr<Configuration> configuration{};
581 
582         // Create vector of Rail objects
583         std::vector<std::unique_ptr<Rail>> rails{};
584         rails.push_back(std::make_unique<Rail>("vdd0"));
585         rails.push_back(std::make_unique<Rail>("vdd1"));
586 
587         // Create Device
588         Device device{
589             "vdd_reg",
590             false,
591             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
592             std::move(createI2CInterface()),
593             std::move(presenceDetection),
594             std::move(configuration),
595             std::move(rails)};
596         EXPECT_EQ(device.getRails().size(), 2);
597         EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
598         EXPECT_EQ(device.getRails()[1]->getID(), "vdd1");
599     }
600 }
601 
602 TEST(DeviceTests, IsPresent)
603 {
604     // Test where PresenceDetection not specified in constructor
605     {
606         // Create Device
607         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
608         std::unique_ptr<Device> device = std::make_unique<Device>(
609             "reg1", true,
610             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
611             std::move(i2cInterface));
612         Device* devicePtr = device.get();
613 
614         // Create Chassis that contains Device
615         std::vector<std::unique_ptr<Device>> devices{};
616         devices.emplace_back(std::move(device));
617         std::unique_ptr<Chassis> chassis =
618             std::make_unique<Chassis>(1, std::move(devices));
619         Chassis* chassisPtr = chassis.get();
620 
621         // Create System that contains Chassis
622         std::vector<std::unique_ptr<Rule>> rules{};
623         std::vector<std::unique_ptr<Chassis>> chassisVec{};
624         chassisVec.emplace_back(std::move(chassis));
625         System system{std::move(rules), std::move(chassisVec)};
626 
627         // Create MockServices
628         MockServices services{};
629 
630         // Since no PresenceDetection defined, isPresent() should return true
631         EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr));
632     }
633 
634     // Test where PresenceDetection was specified in constructor: Is present
635     {
636         // Create PresenceDetection.  Indicates device is present.
637         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
638         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
639         std::vector<std::unique_ptr<Action>> actions{};
640         actions.emplace_back(std::move(action));
641         std::unique_ptr<PresenceDetection> presenceDetection =
642             std::make_unique<PresenceDetection>(std::move(actions));
643 
644         // Create Device
645         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
646         std::unique_ptr<Device> device = std::make_unique<Device>(
647             "reg1", true,
648             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
649             std::move(i2cInterface), std::move(presenceDetection));
650         Device* devicePtr = device.get();
651 
652         // Create Chassis that contains Device
653         std::vector<std::unique_ptr<Device>> devices{};
654         devices.emplace_back(std::move(device));
655         std::unique_ptr<Chassis> chassis =
656             std::make_unique<Chassis>(1, std::move(devices));
657         Chassis* chassisPtr = chassis.get();
658 
659         // Create System that contains Chassis
660         std::vector<std::unique_ptr<Rule>> rules{};
661         std::vector<std::unique_ptr<Chassis>> chassisVec{};
662         chassisVec.emplace_back(std::move(chassis));
663         System system{std::move(rules), std::move(chassisVec)};
664 
665         // Create MockServices
666         MockServices services{};
667 
668         // PresenceDetection::execute() and isPresent() should return true
669         EXPECT_TRUE(devicePtr->isPresent(services, system, *chassisPtr));
670     }
671 
672     // Test where PresenceDetection was specified in constructor: Is not present
673     {
674         // Create PresenceDetection.  Indicates device is not present.
675         std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
676         EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(false));
677         std::vector<std::unique_ptr<Action>> actions{};
678         actions.emplace_back(std::move(action));
679         std::unique_ptr<PresenceDetection> presenceDetection =
680             std::make_unique<PresenceDetection>(std::move(actions));
681 
682         // Create Device
683         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
684         std::unique_ptr<Device> device = std::make_unique<Device>(
685             "reg1", true,
686             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
687             std::move(i2cInterface), std::move(presenceDetection));
688         Device* devicePtr = device.get();
689 
690         // Create Chassis that contains Device
691         std::vector<std::unique_ptr<Device>> devices{};
692         devices.emplace_back(std::move(device));
693         std::unique_ptr<Chassis> chassis =
694             std::make_unique<Chassis>(1, std::move(devices));
695         Chassis* chassisPtr = chassis.get();
696 
697         // Create System that contains Chassis
698         std::vector<std::unique_ptr<Rule>> rules{};
699         std::vector<std::unique_ptr<Chassis>> chassisVec{};
700         chassisVec.emplace_back(std::move(chassis));
701         System system{std::move(rules), std::move(chassisVec)};
702 
703         // Create MockServices
704         MockServices services{};
705 
706         // PresenceDetection::execute() and isPresent() should return false
707         EXPECT_FALSE(devicePtr->isPresent(services, system, *chassisPtr));
708     }
709 }
710 
711 TEST(DeviceTests, IsRegulator)
712 {
713     Device device{
714         "vdd_reg", false,
715         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
716         std::move(createI2CInterface())};
717     EXPECT_EQ(device.isRegulator(), false);
718 }
719 
720 TEST(DeviceTests, MonitorSensors)
721 {
722     // Test where device is not present
723     // TODO: Add this test when sensoring monitoring is fully implemented
724 
725     // Test where Rails were not specified in constructor
726     {
727         // Create mock services.  No logging should occur.
728         MockServices services{};
729         MockJournal& journal = services.getMockJournal();
730         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
731         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
732 
733         // Create mock I2CInterface.  A two-byte read should NOT occur.
734         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
735             std::make_unique<i2c::MockedI2CInterface>();
736         EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint16_t&>())).Times(0);
737 
738         // Create Device
739         std::unique_ptr<Device> device = std::make_unique<Device>(
740             "reg1", true,
741             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
742             std::move(i2cInterface));
743         Device* devicePtr = device.get();
744 
745         // Create Chassis that contains Device
746         std::vector<std::unique_ptr<Device>> devices{};
747         devices.emplace_back(std::move(device));
748         std::unique_ptr<Chassis> chassis =
749             std::make_unique<Chassis>(1, std::move(devices));
750         Chassis* chassisPtr = chassis.get();
751 
752         // Create System that contains Chassis
753         std::vector<std::unique_ptr<Rule>> rules{};
754         std::vector<std::unique_ptr<Chassis>> chassisVec{};
755         chassisVec.emplace_back(std::move(chassis));
756         System system{std::move(rules), std::move(chassisVec)};
757 
758         // Call monitorSensors().
759         devicePtr->monitorSensors(services, system, *chassisPtr);
760     }
761 
762     // Test where Rails were specified in constructor
763     {
764         // Create mock services.  No logging should occur.
765         MockServices services{};
766         MockJournal& journal = services.getMockJournal();
767         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
768         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
769 
770         std::vector<std::unique_ptr<Rail>> rails{};
771 
772         // Create PMBusReadSensorAction
773         pmbus_utils::SensorValueType type{pmbus_utils::SensorValueType::iout};
774         uint8_t command = 0x8C;
775         pmbus_utils::SensorDataFormat format{
776             pmbus_utils::SensorDataFormat::linear_11};
777         std::optional<int8_t> exponent{};
778         std::unique_ptr<PMBusReadSensorAction> action =
779             std::make_unique<PMBusReadSensorAction>(type, command, format,
780                                                     exponent);
781 
782         // Create mock I2CInterface.  A two-byte read should occur.
783         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
784             std::make_unique<i2c::MockedI2CInterface>();
785         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
786         EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
787             .Times(1);
788 
789         // Create SensorMonitoring
790         std::vector<std::unique_ptr<Action>> actions{};
791         actions.emplace_back(std::move(action));
792         std::unique_ptr<SensorMonitoring> sensorMonitoring =
793             std::make_unique<SensorMonitoring>(std::move(actions));
794 
795         // Create Rail
796         std::unique_ptr<Configuration> configuration{};
797         std::unique_ptr<Rail> rail = std::make_unique<Rail>(
798             "vdd0", std::move(configuration), std::move(sensorMonitoring));
799         rails.emplace_back(std::move(rail));
800 
801         // Create Device
802         std::unique_ptr<PresenceDetection> presenceDetection{};
803         std::unique_ptr<Configuration> deviceConfiguration{};
804         std::unique_ptr<Device> device = std::make_unique<Device>(
805             "reg1", true,
806             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
807             std::move(i2cInterface), std::move(presenceDetection),
808             std::move(deviceConfiguration), std::move(rails));
809         Device* devicePtr = device.get();
810 
811         // Create Chassis that contains Device
812         std::vector<std::unique_ptr<Device>> devices{};
813         devices.emplace_back(std::move(device));
814         std::unique_ptr<Chassis> chassis =
815             std::make_unique<Chassis>(1, std::move(devices));
816         Chassis* chassisPtr = chassis.get();
817 
818         // Create System that contains Chassis
819         std::vector<std::unique_ptr<Rule>> rules{};
820         std::vector<std::unique_ptr<Chassis>> chassisVec{};
821         chassisVec.emplace_back(std::move(chassis));
822         System system{std::move(rules), std::move(chassisVec)};
823 
824         // Call monitorSensors().
825         devicePtr->monitorSensors(services, system, *chassisPtr);
826     }
827 }
828