pldm_events: Implement support for state sensorEvents

PLDM supports platform event message by which events can be generated
by a PLDM entity and can be processed by event receiver like BMC. This
patch adds support for remote state sensors which sends PlatformEventMessage
command with sensorEvent type. The sensor is mapped to a D-Bus property
and the eventState is mapped to a D-Bus property value.

Signed-off-by: Tom Joseph <tomjoseph@in.ibm.com>
Change-Id: I50dea23eccbdf29ad1b4cf2c9ab5700d74c12c68
diff --git a/test/libpldmresponder_platform_test.cpp b/test/libpldmresponder_platform_test.cpp
index 9af13d5..f487d3b 100644
--- a/test/libpldmresponder_platform_test.cpp
+++ b/test/libpldmresponder_platform_test.cpp
@@ -1,3 +1,4 @@
+#include "libpldmresponder/event_parser.hpp"
 #include "libpldmresponder/pdr.hpp"
 #include "libpldmresponder/pdr_utils.hpp"
 #include "libpldmresponder/platform.hpp"
@@ -26,7 +27,8 @@
     request->request_count = 100;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -57,7 +59,8 @@
     request->request_count = 1;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -82,7 +85,8 @@
     request->request_count = 1;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -105,7 +109,8 @@
     request->record_handle = 1;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -130,7 +135,8 @@
     request->request_count = 100;
 
     auto pdrRepo = pldm_pdr_init();
-    Handler handler("./pdr_jsons/state_effecter/good", pdrRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    pdrRepo, nullptr);
     Repo repo(pdrRepo);
     ASSERT_EQ(repo.empty(), false);
     auto response = handler.getPDR(req, requestPayloadLength);
@@ -181,7 +187,8 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
     pdr_utils::PdrEntry e;
@@ -216,7 +223,8 @@
     auto inPDRRepo = pldm_pdr_init();
     auto outPDRRepo = pldm_pdr_init();
     Repo outRepo(outPDRRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "./event_jsons/good",
+                    inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, outRepo, PLDM_STATE_EFFECTER_PDR);
     pdr_utils::PdrEntry e;
@@ -255,7 +263,7 @@
     auto inPDRRepo = pldm_pdr_init();
     auto numericEffecterPdrRepo = pldm_pdr_init();
     Repo numericEffecterPDRs(numericEffecterPdrRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "", inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
 
@@ -292,7 +300,7 @@
     auto inPDRRepo = pldm_pdr_init();
     auto numericEffecterPdrRepo = pldm_pdr_init();
     Repo numericEffecterPDRs(numericEffecterPdrRepo);
-    Handler handler("./pdr_jsons/state_effecter/good", inPDRRepo, nullptr);
+    Handler handler("./pdr_jsons/state_effecter/good", "", inPDRRepo, nullptr);
     Repo inRepo(inPDRRepo);
     getRepoByType(inRepo, numericEffecterPDRs, PLDM_NUMERIC_EFFECTER_PDR);
 
@@ -384,3 +392,82 @@
     ASSERT_EQ(le16toh(entityInstance3), 2u);
     ASSERT_EQ(states3, statesCmp3);
 }
+
+TEST(StateSensorHandler, allScenarios)
+{
+    using namespace pldm::responder::events;
+
+    ASSERT_THROW(StateSensorHandler("./event_jsons/malformed1"),
+                 std::exception);
+    ASSERT_THROW(StateSensorHandler("./event_jsons/malformed2"),
+                 std::exception);
+
+    StateSensorHandler handler{"./event_jsons/good"};
+    constexpr uint8_t eventState0 = 0;
+    constexpr uint8_t eventState1 = 1;
+    constexpr uint8_t eventState2 = 2;
+    constexpr uint8_t eventState3 = 3;
+
+    // Event Entry 1
+    {
+        StateSensorEntry entry{1, 64, 1, 0};
+        const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+        DBusMapping mapping{"/xyz/abc/def",
+                            "xyz.openbmc_project.example1.value", "value1",
+                            "string"};
+        ASSERT_EQ(mapping == dbusMapping, true);
+
+        const auto& propValue0 = eventStateMap.at(eventState0);
+        const auto& propValue1 = eventStateMap.at(eventState1);
+        const auto& propValue2 = eventStateMap.at(eventState2);
+        PropertyValue value0{std::in_place_type<std::string>,
+                             "xyz.openbmc_project.State.Normal"};
+        PropertyValue value1{std::in_place_type<std::string>,
+                             "xyz.openbmc_project.State.Critical"};
+        PropertyValue value2{std::in_place_type<std::string>,
+                             "xyz.openbmc_project.State.Fatal"};
+        ASSERT_EQ(value0 == propValue0, true);
+        ASSERT_EQ(value1 == propValue1, true);
+        ASSERT_EQ(value2 == propValue2, true);
+    }
+
+    // Event Entry 2
+    {
+        StateSensorEntry entry{1, 64, 1, 1};
+        const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+        DBusMapping mapping{"/xyz/abc/def",
+                            "xyz.openbmc_project.example2.value", "value2",
+                            "uint8_t"};
+        ASSERT_EQ(mapping == dbusMapping, true);
+
+        const auto& propValue0 = eventStateMap.at(eventState2);
+        const auto& propValue1 = eventStateMap.at(eventState3);
+        PropertyValue value0{std::in_place_type<uint8_t>, 9};
+        PropertyValue value1{std::in_place_type<uint8_t>, 10};
+        ASSERT_EQ(value0 == propValue0, true);
+        ASSERT_EQ(value1 == propValue1, true);
+    }
+
+    // Event Entry 3
+    {
+        StateSensorEntry entry{2, 67, 2, 0};
+        const auto& [dbusMapping, eventStateMap] = handler.getEventInfo(entry);
+        DBusMapping mapping{"/xyz/abc/ghi",
+                            "xyz.openbmc_project.example3.value", "value3",
+                            "bool"};
+        ASSERT_EQ(mapping == dbusMapping, true);
+
+        const auto& propValue0 = eventStateMap.at(eventState0);
+        const auto& propValue1 = eventStateMap.at(eventState1);
+        PropertyValue value0{std::in_place_type<bool>, false};
+        PropertyValue value1{std::in_place_type<bool>, true};
+        ASSERT_EQ(value0 == propValue0, true);
+        ASSERT_EQ(value1 == propValue1, true);
+    }
+
+    // Invalid Entry
+    {
+        StateSensorEntry entry{0, 0, 0, 0};
+        ASSERT_THROW(handler.getEventInfo(entry), std::out_of_range);
+    }
+}