Implement Trigger Actions

Now action is triggered when threshold is crossed. There are 3
actions: write message to journal, write message to journal as
Redfish Event and update an existing Report.
To update an existing Report updateReading method is changed to
public. Added UpdateReport to ReportManager, now object is able
to update readings of any report using report name.

Tested:
 - Unit tests passed
 - Verified that logs are propagated to journal when threshold
   is crossed

Change-Id: Iebca7c8b9ab9b50b4c401877ccf8c2f01f1e6f36
Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
diff --git a/tests/meson.build b/tests/meson.build
index ee57387..393f73f 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -32,11 +32,13 @@
             '../src/sensor.cpp',
             '../src/sensor_cache.cpp',
             '../src/trigger.cpp',
+            '../src/trigger_actions.cpp',
             '../src/trigger_factory.cpp',
             '../src/trigger_manager.cpp',
             'src/dbus_environment.cpp',
             'src/main.cpp',
             'src/stubs/dbus_sensor_object.cpp',
+            'src/test_conversion.cpp',
             'src/test_detached_timer.cpp',
             'src/test_metric.cpp',
             'src/test_numeric_threshold.cpp',
@@ -47,6 +49,7 @@
             'src/test_sensor_cache.cpp',
             'src/test_transform.cpp',
             'src/test_trigger.cpp',
+            'src/test_trigger_actions.cpp',
             'src/test_trigger_manager.cpp',
             'src/test_unique_call.cpp',
             'src/utils/generate_unique_mock_id.cpp',
diff --git a/tests/src/mocks/report_manager_mock.hpp b/tests/src/mocks/report_manager_mock.hpp
index 872a6e6..df79e12 100644
--- a/tests/src/mocks/report_manager_mock.hpp
+++ b/tests/src/mocks/report_manager_mock.hpp
@@ -8,4 +8,5 @@
 {
   public:
     MOCK_METHOD(void, removeReport, (const interfaces::Report*), (override));
+    MOCK_METHOD(void, updateReport, (const std::string& name), (override));
 };
diff --git a/tests/src/mocks/report_mock.hpp b/tests/src/mocks/report_mock.hpp
index f3eafba..726d53c 100644
--- a/tests/src/mocks/report_mock.hpp
+++ b/tests/src/mocks/report_mock.hpp
@@ -23,5 +23,6 @@
 
     MOCK_METHOD(std::string, getName, (), (override, const));
     MOCK_METHOD(std::string, getPath, (), (override, const));
+    MOCK_METHOD(void, updateReadings, (), (override));
     MOCK_METHOD(void, Die, ());
 };
diff --git a/tests/src/test_conversion.cpp b/tests/src/test_conversion.cpp
new file mode 100644
index 0000000..e3984ca
--- /dev/null
+++ b/tests/src/test_conversion.cpp
@@ -0,0 +1,33 @@
+#include "utils/conversion.hpp"
+
+#include <gmock/gmock.h>
+
+using namespace testing;
+
+class TestEnum : public Test
+{
+  public:
+    enum class Enum
+    {
+        zero = 0,
+        one,
+        two
+    };
+
+    Enum toEnum(int x)
+    {
+        return utils::toEnum<Enum, Enum::zero, Enum::two>(x);
+    }
+};
+
+TEST_F(TestEnum, passValueInRangeExpectToGetValidOutput)
+{
+    EXPECT_EQ(toEnum(0), Enum::zero);
+    EXPECT_EQ(toEnum(2), Enum::two);
+}
+
+TEST_F(TestEnum, passInvalidValueExpectToThrowOutOfRangeException)
+{
+    EXPECT_THROW(toEnum(-1), std::out_of_range);
+    EXPECT_THROW(toEnum(3), std::out_of_range);
+}
diff --git a/tests/src/test_report.cpp b/tests/src/test_report.cpp
index 8f2228e..f6c4ee7 100644
--- a/tests/src/test_report.cpp
+++ b/tests/src/test_report.cpp
@@ -375,6 +375,18 @@
                 Eq(GetParam().reportingType()));
 }
 
+TEST_P(TestReportAllReportTypes, updateReadingsCallUpdateReadingsProperty)
+{
+    const uint64_t expectedTime = std::time(0);
+
+    sut->updateReadings();
+
+    const auto [timestamp, readings] =
+        getProperty<Readings>(sut->getPath(), "Readings");
+
+    EXPECT_THAT(timestamp, Ge(expectedTime));
+}
+
 class TestReportOnRequestType : public TestReport
 {
     void SetUp() override
diff --git a/tests/src/test_report_manager.cpp b/tests/src/test_report_manager.cpp
index ac947c4..30628d6 100644
--- a/tests/src/test_report_manager.cpp
+++ b/tests/src/test_report_manager.cpp
@@ -226,6 +226,26 @@
     checkPoint.Call("end");
 }
 
