regulators: Add PhaseFaultDetection to Device

Add a PhaseFaultDetection data member to the Device class.  This is the
first step in enabling phase fault detection for Device objects.

Create and modify gtest test cases to exercise new code.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: Icc771eda5c79ace854acb1d7c395b82b34213996
diff --git a/phosphor-regulators/src/config_file_parser.cpp b/phosphor-regulators/src/config_file_parser.cpp
index 430d490..619a8b6 100644
--- a/phosphor-regulators/src/config_file_parser.cpp
+++ b/phosphor-regulators/src/config_file_parser.cpp
@@ -394,6 +394,20 @@
         ++propertyCount;
     }
 
+    // Optional phase_fault_detection property
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
+    auto phaseFaultDetectionIt = element.find("phase_fault_detection");
+    if (phaseFaultDetectionIt != element.end())
+    {
+        if (!isRegulator)
+        {
+            throw std::invalid_argument{"Invalid phase_fault_detection "
+                                        "property when is_regulator is false"};
+        }
+        phaseFaultDetection = parsePhaseFaultDetection(*phaseFaultDetectionIt);
+        ++propertyCount;
+    }
+
     // Optional rails property
     std::vector<std::unique_ptr<Rail>> rails{};
     auto railsIt = element.find("rails");
@@ -411,10 +425,10 @@
     // Verify no invalid properties exist
     verifyPropertyCount(element, propertyCount);
 
-    return std::make_unique<Device>(id, isRegulator, fru,
-                                    std::move(i2cInterface),
-                                    std::move(presenceDetection),
-                                    std::move(configuration), std::move(rails));
+    return std::make_unique<Device>(
+        id, isRegulator, fru, std::move(i2cInterface),
+        std::move(presenceDetection), std::move(configuration),
+        std::move(phaseFaultDetection), std::move(rails));
 }
 
 std::vector<std::unique_ptr<Device>> parseDeviceArray(const json& element)
diff --git a/phosphor-regulators/src/device.hpp b/phosphor-regulators/src/device.hpp
index 4937567..a8f35b6 100644
--- a/phosphor-regulators/src/device.hpp
+++ b/phosphor-regulators/src/device.hpp
@@ -18,6 +18,7 @@
 #include "configuration.hpp"
 #include "i2c_interface.hpp"
 #include "id_map.hpp"
+#include "phase_fault_detection.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "services.hpp"
@@ -60,6 +61,7 @@
      * @param presenceDetection presence detection for this device, if any
      * @param configuration configuration changes to apply to this device, if
      *                      any
+     * @param phaseFaultDetection phase fault detection for this device, if any
      * @param rails voltage rails produced by this device, if any
      */
     explicit Device(
@@ -67,13 +69,16 @@
         std::unique_ptr<i2c::I2CInterface> i2cInterface,
         std::unique_ptr<PresenceDetection> presenceDetection = nullptr,
         std::unique_ptr<Configuration> configuration = nullptr,
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection = nullptr,
         std::vector<std::unique_ptr<Rail>> rails =
             std::vector<std::unique_ptr<Rail>>{}) :
         id{id},
         isRegulatorDevice{isRegulator}, fru{fru},
         i2cInterface{std::move(i2cInterface)}, presenceDetection{std::move(
                                                    presenceDetection)},
-        configuration{std::move(configuration)}, rails{std::move(rails)}
+        configuration{std::move(configuration)},
+        phaseFaultDetection{std::move(phaseFaultDetection)}, rails{std::move(
+                                                                 rails)}
     {
     }
 
@@ -173,6 +178,17 @@
     }
 
     /**
+     * Returns the phase fault detection for this device, if any.
+     *
+     * @return Pointer to PhaseFaultDetection object.  Will equal nullptr if no
+     *         phase fault detection is defined for this device.
+     */
+    const std::unique_ptr<PhaseFaultDetection>& getPhaseFaultDetection() const
+    {
+        return phaseFaultDetection;
+    }
+
+    /**
      * Returns the presence detection for this device, if any.
      *
      * @return Pointer to PresenceDetection object.  Will equal nullptr if no
@@ -271,6 +287,12 @@
     std::unique_ptr<Configuration> configuration{};
 
     /**
+     * Phase fault detection for this device, if any.  Set to nullptr if no
+     * phase fault detection is defined for this device.
+     */
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
+
+    /**
      * Voltage rails produced by this device, if any.  Vector is empty if no
      * voltage rails are defined for this device.
      */
