made MetricValues persistent

MetricValues are persistent for reportUpdates AppendStopsWhenFull and
reportingType different than OnRequest.

Tested:
- New unit tests are passing
- Confirmed MetricValues are preserved after restarting telemetry
  service

Change-Id: I7e1990fb391da9debb0d7df2f1dbda86473350cc
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/interfaces/report_factory.hpp b/src/interfaces/report_factory.hpp
index e1f9f2a..d8e076a 100644
--- a/src/interfaces/report_factory.hpp
+++ b/src/interfaces/report_factory.hpp
@@ -4,6 +4,7 @@
 #include "interfaces/metric.hpp"
 #include "interfaces/report.hpp"
 #include "interfaces/report_manager.hpp"
+#include "types/readings.hpp"
 #include "types/report_action.hpp"
 #include "types/report_types.hpp"
 #include "types/report_updates.hpp"
@@ -42,7 +43,7 @@
              const ReportUpdates reportUpdates, ReportManager& reportManager,
              JsonStorage& reportStorage,
              std::vector<LabeledMetricParameters> labeledMetricParams,
-             bool enabled) const = 0;
+             bool enabled, Readings) const = 0;
 };
 
 } // namespace interfaces
diff --git a/src/report.cpp b/src/report.cpp
index d9d89b8..945d4e6 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -27,14 +27,16 @@
                interfaces::JsonStorage& reportStorageIn,
                std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
                const interfaces::ReportFactory& reportFactory,
-               const bool enabledIn, std::unique_ptr<interfaces::Clock> clock) :
+               const bool enabledIn, std::unique_ptr<interfaces::Clock> clock,
+               Readings readingsIn) :
     id(reportId),
     name(reportName), reportingType(reportingTypeIn), interval(intervalIn),
     reportActions(reportActionsIn.begin(), reportActionsIn.end()),
     sensorCount(getSensorCount(metricsIn)),
     appendLimit(deduceAppendLimit(appendLimitIn)),
-    reportUpdates(reportUpdatesIn),
-    readingsBuffer(deduceBufferSize(reportUpdates, reportingType)),
+    reportUpdates(reportUpdatesIn), readings(std::move(readingsIn)),
+    readingsBuffer(std::get<1>(readings),
+                   deduceBufferSize(reportUpdates, reportingType)),
     objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
     triggerIds(collectTriggerIds(ioc)), reportStorage(reportStorageIn),
     enabled(enabledIn), clock(std::move(clock)), messanger(ioc)
@@ -62,8 +64,11 @@
             dbusIface.register_method("Delete", [this, &ioc, &reportManager] {
                 if (persistency)
                 {
-                    reportStorage.remove(fileName());
+                    persistency = false;
+
+                    reportIface->signal_property("Persistency");
                 }
+
                 boost::asio::post(ioc, [this, &reportManager] {
                     reportManager.removeReport(this);
                 });
@@ -117,6 +122,21 @@
     });
 }
 
+Report::~Report()
+{
+    if (persistency)
+    {
+        if (shouldStoreMetricValues())
+        {
+            storeConfiguration();
+        }
+    }
+    else
+    {
+        reportStorage.remove(reportFileName());
+    }
+}
+
 uint64_t Report::getSensorCount(
     const std::vector<std::shared_ptr<interfaces::Metric>>& metrics)
 {
@@ -242,7 +262,7 @@
             }
             else
             {
-                reportStorage.remove(fileName());
+                reportStorage.remove(reportFileName());
                 persistency = false;
             }
             return 1;
@@ -458,10 +478,9 @@
         }
     }
 
-    readings = {
+    std::get<0>(readings) =
         std::chrono::duration_cast<Milliseconds>(clock->systemTimestamp())
-            .count(),
-        std::vector<ReadingData>(readingsBuffer.begin(), readingsBuffer.end())};
+            .count();
 
     if (utils::contains(reportActions, ReportAction::emitsReadingsUpdate))
     {
@@ -469,6 +488,12 @@
     }
 }
 
+bool Report::shouldStoreMetricValues() const
+{
+    return reportingType != ReportingType::onRequest &&
+           reportUpdates == ReportUpdates::appendStopsWhenFull;
+}
+
 bool Report::storeConfiguration() const
 {
     try
@@ -493,7 +518,12 @@
                 return metric->dumpConfiguration();
             });
 
