psu-ng: Power supply class updates for input history

Update the meson files to include the record_manager with the
phosphor-psu-monitor application.

Since we do not want to blindly enable input history for all power
supplies, base the enablement of the feature off of the driver name.
Change the PowerSupply class to require the driver name be passed in,
and pass that down via the PSUManager during the configuration
determination.

Add a server manager to the PSUManager to handle the INPUT HISTORY data
that will be under /org/open_power/sensors.

The INPUT_HISTORY command is handled via a sysfs file in binary format,
so add in a readBinary() base function to allow for mock testing.

Change-Id: Iea163892d5482e6f2dacacfbfa746f605af52ed5
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/phosphor-power-supply/test/meson.build b/phosphor-power-supply/test/meson.build
index 0350799..ce429d5 100644
--- a/phosphor-power-supply/test/meson.build
+++ b/phosphor-power-supply/test/meson.build
@@ -1,6 +1,7 @@
 test('phosphor-power-supply-tests',
      executable('phosphor-power-supply-tests',
                 'power_supply_tests.cpp',
+                '../record_manager.cpp',
                 'mock.cpp',
                 dependencies: [
                     gmock,
diff --git a/phosphor-power-supply/test/mock.hpp b/phosphor-power-supply/test/mock.hpp
index edfe7a8..1235c01 100644
--- a/phosphor-power-supply/test/mock.hpp
+++ b/phosphor-power-supply/test/mock.hpp
@@ -24,6 +24,9 @@
                 (override));
     MOCK_METHOD(std::string, readString, (const std::string& name, Type type),
                 (override));
+    MOCK_METHOD(std::vector<uint8_t>, readBinary,
+                (const std::string& name, Type type, size_t length),
+                (override));
     MOCK_METHOD(void, writeBinary,
                 (const std::string& name, std::vector<uint8_t> data, Type type),
                 (override));
diff --git a/phosphor-power-supply/test/power_supply_tests.cpp b/phosphor-power-supply/test/power_supply_tests.cpp
index 1ce91f9..88caee8 100644
--- a/phosphor-power-supply/test/power_supply_tests.cpp
+++ b/phosphor-power-supply/test/power_supply_tests.cpp
@@ -1,4 +1,5 @@
 #include "../power_supply.hpp"
+#include "../record_manager.hpp"
 #include "mock.hpp"
 
 #include <xyz/openbmc_project/Common/Device/error.hpp>
@@ -132,8 +133,8 @@
     // Try where inventory path is empty, constructor should fail.
     try
     {
-        auto psu =
-            std::make_unique<PowerSupply>(bus, "", 3, 0x68, PSUGPIOLineName);
+        auto psu = std::make_unique<PowerSupply>(bus, "", 3, 0x68, "ibm-cffps",
+                                                 PSUGPIOLineName);
         ADD_FAILURE() << "Should not have reached this line.";
     }
     catch (const std::invalid_argument& e)
@@ -150,8 +151,8 @@
     // Try where gpioLineName is empty.
     try
     {
-        auto psu =
-            std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68, "");
+        auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68,
+                                                 "ibm-cffps", "");
         ADD_FAILURE()
             << "Should not have reached this line. Invalid gpioLineName.";
     }
@@ -169,7 +170,7 @@
     try
     {
         auto psu = std::make_unique<PowerSupply>(bus, PSUInventoryPath, 3, 0x68,
-                                                 PSUGPIOLineName);
+                                                 "ibm-cffps", PSUGPIOLineName);
 
         EXPECT_EQ(psu->isPresent(), false);
         EXPECT_EQ(psu->isFaulted(), false);
@@ -217,7 +218,8 @@
         // If I default to reading the GPIO, I will NOT expect a call to
         // getPresence().
 
-        PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
+        PowerSupply psu{bus,  PSUInventoryPath, 4,
+                        0x69, "ibm-cffps",      PSUGPIOLineName};
         MockedGPIOInterface* mockPresenceGPIO =
             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
         EXPECT_CALL(*mockPresenceGPIO, read()).Times(1).WillOnce(Return(0));
@@ -241,7 +243,8 @@
         EXPECT_EQ(psu.hasPSCS12VFault(), false);
     }
 
