18a3afd70SShawn McCarney /**
28a3afd70SShawn McCarney  * Copyright © 2020 IBM Corporation
38a3afd70SShawn McCarney  *
48a3afd70SShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
58a3afd70SShawn McCarney  * you may not use this file except in compliance with the License.
68a3afd70SShawn McCarney  * You may obtain a copy of the License at
78a3afd70SShawn McCarney  *
88a3afd70SShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
98a3afd70SShawn McCarney  *
108a3afd70SShawn McCarney  * Unless required by applicable law or agreed to in writing, software
118a3afd70SShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
128a3afd70SShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138a3afd70SShawn McCarney  * See the License for the specific language governing permissions and
148a3afd70SShawn McCarney  * limitations under the License.
158a3afd70SShawn McCarney  */
16525e20c9SShawn McCarney #include "action.hpp"
178a3afd70SShawn McCarney #include "chassis.hpp"
18525e20c9SShawn McCarney #include "configuration.hpp"
198a3afd70SShawn McCarney #include "device.hpp"
208a3afd70SShawn McCarney #include "i2c_interface.hpp"
21db0b833cSShawn McCarney #include "id_map.hpp"
2250e57c6bSShawn McCarney #include "log_phase_fault_action.hpp"
2317bac89eSShawn McCarney #include "mock_action.hpp"
249f3e54e6SShawn McCarney #include "mock_error_logging.hpp"
25525e20c9SShawn McCarney #include "mock_journal.hpp"
2617bac89eSShawn McCarney #include "mock_sensors.hpp"
2723243f84SBob King #include "mock_services.hpp"
28050531f5SShawn McCarney #include "mocked_i2c_interface.hpp"
2950e57c6bSShawn McCarney #include "phase_fault.hpp"
3032252599SShawn McCarney #include "phase_fault_detection.hpp"
31525e20c9SShawn McCarney #include "presence_detection.hpp"
32525e20c9SShawn McCarney #include "rail.hpp"
33525e20c9SShawn McCarney #include "rule.hpp"
3417bac89eSShawn McCarney #include "sensor_monitoring.hpp"
352f9e14f6SShawn McCarney #include "sensors.hpp"
36525e20c9SShawn McCarney #include "system.hpp"
379f3e54e6SShawn McCarney #include "test_sdbus_error.hpp"
388a3afd70SShawn McCarney #include "test_utils.hpp"
398a3afd70SShawn McCarney 
408a3afd70SShawn McCarney #include <memory>
418a3afd70SShawn McCarney #include <stdexcept>
42525e20c9SShawn McCarney #include <string>
438a3afd70SShawn McCarney #include <utility>
448a3afd70SShawn McCarney #include <vector>
458a3afd70SShawn McCarney 
46a2c81a61SBob King #include <gmock/gmock.h>
478a3afd70SShawn McCarney #include <gtest/gtest.h>
488a3afd70SShawn McCarney 
498a3afd70SShawn McCarney using namespace phosphor::power::regulators;
508a3afd70SShawn McCarney using namespace phosphor::power::regulators::test_utils;
518a3afd70SShawn McCarney 
52a2c81a61SBob King using ::testing::A;
53050531f5SShawn McCarney using ::testing::Return;
549f3e54e6SShawn McCarney using ::testing::Throw;
55a2c81a61SBob King using ::testing::TypedEq;
56050531f5SShawn McCarney 
5783058606SShawn McCarney class ChassisTests : public ::testing::Test
5883058606SShawn McCarney {
5983058606SShawn McCarney   public:
6083058606SShawn McCarney     /**
6183058606SShawn McCarney      * Constructor.
6283058606SShawn McCarney      *
6383058606SShawn McCarney      * Creates the System object needed for calling some Chassis methods.
6483058606SShawn McCarney      */
ChassisTests()6583058606SShawn McCarney     ChassisTests() : ::testing::Test{}
6683058606SShawn McCarney     {
6783058606SShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
6883058606SShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassis{};
6983058606SShawn McCarney         system = std::make_unique<System>(std::move(rules), std::move(chassis));
7083058606SShawn McCarney     }
7183058606SShawn McCarney 
7283058606SShawn McCarney   protected:
7383058606SShawn McCarney     const std::string defaultInventoryPath{
74cb3f6a63SShawn McCarney         "/xyz/openbmc_project/inventory/system/chassis"};
75cb3f6a63SShawn McCarney 
7683058606SShawn McCarney     std::unique_ptr<System> system{};
7783058606SShawn McCarney };
7883058606SShawn McCarney 
TEST_F(ChassisTests,Constructor)7983058606SShawn McCarney TEST_F(ChassisTests, Constructor)
808a3afd70SShawn McCarney {
818a3afd70SShawn McCarney     // Test where works: Only required parameters are specified
828a3afd70SShawn McCarney     {
83cb3f6a63SShawn McCarney         Chassis chassis{2, defaultInventoryPath};
848a3afd70SShawn McCarney         EXPECT_EQ(chassis.getNumber(), 2);
85cb3f6a63SShawn McCarney         EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
868a3afd70SShawn McCarney         EXPECT_EQ(chassis.getDevices().size(), 0);
878a3afd70SShawn McCarney     }
888a3afd70SShawn McCarney 
898a3afd70SShawn McCarney     // Test where works: All parameters are specified
908a3afd70SShawn McCarney     {
918a3afd70SShawn McCarney         // Create vector of Device objects
928a3afd70SShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
93db0b833cSShawn McCarney         devices.emplace_back(createDevice("vdd_reg1"));
94db0b833cSShawn McCarney         devices.emplace_back(createDevice("vdd_reg2"));
958a3afd70SShawn McCarney 
968a3afd70SShawn McCarney         // Create Chassis
97cb3f6a63SShawn McCarney         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
988a3afd70SShawn McCarney         EXPECT_EQ(chassis.getNumber(), 1);
99cb3f6a63SShawn McCarney         EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
1008a3afd70SShawn McCarney         EXPECT_EQ(chassis.getDevices().size(), 2);
1018a3afd70SShawn McCarney     }
1028a3afd70SShawn McCarney 
1038a3afd70SShawn McCarney     // Test where fails: Invalid chassis number < 1
1048a3afd70SShawn McCarney     try
1058a3afd70SShawn McCarney     {
106cb3f6a63SShawn McCarney         Chassis chassis{0, defaultInventoryPath};
1078a3afd70SShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
1088a3afd70SShawn McCarney     }
1098a3afd70SShawn McCarney     catch (const std::invalid_argument& e)
1108a3afd70SShawn McCarney     {
1118a3afd70SShawn McCarney         EXPECT_STREQ(e.what(), "Invalid chassis number: 0");
1128a3afd70SShawn McCarney     }
1138a3afd70SShawn McCarney     catch (...)
1148a3afd70SShawn McCarney     {
1158a3afd70SShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
1168a3afd70SShawn McCarney     }
1178a3afd70SShawn McCarney }
1188a3afd70SShawn McCarney 
TEST_F(ChassisTests,AddToIDMap)11983058606SShawn McCarney TEST_F(ChassisTests, AddToIDMap)
120db0b833cSShawn McCarney {
121db0b833cSShawn McCarney     // Create vector of Device objects
122db0b833cSShawn McCarney     std::vector<std::unique_ptr<Device>> devices{};
123db0b833cSShawn McCarney     devices.emplace_back(createDevice("reg1", {"rail1"}));
124db0b833cSShawn McCarney     devices.emplace_back(createDevice("reg2", {"rail2a", "rail2b"}));
125db0b833cSShawn McCarney     devices.emplace_back(createDevice("reg3"));
126db0b833cSShawn McCarney 
127db0b833cSShawn McCarney     // Create Chassis
128cb3f6a63SShawn McCarney     Chassis chassis{1, defaultInventoryPath, std::move(devices)};
129db0b833cSShawn McCarney 
130db0b833cSShawn McCarney     // Add Device and Rail objects within the Chassis to an IDMap
131db0b833cSShawn McCarney     IDMap idMap{};
132db0b833cSShawn McCarney     chassis.addToIDMap(idMap);
133db0b833cSShawn McCarney 
134db0b833cSShawn McCarney     // Verify all Devices are in the IDMap
135db0b833cSShawn McCarney     EXPECT_NO_THROW(idMap.getDevice("reg1"));
136db0b833cSShawn McCarney     EXPECT_NO_THROW(idMap.getDevice("reg2"));
137db0b833cSShawn McCarney     EXPECT_NO_THROW(idMap.getDevice("reg3"));
138db0b833cSShawn McCarney     EXPECT_THROW(idMap.getDevice("reg4"), std::invalid_argument);
139db0b833cSShawn McCarney 
140db0b833cSShawn McCarney     // Verify all Rails are in the IDMap
141db0b833cSShawn McCarney     EXPECT_NO_THROW(idMap.getRail("rail1"));
142db0b833cSShawn McCarney     EXPECT_NO_THROW(idMap.getRail("rail2a"));
143db0b833cSShawn McCarney     EXPECT_NO_THROW(idMap.getRail("rail2b"));
144db0b833cSShawn McCarney     EXPECT_THROW(idMap.getRail("rail3"), std::invalid_argument);
145db0b833cSShawn McCarney }
146db0b833cSShawn McCarney 
TEST_F(ChassisTests,ClearCache)14783058606SShawn McCarney TEST_F(ChassisTests, ClearCache)
1489bd94d36SShawn McCarney {
1499bd94d36SShawn McCarney     // Create PresenceDetection
1509bd94d36SShawn McCarney     std::vector<std::unique_ptr<Action>> actions{};
15183058606SShawn McCarney     auto presenceDetection =
1529bd94d36SShawn McCarney         std::make_unique<PresenceDetection>(std::move(actions));
1539bd94d36SShawn McCarney     PresenceDetection* presenceDetectionPtr = presenceDetection.get();
1549bd94d36SShawn McCarney 
1559bd94d36SShawn McCarney     // Create Device that contains PresenceDetection
15683058606SShawn McCarney     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
15783058606SShawn McCarney     auto device = std::make_unique<Device>(
1589bd94d36SShawn McCarney         "reg1", true,
1599bd94d36SShawn McCarney         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
1609bd94d36SShawn McCarney         std::move(i2cInterface), std::move(presenceDetection));
1619bd94d36SShawn McCarney     Device* devicePtr = device.get();
1629bd94d36SShawn McCarney 
1639bd94d36SShawn McCarney     // Create Chassis that contains Device
1649bd94d36SShawn McCarney     std::vector<std::unique_ptr<Device>> devices{};
1659bd94d36SShawn McCarney     devices.emplace_back(std::move(device));
16683058606SShawn McCarney     Chassis chassis{1, defaultInventoryPath, std::move(devices)};
1679bd94d36SShawn McCarney 
1689bd94d36SShawn McCarney     // Cache presence value in PresenceDetection
1699bd94d36SShawn McCarney     MockServices services{};
17083058606SShawn McCarney     presenceDetectionPtr->execute(services, *system, chassis, *devicePtr);
1719bd94d36SShawn McCarney     EXPECT_TRUE(presenceDetectionPtr->getCachedPresence().has_value());
1729bd94d36SShawn McCarney 
1739bd94d36SShawn McCarney     // Clear cached data in Chassis
17483058606SShawn McCarney     chassis.clearCache();
1759bd94d36SShawn McCarney 
1769bd94d36SShawn McCarney     // Verify presence value no longer cached in PresenceDetection
1779bd94d36SShawn McCarney     EXPECT_FALSE(presenceDetectionPtr->getCachedPresence().has_value());
1789bd94d36SShawn McCarney }
1799bd94d36SShawn McCarney 
TEST_F(ChassisTests,ClearErrorHistory)18083058606SShawn McCarney TEST_F(ChassisTests, ClearErrorHistory)
1819f3e54e6SShawn McCarney {
1829f3e54e6SShawn McCarney     // Create SensorMonitoring.  Will fail with a DBus exception.
18383058606SShawn McCarney     auto action = std::make_unique<MockAction>();
1849f3e54e6SShawn McCarney     EXPECT_CALL(*action, execute)
1859f3e54e6SShawn McCarney         .WillRepeatedly(Throw(TestSDBusError{"Unable to set sensor value"}));
1869f3e54e6SShawn McCarney     std::vector<std::unique_ptr<Action>> actions{};
1879f3e54e6SShawn McCarney     actions.emplace_back(std::move(action));
18883058606SShawn McCarney     auto sensorMonitoring =
1899f3e54e6SShawn McCarney         std::make_unique<SensorMonitoring>(std::move(actions));
1909f3e54e6SShawn McCarney 
1919f3e54e6SShawn McCarney     // Create Rail
1929f3e54e6SShawn McCarney     std::unique_ptr<Configuration> configuration{};
19383058606SShawn McCarney     auto rail = std::make_unique<Rail>("vddr1", std::move(configuration),
19483058606SShawn McCarney                                        std::move(sensorMonitoring));
1959f3e54e6SShawn McCarney 
1969f3e54e6SShawn McCarney     // Create Device that contains Rail
19783058606SShawn McCarney     auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
1989f3e54e6SShawn McCarney     std::unique_ptr<PresenceDetection> presenceDetection{};
1999f3e54e6SShawn McCarney     std::unique_ptr<Configuration> deviceConfiguration{};
20032252599SShawn McCarney     std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
2019f3e54e6SShawn McCarney     std::vector<std::unique_ptr<Rail>> rails{};
2029f3e54e6SShawn McCarney     rails.emplace_back(std::move(rail));
20383058606SShawn McCarney     auto device = std::make_unique<Device>(
2049f3e54e6SShawn McCarney         "reg1", true,
2059f3e54e6SShawn McCarney         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
2069f3e54e6SShawn McCarney         std::move(i2cInterface), std::move(presenceDetection),
20732252599SShawn McCarney         std::move(deviceConfiguration), std::move(phaseFaultDetection),
20832252599SShawn McCarney         std::move(rails));
2099f3e54e6SShawn McCarney 
2109f3e54e6SShawn McCarney     // Create Chassis that contains Device
2119f3e54e6SShawn McCarney     std::vector<std::unique_ptr<Device>> devices{};
2129f3e54e6SShawn McCarney     devices.emplace_back(std::move(device));
21383058606SShawn McCarney     Chassis chassis{1, defaultInventoryPath, std::move(devices)};
2149f3e54e6SShawn McCarney 
215*fa2734d6SShawn McCarney     // Create lambda that sets MockServices expectations.  The lambda allows
216*fa2734d6SShawn McCarney     // us to set expectations multiple times without duplicate code.
217*fa2734d6SShawn McCarney     auto setExpectations = [](MockServices& services) {
218*fa2734d6SShawn McCarney         // Expect Sensors service to be called 10 times
2199f3e54e6SShawn McCarney         MockSensors& sensors = services.getMockSensors();
2209f3e54e6SShawn McCarney         EXPECT_CALL(sensors, startRail).Times(10);
2219f3e54e6SShawn McCarney         EXPECT_CALL(sensors, setValue).Times(0);
2229f3e54e6SShawn McCarney         EXPECT_CALL(sensors, endRail).Times(10);
2239f3e54e6SShawn McCarney 
224*fa2734d6SShawn McCarney         // Expect Journal service to be called 6 times to log error messages
2259f3e54e6SShawn McCarney         MockJournal& journal = services.getMockJournal();
2269f3e54e6SShawn McCarney         EXPECT_CALL(journal, logError(A<const std::vector<std::string>&>()))
2279f3e54e6SShawn McCarney             .Times(6);
2289f3e54e6SShawn McCarney         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(6);
2299f3e54e6SShawn McCarney 
230*fa2734d6SShawn McCarney         // Expect ErrorLogging service to be called once to log a DBus error
2319f3e54e6SShawn McCarney         MockErrorLogging& errorLogging = services.getMockErrorLogging();
232*fa2734d6SShawn McCarney         EXPECT_CALL(errorLogging, logDBusError).Times(1);
233*fa2734d6SShawn McCarney     };
2349f3e54e6SShawn McCarney 
235*fa2734d6SShawn McCarney     // Monitor sensors 10 times.  Verify errors logged.
236*fa2734d6SShawn McCarney     {
237*fa2734d6SShawn McCarney         // Create mock services.  Set expectations via lambda.
238*fa2734d6SShawn McCarney         MockServices services{};
239*fa2734d6SShawn McCarney         setExpectations(services);
240*fa2734d6SShawn McCarney 
241*fa2734d6SShawn McCarney         for (int i = 1; i <= 10; ++i)
2429f3e54e6SShawn McCarney         {
24383058606SShawn McCarney             chassis.monitorSensors(services, *system);
2449f3e54e6SShawn McCarney         }
245*fa2734d6SShawn McCarney     }
2469f3e54e6SShawn McCarney 
2479f3e54e6SShawn McCarney     // Clear error history
24883058606SShawn McCarney     chassis.clearErrorHistory();
2499f3e54e6SShawn McCarney 
250*fa2734d6SShawn McCarney     // Monitor sensors 10 more times.  Verify errors logged again.
251*fa2734d6SShawn McCarney     {
252*fa2734d6SShawn McCarney         // Create mock services.  Set expectations via lambda.
253*fa2734d6SShawn McCarney         MockServices services{};
254*fa2734d6SShawn McCarney         setExpectations(services);
255*fa2734d6SShawn McCarney 
256*fa2734d6SShawn McCarney         for (int i = 1; i <= 10; ++i)
2579f3e54e6SShawn McCarney         {
25883058606SShawn McCarney             chassis.monitorSensors(services, *system);
2599f3e54e6SShawn McCarney         }
2609f3e54e6SShawn McCarney     }
261*fa2734d6SShawn McCarney }
2629f3e54e6SShawn McCarney 
TEST_F(ChassisTests,CloseDevices)26383058606SShawn McCarney TEST_F(ChassisTests, CloseDevices)
264050531f5SShawn McCarney {
265050531f5SShawn McCarney     // Test where no devices were specified in constructor
266050531f5SShawn McCarney     {
267d692d6dfSBob King         // Create mock services.  Expect logDebug() to be called.
268d692d6dfSBob King         MockServices services{};
269d692d6dfSBob King         MockJournal& journal = services.getMockJournal();
270d692d6dfSBob King         EXPECT_CALL(journal, logDebug("Closing devices in chassis 2")).Times(1);
271d692d6dfSBob King 
272050531f5SShawn McCarney         // Create Chassis
273cb3f6a63SShawn McCarney         Chassis chassis{2, defaultInventoryPath};
274050531f5SShawn McCarney 
275050531f5SShawn McCarney         // Call closeDevices()
276d692d6dfSBob King         chassis.closeDevices(services);
277050531f5SShawn McCarney     }
278050531f5SShawn McCarney 
279050531f5SShawn McCarney     // Test where devices were specified in constructor
280050531f5SShawn McCarney     {
281050531f5SShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
282050531f5SShawn McCarney 
283d692d6dfSBob King         // Create mock services.  Expect logDebug() to be called.
284d692d6dfSBob King         MockServices services{};
285d692d6dfSBob King         MockJournal& journal = services.getMockJournal();
286d692d6dfSBob King         EXPECT_CALL(journal, logDebug("Closing devices in chassis 1")).Times(1);
287d692d6dfSBob King 
288050531f5SShawn McCarney         // Create Device vdd0_reg
289050531f5SShawn McCarney         {
290050531f5SShawn McCarney             // Create mock I2CInterface: isOpen() and close() should be called
29183058606SShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
292050531f5SShawn McCarney             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
293050531f5SShawn McCarney             EXPECT_CALL(*i2cInterface, close).Times(1);
294050531f5SShawn McCarney 
295050531f5SShawn McCarney             // Create Device
29683058606SShawn McCarney             auto device =
297a76898f1SBob King                 std::make_unique<Device>("vdd0_reg", true,
298a76898f1SBob King                                          "/xyz/openbmc_project/inventory/"
299a76898f1SBob King                                          "system/chassis/motherboard/vdd0_reg",
300050531f5SShawn McCarney                                          std::move(i2cInterface));
301050531f5SShawn McCarney             devices.emplace_back(std::move(device));
302050531f5SShawn McCarney         }
303050531f5SShawn McCarney 
304050531f5SShawn McCarney         // Create Device vdd1_reg
305050531f5SShawn McCarney         {
306050531f5SShawn McCarney             // Create mock I2CInterface: isOpen() and close() should be called
30783058606SShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
308050531f5SShawn McCarney             EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
309050531f5SShawn McCarney             EXPECT_CALL(*i2cInterface, close).Times(1);
310050531f5SShawn McCarney 
311050531f5SShawn McCarney             // Create Device
31283058606SShawn McCarney             auto device =
313a76898f1SBob King                 std::make_unique<Device>("vdd1_reg", true,
314a76898f1SBob King                                          "/xyz/openbmc_project/inventory/"
315a76898f1SBob King                                          "system/chassis/motherboard/vdd1_reg",
316050531f5SShawn McCarney                                          std::move(i2cInterface));
317050531f5SShawn McCarney             devices.emplace_back(std::move(device));
318050531f5SShawn McCarney         }
319050531f5SShawn McCarney 
320050531f5SShawn McCarney         // Create Chassis
321cb3f6a63SShawn McCarney         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
322050531f5SShawn McCarney 
323050531f5SShawn McCarney         // Call closeDevices()
324d692d6dfSBob King         chassis.closeDevices(services);
325050531f5SShawn McCarney     }
326050531f5SShawn McCarney }
327050531f5SShawn McCarney 
TEST_F(ChassisTests,Configure)32883058606SShawn McCarney TEST_F(ChassisTests, Configure)
329525e20c9SShawn McCarney {
330525e20c9SShawn McCarney     // Test where no devices were specified in constructor
331525e20c9SShawn McCarney     {
3325cfe5103SBob King         // Create mock services.  Expect logInfo() to be called.
33323243f84SBob King         MockServices services{};
3345cfe5103SBob King         MockJournal& journal = services.getMockJournal();
3355cfe5103SBob King         EXPECT_CALL(journal, logInfo("Configuring chassis 1")).Times(1);
3365cfe5103SBob King         EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
3375cfe5103SBob King         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
33823243f84SBob King 
339525e20c9SShawn McCarney         // Create Chassis
34083058606SShawn McCarney         Chassis chassis{1, defaultInventoryPath};
341525e20c9SShawn McCarney 
342525e20c9SShawn McCarney         // Call configure()
34383058606SShawn McCarney         chassis.configure(services, *system);
344525e20c9SShawn McCarney     }
345525e20c9SShawn McCarney 
346525e20c9SShawn McCarney     // Test where devices were specified in constructor
347525e20c9SShawn McCarney     {
348525e20c9SShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
349525e20c9SShawn McCarney 
3505cfe5103SBob King         // Create mock services.  Expect logInfo() and logDebug() to be called.
3515cfe5103SBob King         MockServices services{};
3525cfe5103SBob King         MockJournal& journal = services.getMockJournal();
3535cfe5103SBob King         EXPECT_CALL(journal, logInfo("Configuring chassis 2")).Times(1);
3545cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vdd0_reg: volts=1.300000"))
3555cfe5103SBob King             .Times(1);
3565cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vdd1_reg: volts=1.200000"))
3575cfe5103SBob King             .Times(1);
3585cfe5103SBob King         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
3595cfe5103SBob King 
360525e20c9SShawn McCarney         // Create Device vdd0_reg
361525e20c9SShawn McCarney         {
362525e20c9SShawn McCarney             // Create Configuration
363525e20c9SShawn McCarney             std::vector<std::unique_ptr<Action>> actions{};
36483058606SShawn McCarney             auto configuration =
365525e20c9SShawn McCarney                 std::make_unique<Configuration>(1.3, std::move(actions));
366525e20c9SShawn McCarney 
367525e20c9SShawn McCarney             // Create Device
36883058606SShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
369525e20c9SShawn McCarney             std::unique_ptr<PresenceDetection> presenceDetection{};
37083058606SShawn McCarney             auto device = std::make_unique<Device>(
371a76898f1SBob King                 "vdd0_reg", true,
372a76898f1SBob King                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
373a76898f1SBob King                 "vdd0_reg",
374525e20c9SShawn McCarney                 std::move(i2cInterface), std::move(presenceDetection),
375525e20c9SShawn McCarney                 std::move(configuration));
376525e20c9SShawn McCarney             devices.emplace_back(std::move(device));
377525e20c9SShawn McCarney         }
378525e20c9SShawn McCarney 
379525e20c9SShawn McCarney         // Create Device vdd1_reg
380525e20c9SShawn McCarney         {
381525e20c9SShawn McCarney             // Create Configuration
382525e20c9SShawn McCarney             std::vector<std::unique_ptr<Action>> actions{};
38383058606SShawn McCarney             auto configuration =
384525e20c9SShawn McCarney                 std::make_unique<Configuration>(1.2, std::move(actions));
385525e20c9SShawn McCarney 
386525e20c9SShawn McCarney             // Create Device
38783058606SShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
388525e20c9SShawn McCarney             std::unique_ptr<PresenceDetection> presenceDetection{};
38983058606SShawn McCarney             auto device = std::make_unique<Device>(
390a76898f1SBob King                 "vdd1_reg", true,
391a76898f1SBob King                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
392a76898f1SBob King                 "vdd1_reg",
393525e20c9SShawn McCarney                 std::move(i2cInterface), std::move(presenceDetection),
394525e20c9SShawn McCarney                 std::move(configuration));
395525e20c9SShawn McCarney             devices.emplace_back(std::move(device));
396525e20c9SShawn McCarney         }
397525e20c9SShawn McCarney 
398525e20c9SShawn McCarney         // Create Chassis
39983058606SShawn McCarney         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
400525e20c9SShawn McCarney 
401525e20c9SShawn McCarney         // Call configure()
40283058606SShawn McCarney         chassis.configure(services, *system);
403525e20c9SShawn McCarney     }
404525e20c9SShawn McCarney }
405525e20c9SShawn McCarney 
TEST_F(ChassisTests,DetectPhaseFaults)40650e57c6bSShawn McCarney TEST_F(ChassisTests, DetectPhaseFaults)
40750e57c6bSShawn McCarney {
40850e57c6bSShawn McCarney     // Test where no devices were specified in constructor
40950e57c6bSShawn McCarney     {
41050e57c6bSShawn McCarney         // Create mock services.  No errors should be logged.
41150e57c6bSShawn McCarney         MockServices services{};
41250e57c6bSShawn McCarney         MockJournal& journal = services.getMockJournal();
41350e57c6bSShawn McCarney         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
41450e57c6bSShawn McCarney         MockErrorLogging& errorLogging = services.getMockErrorLogging();
41550e57c6bSShawn McCarney         EXPECT_CALL(errorLogging, logPhaseFault).Times(0);
41650e57c6bSShawn McCarney 
41750e57c6bSShawn McCarney         // Create Chassis
41850e57c6bSShawn McCarney         Chassis chassis{1, defaultInventoryPath};
41950e57c6bSShawn McCarney 
42050e57c6bSShawn McCarney         // Call detectPhaseFaults() 5 times.  Should do nothing.
42150e57c6bSShawn McCarney         for (int i = 1; i <= 5; ++i)
42250e57c6bSShawn McCarney         {
42350e57c6bSShawn McCarney             chassis.detectPhaseFaults(services, *system);
42450e57c6bSShawn McCarney         }
42550e57c6bSShawn McCarney     }
42650e57c6bSShawn McCarney 
42750e57c6bSShawn McCarney     // Test where devices were specified in constructor
42850e57c6bSShawn McCarney     {
42950e57c6bSShawn McCarney         // Create mock services with the following expectations:
43050e57c6bSShawn McCarney         // - 2 error messages in journal for N phase fault detected in reg0
43150e57c6bSShawn McCarney         // - 2 error messages in journal for N phase fault detected in reg1
43250e57c6bSShawn McCarney         // - 1 N phase fault error logged for reg0
43350e57c6bSShawn McCarney         // - 1 N phase fault error logged for reg1
43450e57c6bSShawn McCarney         MockServices services{};
43550e57c6bSShawn McCarney         MockJournal& journal = services.getMockJournal();
43650e57c6bSShawn McCarney         EXPECT_CALL(
43750e57c6bSShawn McCarney             journal,
43850e57c6bSShawn McCarney             logError("n phase fault detected in regulator reg0: count=1"))
43950e57c6bSShawn McCarney             .Times(1);
44050e57c6bSShawn McCarney         EXPECT_CALL(
44150e57c6bSShawn McCarney             journal,
44250e57c6bSShawn McCarney             logError("n phase fault detected in regulator reg0: count=2"))
44350e57c6bSShawn McCarney             .Times(1);
44450e57c6bSShawn McCarney         EXPECT_CALL(
44550e57c6bSShawn McCarney             journal,
44650e57c6bSShawn McCarney             logError("n phase fault detected in regulator reg1: count=1"))
44750e57c6bSShawn McCarney             .Times(1);
44850e57c6bSShawn McCarney         EXPECT_CALL(
44950e57c6bSShawn McCarney             journal,
45050e57c6bSShawn McCarney             logError("n phase fault detected in regulator reg1: count=2"))
45150e57c6bSShawn McCarney             .Times(1);
45250e57c6bSShawn McCarney         MockErrorLogging& errorLogging = services.getMockErrorLogging();
45350e57c6bSShawn McCarney         EXPECT_CALL(errorLogging, logPhaseFault).Times(2);
45450e57c6bSShawn McCarney 
45550e57c6bSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
45650e57c6bSShawn McCarney 
45750e57c6bSShawn McCarney         // Create Device reg0
45850e57c6bSShawn McCarney         {
45950e57c6bSShawn McCarney             // Create PhaseFaultDetection
46050e57c6bSShawn McCarney             auto action =
46150e57c6bSShawn McCarney                 std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
46250e57c6bSShawn McCarney             std::vector<std::unique_ptr<Action>> actions{};
46350e57c6bSShawn McCarney             actions.push_back(std::move(action));
46450e57c6bSShawn McCarney             auto phaseFaultDetection =
46550e57c6bSShawn McCarney                 std::make_unique<PhaseFaultDetection>(std::move(actions));
46650e57c6bSShawn McCarney 
46750e57c6bSShawn McCarney             // Create Device
46850e57c6bSShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
46950e57c6bSShawn McCarney             std::unique_ptr<PresenceDetection> presenceDetection{};
47050e57c6bSShawn McCarney             std::unique_ptr<Configuration> configuration{};
47150e57c6bSShawn McCarney             auto device = std::make_unique<Device>(
47250e57c6bSShawn McCarney                 "reg0", true,
47350e57c6bSShawn McCarney                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
47450e57c6bSShawn McCarney                 "reg0",
47550e57c6bSShawn McCarney                 std::move(i2cInterface), std::move(presenceDetection),
47650e57c6bSShawn McCarney                 std::move(configuration), std::move(phaseFaultDetection));
47750e57c6bSShawn McCarney             devices.emplace_back(std::move(device));
47850e57c6bSShawn McCarney         }
47950e57c6bSShawn McCarney 
48050e57c6bSShawn McCarney         // Create Device reg1
48150e57c6bSShawn McCarney         {
48250e57c6bSShawn McCarney             // Create PhaseFaultDetection
48350e57c6bSShawn McCarney             auto action =
48450e57c6bSShawn McCarney                 std::make_unique<LogPhaseFaultAction>(PhaseFaultType::n);
48550e57c6bSShawn McCarney             std::vector<std::unique_ptr<Action>> actions{};
48650e57c6bSShawn McCarney             actions.push_back(std::move(action));
48750e57c6bSShawn McCarney             auto phaseFaultDetection =
48850e57c6bSShawn McCarney                 std::make_unique<PhaseFaultDetection>(std::move(actions));
48950e57c6bSShawn McCarney 
49050e57c6bSShawn McCarney             // Create Device
49150e57c6bSShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
49250e57c6bSShawn McCarney             std::unique_ptr<PresenceDetection> presenceDetection{};
49350e57c6bSShawn McCarney             std::unique_ptr<Configuration> configuration{};
49450e57c6bSShawn McCarney             auto device = std::make_unique<Device>(
49550e57c6bSShawn McCarney                 "reg1", true,
49650e57c6bSShawn McCarney                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
49750e57c6bSShawn McCarney                 "reg1",
49850e57c6bSShawn McCarney                 std::move(i2cInterface), std::move(presenceDetection),
49950e57c6bSShawn McCarney                 std::move(configuration), std::move(phaseFaultDetection));
50050e57c6bSShawn McCarney             devices.emplace_back(std::move(device));
50150e57c6bSShawn McCarney         }
50250e57c6bSShawn McCarney 
50350e57c6bSShawn McCarney         // Create Chassis
50450e57c6bSShawn McCarney         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
50550e57c6bSShawn McCarney 
50650e57c6bSShawn McCarney         // Call detectPhaseFaults() 5 times
50750e57c6bSShawn McCarney         for (int i = 1; i <= 5; ++i)
50850e57c6bSShawn McCarney         {
50950e57c6bSShawn McCarney             chassis.detectPhaseFaults(services, *system);
51050e57c6bSShawn McCarney         }
51150e57c6bSShawn McCarney     }
51250e57c6bSShawn McCarney }
51350e57c6bSShawn McCarney 
TEST_F(ChassisTests,GetDevices)51483058606SShawn McCarney TEST_F(ChassisTests, GetDevices)
5158a3afd70SShawn McCarney {
5168a3afd70SShawn McCarney     // Test where no devices were specified in constructor
5178a3afd70SShawn McCarney     {
518cb3f6a63SShawn McCarney         Chassis chassis{2, defaultInventoryPath};
5198a3afd70SShawn McCarney         EXPECT_EQ(chassis.getDevices().size(), 0);
5208a3afd70SShawn McCarney     }
5218a3afd70SShawn McCarney 
5228a3afd70SShawn McCarney     // Test where devices were specified in constructor
5238a3afd70SShawn McCarney     {
5248a3afd70SShawn McCarney         // Create vector of Device objects
5258a3afd70SShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
526db0b833cSShawn McCarney         devices.emplace_back(createDevice("vdd_reg1"));
527db0b833cSShawn McCarney         devices.emplace_back(createDevice("vdd_reg2"));
5288a3afd70SShawn McCarney 
5298a3afd70SShawn McCarney         // Create Chassis
530cb3f6a63SShawn McCarney         Chassis chassis{1, defaultInventoryPath, std::move(devices)};
5318a3afd70SShawn McCarney         EXPECT_EQ(chassis.getDevices().size(), 2);
5328a3afd70SShawn McCarney         EXPECT_EQ(chassis.getDevices()[0]->getID(), "vdd_reg1");
5338a3afd70SShawn McCarney         EXPECT_EQ(chassis.getDevices()[1]->getID(), "vdd_reg2");
5348a3afd70SShawn McCarney     }
5358a3afd70SShawn McCarney }
5368a3afd70SShawn McCarney 
TEST_F(ChassisTests,GetInventoryPath)53783058606SShawn McCarney TEST_F(ChassisTests, GetInventoryPath)
538cb3f6a63SShawn McCarney {
539cb3f6a63SShawn McCarney     Chassis chassis{3, defaultInventoryPath};
540cb3f6a63SShawn McCarney     EXPECT_EQ(chassis.getInventoryPath(), defaultInventoryPath);
541cb3f6a63SShawn McCarney }
542cb3f6a63SShawn McCarney 
TEST_F(ChassisTests,GetNumber)54383058606SShawn McCarney TEST_F(ChassisTests, GetNumber)
5448a3afd70SShawn McCarney {
545cb3f6a63SShawn McCarney     Chassis chassis{3, defaultInventoryPath};
5468a3afd70SShawn McCarney     EXPECT_EQ(chassis.getNumber(), 3);
5478a3afd70SShawn McCarney }
548a2c81a61SBob King 
TEST_F(ChassisTests,MonitorSensors)54983058606SShawn McCarney TEST_F(ChassisTests, MonitorSensors)
550a2c81a61SBob King {
551a2c81a61SBob King     // Test where no devices were specified in constructor
552a2c81a61SBob King     {
55317bac89eSShawn McCarney         // Create mock services.  No Sensors methods should be called.
5548a55292dSBob King         MockServices services{};
55517bac89eSShawn McCarney         MockSensors& sensors = services.getMockSensors();
55617bac89eSShawn McCarney         EXPECT_CALL(sensors, startRail).Times(0);
55717bac89eSShawn McCarney         EXPECT_CALL(sensors, setValue).Times(0);
55817bac89eSShawn McCarney         EXPECT_CALL(sensors, endRail).Times(0);
5598a55292dSBob King 
560a2c81a61SBob King         // Create Chassis
56183058606SShawn McCarney         Chassis chassis{1, defaultInventoryPath};
562a2c81a61SBob King 
563a2c81a61SBob King         // Call monitorSensors().  Should do nothing.
56483058606SShawn McCarney         chassis.monitorSensors(services, *system);
565a2c81a61SBob King     }
566a2c81a61SBob King 
567a2c81a61SBob King     // Test where devices were specified in constructor
568a2c81a61SBob King     {
56917bac89eSShawn McCarney         // Create mock services.  Set Sensors service expectations.
5708a55292dSBob King         MockServices services{};
57117bac89eSShawn McCarney         MockSensors& sensors = services.getMockSensors();
57217bac89eSShawn McCarney         EXPECT_CALL(sensors, startRail("vdd0",
57317bac89eSShawn McCarney                                        "/xyz/openbmc_project/inventory/system/"
57417bac89eSShawn McCarney                                        "chassis/motherboard/vdd0_reg",
57517bac89eSShawn McCarney                                        defaultInventoryPath))
57617bac89eSShawn McCarney             .Times(1);
57717bac89eSShawn McCarney         EXPECT_CALL(sensors, startRail("vdd1",
57817bac89eSShawn McCarney                                        "/xyz/openbmc_project/inventory/system/"
57917bac89eSShawn McCarney                                        "chassis/motherboard/vdd1_reg",
58017bac89eSShawn McCarney                                        defaultInventoryPath))
58117bac89eSShawn McCarney             .Times(1);
58217bac89eSShawn McCarney         EXPECT_CALL(sensors, setValue).Times(0);
58317bac89eSShawn McCarney         EXPECT_CALL(sensors, endRail(false)).Times(2);
5848a55292dSBob King 
585a2c81a61SBob King         std::vector<std::unique_ptr<Device>> devices{};
586a2c81a61SBob King 
58717bac89eSShawn McCarney         // Create Device vdd0_reg
58817bac89eSShawn McCarney         {
58917bac89eSShawn McCarney             // Create SensorMonitoring for Rail
59083058606SShawn McCarney             auto action = std::make_unique<MockAction>();
59117bac89eSShawn McCarney             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
592a2c81a61SBob King             std::vector<std::unique_ptr<Action>> actions{};
593a2c81a61SBob King             actions.emplace_back(std::move(action));
59483058606SShawn McCarney             auto sensorMonitoring =
595a2c81a61SBob King                 std::make_unique<SensorMonitoring>(std::move(actions));
596a2c81a61SBob King 
597a2c81a61SBob King             // Create Rail
598a2c81a61SBob King             std::unique_ptr<Configuration> configuration{};
59983058606SShawn McCarney             auto rail = std::make_unique<Rail>("vdd0", std::move(configuration),
60083058606SShawn McCarney                                                std::move(sensorMonitoring));
601a2c81a61SBob King 
602a2c81a61SBob King             // Create Device
60383058606SShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
604a2c81a61SBob King             std::unique_ptr<PresenceDetection> presenceDetection{};
605a2c81a61SBob King             std::unique_ptr<Configuration> deviceConfiguration{};
60632252599SShawn McCarney             std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
60717bac89eSShawn McCarney             std::vector<std::unique_ptr<Rail>> rails{};
60817bac89eSShawn McCarney             rails.emplace_back(std::move(rail));
60983058606SShawn McCarney             auto device = std::make_unique<Device>(
61017bac89eSShawn McCarney                 "vdd0_reg", true,
61117bac89eSShawn McCarney                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
61217bac89eSShawn McCarney                 "vdd0_reg",
613a2c81a61SBob King                 std::move(i2cInterface), std::move(presenceDetection),
61432252599SShawn McCarney                 std::move(deviceConfiguration), std::move(phaseFaultDetection),
61532252599SShawn McCarney                 std::move(rails));
616a2c81a61SBob King             devices.emplace_back(std::move(device));
61717bac89eSShawn McCarney         }
61817bac89eSShawn McCarney 
61917bac89eSShawn McCarney         // Create Device vdd1_reg
62017bac89eSShawn McCarney         {
62117bac89eSShawn McCarney             // Create SensorMonitoring for Rail
62283058606SShawn McCarney             auto action = std::make_unique<MockAction>();
62317bac89eSShawn McCarney             EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
62417bac89eSShawn McCarney             std::vector<std::unique_ptr<Action>> actions{};
62517bac89eSShawn McCarney             actions.emplace_back(std::move(action));
62683058606SShawn McCarney             auto sensorMonitoring =
62717bac89eSShawn McCarney                 std::make_unique<SensorMonitoring>(std::move(actions));
62817bac89eSShawn McCarney 
62917bac89eSShawn McCarney             // Create Rail
63017bac89eSShawn McCarney             std::unique_ptr<Configuration> configuration{};
63183058606SShawn McCarney             auto rail = std::make_unique<Rail>("vdd1", std::move(configuration),
63283058606SShawn McCarney                                                std::move(sensorMonitoring));
63317bac89eSShawn McCarney 
63417bac89eSShawn McCarney             // Create Device
63583058606SShawn McCarney             auto i2cInterface = std::make_unique<i2c::MockedI2CInterface>();
63617bac89eSShawn McCarney             std::unique_ptr<PresenceDetection> presenceDetection{};
63717bac89eSShawn McCarney             std::unique_ptr<Configuration> deviceConfiguration{};
63832252599SShawn McCarney             std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
63917bac89eSShawn McCarney             std::vector<std::unique_ptr<Rail>> rails{};
64017bac89eSShawn McCarney             rails.emplace_back(std::move(rail));
64183058606SShawn McCarney             auto device = std::make_unique<Device>(
64217bac89eSShawn McCarney                 "vdd1_reg", true,
64317bac89eSShawn McCarney                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
64417bac89eSShawn McCarney                 "vdd1_reg",
64517bac89eSShawn McCarney                 std::move(i2cInterface), std::move(presenceDetection),
64632252599SShawn McCarney                 std::move(deviceConfiguration), std::move(phaseFaultDetection),
64732252599SShawn McCarney                 std::move(rails));
64817bac89eSShawn McCarney             devices.emplace_back(std::move(device));
64917bac89eSShawn McCarney         }
65017bac89eSShawn McCarney 
65117bac89eSShawn McCarney         // Create Chassis that contains Devices
65283058606SShawn McCarney         Chassis chassis{2, defaultInventoryPath, std::move(devices)};
653a2c81a61SBob King 
654a2c81a61SBob King         // Call monitorSensors()
65583058606SShawn McCarney         chassis.monitorSensors(services, *system);
656a2c81a61SBob King     }
657a2c81a61SBob King }
658