-        reportStorage.store(fileName(), data);
+        if (shouldStoreMetricValues())
+        {
+            data["MetricValues"] = utils::toLabeledReadings(readings);
+        }
+
+        reportStorage.store(reportFileName(), data);
     }
     catch (const std::exception& e)
     {
@@ -506,7 +536,7 @@
     return true;
 }
 
-interfaces::JsonStorage::FilePath Report::fileName() const
+interfaces::JsonStorage::FilePath Report::reportFileName() const
 {
     return interfaces::JsonStorage::FilePath{
         std::to_string(std::hash<std::string>{}(id))};
diff --git a/src/report.hpp b/src/report.hpp
index 213265c..6d8c6b4 100644
--- a/src/report.hpp
+++ b/src/report.hpp
@@ -7,6 +7,7 @@
 #include "interfaces/report.hpp"
 #include "interfaces/report_factory.hpp"
 #include "interfaces/report_manager.hpp"
+#include "types/readings.hpp"
 #include "types/report_action.hpp"
 #include "types/report_types.hpp"
 #include "types/report_updates.hpp"
@@ -60,7 +61,8 @@
            interfaces::JsonStorage& reportStorage,
            std::vector<std::shared_ptr<interfaces::Metric>> metrics,
            const interfaces::ReportFactory& reportFactory, const bool enabled,
-           std::unique_ptr<interfaces::Clock> clock);
+           std::unique_ptr<interfaces::Clock> clock, Readings);
+    ~Report();
 
     Report(const Report&) = delete;
     Report(Report&&) = delete;
@@ -96,10 +98,11 @@
     void setReportUpdates(const ReportUpdates newReportUpdates);
     static uint64_t getSensorCount(
         const std::vector<std::shared_ptr<interfaces::Metric>>& metrics);
-    interfaces::JsonStorage::FilePath fileName() const;
+    interfaces::JsonStorage::FilePath reportFileName() const;
     std::unordered_set<std::string>
         collectTriggerIds(boost::asio::io_context& ioc) const;
     bool storeConfiguration() const;
+    bool shouldStoreMetricValues() const;
     void updateReadings();
     void updateReportingType(ReportingType);
 
@@ -114,8 +117,8 @@
     uint64_t sensorCount;
     std::optional<uint64_t> appendLimit;
     ReportUpdates reportUpdates;
-    CircularVector<ReadingData> readingsBuffer;
     Readings readings = {};
+    CircularVector<ReadingData> readingsBuffer;
     std::shared_ptr<sdbusplus::asio::object_server> objServer;
     std::unique_ptr<sdbusplus::asio::dbus_interface> reportIface;
     std::unique_ptr<sdbusplus::asio::dbus_interface> deleteIface;
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index 0d7f011..1c530f3 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -23,8 +23,8 @@
     uint64_t appendLimit, const ReportUpdates reportUpdates,
     interfaces::ReportManager& reportManager,
     interfaces::JsonStorage& reportStorage,
-    std::vector<LabeledMetricParameters> labeledMetricParams,
-    bool enabled) const
+    std::vector<LabeledMetricParameters> labeledMetricParams, bool enabled,
+    Readings readings) const
 {
     auto metrics = utils::transform(
         labeledMetricParams,
@@ -40,11 +40,11 @@
                 std::make_unique<Clock>());
         });
 