+TEST_F(TestReportManager, updateReportCallsUpdateReadingsForExistReport)
+{
+    reportFactoryMock.expectMake(_, reportParams, Ref(*sut), Ref(storageMock))
+        .WillOnce(Return(ByMove(std::move(reportMockPtr))));
+    EXPECT_CALL(reportMock, updateReadings());
+
+    addReport(reportParams);
+    sut->updateReport(reportParams.reportName());
+}
+
+TEST_F(TestReportManager, updateReportDoNothingIfReportDoesNotExist)
+{
+    reportFactoryMock.expectMake(_, reportParams, Ref(*sut), Ref(storageMock))
+        .WillOnce(Return(ByMove(std::move(reportMockPtr))));
+    EXPECT_CALL(reportMock, updateReadings()).Times(0);
+
+    addReport(reportParams);
+    sut->updateReport("NotAReport");
+}
+
 class TestReportManagerStorage : public TestReportManager
 {
   public:
diff --git a/tests/src/test_trigger_actions.cpp b/tests/src/test_trigger_actions.cpp
new file mode 100644
index 0000000..2fa220a
--- /dev/null
+++ b/tests/src/test_trigger_actions.cpp
@@ -0,0 +1,121 @@
+#include "mocks/report_manager_mock.hpp"
+#include "trigger_actions.hpp"
+
+#include <stdexcept>
+
+using namespace testing;
+
+namespace action
+{
+
+using LogParam = std::pair<numeric::Type, double>;
+
+class TestLogToJournal : public Test, public WithParamInterface<LogParam>
+{
+  public:
+    void SetUp() override
+    {
+        auto [type, threshold] = GetParam();
+        sut = std::make_unique<LogToJournal>(type, threshold);
+    }
+
+    std::unique_ptr<LogToJournal> sut;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    LogToJournalParams, TestLogToJournal,
+    Values(std::make_pair(numeric::Type::upperCritical, 91.1),
+           std::make_pair(numeric::Type::lowerCritical, 91.2),
+           std::make_pair(numeric::Type::upperWarning, 88.5),
+           std::make_pair(numeric::Type::lowerWarning, 88.6)));
+
+TEST_P(TestLogToJournal, commitAnActionDoesNotThrow)
+{
+    EXPECT_NO_THROW(sut->commit("Test", 100'000, 90.0));
+}
+
+class TestLogToJournalThrow : public TestLogToJournal
+{};
+
+INSTANTIATE_TEST_SUITE_P(
+    _, TestLogToJournalThrow,
+    Values(std::make_pair(numeric::Type::upperCritical, 90.0),
+           std::make_pair(static_cast<numeric::Type>(-1), 88.0),
+           std::make_pair(static_cast<numeric::Type>(123), 123.0)));
+
+TEST_P(TestLogToJournalThrow, commitAnActionExpectThrow)
+{
+    EXPECT_THROW(sut->commit("Test", 100'000, 90.0), std::runtime_error);
+}
+
+class TestLogToRedfish : public Test, public WithParamInterface<LogParam>
+{
+  public:
+    void SetUp() override
+    {
+        auto [type, threshold] = GetParam();
+        sut = std::make_unique<LogToRedfish>(type, threshold);
+    }
+
+    std::unique_ptr<LogToRedfish> sut;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    LogToRedfishParams, TestLogToRedfish,
+    Values(std::make_pair(numeric::Type::upperCritical, 91.1),
+           std::make_pair(numeric::Type::lowerCritical, 91.4),
+           std::make_pair(numeric::Type::upperWarning, 88.6),
+           std::make_pair(numeric::Type::lowerWarning, 88.5)));
+
+TEST_P(TestLogToRedfish, commitExpectNoThrow)
+{
+    EXPECT_NO_THROW(sut->commit("Test", 100'000, 90.0));
+}
+
+class TestLogToRedfishThrow : public TestLogToRedfish
+{};
+
+INSTANTIATE_TEST_SUITE_P(
+    _, TestLogToRedfishThrow,
+    Values(std::make_pair(numeric::Type::upperCritical, 90.0),
+           std::make_pair(static_cast<numeric::Type>(-1), 88.5),
+           std::make_pair(static_cast<numeric::Type>(123), 123.6)));
+
+TEST_P(TestLogToRedfishThrow, commitExpectToThrow)
+{
+    EXPECT_THROW(sut->commit("Test", 100'000, 90.0), std::runtime_error);
+}
+
+class TestUpdateReport : public Test
+{
+  public:
+    void make(std::vector<std::string> names)
+    {
+        sut = std::make_unique<UpdateReport>(reportManager, std::move(names));
+    }
+
+    NiceMock<ReportManagerMock> reportManager;
+    std::unique_ptr<UpdateReport> sut;
+};
+
+TEST_F(TestUpdateReport, commitWhenReportNameIsEmptyExpectNoReportUpdate)
+{
+    EXPECT_CALL(reportManager, updateReport(_)).Times(0);
+
+    make({});
+    sut->commit("Test", 100'000, 90.0);
+}
+
+TEST_F(TestUpdateReport, commitExpectReportUpdate)
+{
+    std::vector<std::string> names = {"Report1", "Report2", "Report3"};
+    for (const auto& name : names)
+    {
+        EXPECT_CALL(reportManager, updateReport(name));
+    }
+
+    make(names);
+    sut->commit("Test", 100'000, 90.0);
+}
+
+} // namespace action