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