regulators: Complete SensorMonitoring class

Complete the SensorMonitoring class.  This class implements the
"sensor_monitoring" object in the JSON config file.

Add calls to the startRail() and endRail() methods of the Sensors
service.

Add ErrorHistory data member so that errors are only logged once per
boot since sensor monitoring occurs repeatedly once per second.

Add error count data member to limit the number of error messages
written to the journal since monitoring occurs repeatedly.

Update all affected test cases.

Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
Change-Id: I0bd20d03ccea9e15cd0f97529f6ccdad2fa015c8
diff --git a/phosphor-regulators/test/chassis_tests.cpp b/phosphor-regulators/test/chassis_tests.cpp
index c04e917..def281c 100644
--- a/phosphor-regulators/test/chassis_tests.cpp
+++ b/phosphor-regulators/test/chassis_tests.cpp
@@ -19,13 +19,15 @@
 #include "device.hpp"
 #include "i2c_interface.hpp"
 #include "id_map.hpp"
+#include "mock_action.hpp"
 #include "mock_journal.hpp"
+#include "mock_sensors.hpp"
 #include "mock_services.hpp"
 #include "mocked_i2c_interface.hpp"
-#include "pmbus_read_sensor_action.hpp"
 #include "presence_detection.hpp"
 #include "rail.hpp"
 #include "rule.hpp"
+#include "sensor_monitoring.hpp"
 #include "sensors.hpp"
 #include "system.hpp"
 #include "test_utils.hpp"