diff --git a/phosphor-regulators/test/chassis_tests.cpp b/phosphor-regulators/test/chassis_tests.cpp
index 69968a0..72d1594 100644
--- a/phosphor-regulators/test/chassis_tests.cpp
+++ b/phosphor-regulators/test/chassis_tests.cpp
@@ -25,6 +25,7 @@
 #include "mock_sensors.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
+#include "phase_fault_detection.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
@@ -185,13 +186,15 @@
         std::make_unique<i2c::MockedI2CInterface>();
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> deviceConfiguration{};
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
     std::vector<std::unique_ptr<Rail>> rails{};
     rails.emplace_back(std::move(rail));
     std::unique_ptr<Device> device = std::make_unique<Device>(
         "reg1", true,
         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
         std::move(i2cInterface), std::move(presenceDetection),
-        std::move(deviceConfiguration), std::move(rails));
+        std::move(deviceConfiguration), std::move(phaseFaultDetection),
+        std::move(rails));
 
     // Create Chassis that contains Device
     std::vector<std::unique_ptr<Device>> devices{};
@@ -507,6 +510,7 @@
                 createI2CInterface();
             std::unique_ptr<PresenceDetection> presenceDetection{};
             std::unique_ptr<Configuration> deviceConfiguration{};
+            std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
             std::vector<std::unique_ptr<Rail>> rails{};
             rails.emplace_back(std::move(rail));
             std::unique_ptr<Device> device = std::make_unique<Device>(
@@ -514,7 +518,8 @@
                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
                 "vdd0_reg",
                 std::move(i2cInterface), std::move(presenceDetection),
-                std::move(deviceConfiguration), std::move(rails));
+                std::move(deviceConfiguration), std::move(phaseFaultDetection),
+                std::move(rails));
             devices.emplace_back(std::move(device));
         }
 
@@ -538,6 +543,7 @@
                 createI2CInterface();
             std::unique_ptr<PresenceDetection> presenceDetection{};
             std::unique_ptr<Configuration> deviceConfiguration{};
+            std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
             std::vector<std::unique_ptr<Rail>> rails{};
             rails.emplace_back(std::move(rail));
             std::unique_ptr<Device> device = std::make_unique<Device>(
@@ -545,7 +551,8 @@
                 "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
                 "vdd1_reg",
                 std::move(i2cInterface), std::move(presenceDetection),
-                std::move(deviceConfiguration), std::move(rails));
+                std::move(deviceConfiguration), std::move(phaseFaultDetection),
+                std::move(rails));
             devices.emplace_back(std::move(device));
         }
 
diff --git a/phosphor-regulators/test/config_file_parser_tests.cpp b/phosphor-regulators/test/config_file_parser_tests.cpp
index 79e2cf4..c17703a 100644
--- a/phosphor-regulators/test/config_file_parser_tests.cpp
+++ b/phosphor-regulators/test/config_file_parser_tests.cpp
@@ -1532,6 +1532,7 @@
         EXPECT_NE(&(device->getI2CInterface()), nullptr);
         EXPECT_EQ(device->getPresenceDetection(), nullptr);
         EXPECT_EQ(device->getConfiguration(), nullptr);
+        EXPECT_EQ(device->getPhaseFaultDetection(), nullptr);
         EXPECT_EQ(device->getRails().size(), 0);
     }
 