-    return std::make_unique<Report>(bus->get_io_context(), objServer, id, name,
-                                    reportingType, reportActions, period,
-                                    appendLimit, reportUpdates, reportManager,
-                                    reportStorage, std::move(metrics), *this,
-                                    enabled, std::make_unique<Clock>());
+    return std::make_unique<Report>(
+        bus->get_io_context(), objServer, id, name, reportingType,
+        reportActions, period, appendLimit, reportUpdates, reportManager,
+        reportStorage, std::move(metrics), *this, enabled,
+        std::make_unique<Clock>(), std::move(readings));
 }
 
 void ReportFactory::updateMetrics(
diff --git a/src/report_factory.hpp b/src/report_factory.hpp
index 8431f40..e8729b1 100644
--- a/src/report_factory.hpp
+++ b/src/report_factory.hpp
@@ -38,7 +38,7 @@
              interfaces::ReportManager& reportManager,
              interfaces::JsonStorage& reportStorage,
              std::vector<LabeledMetricParameters> labeledMetricParams,
-             bool enabled) const override;
+             bool enabled, Readings) const override;
 
   private:
     Sensors getSensors(const std::vector<LabeledSensorInfo>& sensorPaths) const;
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index 7600088..926b642 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -205,7 +205,7 @@
 
     return addReport(reportId, reportName, reportingType, reportActions,
                      interval, appendLimit, reportUpdates,
-                     std::move(labeledMetricParams), enabled);
+                     std::move(labeledMetricParams), enabled, Readings{});
 }
 
 interfaces::Report& ReportManager::addReport(
@@ -214,7 +214,7 @@
     const std::vector<ReportAction>& reportActions, Milliseconds interval,
     const uint64_t appendLimit, const ReportUpdates reportUpdates,
     std::vector<LabeledMetricParameters> labeledMetricParams,
-    const bool enabled)
+    const bool enabled, Readings readings)
 {
     const auto existingReportIds = utils::transform(
         reports, [](const auto& report) { return report->getId(); });
@@ -225,9 +225,10 @@
     verifyAddReport(id, name, reportingType, interval, reportUpdates,
                     appendLimit, labeledMetricParams);
 
-    reports.emplace_back(reportFactory->make(
-        id, name, reportingType, reportActions, interval, appendLimit,
-        reportUpdates, *this, *reportStorage, labeledMetricParams, enabled));
+    reports.emplace_back(
+        reportFactory->make(id, name, reportingType, reportActions, interval,
+                            appendLimit, reportUpdates, *this, *reportStorage,
+                            labeledMetricParams, enabled, std::move(readings)));
     return *reports.back();
 }
 
@@ -263,10 +264,19 @@
                 data->at("ReadingParameters")
                     .get<std::vector<LabeledMetricParameters>>();
 
+            Readings readings = {};
+
+            if (auto it = data->find("MetricValues"); it != data->end())
+            {
+                const auto labeledReadings = it->get<LabeledReadings>();
+                readings = utils::toReadings(labeledReadings);
+            }
+
             addReport(id, name, utils::toReportingType(reportingType),
                       reportActions, Milliseconds(interval), appendLimit,
                       utils::toReportUpdates(reportUpdates),
-                      std::move(readingParameters), enabled);
+                      std::move(readingParameters), enabled,
+                      std::move(readings));
         }
         catch (const std::exception& e)
         {
diff --git a/src/report_manager.hpp b/src/report_manager.hpp
index 96e7cab..d5653b2 100644
--- a/src/report_manager.hpp
+++ b/src/report_manager.hpp
@@ -50,12 +50,14 @@
         const std::vector<ReportAction>& reportActions, Milliseconds interval,
         const uint64_t appendLimit, const ReportUpdates reportUpdates,
         ReadingParameters metricParams, const bool enabled);
-    interfaces::Report& addReport(
-        const std::string& reportId, const std::string& reportName,
-        const ReportingType reportingType,
-        const std::vector<ReportAction>& reportActions, Milliseconds interval,
-        const uint64_t appendLimit, const ReportUpdates reportUpdates,
-        std::vector<LabeledMetricParameters> metricParams, const bool enabled);
+    interfaces::Report&
+        addReport(const std::string& reportId, const std::string& reportName,
+                  const ReportingType reportingType,
+                  const std::vector<ReportAction>& reportActions,
+                  Milliseconds interval, const uint64_t appendLimit,
+                  const ReportUpdates reportUpdates,
+                  std::vector<LabeledMetricParameters> metricParams,
+                  const bool enabled, Readings);
     void loadFromPersistent();
 
   public:
