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