@@ -1539,6 +1540,7 @@
     {
         const json element = R"(
             {
+              "comments": [ "VDD Regulator" ],
               "id": "vdd_regulator",
               "is_regulator": true,
               "fru": "system/chassis/motherboard/regulator2",
@@ -1547,13 +1549,17 @@
                   "bus": 1,
                   "address": "0x70"
               },
+              "presence_detection":
+              {
+                  "rule_id": "is_foobar_backplane_installed_rule"
+              },
               "configuration":
               {
                   "rule_id": "configure_ir35221_rule"
               },
-              "presence_detection":
+              "phase_fault_detection":
               {
-                  "rule_id": "is_foobar_backplane_installed_rule"
+                  "rule_id": "detect_phase_fault_rule"
               },
               "rails":
               [
@@ -1571,9 +1577,39 @@
         EXPECT_NE(&(device->getI2CInterface()), nullptr);
         EXPECT_NE(device->getPresenceDetection(), nullptr);
         EXPECT_NE(device->getConfiguration(), nullptr);
+        EXPECT_NE(device->getPhaseFaultDetection(), nullptr);
         EXPECT_EQ(device->getRails().size(), 1);
     }
 
+    // Test where fails: phase_fault_detection property exists and is_regulator
+    // is false
+    try
+    {
+        const json element = R"(
+            {
+              "id": "vdd_regulator",
+              "is_regulator": false,
+              "fru": "system/chassis/motherboard/regulator2",
+              "i2c_interface":
+              {
+                  "bus": 1,
+                  "address": "0x70"
+              },
+              "phase_fault_detection":
+              {
+                  "rule_id": "detect_phase_fault_rule"
+              }
+            }
+        )"_json;
+        parseDevice(element);
+        ADD_FAILURE() << "Should not have reached this line.";
+    }
+    catch (const std::invalid_argument& e)
+    {
+        EXPECT_STREQ(e.what(), "Invalid phase_fault_detection property when "
+                               "is_regulator is false");
+    }
+
     // Test where fails: rails property exists and is_regulator is false
     try
     {
diff --git a/phosphor-regulators/test/configuration_tests.cpp b/phosphor-regulators/test/configuration_tests.cpp
index 2f4ded6..c285480 100644
--- a/phosphor-regulators/test/configuration_tests.cpp
+++ b/phosphor-regulators/test/configuration_tests.cpp
@@ -24,6 +24,7 @@
 #include "mock_journal.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
+#include "phase_fault_detection.hpp"
 #include "pmbus_utils.hpp"
 #include "pmbus_write_vout_command_action.hpp"
 #include "presence_detection.hpp"
@@ -305,13 +306,15 @@
         // Create Device that contains Rail
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -374,13 +377,15 @@
         // Create Device that contains Rail
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -450,13 +455,15 @@
         // Create Device that contains Rail
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
diff --git a/phosphor-regulators/test/device_tests.cpp b/phosphor-regulators/test/device_tests.cpp
index bda036f..49a8a8d 100644
--- a/phosphor-regulators/test/device_tests.cpp
+++ b/phosphor-regulators/test/device_tests.cpp
@@ -25,6 +25,7 @@
 #include "mock_sensors.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
+#include "phase_fault_detection.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
@@ -73,6 +74,7 @@
         EXPECT_EQ(&(device.getI2CInterface()), i2cInterfacePtr);
         EXPECT_EQ(device.getPresenceDetection(), nullptr);
         EXPECT_EQ(device.getConfiguration(), nullptr);
+        EXPECT_EQ(device.getPhaseFaultDetection(), nullptr);
         EXPECT_EQ(device.getRails().size(), 0);
     }
 
@@ -96,6 +98,14 @@
         std::unique_ptr<Configuration> configuration =
             std::make_unique<Configuration>(volts, std::move(actions));
 
+        // Create PhaseFaultDetection
+        actions.clear();
+        actions.push_back(std::make_unique<MockAction>());
+        actions.push_back(std::make_unique<MockAction>());
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection =
+            std::make_unique<PhaseFaultDetection>(std::move(actions));
+
         // Create vector of Rail objects
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.push_back(std::make_unique<Rail>("vdd0"));
@@ -109,6 +119,7 @@
             std::move(i2cInterface),
             std::move(presenceDetection),
             std::move(configuration),
+            std::move(phaseFaultDetection),
             std::move(rails)};
         EXPECT_EQ(device.getID(), "vdd_reg");
         EXPECT_EQ(device.isRegulator(), false);
@@ -121,6 +132,8 @@
         EXPECT_NE(device.getConfiguration(), nullptr);
         EXPECT_EQ(device.getConfiguration()->getVolts().has_value(), false);
         EXPECT_EQ(device.getConfiguration()->getActions().size(), 2);
+        EXPECT_NE(device.getPhaseFaultDetection(), nullptr);
+        EXPECT_EQ(device.getPhaseFaultDetection()->getActions().size(), 3);
         EXPECT_EQ(device.getRails().size(), 2);
     }
 }
@@ -129,6 +142,7 @@
 {
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> configuration{};
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
 
     // Create vector of Rail objects
     std::vector<std::unique_ptr<Rail>> rails{};
@@ -143,6 +157,7 @@
         std::move(createI2CInterface()),
         std::move(presenceDetection),
         std::move(configuration),
+        std::move(phaseFaultDetection),
         std::move(rails)};
 
     // Add Device and Rail objects to an IDMap
