regulators: Close devices when system powering off

Modify the Manager class to close all regulator devices when monitoring
is disabled.  Monitoring is normally disabled because the system is
being powered off.

Also add a closeDevices() method to the System class that closes all
devices in the system.

Tested:
  * Tested when monitoring was disabled.  Verified debug journal message
    stating devices were closed.
  * Tested multiple consecutive power on/off cycles to ensure device
    access remained functional.
  * Performed regression test on existing function.
  * Created and executed automated tests for System::closeDevices()

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I074190454c505116cccf1bc130a70205f34d0e26
diff --git a/phosphor-regulators/src/manager.cpp b/phosphor-regulators/src/manager.cpp
index cbcdec4..10b9de9 100644
--- a/phosphor-regulators/src/manager.cpp
+++ b/phosphor-regulators/src/manager.cpp
@@ -99,22 +99,34 @@
     // fail the call(busctl) to this method
 }
 
-void Manager::monitor(bool /*enable*/)
+void Manager::monitor(bool enable)
 {
-    /* Temporarily comment out until monitoring is supported.
     if (enable)
     {
-        Timer timer(eventLoop, std::bind(&Manager::timerExpired, this));
-        // Set timer as a repeating 1sec timer
-        timer.restart(std::chrono::milliseconds(1000));
-        timers.emplace_back(std::move(timer));
+        /* Temporarily comment out until monitoring is supported.
+            Timer timer(eventLoop, std::bind(&Manager::timerExpired, this));
+            // Set timer as a repeating 1sec timer
+            timer.restart(std::chrono::milliseconds(1000));
+            timers.emplace_back(std::move(timer));
+        */
     }
     else
     {
-        // Delete all timers to disable monitoring
-        timers.clear();
+        /* Temporarily comment out until monitoring is supported.
+            // Delete all timers to disable monitoring
+            timers.clear();
+        */
+
+        // Verify System object exists; this means config file has been loaded
+        if (system)
+        {
+            // Close the regulator devices in the system.  Monitoring is
+            // normally disabled because the system is being powered off.  The
+            // devices should be closed in case hardware is removed or replaced
+            // while the system is at standby.
+            system->closeDevices();
+        }
     }
-    */
 }
 
 void Manager::timerExpired()
diff --git a/phosphor-regulators/src/system.cpp b/phosphor-regulators/src/system.cpp
index 57df6ef..29dad5e 100644
--- a/phosphor-regulators/src/system.cpp
+++ b/phosphor-regulators/src/system.cpp
@@ -34,6 +34,15 @@
     }
 }
 
+void System::closeDevices()
+{
+    // Close devices in each chassis
+    for (std::unique_ptr<Chassis>& oneChassis : chassis)
+    {
+        oneChassis->closeDevices();
+    }
+}
+
 void System::configure()
 {
     // Configure devices in each chassis
diff --git a/phosphor-regulators/src/system.hpp b/phosphor-regulators/src/system.hpp
index 16e55b4..46c3d7c 100644
--- a/phosphor-regulators/src/system.hpp
+++ b/phosphor-regulators/src/system.hpp
@@ -60,6 +60,11 @@
     }
 
     /**
+     * Close the regulator devices in the system.
+     */
+    void closeDevices();
+
+    /**
      * Configure the regulator devices in the system.
      *
      * This method should be called during the boot before regulators are
diff --git a/phosphor-regulators/test/system_tests.cpp b/phosphor-regulators/test/system_tests.cpp
index 85a1da6..dfc22a0 100644
--- a/phosphor-regulators/test/system_tests.cpp
+++ b/phosphor-regulators/test/system_tests.cpp
@@ -58,6 +58,29 @@
     EXPECT_EQ(system.getRules()[0]->getID(), "set_voltage_rule");
 }
 
+TEST(SystemTests, CloseDevices)
+{
+    // Specify an empty rules vector
+    std::vector<std::unique_ptr<Rule>> rules{};
+
+    // Create Chassis
+    std::vector<std::unique_ptr<Chassis>> chassis{};
+    chassis.emplace_back(std::make_unique<Chassis>(1));
+    chassis.emplace_back(std::make_unique<Chassis>(3));
+
+    // Create System
+    System system{std::move(rules), std::move(chassis)};
+
+    // Call closeDevices()
+    journal::clear();
+    system.closeDevices();
+    EXPECT_EQ(journal::getErrMessages().size(), 0);
+    EXPECT_EQ(journal::getInfoMessages().size(), 0);
+    std::vector<std::string> expectedDebugMessages{
+        "Closing devices in chassis 1", "Closing devices in chassis 3"};
+    EXPECT_EQ(journal::getDebugMessages(), expectedDebugMessages);
+}
+
 TEST(SystemTests, Configure)
 {
     // Specify an empty rules vector