Add a class to handle ExternalStorer file writes.

Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Ic1092a6a1da3375f595774018abfecd08a3cb7d8
diff --git a/test/external_storer_file_test.cpp b/test/external_storer_file_test.cpp
new file mode 100644
index 0000000..fc550ee
--- /dev/null
+++ b/test/external_storer_file_test.cpp
@@ -0,0 +1,189 @@
+#include "rde/external_storer_file.hpp"
+
+#include <string_view>
+
+#include <gmock/gmock-matchers.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bios_bmc_smm_error_logger
+{
+namespace rde
+{
+
+using ::testing::_;
+using ::testing::DoAll;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+class MockFileWriter : public FileHandlerInterface
+{
+  public:
+    MOCK_METHOD(bool, createFolder, (const std::string& path),
+                (const, override));
+    MOCK_METHOD(bool, createFile,
+                (const std::string& path, const nlohmann::json& jsonPdr),
+                (const, override));
+};
+
+class ExternalStorerFileTest : public ::testing::Test
+{
+  public:
+    ExternalStorerFileTest() :
+        mockFileWriter(std::make_unique<MockFileWriter>())
+    {
+        mockFileWriterPtr = dynamic_cast<MockFileWriter*>(mockFileWriter.get());
+        exStorer = std::make_unique<ExternalStorerFileInterface>(
+            rootPath, std::move(mockFileWriter));
+    }
+
+  protected:
+    std::unique_ptr<FileHandlerInterface> mockFileWriter;
+    std::unique_ptr<ExternalStorerFileInterface> exStorer;
+    MockFileWriter* mockFileWriterPtr;
+    const std::string rootPath = "/some/path";
+};
+
+TEST_F(ExternalStorerFileTest, InvalidJsonTest)
+{
+    // Try an invalid JSON.
+    std::string jsonStr = "Invalid JSON";
+    EXPECT_THAT(exStorer->publishJson(jsonStr), false);
+}
+
+TEST_F(ExternalStorerFileTest, NoOdataTypeFailureTest)
+{
+    // Try a JSON without @odata.type.
+    std::string jsonStr = R"(
+      {
+        "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
+        "Id":"Metrics"
+      }
+    )";
+    EXPECT_THAT(exStorer->publishJson(jsonStr), false);
+}
+
+TEST_F(ExternalStorerFileTest, LogServiceNoOdataIdTest)
+{
+    // Try a LogService without @odata.id.
+    std::string jsonStr = R"(
+      {
+        "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
+      }
+    )";
+    EXPECT_THAT(exStorer->publishJson(jsonStr), false);
+}
+
+TEST_F(ExternalStorerFileTest, LogServiceNoIdTest)
+{
+    // Try a LogService without Id.
+    std::string jsonStr = R"(
+      {
+        "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
+        "@odata.type": "#LogService.v1_1_0.LogService"
+      }
+    )";
+    EXPECT_THAT(exStorer->publishJson(jsonStr), false);
+}
+
+TEST_F(ExternalStorerFileTest, LogServiceTest)
+{
+    // A valid LogService test.
+    std::string jsonStr = R"(
+      {
+        "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
+        "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
+        }
+      )";
+    std::string exServiceFolder =
+        "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
+    std::string exEntriesFolder =
+        "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
+    nlohmann::json exEntriesJson = "{}"_json;
+    nlohmann::json exServiceJson = nlohmann::json::parse(jsonStr);
+    EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
+        .WillOnce(Return(true));
+    EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
+        .WillOnce(Return(true));
+    EXPECT_THAT(exStorer->publishJson(jsonStr), true);
+}
+
+TEST_F(ExternalStorerFileTest, LogEntryWithoutLogServiceTest)
+{
+    // Try a LogEntry without sending a LogService first.
+    std::string jsonLogEntry = R"(
+      {
+        "@odata.type": "#LogEntry.v1_13_0.LogEntry"
+      }
+    )";
+    EXPECT_THAT(exStorer->publishJson(jsonLogEntry), false);
+}
+
+TEST_F(ExternalStorerFileTest, LogEntryTest)
+{
+    // Before sending a LogEntry, first we need to push a LogService.
+    std::string jsonLogSerivce = R"(
+      {
+        "@odata.id": "/redfish/v1/Systems/system/LogServices/6F7-C1A7C",
+        "@odata.type": "#LogService.v1_1_0.LogService","Id":"6F7-C1A7C"
+      }
+    )";
+    std::string exServiceFolder =
+        "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C";
+    std::string exEntriesFolder =
+        "/some/path/redfish/v1/Systems/system/LogServices/6F7-C1A7C/Entries";
+    nlohmann::json exEntriesJson = "{}"_json;
+    nlohmann::json exServiceJson = nlohmann::json::parse(jsonLogSerivce);
+    EXPECT_CALL(*mockFileWriterPtr, createFile(exServiceFolder, exServiceJson))
+        .WillOnce(Return(true));
+    EXPECT_CALL(*mockFileWriterPtr, createFile(exEntriesFolder, exEntriesJson))
+        .WillOnce(Return(true));
+    EXPECT_THAT(exStorer->publishJson(jsonLogSerivce), true);
+
+    // Now send a LogEntry
+    std::string jsonLogEntry = R"(
+      {
+        "@odata.id": "/some/odata/id",
+        "@odata.type": "#LogEntry.v1_13_0.LogEntry"
+      }
+    )";
+    nlohmann::json logEntryOut;
+    EXPECT_CALL(*mockFileWriterPtr, createFile(_, _))
+        .WillOnce(DoAll(SaveArg<1>(&logEntryOut), Return(true)));
+    EXPECT_THAT(exStorer->publishJson(jsonLogEntry), true);
+    EXPECT_NE(logEntryOut["Id"], nullptr);
+    EXPECT_EQ(logEntryOut["@odata.id"], nullptr);
+}
+
+TEST_F(ExternalStorerFileTest, OtherSchemaNoOdataIdTest)
+{
+    // Try a another PDRs without @odata.id.
+    std::string jsonStr = R"(
+      {
+        "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
+        "Id":"Metrics"
+      }
+    )";
+    EXPECT_THAT(exStorer->publishJson(jsonStr), false);
+}
+
+TEST_F(ExternalStorerFileTest, OtherSchemaTypeTest)
+{
+    // A valid MemoryMetrics PDR.
+    std::string jsonStr = R"(
+      {
+        "@odata.id": "/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics",
+        "@odata.type": "#MemoryMetrics.v1_4_1.MemoryMetrics",
+        "Id": "Metrics"
+      }
+    )";
+    std::string exFolder =
+        "/some/path/redfish/v1/Systems/system/Memory/dimm0/MemoryMetrics";
+    nlohmann::json exJson = nlohmann::json::parse(jsonStr);
+    EXPECT_CALL(*mockFileWriterPtr, createFile(exFolder, exJson))
+        .WillOnce(Return(true));
+    EXPECT_THAT(exStorer->publishJson(jsonStr), true);
+}
+
+} // namespace rde
+} // namespace bios_bmc_smm_error_logger
diff --git a/test/meson.build b/test/meson.build
index 6f72d9f..01a92a2 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -26,6 +26,7 @@
   'pci_handler',
   'rde_dictionary_manager',
   'buffer',
+  'external_storer_file',
 ]
 foreach t : gtests
   test(t, executable(t.underscorify(), t + '_test.cpp',