@@ -361,16 +363,16 @@
 {
     // Test where no devices were specified in constructor
     {
-        // Create mock services.  No logging should occur.
+        // Create mock services.  No Sensors methods should be called.
         MockServices services{};
-        MockJournal& journal = services.getMockJournal();
-        EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
-        EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
+        MockSensors& sensors = services.getMockSensors();
+        EXPECT_CALL(sensors, startRail).Times(0);
+        EXPECT_CALL(sensors, setValue).Times(0);
+        EXPECT_CALL(sensors, endRail).Times(0);
 
         // Create Chassis
-        std::vector<std::unique_ptr<Device>> devices{};
-        std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(
-            1, defaultInventoryPath, std::move(devices));
+        std::unique_ptr<Chassis> chassis =
+            std::make_unique<Chassis>(1, defaultInventoryPath);
         Chassis* chassisPtr = chassis.get();
 
         // Create System that contains Chassis
@@ -385,57 +387,89 @@
 
     // Test where devices were specified in constructor
     {
-        // Create mock services.  No logging should occur.
+        // Create mock services.  Set Sensors service expectations.
         MockServices services{};
-        MockJournal& journal = services.getMockJournal();
-        EXPECT_CALL(journal, logDebug(A<const std::string&>())).Times(0);
-        EXPECT_CALL(journal, logError(A<const std::string&>())).Times(0);
+        MockSensors& sensors = services.getMockSensors();
+        EXPECT_CALL(sensors, startRail("vdd0",
+                                       "/xyz/openbmc_project/inventory/system/"
+                                       "chassis/motherboard/vdd0_reg",
+                                       defaultInventoryPath))
+            .Times(1);
+        EXPECT_CALL(sensors, startRail("vdd1",
+                                       "/xyz/openbmc_project/inventory/system/"
+                                       "chassis/motherboard/vdd1_reg",
+                                       defaultInventoryPath))
+            .Times(1);
+        EXPECT_CALL(sensors, setValue).Times(0);
+        EXPECT_CALL(sensors, endRail(false)).Times(2);
 
         std::vector<std::unique_ptr<Device>> devices{};
 
-        // Create PMBusReadSensorAction
-        SensorType type{SensorType::iout};
-        uint8_t command = 0x8C;
-        pmbus_utils::SensorDataFormat format{
-            pmbus_utils::SensorDataFormat::linear_11};
-        std::optional<int8_t> exponent{};
-        std::unique_ptr<PMBusReadSensorAction> action =
-            std::make_unique<PMBusReadSensorAction>(type, command, format,
-                                                    exponent);
+        // Create Device vdd0_reg
+        {
+            // Create SensorMonitoring for Rail
+            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<SensorMonitoring> sensorMonitoring =
+                std::make_unique<SensorMonitoring>(std::move(actions));
 
-        // Create mock I2CInterface.  A two-byte read should occur.
-        std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
-            std::make_unique<i2c::MockedI2CInterface>();
-        EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
-        EXPECT_CALL(*i2cInterface, read(TypedEq<uint8_t>(0x8C), A<uint16_t&>()))
-            .Times(1);
+            // Create Rail
+            std::unique_ptr<Configuration> configuration{};
+            std::unique_ptr<Rail> rail = std::make_unique<Rail>(
+                "vdd0", std::move(configuration), std::move(sensorMonitoring));
 
-        // Create SensorMonitoring
-        std::vector<std::unique_ptr<Action>> actions{};
-        actions.emplace_back(std::move(action));
-        std::unique_ptr<SensorMonitoring> sensorMonitoring =
-            std::make_unique<SensorMonitoring>(std::move(actions));
+            // Create Device
+            std::unique_ptr<i2c::I2CInterface> i2cInterface =
+                createI2CInterface();
+            std::unique_ptr<PresenceDetection> presenceDetection{};
+            std::unique_ptr<Configuration> deviceConfiguration{};
+            std::vector<std::unique_ptr<Rail>> rails{};
+            rails.emplace_back(std::move(rail));
+            std::unique_ptr<Device> device = std::make_unique<Device>(
+                "vdd0_reg", true,
+                "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
+                "vdd0_reg",
+                std::move(i2cInterface), std::move(presenceDetection),
+                std::move(deviceConfiguration), std::move(rails));
+            devices.emplace_back(std::move(device));
+        }
 
-        // Create Rail
-        std::vector<std::unique_ptr<Rail>> rails{};
-        std::unique_ptr<Configuration> configuration{};
-        std::unique_ptr<Rail> rail = std::make_unique<Rail>(
-            "vdd0", std::move(configuration), std::move(sensorMonitoring));
-        rails.emplace_back(std::move(rail));
+        // Create Device vdd1_reg
+        {
+            // Create SensorMonitoring for Rail
+            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<SensorMonitoring> sensorMonitoring =
+                std::make_unique<SensorMonitoring>(std::move(actions));
 
-        // Create Device
-        std::unique_ptr<PresenceDetection> presenceDetection{};
-        std::unique_ptr<Configuration> deviceConfiguration{};
-        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));
+            // Create Rail
+            std::unique_ptr<Configuration> configuration{};
+            std::unique_ptr<Rail> rail = std::make_unique<Rail>(
+                "vdd1", std::move(configuration), std::move(sensorMonitoring));
 
-        // Create Chassis
-        devices.emplace_back(std::move(device));
+            // Create Device
+            std::unique_ptr<i2c::I2CInterface> i2cInterface =
+                createI2CInterface();
+            std::unique_ptr<PresenceDetection> presenceDetection{};
+            std::unique_ptr<Configuration> deviceConfiguration{};
+            std::vector<std::unique_ptr<Rail>> rails{};
+            rails.emplace_back(std::move(rail));
+            std::unique_ptr<Device> device = std::make_unique<Device>(
+                "vdd1_reg", true,
+                "/xyz/openbmc_project/inventory/system/chassis/motherboard/"
+                "vdd1_reg",
+                std::move(i2cInterface), std::move(presenceDetection),
+                std::move(deviceConfiguration), std::move(rails));
+            devices.emplace_back(std::move(device));
+        }
+
+        // Create Chassis that contains Devices
         std::unique_ptr<Chassis> chassis = std::make_unique<Chassis>(
-            1, defaultInventoryPath, std::move(devices));
+            2, defaultInventoryPath, std::move(devices));
         Chassis* chassisPtr = chassis.get();
 
         // Create System that contains Chassis