Update Submit Test event feature to send custom data

Changes Added : Updated the submit test event feature to send test
data as per spec

https://www.dmtf.org/sites/default/files/standards/documents/
DSP2046_2019.1.pdf


Testing :

Tested sending custom test data
and same data received at the event listener
Change-Id: I2c2363a676aafd39c121c9fe4e16402c0f5961e2
Signed-off-by: Chandramohan Harkude <chandramohan.harkude@gmail.com>
diff --git a/Redfish.md b/Redfish.md
index cd5b726..f561f2f 100644
--- a/Redfish.md
+++ b/Redfish.md
@@ -466,6 +466,16 @@
 #### EventService
 
 - Actions
+- SubmitTestEvent
+  - eventGroupId
+  - eventId
+  - eventTimestamp
+  - message
+  - messageArgs
+  - messageId
+  - originOfCondition
+  - resolution
+  - severity
 - DeliveryRetryAttempts
   - Defaults to 3
 - DeliveryRetryIntervalSeconds
diff --git a/meson.build b/meson.build
index 093e60f..d3833bc 100644
--- a/meson.build
+++ b/meson.build
@@ -436,6 +436,7 @@
     'test/include/str_utility_test.cpp',
     'test/redfish-core/include/event_log_test.cpp',
     'test/redfish-core/include/event_matches_filter_test.cpp',
+    'test/redfish-core/include/submit_test_event_test.cpp',
     'test/redfish-core/include/filter_expr_executor_test.cpp',
     'test/redfish-core/include/filter_expr_parser_test.cpp',
     'test/redfish-core/include/privileges_test.cpp',
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index ad756df..c05417c 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -588,12 +588,12 @@
         return idList;
     }
 
