regulators: Add configure support to Device class

Implemented the configure() method in the Device class.  This method
applies any configuration changes that are defined for the device.  Also
configures all rails within the device.

Also added a missing #include to rail_tests.cpp.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I2faceb7d968b6bb01ee7e1116367afee5864ca28
diff --git a/phosphor-regulators/test/device_tests.cpp b/phosphor-regulators/test/device_tests.cpp
index c4875bf..1ce065c 100644
--- a/phosphor-regulators/test/device_tests.cpp
+++ b/phosphor-regulators/test/device_tests.cpp
@@ -14,13 +14,19 @@
  * limitations under the License.
  */
 #include "action.hpp"
+#include "chassis.hpp"
 #include "configuration.hpp"
 #include "device.hpp"
 #include "i2c_interface.hpp"
 #include "id_map.hpp"
+#include "journal.hpp"
 #include "mock_action.hpp"
+#include "mock_journal.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
+#include "rule.hpp"
+#include "sensor_monitoring.hpp"
+#include "system.hpp"
 #include "test_utils.hpp"
 
 #include <memory>
@@ -28,11 +34,14 @@
 #include <utility>
 #include <vector>
 
+#include <gmock/gmock.h>
 #include <gtest/gtest.h>
 
 using namespace phosphor::power::regulators;
 using namespace phosphor::power::regulators::test_utils;
 
+using ::testing::Return;
+
 TEST(DeviceTests, Constructor)
 {
     // Test where only required parameters are specified
@@ -129,6 +138,120 @@
     EXPECT_THROW(idMap.getRail("vdd2"), std::invalid_argument);
 }
 
+TEST(DeviceTests, Configure)
+{
+    // Test where Configuration and Rails were not specified in constructor
+    {
+        // Create Device
+        std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
+        std::unique_ptr<Device> device = std::make_unique<Device>(
+            "reg1", true, "/system/chassis/motherboard/reg1",
+            std::move(i2cInterface));
+        Device* devicePtr = device.get();
+
+        // Create Chassis that contains Device
+        std::vector<std::unique_ptr<Device>> devices{};
+        devices.emplace_back(std::move(device));
+        std::unique_ptr<Chassis> chassis =
+            std::make_unique<Chassis>(1, std::move(devices));
+        Chassis* chassisPtr = chassis.get();
+
+        // Create System that contains Chassis
+        std::vector<std::unique_ptr<Rule>> rules{};
+        std::vector<std::unique_ptr<Chassis>> chassisVec{};
+        chassisVec.emplace_back(std::move(chassis));
+        System system{std::move(rules), std::move(chassisVec)};
+
+        // Call configure().  Should do nothing.
+        journal::clear();
+        devicePtr->configure(system, *chassisPtr);
+        EXPECT_EQ(journal::getDebugMessages().size(), 0);
+        EXPECT_EQ(journal::getErrMessages().size(), 0);
+    }
+
+    // Test where Configuration and Rails were specified in constructor
+    {
+        std::vector<std::unique_ptr<Rail>> rails{};
+
+        // Create Rail vdd0
+        {
+            // Create Configuration for Rail
+            std::optional<double> volts{1.3};
+            std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
+            EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
+            std::vector<std::unique_ptr<Action>> actions{};
+            actions.emplace_back(std::move(action));
+            std::unique_ptr<Configuration> configuration =
+                std::make_unique<Configuration>(volts, std::move(actions));
+
+            // Create Rail
+            std::unique_ptr<Rail> rail =
+                std::make_unique<Rail>("vdd0", std::move(configuration));
+            rails.emplace_back(std::move(rail));
+        }
+
+        // Create Rail vio0
+        {
+            // Create Configuration for Rail
+            std::optional<double> volts{3.2};
+            std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
+            EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
+            std::vector<std::unique_ptr<Action>> actions{};
+            actions.emplace_back(std::move(action));
+            std::unique_ptr<Configuration> configuration =
+                std::make_unique<Configuration>(volts, std::move(actions));
+
+            // Create Rail
+            std::unique_ptr<Rail> rail =
+                std::make_unique<Rail>("vio0", std::move(configuration));
+            rails.emplace_back(std::move(rail));
+        }
+
+        // Create Configuration for Device
+        std::optional<double> volts{};
+        std::unique_ptr<MockAction> action = std::make_unique<MockAction>();
+        EXPECT_CALL(*action, execute).Times(1).WillOnce(Return(true));
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.emplace_back(std::move(action));
+        std::unique_ptr<Configuration> configuration =
+            std::make_unique<Configuration>(volts, std::move(actions));
+
+        // Create Device
+        std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
+        std::unique_ptr<PresenceDetection> presenceDetection{};
+        std::unique_ptr<Device> device = std::make_unique<Device>(
+            "reg1", true, "/system/chassis/motherboard/reg1",
+            std::move(i2cInterface), std::move(presenceDetection),
+            std::move(configuration), std::move(rails));
+        Device* devicePtr = device.get();
+
+        // Create Chassis that contains Device
+        std::vector<std::unique_ptr<Device>> devices{};
+        devices.emplace_back(std::move(device));
+        std::unique_ptr<Chassis> chassis =
+            std::make_unique<Chassis>(1, std::move(devices));
+        Chassis* chassisPtr = chassis.get();
+
+        // Create System that contains Chassis
+        std::vector<std::unique_ptr<Rule>> rules{};
+        std::vector<std::unique_ptr<Chassis>> chassisVec{};
+        chassisVec.emplace_back(std::move(chassis));
+        System system{std::move(rules), std::move(chassisVec)};
+
+        // Call configure().  For the Device and both Rails, should execute the
+        // Configuration and log a debug message.
+        journal::clear();
+        devicePtr->configure(system, *chassisPtr);
+        std::vector<std::string> expectedDebugMessages{
+            "Configuring reg1",
+            "Configuring vdd0: volts=1.300000",
+            "Configuring vio0: volts=3.200000",
+        };
+        EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
+        EXPECT_EQ(journal::getErrMessages().size(), 0);
+    }
+}
+
 TEST(DeviceTests, GetConfiguration)
 {
     // Test where Configuration was not specified in constructor