-    PowerSupply psu2{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
+    PowerSupply psu2{bus,  PSUInventoryPath, 5,
+                     0x6a, "ibm-cffps",      PSUGPIOLineName};
     // In order to get the various faults tested, the power supply needs to
     // be present in order to read from the PMBus device(s).
     MockedGPIOInterface* mockPresenceGPIO2 =
@@ -724,7 +727,8 @@
     {
         // Assume GPIO presence, not inventory presence?
         EXPECT_CALL(mockedUtil, setAvailable(_, _, _)).Times(0);
-        PowerSupply psu{bus, PSUInventoryPath, 4, 0x69, PSUGPIOLineName};
+        PowerSupply psu{bus,  PSUInventoryPath, 4,
+                        0x69, "ibm-cffps",      PSUGPIOLineName};
 
         MockedGPIOInterface* mockPresenceGPIO =
             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
@@ -743,7 +747,8 @@
     {
         // Assume GPIO presence, not inventory presence?
         EXPECT_CALL(mockedUtil, setAvailable(_, _, true));
-        PowerSupply psu{bus, PSUInventoryPath, 5, 0x6a, PSUGPIOLineName};
+        PowerSupply psu{bus,  PSUInventoryPath, 5,
+                        0x6a, "ibm-cffps",      PSUGPIOLineName};
         MockedGPIOInterface* mockPresenceGPIO =
             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
         // There will potentially be multiple calls, we want it to continue
@@ -772,7 +777,8 @@
 TEST_F(PowerSupplyTests, ClearFaults)
 {
     auto bus = sdbusplus::bus::new_default();
-    PowerSupply psu{bus, PSUInventoryPath, 13, 0x68, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 13,
+                    0x68, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -992,7 +998,8 @@
 
     try
     {
-        PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
+        PowerSupply psu{bus,  PSUInventoryPath, 3,
+                        0x68, "ibm-cffps",      PSUGPIOLineName};
         MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
         // If it is not present, I should not be trying to read a string
         EXPECT_CALL(mockPMBus, readString(_, _)).Times(0);
@@ -1005,7 +1012,8 @@
 
     try
     {
-        PowerSupply psu{bus, PSUInventoryPath, 13, 0x69, PSUGPIOLineName};
+        PowerSupply psu{bus,  PSUInventoryPath, 13,
+                        0x69, "ibm-cffps",      PSUGPIOLineName};
         MockedGPIOInterface* mockPresenceGPIO =
             static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
         // GPIO read return 1 to indicate present.
@@ -1046,7 +1054,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x68, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     EXPECT_EQ(psu.isPresent(), false);
@@ -1074,7 +1083,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 11, 0x6f, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 11,
+                    0x6f, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1127,7 +1137,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x68, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1177,7 +1188,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x68, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1221,7 +1233,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x68, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x68, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1285,7 +1298,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x69, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x69, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1329,7 +1343,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x6d, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x6d, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1378,7 +1393,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x6a, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x6a, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1425,7 +1441,8 @@
     EXPECT_CALL(mockedUtil, setAvailable(_, _, true)).Times(1);
     EXPECT_CALL(mockedUtil, setAvailable(_, _, false)).Times(0);
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x6d, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x6d, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1474,7 +1491,8 @@
     EXPECT_CALL(mockedUtil, setAvailable(_, _, true)).Times(1);
     EXPECT_CALL(mockedUtil, setAvailable(_, _, false)).Times(0);
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x6a, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x6a, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1520,7 +1538,8 @@
 {
     auto bus = sdbusplus::bus::new_default();
 
-    PowerSupply psu{bus, PSUInventoryPath, 3, 0x6b, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 3,
+                    0x6b, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1622,7 +1641,8 @@
 TEST_F(PowerSupplyTests, HasPSKillFault)
 {
     auto bus = sdbusplus::bus::new_default();
-    PowerSupply psu{bus, PSUInventoryPath, 4, 0x6d, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 4,
+                    0x6d, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1705,7 +1725,8 @@
 TEST_F(PowerSupplyTests, HasPS12VcsFault)
 {
     auto bus = sdbusplus::bus::new_default();
-    PowerSupply psu{bus, PSUInventoryPath, 5, 0x6e, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 5,
+                    0x6e, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1772,7 +1793,8 @@
 TEST_F(PowerSupplyTests, HasPSCS12VFault)
 {
     auto bus = sdbusplus::bus::new_default();
-    PowerSupply psu{bus, PSUInventoryPath, 6, 0x6f, PSUGPIOLineName};
+    PowerSupply psu{bus,  PSUInventoryPath, 6,
+                    0x6f, "ibm-cffps",      PSUGPIOLineName};
     MockedGPIOInterface* mockPresenceGPIO =
         static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
     // Always return 1 to indicate present.
@@ -1834,3 +1856,115 @@
     psu.analyze();
     EXPECT_EQ(psu.hasPSCS12VFault(), false);
 }
+
+TEST_F(PowerSupplyTests, SetupInputHistory)
+{
+    auto bus = sdbusplus::bus::new_default();
+    {
+        PowerSupply psu{bus,  PSUInventoryPath, 6,
+                        0x6f, "ibm-cffps",      PSUGPIOLineName};
+        // Defaults to not present due to constructor and mock ordering.
+        psu.setupInputHistory();
+        EXPECT_EQ(psu.hasInputHistory(), false);
+        MockedGPIOInterface* mockPresenceGPIO =
+            static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+        // Always return 1 to indicate present.
+        EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+        psu.analyze();
+        psu.setupInputHistory();
+        EXPECT_EQ(psu.hasInputHistory(), true);
+    }
+    {
+        PowerSupply psu{bus,  PSUInventoryPath, 11,
+                        0x58, "inspur-ipsps",   PSUGPIOLineName};
+        // Defaults to not present due to constructor and mock ordering.
+        psu.setupInputHistory();
+        EXPECT_EQ(psu.hasInputHistory(), false);
+        MockedGPIOInterface* mockPresenceGPIO =
+            static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+        // Always return 1 to indicate present.
+        EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+        psu.analyze();
+        psu.setupInputHistory();
+        // After updating to present, and retrying setup, expect inspur-ipsps to
+        // still not support INPUT_HISTORY.
+        EXPECT_EQ(psu.hasInputHistory(), false);
+    }
+}
+
+TEST_F(PowerSupplyTests, UpdateHistory)
+{
+    auto bus = sdbusplus::bus::new_default();
+    PowerSupply psu{bus,  PSUInventoryPath, 7,
+                    0x6e, "ibm-cffps",      PSUGPIOLineName};
+    EXPECT_EQ(psu.hasInputHistory(), false);
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 0);
+    MockedGPIOInterface* mockPresenceGPIO =
+        static_cast<MockedGPIOInterface*>(psu.getPresenceGPIO());
+    // Always return 1 to indicate present.
+    EXPECT_CALL(*mockPresenceGPIO, read()).WillRepeatedly(Return(1));
+    MockedPMBus& mockPMBus = static_cast<MockedPMBus&>(psu.getPMBus());
+    setMissingToPresentExpects(mockPMBus, mockedUtil);
+    PMBusExpectations expectations;
+    setPMBusExpectations(mockPMBus, expectations);
+    EXPECT_CALL(mockPMBus, readString(READ_VIN, _))
+        .Times(6)
+        .WillRepeatedly(Return("205000"));
+    EXPECT_CALL(mockedUtil, setAvailable(_, _, true));
+    // First read after missing/present will have no data.
+    std::vector<uint8_t> emptyHistory{};
+    // Second read, after about 30 seconds, should have a record. 5-bytes.
+    // Sequence Number: 0x00, Average: 0x50 0xf3 (212), Maximum: 0x54 0xf3 (213)
+    std::vector<uint8_t> firstHistory{0x00, 0x50, 0xf3, 0x54, 0xf3};
+    // Third read, after about 60 seconds, should have two records, 10-bytes,
+    // but only reading 5 bytes, so make sure new/next sequence number
+    std::vector<uint8_t> secondHistory{0x01, 0x54, 0xf3, 0x58, 0xf3};
+    // Fourth read, 3rd sequence number (0x02).
+    std::vector<uint8_t> thirdHistory{0x02, 0x54, 0xf3, 0x58, 0xf3};
+    // Fifth read, out of sequence, clear and insert this one?
+    std::vector<uint8_t> outseqHistory{0xff, 0x5c, 0xf3, 0x60, 0xf3};
+    EXPECT_CALL(
+        mockPMBus,
+        readBinary(INPUT_HISTORY, Type::HwmonDeviceDebug,
+                   phosphor::power::history::RecordManager::RAW_RECORD_SIZE))
+        .Times(6)
+        .WillOnce(Return(emptyHistory))
+        .WillOnce(Return(firstHistory))
+        .WillOnce(Return(secondHistory))
+        .WillOnce(Return(thirdHistory))
+        .WillOnce(Return(outseqHistory))
+        .WillOnce(Return(emptyHistory));
+    // Calling analyze will update the presence, which will setup the input
+    // history if the power supply went from missing to present.
+    psu.analyze();
+    // The ibm-cffps power supply should support input history
+    EXPECT_EQ(psu.hasInputHistory(), true);
+    // Usually should have empty buffer right after missing to present.
+    // Faked that out above with mocked readBinary with emptyHistory data.
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 0);
+    // Second run through...
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasInputHistory(), true);
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 1);
+    // Third run through
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasInputHistory(), true);
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 2);
+    // Fourth run through. Up to 3 records now?
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasInputHistory(), true);
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 3);
+    // Out of sequencer, reset, insert new one.
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasInputHistory(), true);
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 1);
+    // Empty one after last one good. Reset/clear.
+    setPMBusExpectations(mockPMBus, expectations);
+    psu.analyze();
+    EXPECT_EQ(psu.hasInputHistory(), true);
+    EXPECT_EQ(psu.getNumInputHistoryRecords(), 0);
+}