@@ -239,13 +254,15 @@
         std::make_unique<i2c::MockedI2CInterface>();
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> deviceConfiguration{};
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
     std::vector<std::unique_ptr<Rail>> rails{};
     rails.emplace_back(std::move(rail));
     std::unique_ptr<Device> device = std::make_unique<Device>(
         "reg1", true,
         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
         std::move(i2cInterface), std::move(presenceDetection),
-        std::move(deviceConfiguration), std::move(rails));
+        std::move(deviceConfiguration), std::move(phaseFaultDetection),
+        std::move(rails));
     Device* devicePtr = device.get();
 
     // Create Chassis that contains Device
@@ -535,11 +552,13 @@
         // Create Device
         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
         std::unique_ptr<PresenceDetection> presenceDetection{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(configuration), std::move(rails));
+            std::move(configuration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -628,6 +647,41 @@
     EXPECT_EQ(device.getID(), "vdd_reg");
 }
 
+TEST(DeviceTests, GetPhaseFaultDetection)
+{
+    // Test where PhaseFaultDetection was not specified in constructor
+    {
+        Device device{
+            "vdd_reg", true,
+            "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
+            std::move(createI2CInterface())};
+        EXPECT_EQ(device.getPhaseFaultDetection(), nullptr);
+    }
+
+    // Test where PhaseFaultDetection was specified in constructor
+    {
+        // Create PhaseFaultDetection
+        std::vector<std::unique_ptr<Action>> actions{};
+        actions.push_back(std::make_unique<MockAction>());
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection =
+            std::make_unique<PhaseFaultDetection>(std::move(actions));
+
+        // Create Device
+        std::unique_ptr<PresenceDetection> presenceDetection{};
+        std::unique_ptr<Configuration> configuration{};
+        Device device{
+            "vdd_reg",
+            false,
+            "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
+            std::move(createI2CInterface()),
+            std::move(presenceDetection),
+            std::move(configuration),
+            std::move(phaseFaultDetection)};
+        EXPECT_NE(device.getPhaseFaultDetection(), nullptr);
+        EXPECT_EQ(device.getPhaseFaultDetection()->getActions().size(), 1);
+    }
+}
+
 TEST(DeviceTests, GetPresenceDetection)
 {
     // Test where PresenceDetection was not specified in constructor
@@ -672,6 +726,7 @@
     {
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> configuration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
 
         // Create vector of Rail objects
         std::vector<std::unique_ptr<Rail>> rails{};
@@ -686,6 +741,7 @@
             std::move(createI2CInterface()),
             std::move(presenceDetection),
             std::move(configuration),
+            std::move(phaseFaultDetection),
             std::move(rails)};
         EXPECT_EQ(device.getRails().size(), 2);
         EXPECT_EQ(device.getRails()[0]->getID(), "vdd0");
@@ -846,13 +902,15 @@
         // Create Device
         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -964,11 +1022,13 @@
         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> configuration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(configuration), std::move(rails));
+            std::move(configuration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
diff --git a/phosphor-regulators/test/rail_tests.cpp b/phosphor-regulators/test/rail_tests.cpp
index ab34d20..db4294f 100644
--- a/phosphor-regulators/test/rail_tests.cpp
+++ b/phosphor-regulators/test/rail_tests.cpp
@@ -24,6 +24,7 @@
 #include "mock_sensors.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
+#include "phase_fault_detection.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
@@ -111,13 +112,15 @@
         std::make_unique<i2c::MockedI2CInterface>();
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> deviceConfiguration{};
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
     std::vector<std::unique_ptr<Rail>> rails{};
     rails.emplace_back(std::move(rail));
     std::unique_ptr<Device> device = std::make_unique<Device>(
         "reg1", true,
         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
         std::move(i2cInterface), std::move(presenceDetection),
-        std::move(deviceConfiguration), std::move(rails));
+        std::move(deviceConfiguration), std::move(phaseFaultDetection),
+        std::move(rails));
     Device* devicePtr = device.get();
 
     // Create Chassis that contains Device
@@ -189,13 +192,15 @@
             std::make_unique<i2c::MockedI2CInterface>();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -243,13 +248,15 @@
             std::make_unique<i2c::MockedI2CInterface>();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -322,13 +329,15 @@
             std::make_unique<i2c::MockedI2CInterface>();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
@@ -381,13 +390,15 @@
             std::make_unique<i2c::MockedI2CInterface>();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
             "reg1", true,
             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
         Device* devicePtr = device.get();
 
         // Create Chassis that contains Device
