Add support for log-handler

This handler is based off of version handler with major differences in
handler_builder

Tested:
created the blackbox blob successfully using this lib.
Read the data from the blob using a host side tool

Signed-off-by: Gaurav Gandhi <gauravgandhi@google.com>
Change-Id: I9ef775af752156a1647453ff3831ef4c0449d546
diff --git a/bmc/log-handler/test/log_json_unittest.cpp b/bmc/log-handler/test/log_json_unittest.cpp
new file mode 100644
index 0000000..5759c25
--- /dev/null
+++ b/bmc/log-handler/test/log_json_unittest.cpp
@@ -0,0 +1,314 @@
+// Copyright 2021 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "general_systemd.hpp"
+#include "log_handlers_builder.hpp"
+#include "skip_action.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace ipmi_flash
+{
+namespace
+{
+using ::testing::IsEmpty;
+
+using json = nlohmann::json;
+
+TEST(LogJsonTest, ValidConfigurationNoLogHandler)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/sink_seq",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute"
+                    }
+                 }
+            }
+         }]
+    )"_json;
+    auto h = LogHandlersBuilder().buildHandlerFromJson(j2);
+    ASSERT_THAT(h, ::testing::SizeIs(1));
+    EXPECT_THAT(h[0].blobId, "/log/sink_seq");
+    EXPECT_FALSE(h[0].actions == nullptr);
+    EXPECT_FALSE(h[0].handler == nullptr);
+}
+
+TEST(LogJsonTest, ValidConfigurationLogBlobName)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/log/sink_seq",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions": {
+                    "open" : {
+                    "type" : "systemd",
+                    "unit" : "phosphor-ipmi-flash-log-sink-sequencer.target"
+                    }
+                 }
+            }
+         }]
+    )"_json;
+    auto h = LogHandlersBuilder().buildHandlerFromJson(j2);
+    ASSERT_THAT(h, ::testing::SizeIs(1));
+    EXPECT_THAT(h[0].blobId, "/log/sink_seq");
+    EXPECT_FALSE(h[0].actions == nullptr);
+    EXPECT_FALSE(h[0].handler == nullptr);
+}
+
+TEST(LogJsonTest, MissingHandlerType)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/image",
+            "log":{
+                "handler": {
+                   "path" : "/tmp/log_info"
+                 },
+                "actions": {
+                  "open" : {
+                  "type" : "systemd",
+                  "unit" : "absolute"}
+                 }
+            }
+         }]
+    )"_json;
+    EXPECT_THAT(LogHandlersBuilder().buildHandlerFromJson(j2), IsEmpty());
+}
+
+TEST(LogJsonTest, BadBlobName)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/bad/image",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions": {
+                  "open" : {
+                  "type" : "systemd",
+                  "unit" : "absolute"}
+                 }
+            }
+         }]
+    )"_json;
+    EXPECT_THAT(LogHandlersBuilder().buildHandlerFromJson(j2), IsEmpty());
+}
+
+TEST(LogJsonTest, MissingActions)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/image",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 }
+            }
+         }]
+    )"_json;
+    EXPECT_THAT(LogHandlersBuilder().buildHandlerFromJson(j2), IsEmpty());
+}
+
+TEST(LogJsonTest, MissingOpenAction)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/image",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions": {}
+            }
+         }]
+    )"_json;
+    EXPECT_THAT(LogHandlersBuilder().buildHandlerFromJson(j2), IsEmpty());
+}
+
+TEST(LogJsonTest, OneInvalidTwoValidSucceeds)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/sink_seq0",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute"
+                    }
+                 }
+            }
+         },
+         {
+            "blob" : "/log/sink_seq1",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute"
+                    }
+                 }
+            }
+         },
+         {
+            "blob" : "/bad/sink_seq",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute"
+                    }
+                 }
+            }
+         }
+         ]
+    )"_json;
+    auto h = LogHandlersBuilder().buildHandlerFromJson(j2);
+    ASSERT_THAT(h, ::testing::SizeIs(2));
+    EXPECT_THAT(h[0].blobId, "/log/sink_seq0");
+    EXPECT_THAT(h[1].blobId, "/log/sink_seq1");
+}
+
+TEST(LogJsonTest, BlobNameIsTooShort)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute"
+                    }
+                 }
+            }
+         }]
+    )"_json;
+    EXPECT_THAT(LogHandlersBuilder().buildHandlerFromJson(j2), IsEmpty());
+}
+
+TEST(LogJsonTest, OpenSkipAction)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/sink_seqs",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "skip"
+                    }
+                 }
+            }
+         }]
+    )"_json;
+    auto h = LogHandlersBuilder().buildHandlerFromJson(j2);
+    EXPECT_THAT(h, ::testing::SizeIs(1));
+    EXPECT_TRUE(h[0].blobId == "/log/sink_seqs");
+    ASSERT_FALSE(h[0].actions == nullptr);
+    EXPECT_FALSE(h[0].actions->onOpen == nullptr);
+}
+
+TEST(LogJsonTest, OpenActionsWithDifferentModes)
+{
+    auto j2 = R"(
+        [{
+            "blob" : "/flash/blob1",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute",
+                    "mode" : "replace-nope"
+                    }
+                 }
+            }
+         },
+         {
+            "blob" : "/flash/blob2",
+            "log":{
+                "handler": {
+                   "type" : "file",
+                   "path" : "/tmp/log_info"
+                 },
+                "actions":{
+                    "open" :{
+                    "type" : "systemd",
+                    "unit" : "absolute",
+                    "mode" : "replace-fake"
+                    }
+                 }
+            }
+         }
+         ]
+    )"_json;
+    auto h = LogHandlersBuilder().buildHandlerFromJson(j2);
+    ASSERT_THAT(h, ::testing::SizeIs(2));
+
+    EXPECT_FALSE(h[0].handler == nullptr);
+    EXPECT_FALSE(h[0].actions == nullptr);
+    EXPECT_THAT(h[0].blobId, "/log/blob1");
+    auto onOpen0 = reinterpret_cast<SystemdNoFile*>(h[0].actions->onOpen.get());
+    EXPECT_THAT(onOpen0->getMode(), "replace-nope");
+
+    EXPECT_FALSE(h[1].handler == nullptr);
+    EXPECT_FALSE(h[1].actions == nullptr);
+    EXPECT_THAT(h[1].blobId, "/log/blob2");
+    auto onOpen1 = reinterpret_cast<SystemdNoFile*>(h[1].actions->onOpen.get());
+    EXPECT_THAT(onOpen1->getMode(), "replace-fake");
+}
+} // namespace
+} // namespace ipmi_flash