Implement Report persistency

Now Report properties are stored in non-volatile memory. It allows
to restore Report after system restart. Persistency of a report is
controlled by Persistency property in Report interface.

Tested:
 - Passed unit tests
 - Verified that report is stored in /var/lib/telemetry dir
 - Verified that report is restored from storage after telemetry
   service start

Signed-off-by: Wludzik, Jozef <jozef.wludzik@intel.com>
Change-Id: Iccfe21603eecffc4e174a4403f699b03de320db9
diff --git a/tests/src/test_report.cpp b/tests/src/test_report.cpp
index bb0f4c5..b53d359 100644
--- a/tests/src/test_report.cpp
+++ b/tests/src/test_report.cpp
@@ -1,7 +1,9 @@
 #include "dbus_environment.hpp"
+#include "mocks/json_storage_mock.hpp"
 #include "mocks/metric_mock.hpp"
 #include "mocks/report_manager_mock.hpp"
 #include "params/report_params.hpp"
+#include "printers.hpp"
 #include "report.hpp"
 #include "report_manager.hpp"
 #include "utils/conv_container.hpp"
@@ -15,32 +17,56 @@
 class TestReport : public Test
 {
   public:
-    bool defaultEmitReadingSignal = true;
-    bool defaultLogToMetricReportCollection = true;
-    uint64_t defaultInterval = ReportManager::minInterval.count();
-    ReadingParameters defaultReadingParams = {};
+    ReportParams defaultParams;
 
     std::unique_ptr<ReportManagerMock> reportManagerMock =
-        std::make_unique<StrictMock<ReportManagerMock>>();
+        std::make_unique<NiceMock<ReportManagerMock>>();
+    testing::NiceMock<StorageMock> storageMock;
     std::vector<std::shared_ptr<MetricMock>> metricMocks = {
         std::make_shared<NiceMock<MetricMock>>(),
         std::make_shared<NiceMock<MetricMock>>(),
         std::make_shared<NiceMock<MetricMock>>()};
     std::unique_ptr<Report> sut;
 
+    MockFunction<void()> checkPoint;
+
+    TestReport()
+    {
+        ON_CALL(*metricMocks[0], getReadings())
+            .WillByDefault(ReturnRefOfCopy(std::vector<MetricValue>(
+                {MetricValue{"a", "b", 17.1, 114},
+                 MetricValue{"aaa", "bbb", 21.7, 100}})));
+        ON_CALL(*metricMocks[1], getReadings())
+            .WillByDefault(ReturnRefOfCopy(
+                std::vector<MetricValue>({MetricValue{"aa", "bb", 42.0, 74}})));
+
+        for (size_t i = 0; i < metricMocks.size(); ++i)
+        {
+            ON_CALL(*metricMocks[i], to_json())
+                .WillByDefault(
+                    Return(nlohmann::json("metric"s + std::to_string(i))));
+        }
+    }
+
     void SetUp() override
     {
         sut = makeReport(ReportParams());
     }
 
+    static interfaces::JsonStorage::FilePath to_file_path(std::string name)
+    {
+        return interfaces::JsonStorage::FilePath(
+            std::to_string(std::hash<std::string>{}(name)));
+    }
+
     std::unique_ptr<Report> makeReport(const ReportParams& params)
     {
         return std::make_unique<Report>(
             DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
             params.reportName(), params.reportingType(),
-            defaultEmitReadingSignal, defaultLogToMetricReportCollection,
-            std::chrono::milliseconds(defaultInterval), defaultReadingParams,
-            *reportManagerMock,
+            params.emitReadingUpdate(), params.logToMetricReportCollection(),
+            params.interval(), params.readingParameters(), *reportManagerMock,
+            storageMock,
             utils::convContainer<std::shared_ptr<interfaces::Metric>>(
                 metricMocks));
     }
@@ -97,16 +123,16 @@
 TEST_F(TestReport, verifyIfPropertiesHaveValidValue)
 {
     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
-                Eq(defaultInterval));
-    EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(false));
+                Eq(defaultParams.interval().count()));
+    EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(true));
     EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
-                Eq(defaultEmitReadingSignal));
+                Eq(defaultParams.emitReadingUpdate()));
     EXPECT_THAT(
         getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
-        Eq(defaultLogToMetricReportCollection));
+        Eq(defaultParams.logToMetricReportCollection()));
     EXPECT_THAT(
         getProperty<ReadingParameters>(sut->getPath(), "ReadingParameters"),
-        Eq(defaultReadingParams));
+        Eq(defaultParams.readingParameters()));
 }
 
 TEST_F(TestReport, readingsAreInitialyEmpty)
@@ -117,7 +143,7 @@
 
 TEST_F(TestReport, setIntervalWithValidValue)
 {
-    uint64_t newValue = defaultInterval + 1;
+    uint64_t newValue = defaultParams.interval().count() + 1;
     EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
                 Eq(boost::system::errc::success));
     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
@@ -126,11 +152,22 @@
 
 TEST_F(TestReport, settingIntervalWithInvalidValueDoesNotChangeProperty)
 {
-    uint64_t newValue = defaultInterval - 1;
+    uint64_t newValue = defaultParams.interval().count() - 1;
     EXPECT_THAT(setProperty(sut->getPath(), "Interval", newValue).value(),
                 Eq(boost::system::errc::success));
     EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "Interval"),