diff --git a/phosphor-regulators/test/sensor_monitoring_tests.cpp b/phosphor-regulators/test/sensor_monitoring_tests.cpp
index 6ed7e86..b8d56ff 100644
--- a/phosphor-regulators/test/sensor_monitoring_tests.cpp
+++ b/phosphor-regulators/test/sensor_monitoring_tests.cpp
@@ -24,6 +24,7 @@
 #include "mock_sensors.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
+#include "phase_fault_detection.hpp"
 #include "pmbus_read_sensor_action.hpp"
 #include "pmbus_utils.hpp"
 #include "presence_detection.hpp"
@@ -87,13 +88,15 @@
     // Create Device that contains Rail
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> deviceConfiguration{};
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
     std::vector<std::unique_ptr<Rail>> rails{};
     rails.emplace_back(std::move(rail));
     std::unique_ptr<Device> device = std::make_unique<Device>(
         "vdd_reg", true,
         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg2",
         std::move(i2cInterface), std::move(presenceDetection),
-        std::move(deviceConfiguration), std::move(rails));
+        std::move(deviceConfiguration), std::move(phaseFaultDetection),
+        std::move(rails));
     Device* devicePtr = device.get();
 
     // Create Chassis that contains Device
diff --git a/phosphor-regulators/test/system_tests.cpp b/phosphor-regulators/test/system_tests.cpp
index 441bbfe..f75b62b 100644
--- a/phosphor-regulators/test/system_tests.cpp
+++ b/phosphor-regulators/test/system_tests.cpp
@@ -25,6 +25,7 @@
 #include "mock_sensors.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
+#include "phase_fault_detection.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
@@ -142,13 +143,15 @@
         std::make_unique<i2c::MockedI2CInterface>();
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> deviceConfiguration{};
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
     std::vector<std::unique_ptr<Rail>> rails{};
     rails.emplace_back(std::move(rail));
     std::unique_ptr<Device> device = std::make_unique<Device>(
         "reg1", true,
         "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
         std::move(i2cInterface), std::move(presenceDetection),
-        std::move(deviceConfiguration), std::move(rails));
+        std::move(deviceConfiguration), std::move(phaseFaultDetection),
+        std::move(rails));
 
     // Create Chassis that contains Device
     std::vector<std::unique_ptr<Device>> devices{};
@@ -374,6 +377,7 @@
         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
@@ -381,7 +385,8 @@
             "/xyz/openbmc_project/inventory/system/chassis1/motherboard/"
             "vdd0_reg",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
 
         // Create Chassis
         std::vector<std::unique_ptr<Device>> devices{};
@@ -410,6 +415,7 @@
         std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
         std::unique_ptr<PresenceDetection> presenceDetection{};
         std::unique_ptr<Configuration> deviceConfiguration{};
+        std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
         std::vector<std::unique_ptr<Rail>> rails{};
         rails.emplace_back(std::move(rail));
         std::unique_ptr<Device> device = std::make_unique<Device>(
@@ -417,7 +423,8 @@
             "/xyz/openbmc_project/inventory/system/chassis2/motherboard/"
             "vdd0_reg",
             std::move(i2cInterface), std::move(presenceDetection),
-            std::move(deviceConfiguration), std::move(rails));
+            std::move(deviceConfiguration), std::move(phaseFaultDetection),
+            std::move(rails));
 
         // Create Chassis
         std::vector<std::unique_ptr<Device>> devices{};
diff --git a/phosphor-regulators/test/test_utils.hpp b/phosphor-regulators/test/test_utils.hpp
index 2903d3c..e04dd6d 100644
--- a/phosphor-regulators/test/test_utils.hpp
+++ b/phosphor-regulators/test/test_utils.hpp
@@ -19,6 +19,7 @@
 #include "device.hpp"
 #include "i2c_interface.hpp"
 #include "mock_action.hpp"
+#include "phase_fault_detection.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
@@ -72,10 +73,11 @@
     std::unique_ptr<i2c::I2CInterface> i2cInterface = createI2CInterface();
     std::unique_ptr<PresenceDetection> presenceDetection{};
     std::unique_ptr<Configuration> configuration{};
-    return std::make_unique<Device>(id, isRegulator, fru,
-                                    std::move(i2cInterface),
-                                    std::move(presenceDetection),
-                                    std::move(configuration), std::move(rails));
+    std::unique_ptr<PhaseFaultDetection> phaseFaultDetection{};
+    return std::make_unique<Device>(
+        id, isRegulator, fru, std::move(i2cInterface),
+        std::move(presenceDetection), std::move(configuration),
+        std::move(phaseFaultDetection), std::move(rails));
 }
 
 /**