-    bool sendTestEventLog()
+    bool sendTestEventLog(TestEvent& testEvent)
     {
         for (const auto& it : subscriptionsMap)
         {
             std::shared_ptr<Subscription> entry = it.second;
-            if (!entry->sendTestEventLog())
+            if (!entry->sendTestEventLog(testEvent))
             {
                 return false;
             }
diff --git a/redfish-core/include/subscription.hpp b/redfish-core/include/subscription.hpp
index d1c3ab8..2f93f74 100644
--- a/redfish-core/include/subscription.hpp
+++ b/redfish-core/include/subscription.hpp
@@ -33,6 +33,30 @@
 
 static constexpr const uint8_t maxNoOfSubscriptions = 20;
 static constexpr const uint8_t maxNoOfSSESubscriptions = 10;
+struct TestEvent
+{
+    std::optional<int64_t> eventGroupId;
+    std::optional<std::string> eventId;
+    std::optional<std::string> eventTimestamp;
+    std::optional<std::string> message;
+    std::optional<std::vector<std::string>> messageArgs;
+    std::optional<std::string> messageId;
+    std::optional<std::string> originOfCondition;
+    std::optional<std::string> resolution;
+    std::optional<std::string> severity;
+    // default constructor
+    TestEvent() = default;
+    // default assignment operator
+    TestEvent& operator=(const TestEvent&) = default;
+    // default copy constructor
+    TestEvent(const TestEvent&) = default;
+    // default move constructor
+    TestEvent(TestEvent&&) = default;
+    // default move assignment operator
+    TestEvent& operator=(TestEvent&&) = default;
+    // default destructor
+    ~TestEvent() = default;
+};
 
 class Subscription : public std::enable_shared_from_this<Subscription>
 {
@@ -62,7 +86,7 @@
 
     bool sendEventToSubscriber(std::string&& msg);
 
-    bool sendTestEventLog();
+    bool sendTestEventLog(TestEvent& testEvent);
 
     void filterAndSendEventLogs(
         const std::vector<EventLogObjectsType>& eventRecords);
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index 57385a2..cf32bcf 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -189,7 +189,27 @@
                 {
                     return;
                 }
-                if (!EventServiceManager::getInstance().sendTestEventLog())
+
+                TestEvent testEvent;
+                // clang-format off
+                if (!json_util::readJsonAction(
+                        req, asyncResp->res,
+                        "EventGroupId", testEvent.eventGroupId,
+                        "EventId", testEvent.eventId,
+                        "EventTimestamp", testEvent.eventTimestamp,
+                        "Message", testEvent.message,
+                        "MessageArgs", testEvent.messageArgs,
+                        "MessageId", testEvent.messageId,
+                        "OriginOfCondition", testEvent.originOfCondition,
+                        "Resolution", testEvent.resolution,
+                        "Severity", testEvent.severity))
+                {
+                    return;
+                }
+                // clang-format on
+
+                if (!EventServiceManager::getInstance().sendTestEventLog(
+                        testEvent))
                 {
                     messages::serviceDisabled(asyncResp->res,
                                               "/redfish/v1/EventService/");
diff --git a/redfish-core/src/subscription.cpp b/redfish-core/src/subscription.cpp
index 821077a..34dc76f 100644
--- a/redfish-core/src/subscription.cpp
+++ b/redfish-core/src/subscription.cpp
@@ -21,7 +21,6 @@
 #include "event_matches_filter.hpp"
 #include "event_service_store.hpp"
 #include "filter_expr_executor.hpp"
-#include "generated/enums/log_entry.hpp"
 #include "heartbeat_messages.hpp"
 #include "http_client.hpp"
 #include "http_response.hpp"
@@ -210,21 +209,57 @@
     return true;
 }
 
-bool Subscription::sendTestEventLog()
+bool Subscription::sendTestEventLog(TestEvent& testEvent)
 {
     nlohmann::json::array_t logEntryArray;
     nlohmann::json& logEntryJson = logEntryArray.emplace_back();
 
-    logEntryJson["EventId"] = "TestID";
-    logEntryJson["Severity"] = log_entry::EventSeverity::OK;
-    logEntryJson["Message"] = "Generated test event";
-    logEntryJson["MessageId"] = "OpenBMC.0.2.TestEventLog";
+    if (testEvent.eventGroupId)
+    {
+        logEntryJson["EventGroupId"] = *testEvent.eventGroupId;
+    }
+
+    if (testEvent.eventId)
+    {
+        logEntryJson["EventId"] = *testEvent.eventId;
+    }
+
+    if (testEvent.eventTimestamp)
+    {
+        logEntryJson["EventTimestamp"] = *testEvent.eventTimestamp;
+    }
+
+    if (testEvent.originOfCondition)
+    {
+        logEntryJson["OriginOfCondition"]["@odata.id"] =
+            *testEvent.originOfCondition;
+    }
+    if (testEvent.severity)
+    {
+        logEntryJson["Severity"] = *testEvent.severity;
+    }
+
+    if (testEvent.message)
+    {
+        logEntryJson["Message"] = *testEvent.message;
+    }
+
+    if (testEvent.resolution)
+    {
+        logEntryJson["Resolution"] = *testEvent.resolution;
+    }
+
+    if (testEvent.messageId)
+    {
+        logEntryJson["MessageId"] = *testEvent.messageId;
+    }
+
+    if (testEvent.messageArgs)
+    {
+        logEntryJson["MessageArgs"] = *testEvent.messageArgs;
+    }
     // MemberId is 0 : since we are sending one event record.
     logEntryJson["MemberId"] = "0";
-    logEntryJson["MessageArgs"] = nlohmann::json::array();
-    logEntryJson["EventTimestamp"] =
-        redfish::time_utils::getDateTimeOffsetNow().first;
-    logEntryJson["Context"] = userSub->customText;
 
     nlohmann::json msg;
     msg["@odata.type"] = "#Event.v1_4_0.Event";
diff --git a/test/redfish-core/include/submit_test_event_test.cpp b/test/redfish-core/include/submit_test_event_test.cpp
new file mode 100644
index 0000000..1451cc4
--- /dev/null
+++ b/test/redfish-core/include/submit_test_event_test.cpp
@@ -0,0 +1,104 @@
+#include "event_service_store.hpp"
+#include "subscription.hpp"
+
+#include <boost/asio/io_context.hpp>
+#include <boost/url/url.hpp>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <gtest/gtest.h>
+namespace redfish
+{
+static TestEvent createTestEvent()
+{
+    TestEvent testEvent;
+    testEvent.eventGroupId = 1;
+    testEvent.eventId = "dummyEvent";
+    testEvent.eventTimestamp = "2021-01";
+    testEvent.message = "Test Message";
+    testEvent.messageArgs = std::vector<std::string>{"arg1", "arg2"};
+    testEvent.messageId = "Dummy message ID";
+    testEvent.originOfCondition = "/redfish/v1/Chassis/GPU_SXM_1";
+    testEvent.resolution = "custom resolution";
+    testEvent.severity = "whatever";
+    return testEvent;
+}
+
+TEST(Subscription, submitTestEVent)
+{
+    boost::asio::io_context io;
+    boost::urls::url url;
+    auto userSubscription =
+        std::make_shared<persistent_data::UserSubscription>();
+    {
+        auto sub = std::make_shared<Subscription>(userSubscription, url, io);
+        TestEvent testEvent;
+        EXPECT_TRUE(sub->sendTestEventLog(testEvent));
+    }
+    {
+        auto sub = std::make_shared<Subscription>(userSubscription, url, io);
+        TestEvent testEvent;
+        testEvent.eventGroupId = 1;
+        testEvent.eventId = "GPU-RST-RECOMM-EVENT";
+        testEvent.eventTimestamp = "2021-01-01T00:00:00Z";
+        testEvent.message = "Custom Message";
+        testEvent.messageArgs =
+            std::vector<std::string>{"GPU_SXM_1", "Restart Recommended"};
+        testEvent.messageId = "Base.1.13.ResetRecommended";
+        testEvent.originOfCondition = "/redfish/v1/Chassis/GPU_SXM_1";
+        testEvent.resolution =
+            "Reset the GPU at the next service window since the ECC errors are contained";
+        testEvent.severity = "Informational";
+        EXPECT_TRUE(sub->sendTestEventLog(testEvent));
+    }
+    {
+        auto sub = std::make_shared<Subscription>(userSubscription, url, io);
+        TestEvent testEvent = createTestEvent();
+
+        bool result = sub->sendTestEventLog(testEvent);
+
+        EXPECT_TRUE(result);
+        if (testEvent.eventGroupId.has_value())
+        {
+            EXPECT_EQ(testEvent.eventGroupId.value(), 1);
+        }
+        if (testEvent.eventId.has_value())
+        {
+            EXPECT_EQ(testEvent.eventId.value(), "dummyEvent");
+        }
+        if (testEvent.eventTimestamp.has_value())
+        {
+            EXPECT_EQ(testEvent.eventTimestamp.value(), "2021-01");
+        }
+        if (testEvent.message.has_value())
+        {
+            EXPECT_EQ(testEvent.message.value(), "Test Message");
+        }
+        if (testEvent.messageArgs.has_value())
+        {
+            EXPECT_EQ(testEvent.messageArgs.value().size(), 2);
+            EXPECT_EQ(testEvent.messageArgs.value()[0], "arg1");
+            EXPECT_EQ(testEvent.messageArgs.value()[1], "arg2");
+        }
+        if (testEvent.messageId.has_value())
+        {
+            EXPECT_EQ(testEvent.messageId.value(), "Dummy message ID");
+        }
+        if (testEvent.originOfCondition.has_value())
+        {
+            EXPECT_EQ(testEvent.originOfCondition.value(),
+                      "/redfish/v1/Chassis/GPU_SXM_1");
+        }
+        if (testEvent.resolution.has_value())
+        {
+            EXPECT_EQ(testEvent.resolution.value(), "custom resolution");
+        }
+        if (testEvent.severity.has_value())
+        {
+            EXPECT_EQ(testEvent.severity.value(), "whatever");
+        }
+    }
+}
+} // namespace redfish