-                Eq(defaultInterval));
+                Eq(defaultParams.interval().count()));
+}
+
+TEST_F(TestReport, settingPersistencyToFalseRemovesReportFromStorage)
+{
+    EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
+
+    bool persistency = false;
+    EXPECT_THAT(setProperty(sut->getPath(), "Persistency", persistency).value(),
+                Eq(boost::system::errc::success));
+    EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"),
+                Eq(persistency));
 }
 
 TEST_F(TestReport, deleteReport)
@@ -146,6 +183,74 @@
     EXPECT_THAT(ec.value(), Eq(EBADR));
 }
 
+TEST_F(TestReport, deleteReportExpectThatFileIsRemoveFromStorage)
+{
+    EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
+    auto ec = deleteReport(sut->getPath());
+    EXPECT_THAT(ec, Eq(boost::system::errc::success));
+}
+
+class TestReportStore :
+    public TestReport,
+    public WithParamInterface<std::pair<std::string, nlohmann::json>>
+{
+  public:
+    void SetUp() override
+    {}
+
+    nlohmann::json storedConfiguration;
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    _, TestReportStore,
+    Values(std::make_pair("Version"s, nlohmann::json(1)),
+           std::make_pair("Name"s, nlohmann::json(ReportParams().reportName())),
+           std::make_pair("ReportingType",
+                          nlohmann::json(ReportParams().reportingType())),
+           std::make_pair("EmitsReadingsUpdate",
+                          nlohmann::json(ReportParams().emitReadingUpdate())),
+           std::make_pair(
+               "LogToMetricReportsCollection",
+               nlohmann::json(ReportParams().logToMetricReportCollection())),
+           std::make_pair("Interval",
+                          nlohmann::json(ReportParams().interval().count())),
+           std::make_pair("ReadingParameters",
+                          nlohmann::json({"metric0", "metric1", "metric2"}))));
+
+TEST_P(TestReportStore, settingPersistencyToTrueStoresReport)
+{
+    sut = makeReport(ReportParams());
+
+    {
+        InSequence seq;
+        EXPECT_CALL(storageMock, remove(to_file_path(sut->getName())));
+        EXPECT_CALL(checkPoint, Call());
+        EXPECT_CALL(storageMock, store(to_file_path(sut->getName()), _))
+            .WillOnce(SaveArg<1>(&storedConfiguration));
+    }
+
+    setProperty(sut->getPath(), "Persistency", false);
+    checkPoint.Call();
+    setProperty(sut->getPath(), "Persistency", true);
+
+    const auto& [key, value] = GetParam();
+
+    ASSERT_THAT(storedConfiguration.at(key), Eq(value));
+}
+
+TEST_P(TestReportStore, reportIsSavedToStorageAfterCreated)
+{
+    EXPECT_CALL(storageMock,
+                store(to_file_path(ReportParams().reportName()), _))
+        .WillOnce(SaveArg<1>(&storedConfiguration));
+
+    sut = makeReport(ReportParams());
+
+    const auto& [key, value] = GetParam();
+
+    ASSERT_THAT(storedConfiguration.at(key), Eq(value));
+}
+
 class TestReportValidNames :
     public TestReport,
     public WithParamInterface<ReportParams>
@@ -187,6 +292,13 @@
     EXPECT_THROW(makeReport(GetParam()), sdbusplus::exception::SdBusError);
 }
 
+TEST_F(TestReportInvalidNames, reportCtorThrowOnInvalidNameAndNoStoreIsCalled)
+{
+    EXPECT_CALL(storageMock, store).Times(0);
+    EXPECT_THROW(makeReport(ReportParams().reportName("/Invalid")),
+                 sdbusplus::exception::SdBusError);
+}
+
 class TestReportAllReportTypes :
     public TestReport,
     public WithParamInterface<ReportParams>
@@ -270,3 +382,51 @@
                             std::make_tuple("aaa"s, "bbb"s, 21.7, 100u),
                             std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
 }
+
+class TestReportInitialization : public TestReport
+{
+  public:
+    void SetUp() override
+    {}
+
+    void monitorProc(sdbusplus::message::message& msg)
+    {
+        std::string iface;
+        std::vector<std::pair<std::string, std::variant<Readings>>>
+            changed_properties;
+        std::vector<std::string> invalidated_properties;
+
+        msg.read(iface, changed_properties, invalidated_properties);
+
+        if (iface == Report::reportIfaceName)
+        {
+            for (const auto& [name, value] : changed_properties)
+            {
+                if (name == "Readings")
+                {
+                    readingsUpdated.Call();
+                }
+            }
+        }
+    }
+
+    void makeMonitor()
+    {
+        monitor = std::make_unique<sdbusplus::bus::match::match>(
+            *DbusEnvironment::getBus(),
+            sdbusplus::bus::match::rules::propertiesChanged(
+                sut->getPath(), Report::reportIfaceName),
+            [this](auto& msg) { monitorProc(msg); });
+    }
+
+    std::unique_ptr<sdbusplus::bus::match::match> monitor;
+    MockFunction<void()> readingsUpdated;
+};
+
+TEST_F(TestReportInitialization, readingsPropertiesChangedSingalEmits)
+{
+    sut = makeReport(defaultParams.reportingType("Periodic"));
+    EXPECT_CALL(readingsUpdated, Call());
+    makeMonitor();
+    DbusEnvironment::sleepFor(defaultParams.interval() + 1ms);
+}