diff --git a/src/types/readings.cpp b/src/types/readings.cpp
new file mode 100644
index 0000000..2f6246b
--- /dev/null
+++ b/src/types/readings.cpp
@@ -0,0 +1,28 @@
+#include "types/readings.hpp"
+
+#include "utils/transform.hpp"
+
+namespace utils
+{
+
+namespace ts = utils::tstring;
+
+LabeledReadings toLabeledReadings(const Readings& readings)
+{
+    return LabeledReadings{
+        std::get<0>(readings),
+        utils::transform(std::get<1>(readings), [](const auto& readingData) {
+            return LabeledReadingData{readingData};
+        })};
+}
+
+Readings toReadings(const LabeledReadings& labeledReadings)
+{
+    return Readings{labeledReadings.at_label<ts::Timestamp>(),
+                    utils::transform(labeledReadings.at_label<ts::Readings>(),
+                                     [](const auto& labeledReadingData) {
+                                         return labeledReadingData.to_tuple();
+                                     })};
+}
+
+} // namespace utils
diff --git a/src/types/readings.hpp b/src/types/readings.hpp
new file mode 100644
index 0000000..6749bbf
--- /dev/null
+++ b/src/types/readings.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "utils/labeled_tuple.hpp"
+#include "utils/tstring.hpp"
+
+using ReadingData = std::tuple<std::string, std::string, double, uint64_t>;
+using Readings = std::tuple<uint64_t, std::vector<ReadingData>>;
+
+using LabeledReadingData =
+    utils::LabeledTuple<ReadingData, utils::tstring::MetricId,
+                        utils::tstring::MetricProperty,
+                        utils::tstring::MetricValue, utils::tstring::Timestamp>;
+
+using LabeledReadings =
+    utils::LabeledTuple<std::tuple<uint64_t, std::vector<LabeledReadingData>>,
+                        utils::tstring::Timestamp, utils::tstring::Readings>;
+
+namespace utils
+{
+
+LabeledReadings toLabeledReadings(const Readings&);
+Readings toReadings(const LabeledReadings&);
+
+} // namespace utils
diff --git a/src/types/report_types.hpp b/src/types/report_types.hpp
index c0f7b39..d927d0e 100644
--- a/src/types/report_types.hpp
+++ b/src/types/report_types.hpp
@@ -30,9 +30,5 @@
     utils::tstring::Id, utils::tstring::CollectionTimeScope,
     utils::tstring::CollectionDuration>;
 
-using ReadingData = std::tuple<std::string, std::string, double, uint64_t>;
-
-using Readings = std::tuple<uint64_t, std::vector<ReadingData>>;
-
 ReadingParameters
     toReadingParameters(const std::vector<LabeledMetricParameters>& labeled);
diff --git a/src/utils/circular_vector.hpp b/src/utils/circular_vector.hpp
index ba185ec..f7ac8e5 100644
--- a/src/utils/circular_vector.hpp
+++ b/src/utils/circular_vector.hpp
@@ -4,7 +4,8 @@
 class CircularVector
 {
   public:
-    explicit CircularVector(size_t maxSizeIn) : maxSize(maxSizeIn)
+    explicit CircularVector(std::vector<T>& externalVec, size_t maxSizeIn) :
+        vec(externalVec), maxSize(maxSizeIn)
     {}
 
     template <class... Args>
@@ -53,7 +54,7 @@
     }
 
   private:
+    std::vector<T>& vec;
     size_t maxSize = 0;
     size_t idx = 0;
-    std::vector<T> vec;
 };
diff --git a/src/utils/labeled_tuple.hpp b/src/utils/labeled_tuple.hpp
index 71bf4b0..e6203dd 100644
--- a/src/utils/labeled_tuple.hpp
+++ b/src/utils/labeled_tuple.hpp
@@ -76,6 +76,11 @@
         return j;
     }
 
+    const tuple_type& to_tuple() const
+    {
+        return value;
+    }
+
     void from_json(const nlohmann::json& j)
     {
         from_json_all(j, std::make_index_sequence<sizeof...(Args)>());
diff --git a/src/utils/tstring.hpp b/src/utils/tstring.hpp
index e4529d8..67ad3c4 100644
--- a/src/utils/tstring.hpp
+++ b/src/utils/tstring.hpp
@@ -144,5 +144,45 @@
     }
 };
 
+struct MetricId
+{
+    static std::string str()
+    {
+        return "MetricId";
+    }
+};
+
+struct MetricProperty
+{
+    static std::string str()
+    {
+        return "MetricProperty";
+    }
+};
+
+struct MetricValue
+{
+    static std::string str()
+    {
+        return "MetricValue";
+    }
+};
+
+struct Timestamp
+{
+    static std::string str()
+    {
+        return "Timestamp";
+    }
+};
+
+struct Readings
+{
+    static std::string str()
+    {
+        return "Readings";
+    }
+};
+
 } // namespace tstring
 } // namespace utils