xref: /openbmc/phosphor-power/phosphor-regulators/test/configuration_tests.cpp (revision 3225259929b0a97c51ca96b399c8ff149ee99e30)
1d3a8aab4SShawn McCarney /**
2d3a8aab4SShawn McCarney  * Copyright © 2020 IBM Corporation
3d3a8aab4SShawn McCarney  *
4d3a8aab4SShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
5d3a8aab4SShawn McCarney  * you may not use this file except in compliance with the License.
6d3a8aab4SShawn McCarney  * You may obtain a copy of the License at
7d3a8aab4SShawn McCarney  *
8d3a8aab4SShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
9d3a8aab4SShawn McCarney  *
10d3a8aab4SShawn McCarney  * Unless required by applicable law or agreed to in writing, software
11d3a8aab4SShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
12d3a8aab4SShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3a8aab4SShawn McCarney  * See the License for the specific language governing permissions and
14d3a8aab4SShawn McCarney  * limitations under the License.
15d3a8aab4SShawn McCarney  */
16d3a8aab4SShawn McCarney #include "action.hpp"
173976500fSShawn McCarney #include "chassis.hpp"
18d3a8aab4SShawn McCarney #include "configuration.hpp"
193976500fSShawn McCarney #include "device.hpp"
203976500fSShawn McCarney #include "i2c_interface.hpp"
213976500fSShawn McCarney #include "i2c_write_byte_action.hpp"
22d3a8aab4SShawn McCarney #include "mock_action.hpp"
2381a2f90bSShawn McCarney #include "mock_error_logging.hpp"
243976500fSShawn McCarney #include "mock_journal.hpp"
2523243f84SBob King #include "mock_services.hpp"
263976500fSShawn McCarney #include "mocked_i2c_interface.hpp"
27*32252599SShawn McCarney #include "phase_fault_detection.hpp"
283976500fSShawn McCarney #include "pmbus_utils.hpp"
293976500fSShawn McCarney #include "pmbus_write_vout_command_action.hpp"
30779b9565SShawn McCarney #include "presence_detection.hpp"
313976500fSShawn McCarney #include "rail.hpp"
32779b9565SShawn McCarney #include "rule.hpp"
333976500fSShawn McCarney #include "system.hpp"
34d3a8aab4SShawn McCarney 
35779b9565SShawn McCarney #include <cstdint>
36d3a8aab4SShawn McCarney #include <memory>
37d3a8aab4SShawn McCarney #include <optional>
38d3a8aab4SShawn McCarney #include <utility>
39d3a8aab4SShawn McCarney #include <vector>
40d3a8aab4SShawn McCarney 
413976500fSShawn McCarney #include <gmock/gmock.h>
42d3a8aab4SShawn McCarney #include <gtest/gtest.h>
43d3a8aab4SShawn McCarney 
44d3a8aab4SShawn McCarney using namespace phosphor::power::regulators;
453976500fSShawn McCarney using namespace phosphor::power::regulators::pmbus_utils;
463976500fSShawn McCarney 
475cfe5103SBob King using ::testing::A;
4881a2f90bSShawn McCarney using ::testing::Ref;
493976500fSShawn McCarney using ::testing::Return;
503976500fSShawn McCarney using ::testing::Throw;
513976500fSShawn McCarney using ::testing::TypedEq;
52d3a8aab4SShawn McCarney 
53cb3f6a63SShawn McCarney static const std::string chassisInvPath{
54cb3f6a63SShawn McCarney     "/xyz/openbmc_project/inventory/system/chassis"};
55cb3f6a63SShawn McCarney 
TEST(ConfigurationTests,Constructor)56d3a8aab4SShawn McCarney TEST(ConfigurationTests, Constructor)
57d3a8aab4SShawn McCarney {
58d3a8aab4SShawn McCarney     // Test where volts value specified
59d3a8aab4SShawn McCarney     {
60d3a8aab4SShawn McCarney         std::optional<double> volts{1.3};
61d3a8aab4SShawn McCarney 
62d3a8aab4SShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
63d3a8aab4SShawn McCarney         actions.push_back(std::make_unique<MockAction>());
64d3a8aab4SShawn McCarney         actions.push_back(std::make_unique<MockAction>());
65d3a8aab4SShawn McCarney 
66d3a8aab4SShawn McCarney         Configuration configuration(volts, std::move(actions));
67d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getVolts().has_value(), true);
68d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getVolts().value(), 1.3);
69d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getActions().size(), 2);
70d3a8aab4SShawn McCarney     }
71d3a8aab4SShawn McCarney 
72d3a8aab4SShawn McCarney     // Test where volts value not specified
73d3a8aab4SShawn McCarney     {
74d3a8aab4SShawn McCarney         std::optional<double> volts{};
75d3a8aab4SShawn McCarney 
76d3a8aab4SShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
77d3a8aab4SShawn McCarney         actions.push_back(std::make_unique<MockAction>());
78d3a8aab4SShawn McCarney 
79d3a8aab4SShawn McCarney         Configuration configuration(volts, std::move(actions));
80d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getVolts().has_value(), false);
81d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getActions().size(), 1);
82d3a8aab4SShawn McCarney     }
83d3a8aab4SShawn McCarney }
84d3a8aab4SShawn McCarney 
855cfe5103SBob King // Test for execute(Services&, System&, Chassis&, Device&)
TEST(ConfigurationTests,ExecuteForDevice)863976500fSShawn McCarney TEST(ConfigurationTests, ExecuteForDevice)
87d3a8aab4SShawn McCarney {
883976500fSShawn McCarney     // Test where works: Volts value not specified
893976500fSShawn McCarney     {
905cfe5103SBob King         // Create mock services.  Expect logDebug() to be called.
9123243f84SBob King         MockServices services{};
925cfe5103SBob King         MockJournal& journal = services.getMockJournal();
935cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vdd_reg")).Times(1);
945cfe5103SBob King         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
9523243f84SBob King 
963976500fSShawn McCarney         // Create I2CWriteByteAction with register 0x7C and value 0x0A
973976500fSShawn McCarney         std::unique_ptr<I2CWriteByteAction> action =
983976500fSShawn McCarney             std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
993976500fSShawn McCarney 
1003976500fSShawn McCarney         // Create mock I2CInterface.  Expect action to write 0x0A to 0x7C.
1013976500fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
1023976500fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
1033976500fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
1043976500fSShawn McCarney         EXPECT_CALL(*i2cInterface,
1053976500fSShawn McCarney                     write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
1063976500fSShawn McCarney             .Times(1);
1073976500fSShawn McCarney 
1083976500fSShawn McCarney         // Create Configuration with no volts value specified
1093976500fSShawn McCarney         std::optional<double> volts{};
1103976500fSShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
1113976500fSShawn McCarney         actions.emplace_back(std::move(action));
1123976500fSShawn McCarney         std::unique_ptr<Configuration> configuration =
1133976500fSShawn McCarney             std::make_unique<Configuration>(volts, std::move(actions));
1143976500fSShawn McCarney         Configuration* configurationPtr = configuration.get();
1153976500fSShawn McCarney 
1163976500fSShawn McCarney         // Create Device that contains Configuration
1173976500fSShawn McCarney         std::unique_ptr<PresenceDetection> presenceDetection{};
1183976500fSShawn McCarney         std::unique_ptr<Device> device = std::make_unique<Device>(
119a76898f1SBob King             "vdd_reg", true,
120a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
1213976500fSShawn McCarney             std::move(i2cInterface), std::move(presenceDetection),
1223976500fSShawn McCarney             std::move(configuration));
1233976500fSShawn McCarney         Device* devicePtr = device.get();
1243976500fSShawn McCarney 
1253976500fSShawn McCarney         // Create Chassis that contains Device
1263976500fSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
1273976500fSShawn McCarney         devices.emplace_back(std::move(device));
1283976500fSShawn McCarney         std::unique_ptr<Chassis> chassis =
129cb3f6a63SShawn McCarney             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
1303976500fSShawn McCarney         Chassis* chassisPtr = chassis.get();
1313976500fSShawn McCarney 
1323976500fSShawn McCarney         // Create System that contains Chassis
1333976500fSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
1343976500fSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassisVec{};
1353976500fSShawn McCarney         chassisVec.emplace_back(std::move(chassis));
1363976500fSShawn McCarney         System system{std::move(rules), std::move(chassisVec)};
1373976500fSShawn McCarney 
1383976500fSShawn McCarney         // Execute Configuration
13923243f84SBob King         configurationPtr->execute(services, system, *chassisPtr, *devicePtr);
1403976500fSShawn McCarney     }
1413976500fSShawn McCarney 
1423976500fSShawn McCarney     // Test where works: Volts value specified
1433976500fSShawn McCarney     {
1445cfe5103SBob King         // Create mock services.  Expect logDebug() to be called.
14523243f84SBob King         MockServices services{};
1465cfe5103SBob King         MockJournal& journal = services.getMockJournal();
1475cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vdd_reg: volts=1.300000"))
1485cfe5103SBob King             .Times(1);
1495cfe5103SBob King         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
15023243f84SBob King 
1513976500fSShawn McCarney         // Create PMBusWriteVoutCommandAction.  Do not specify a volts value
1523976500fSShawn McCarney         // because it will get a value of 1.3V from the
1533976500fSShawn McCarney         // ActionEnvironment/Configuration.  Specify a -8 exponent.
1543976500fSShawn McCarney         // Linear format volts value = (1.3 / 2^(-8)) = 332.8 = 333 = 0x014D.
1553976500fSShawn McCarney         std::optional<double> volts{};
1563976500fSShawn McCarney         std::unique_ptr<PMBusWriteVoutCommandAction> action =
1573976500fSShawn McCarney             std::make_unique<PMBusWriteVoutCommandAction>(
1583976500fSShawn McCarney                 volts, pmbus_utils::VoutDataFormat::linear, -8, false);
1593976500fSShawn McCarney 
1603976500fSShawn McCarney         // Create mock I2CInterface.  Expect action to write 0x014D to
1613976500fSShawn McCarney         // VOUT_COMMAND (command/register 0x21).
1623976500fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
1633976500fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
1643976500fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
1653976500fSShawn McCarney         EXPECT_CALL(*i2cInterface,
1663976500fSShawn McCarney                     write(TypedEq<uint8_t>(0x21), TypedEq<uint16_t>(0x014D)))
1673976500fSShawn McCarney             .Times(1);
1683976500fSShawn McCarney 
1693976500fSShawn McCarney         // Create Configuration with volts value 1.3V
1703976500fSShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
1713976500fSShawn McCarney         actions.emplace_back(std::move(action));
1723976500fSShawn McCarney         std::unique_ptr<Configuration> configuration =
1733976500fSShawn McCarney             std::make_unique<Configuration>(1.3, std::move(actions));
1743976500fSShawn McCarney         Configuration* configurationPtr = configuration.get();
1753976500fSShawn McCarney 
1763976500fSShawn McCarney         // Create Device that contains Configuration
1773976500fSShawn McCarney         std::unique_ptr<PresenceDetection> presenceDetection{};
1783976500fSShawn McCarney         std::unique_ptr<Device> device = std::make_unique<Device>(
179a76898f1SBob King             "vdd_reg", true,
180a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
1813976500fSShawn McCarney             std::move(i2cInterface), std::move(presenceDetection),
1823976500fSShawn McCarney             std::move(configuration));
1833976500fSShawn McCarney         Device* devicePtr = device.get();
1843976500fSShawn McCarney 
1853976500fSShawn McCarney         // Create Chassis that contains Device
1863976500fSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
1873976500fSShawn McCarney         devices.emplace_back(std::move(device));
1883976500fSShawn McCarney         std::unique_ptr<Chassis> chassis =
189cb3f6a63SShawn McCarney             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
1903976500fSShawn McCarney         Chassis* chassisPtr = chassis.get();
1913976500fSShawn McCarney 
1923976500fSShawn McCarney         // Create System that contains Chassis
1933976500fSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
1943976500fSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassisVec{};
1953976500fSShawn McCarney         chassisVec.emplace_back(std::move(chassis));
1963976500fSShawn McCarney         System system{std::move(rules), std::move(chassisVec)};
1973976500fSShawn McCarney 
1983976500fSShawn McCarney         // Execute Configuration
19923243f84SBob King         configurationPtr->execute(services, system, *chassisPtr, *devicePtr);
2003976500fSShawn McCarney     }
2013976500fSShawn McCarney 
2023976500fSShawn McCarney     // Test where fails
2033976500fSShawn McCarney     {
20481a2f90bSShawn McCarney         // Create mock services.  Expect logDebug(), logError(), and
20581a2f90bSShawn McCarney         // logI2CError() to be called.
20623243f84SBob King         MockServices services{};
20781a2f90bSShawn McCarney         MockErrorLogging& errorLogging = services.getMockErrorLogging();
2085cfe5103SBob King         MockJournal& journal = services.getMockJournal();
2095cfe5103SBob King         std::vector<std::string> expectedErrMessagesException{
2105cfe5103SBob King             "I2CException: Failed to write byte: bus /dev/i2c-1, addr 0x70",
2115cfe5103SBob King             "ActionError: i2c_write_byte: { register: 0x7C, value: 0xA, mask: "
2125cfe5103SBob King             "0xFF }"};
2135cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vdd_reg")).Times(1);
2145cfe5103SBob King         EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1);
2155cfe5103SBob King         EXPECT_CALL(journal, logError("Unable to configure vdd_reg")).Times(1);
21681a2f90bSShawn McCarney         EXPECT_CALL(errorLogging,
21781a2f90bSShawn McCarney                     logI2CError(Entry::Level::Warning, Ref(journal),
21881a2f90bSShawn McCarney                                 "/dev/i2c-1", 0x70, 0))
21981a2f90bSShawn McCarney             .Times(1);
22023243f84SBob King 
2213976500fSShawn McCarney         // Create I2CWriteByteAction with register 0x7C and value 0x0A
2223976500fSShawn McCarney         std::unique_ptr<I2CWriteByteAction> action =
2233976500fSShawn McCarney             std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
2243976500fSShawn McCarney 
2253976500fSShawn McCarney         // Create mock I2CInterface.  write() throws an I2CException.
2263976500fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
2273976500fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
2283976500fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
2293976500fSShawn McCarney         EXPECT_CALL(*i2cInterface,
2303976500fSShawn McCarney                     write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
2313976500fSShawn McCarney             .Times(1)
2323976500fSShawn McCarney             .WillOnce(Throw(
2333976500fSShawn McCarney                 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70}));
2343976500fSShawn McCarney 
2353976500fSShawn McCarney         // Create Configuration with no volts value specified
2363976500fSShawn McCarney         std::optional<double> volts{};
2373976500fSShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
2383976500fSShawn McCarney         actions.emplace_back(std::move(action));
2393976500fSShawn McCarney         std::unique_ptr<Configuration> configuration =
2403976500fSShawn McCarney             std::make_unique<Configuration>(volts, std::move(actions));
2413976500fSShawn McCarney         Configuration* configurationPtr = configuration.get();
2423976500fSShawn McCarney 
2433976500fSShawn McCarney         // Create Device that contains Configuration
2443976500fSShawn McCarney         std::unique_ptr<PresenceDetection> presenceDetection{};
2453976500fSShawn McCarney         std::unique_ptr<Device> device = std::make_unique<Device>(
246a76898f1SBob King             "vdd_reg", true,
247a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
2483976500fSShawn McCarney             std::move(i2cInterface), std::move(presenceDetection),
2493976500fSShawn McCarney             std::move(configuration));
2503976500fSShawn McCarney         Device* devicePtr = device.get();
2513976500fSShawn McCarney 
2523976500fSShawn McCarney         // Create Chassis that contains Device
2533976500fSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
2543976500fSShawn McCarney         devices.emplace_back(std::move(device));
2553976500fSShawn McCarney         std::unique_ptr<Chassis> chassis =
256cb3f6a63SShawn McCarney             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
2573976500fSShawn McCarney         Chassis* chassisPtr = chassis.get();
2583976500fSShawn McCarney 
2593976500fSShawn McCarney         // Create System that contains Chassis
2603976500fSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
2613976500fSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassisVec{};
2623976500fSShawn McCarney         chassisVec.emplace_back(std::move(chassis));
2633976500fSShawn McCarney         System system{std::move(rules), std::move(chassisVec)};
2643976500fSShawn McCarney 
2653976500fSShawn McCarney         // Execute Configuration
26623243f84SBob King         configurationPtr->execute(services, system, *chassisPtr, *devicePtr);
2673976500fSShawn McCarney     }
2683976500fSShawn McCarney }
2693976500fSShawn McCarney 
2705cfe5103SBob King // Test for execute(Services&, System&, Chassis&, Device&, Rail&)
TEST(ConfigurationTests,ExecuteForRail)2713976500fSShawn McCarney TEST(ConfigurationTests, ExecuteForRail)
2723976500fSShawn McCarney {
2733976500fSShawn McCarney     // Test where works: Volts value not specified
2743976500fSShawn McCarney     {
2755cfe5103SBob King         // Create mock services.  Expect logDebug() to be called.
27623243f84SBob King         MockServices services{};
2775cfe5103SBob King         MockJournal& journal = services.getMockJournal();
2785cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vio2")).Times(1);
2795cfe5103SBob King         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
28023243f84SBob King 
2813976500fSShawn McCarney         // Create I2CWriteByteAction with register 0x7C and value 0x0A
2823976500fSShawn McCarney         std::unique_ptr<I2CWriteByteAction> action =
2833976500fSShawn McCarney             std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
2843976500fSShawn McCarney 
2853976500fSShawn McCarney         // Create mock I2CInterface.  Expect action to write 0x0A to 0x7C.
2863976500fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
2873976500fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
2883976500fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
2893976500fSShawn McCarney         EXPECT_CALL(*i2cInterface,
2903976500fSShawn McCarney                     write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
2913976500fSShawn McCarney             .Times(1);
2923976500fSShawn McCarney 
2933976500fSShawn McCarney         // Create Configuration with no volts value specified
2943976500fSShawn McCarney         std::optional<double> volts{};
2953976500fSShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
2963976500fSShawn McCarney         actions.emplace_back(std::move(action));
2973976500fSShawn McCarney         std::unique_ptr<Configuration> configuration =
2983976500fSShawn McCarney             std::make_unique<Configuration>(volts, std::move(actions));
2993976500fSShawn McCarney         Configuration* configurationPtr = configuration.get();
3003976500fSShawn McCarney 
3013976500fSShawn McCarney         // Create Rail that contains Configuration
3023976500fSShawn McCarney         std::unique_ptr<Rail> rail =
3033976500fSShawn McCarney             std::make_unique<Rail>("vio2", std::move(configuration));
3043976500fSShawn McCarney         Rail* railPtr = rail.get();
3053976500fSShawn McCarney 
3063976500fSShawn McCarney         // Create Device that contains Rail
3073976500fSShawn McCarney         std::unique_ptr<PresenceDetection> presenceDetection{};
3083976500fSShawn McCarney         std::unique_ptr<Configuration> deviceConfiguration{};
309*32252599SShawn McCarney         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
3103976500fSShawn McCarney         std::vector<std::unique_ptr<Rail>> rails{};
3113976500fSShawn McCarney         rails.emplace_back(std::move(rail));
3123976500fSShawn McCarney         std::unique_ptr<Device> device = std::make_unique<Device>(
313a76898f1SBob King             "reg1", true,
314a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
3153976500fSShawn McCarney             std::move(i2cInterface), std::move(presenceDetection),
316*32252599SShawn McCarney             std::move(deviceConfiguration), std::move(phaseFaultDetection),
317*32252599SShawn McCarney             std::move(rails));
3183976500fSShawn McCarney         Device* devicePtr = device.get();
3193976500fSShawn McCarney 
3203976500fSShawn McCarney         // Create Chassis that contains Device
3213976500fSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
3223976500fSShawn McCarney         devices.emplace_back(std::move(device));
3233976500fSShawn McCarney         std::unique_ptr<Chassis> chassis =
324cb3f6a63SShawn McCarney             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
3253976500fSShawn McCarney         Chassis* chassisPtr = chassis.get();
3263976500fSShawn McCarney 
3273976500fSShawn McCarney         // Create System that contains Chassis
3283976500fSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
3293976500fSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassisVec{};
3303976500fSShawn McCarney         chassisVec.emplace_back(std::move(chassis));
3313976500fSShawn McCarney         System system{std::move(rules), std::move(chassisVec)};
3323976500fSShawn McCarney 
3333976500fSShawn McCarney         // Execute Configuration
33423243f84SBob King         configurationPtr->execute(services, system, *chassisPtr, *devicePtr,
33523243f84SBob King                                   *railPtr);
3363976500fSShawn McCarney     }
3373976500fSShawn McCarney 
3383976500fSShawn McCarney     // Test where works: Volts value specified
3393976500fSShawn McCarney     {
3405cfe5103SBob King         // Create mock services.  Expect logDebug() to be called.
34123243f84SBob King         MockServices services{};
3425cfe5103SBob King         MockJournal& journal = services.getMockJournal();
3435cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vio2: volts=1.300000"))
3445cfe5103SBob King             .Times(1);
3455cfe5103SBob King         EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
34623243f84SBob King 
3473976500fSShawn McCarney         // Create PMBusWriteVoutCommandAction.  Do not specify a volts value
3483976500fSShawn McCarney         // because it will get a value of 1.3V from the
3493976500fSShawn McCarney         // ActionEnvironment/Configuration.  Specify a -8 exponent.
3503976500fSShawn McCarney         // Linear format volts value = (1.3 / 2^(-8)) = 332.8 = 333 = 0x014D.
3513976500fSShawn McCarney         std::optional<double> volts{};
3523976500fSShawn McCarney         std::unique_ptr<PMBusWriteVoutCommandAction> action =
3533976500fSShawn McCarney             std::make_unique<PMBusWriteVoutCommandAction>(
3543976500fSShawn McCarney                 volts, pmbus_utils::VoutDataFormat::linear, -8, false);
3553976500fSShawn McCarney 
3563976500fSShawn McCarney         // Create mock I2CInterface.  Expect action to write 0x014D to
3573976500fSShawn McCarney         // VOUT_COMMAND (command/register 0x21).
3583976500fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
3593976500fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
3603976500fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
3613976500fSShawn McCarney         EXPECT_CALL(*i2cInterface,
3623976500fSShawn McCarney                     write(TypedEq<uint8_t>(0x21), TypedEq<uint16_t>(0x014D)))
3633976500fSShawn McCarney             .Times(1);
3643976500fSShawn McCarney 
3653976500fSShawn McCarney         // Create Configuration with volts value 1.3V
3663976500fSShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
3673976500fSShawn McCarney         actions.emplace_back(std::move(action));
3683976500fSShawn McCarney         std::unique_ptr<Configuration> configuration =
3693976500fSShawn McCarney             std::make_unique<Configuration>(1.3, std::move(actions));
3703976500fSShawn McCarney         Configuration* configurationPtr = configuration.get();
3713976500fSShawn McCarney 
3723976500fSShawn McCarney         // Create Rail that contains Configuration
3733976500fSShawn McCarney         std::unique_ptr<Rail> rail =
3743976500fSShawn McCarney             std::make_unique<Rail>("vio2", std::move(configuration));
3753976500fSShawn McCarney         Rail* railPtr = rail.get();
3763976500fSShawn McCarney 
3773976500fSShawn McCarney         // Create Device that contains Rail
3783976500fSShawn McCarney         std::unique_ptr<PresenceDetection> presenceDetection{};
3793976500fSShawn McCarney         std::unique_ptr<Configuration> deviceConfiguration{};
380*32252599SShawn McCarney         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
3813976500fSShawn McCarney         std::vector<std::unique_ptr<Rail>> rails{};
3823976500fSShawn McCarney         rails.emplace_back(std::move(rail));
3833976500fSShawn McCarney         std::unique_ptr<Device> device = std::make_unique<Device>(
384a76898f1SBob King             "reg1", true,
385a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
3863976500fSShawn McCarney             std::move(i2cInterface), std::move(presenceDetection),
387*32252599SShawn McCarney             std::move(deviceConfiguration), std::move(phaseFaultDetection),
388*32252599SShawn McCarney             std::move(rails));
3893976500fSShawn McCarney         Device* devicePtr = device.get();
3903976500fSShawn McCarney 
3913976500fSShawn McCarney         // Create Chassis that contains Device
3923976500fSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
3933976500fSShawn McCarney         devices.emplace_back(std::move(device));
3943976500fSShawn McCarney         std::unique_ptr<Chassis> chassis =
395cb3f6a63SShawn McCarney             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
3963976500fSShawn McCarney         Chassis* chassisPtr = chassis.get();
3973976500fSShawn McCarney 
3983976500fSShawn McCarney         // Create System that contains Chassis
3993976500fSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
4003976500fSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassisVec{};
4013976500fSShawn McCarney         chassisVec.emplace_back(std::move(chassis));
4023976500fSShawn McCarney         System system{std::move(rules), std::move(chassisVec)};
4033976500fSShawn McCarney 
4043976500fSShawn McCarney         // Execute Configuration
40523243f84SBob King         configurationPtr->execute(services, system, *chassisPtr, *devicePtr,
40623243f84SBob King                                   *railPtr);
4073976500fSShawn McCarney     }
4083976500fSShawn McCarney 
4093976500fSShawn McCarney     // Test where fails
4103976500fSShawn McCarney     {
41181a2f90bSShawn McCarney         // Create mock services.  Expect logDebug(), logError(), and logI2CError
41281a2f90bSShawn McCarney         // to be called.
41323243f84SBob King         MockServices services{};
41481a2f90bSShawn McCarney         MockErrorLogging& errorLogging = services.getMockErrorLogging();
4155cfe5103SBob King         MockJournal& journal = services.getMockJournal();
4165cfe5103SBob King         std::vector<std::string> expectedErrMessagesException{
4175cfe5103SBob King             "I2CException: Failed to write byte: bus /dev/i2c-1, addr 0x70",
4185cfe5103SBob King             "ActionError: i2c_write_byte: { register: 0x7C, value: 0xA, mask: "
4195cfe5103SBob King             "0xFF }"};
4205cfe5103SBob King         EXPECT_CALL(journal, logDebug("Configuring vio2")).Times(1);
4215cfe5103SBob King         EXPECT_CALL(journal, logError(expectedErrMessagesException)).Times(1);
4225cfe5103SBob King         EXPECT_CALL(journal, logError("Unable to configure vio2")).Times(1);
42381a2f90bSShawn McCarney         EXPECT_CALL(errorLogging,
42481a2f90bSShawn McCarney                     logI2CError(Entry::Level::Warning, Ref(journal),
42581a2f90bSShawn McCarney                                 "/dev/i2c-1", 0x70, 0))
42681a2f90bSShawn McCarney             .Times(1);
42723243f84SBob King 
4283976500fSShawn McCarney         // Create I2CWriteByteAction with register 0x7C and value 0x0A
4293976500fSShawn McCarney         std::unique_ptr<I2CWriteByteAction> action =
4303976500fSShawn McCarney             std::make_unique<I2CWriteByteAction>(0x7C, 0x0A);
4313976500fSShawn McCarney 
4323976500fSShawn McCarney         // Create mock I2CInterface.  write() throws an I2CException.
4333976500fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
4343976500fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
4353976500fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
4363976500fSShawn McCarney         EXPECT_CALL(*i2cInterface,
4373976500fSShawn McCarney                     write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
4383976500fSShawn McCarney             .Times(1)
4393976500fSShawn McCarney             .WillOnce(Throw(
4403976500fSShawn McCarney                 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70}));
4413976500fSShawn McCarney 
4423976500fSShawn McCarney         // Create Configuration with no volts value specified
4433976500fSShawn McCarney         std::optional<double> volts{};
4443976500fSShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
4453976500fSShawn McCarney         actions.emplace_back(std::move(action));
4463976500fSShawn McCarney         std::unique_ptr<Configuration> configuration =
4473976500fSShawn McCarney             std::make_unique<Configuration>(volts, std::move(actions));
4483976500fSShawn McCarney         Configuration* configurationPtr = configuration.get();
4493976500fSShawn McCarney 
4503976500fSShawn McCarney         // Create Rail that contains Configuration
4513976500fSShawn McCarney         std::unique_ptr<Rail> rail =
4523976500fSShawn McCarney             std::make_unique<Rail>("vio2", std::move(configuration));
4533976500fSShawn McCarney         Rail* railPtr = rail.get();
4543976500fSShawn McCarney 
4553976500fSShawn McCarney         // Create Device that contains Rail
4563976500fSShawn McCarney         std::unique_ptr<PresenceDetection> presenceDetection{};
4573976500fSShawn McCarney         std::unique_ptr<Configuration> deviceConfiguration{};
458*32252599SShawn McCarney         std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
4593976500fSShawn McCarney         std::vector<std::unique_ptr<Rail>> rails{};
4603976500fSShawn McCarney         rails.emplace_back(std::move(rail));
4613976500fSShawn McCarney         std::unique_ptr<Device> device = std::make_unique<Device>(
462a76898f1SBob King             "reg1", true,
463a76898f1SBob King             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
4643976500fSShawn McCarney             std::move(i2cInterface), std::move(presenceDetection),
465*32252599SShawn McCarney             std::move(deviceConfiguration), std::move(phaseFaultDetection),
466*32252599SShawn McCarney             std::move(rails));
4673976500fSShawn McCarney         Device* devicePtr = device.get();
4683976500fSShawn McCarney 
4693976500fSShawn McCarney         // Create Chassis that contains Device
4703976500fSShawn McCarney         std::vector<std::unique_ptr<Device>> devices{};
4713976500fSShawn McCarney         devices.emplace_back(std::move(device));
4723976500fSShawn McCarney         std::unique_ptr<Chassis> chassis =
473cb3f6a63SShawn McCarney             std::make_unique<Chassis>(1, chassisInvPath, std::move(devices));
4743976500fSShawn McCarney         Chassis* chassisPtr = chassis.get();
4753976500fSShawn McCarney 
4763976500fSShawn McCarney         // Create System that contains Chassis
4773976500fSShawn McCarney         std::vector<std::unique_ptr<Rule>> rules{};
4783976500fSShawn McCarney         std::vector<std::unique_ptr<Chassis>> chassisVec{};
4793976500fSShawn McCarney         chassisVec.emplace_back(std::move(chassis));
4803976500fSShawn McCarney         System system{std::move(rules), std::move(chassisVec)};
4813976500fSShawn McCarney 
4823976500fSShawn McCarney         // Execute Configuration
48323243f84SBob King         configurationPtr->execute(services, system, *chassisPtr, *devicePtr,
48423243f84SBob King                                   *railPtr);
4853976500fSShawn McCarney     }
486d3a8aab4SShawn McCarney }
487d3a8aab4SShawn McCarney 
TEST(ConfigurationTests,GetActions)488d3a8aab4SShawn McCarney TEST(ConfigurationTests, GetActions)
489d3a8aab4SShawn McCarney {
490d3a8aab4SShawn McCarney     std::optional<double> volts{1.3};
491d3a8aab4SShawn McCarney 
492d3a8aab4SShawn McCarney     std::vector<std::unique_ptr<Action>> actions{};
493d3a8aab4SShawn McCarney 
494d3a8aab4SShawn McCarney     MockAction* action1 = new MockAction{};
495d3a8aab4SShawn McCarney     actions.push_back(std::unique_ptr<MockAction>{action1});
496d3a8aab4SShawn McCarney 
497d3a8aab4SShawn McCarney     MockAction* action2 = new MockAction{};
498d3a8aab4SShawn McCarney     actions.push_back(std::unique_ptr<MockAction>{action2});
499d3a8aab4SShawn McCarney 
500d3a8aab4SShawn McCarney     Configuration configuration(volts, std::move(actions));
501d3a8aab4SShawn McCarney     EXPECT_EQ(configuration.getActions().size(), 2);
502d3a8aab4SShawn McCarney     EXPECT_EQ(configuration.getActions()[0].get(), action1);
503d3a8aab4SShawn McCarney     EXPECT_EQ(configuration.getActions()[1].get(), action2);
504d3a8aab4SShawn McCarney }
505d3a8aab4SShawn McCarney 
TEST(ConfigurationTests,GetVolts)506d3a8aab4SShawn McCarney TEST(ConfigurationTests, GetVolts)
507d3a8aab4SShawn McCarney {
508d3a8aab4SShawn McCarney     // Test where volts value specified
509d3a8aab4SShawn McCarney     {
510d3a8aab4SShawn McCarney         std::optional<double> volts{3.2};
511d3a8aab4SShawn McCarney 
512d3a8aab4SShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
513d3a8aab4SShawn McCarney         actions.push_back(std::make_unique<MockAction>());
514d3a8aab4SShawn McCarney 
515d3a8aab4SShawn McCarney         Configuration configuration(volts, std::move(actions));
516d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getVolts().has_value(), true);
517d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getVolts().value(), 3.2);
518d3a8aab4SShawn McCarney     }
519d3a8aab4SShawn McCarney 
520d3a8aab4SShawn McCarney     // Test where volts value not specified
521d3a8aab4SShawn McCarney     {
522d3a8aab4SShawn McCarney         std::optional<double> volts{};
523d3a8aab4SShawn McCarney 
524d3a8aab4SShawn McCarney         std::vector<std::unique_ptr<Action>> actions{};
525d3a8aab4SShawn McCarney         actions.push_back(std::make_unique<MockAction>());
526d3a8aab4SShawn McCarney 
527d3a8aab4SShawn McCarney         Configuration configuration(volts, std::move(actions));
528d3a8aab4SShawn McCarney         EXPECT_EQ(configuration.getVolts().has_value(), false);
529d3a8aab4SShawn McCarney     }
530d3a8aab4SShawn McCarney }
531