Added Periodic reportingType support to Report

When report interval expires report will collect readings from
metrics and update timestamp.

Tested:
  - Added new units tests covering added code
  - All existing unit tests are passing

Change-Id: I7f23ca05d77efb0f18d2c0d0f138c524ffb4f6af
Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com>
diff --git a/src/report.cpp b/src/report.cpp
index 81e3b05..2e68d45 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -2,9 +2,7 @@
 
 #include "report_manager.hpp"
 
-using Readings = std::tuple<
-    uint64_t,
-    std::vector<std::tuple<std::string, std::string, double, uint64_t>>>;
+#include <numeric>
 
 Report::Report(boost::asio::io_context& ioc,
                const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
@@ -13,9 +11,11 @@
                const bool logToMetricReportsCollection,
                const std::chrono::milliseconds period,
                const ReadingParameters& metricParams,
-               interfaces::ReportManager& reportManager) :
-    name{reportName},
-    path{reportDir + name}, interval{period}, objServer(objServer)
+               interfaces::ReportManager& reportManager,
+               std::vector<std::shared_ptr<interfaces::Metric>> metrics) :
+    name(reportName),
+    path(reportDir + name), interval(period), objServer(objServer),
+    metrics(std::move(metrics)), timer(ioc)
 {
     reportIface = objServer->add_unique_interface(
         path, reportIfaceName,
@@ -34,7 +34,10 @@
                     return true;
                 });
             dbusIface.register_property("Persistency", bool{false});
-            dbusIface.register_property("Readings", Readings{});
+            dbusIface.register_property_r(
+                "Readings", readings,
+                sdbusplus::vtable::property_::emits_change,
+                [this](const auto&) { return readings; });
             dbusIface.register_property("ReportingType", reportingType);
             dbusIface.register_property("ReadingParameters", metricParams);
             dbusIface.register_property("EmitsReadingsUpdate",
@@ -51,4 +54,52 @@
                 });
             });
         });
+
+    if (reportingType == "Periodic")
+    {
+        scheduleTimer(interval);
+    }
+}
+
+void Report::timerProc(boost::system::error_code ec, Report& self)
+{
+    if (ec)
+    {
+        return;
+    }
+
+    self.updateReadings();
+    self.scheduleTimer(self.interval);
+}
+
+void Report::scheduleTimer(std::chrono::milliseconds timerInterval)
+{
+    timer.expires_after(timerInterval);
+    timer.async_wait(
+        [this](boost::system::error_code ec) { timerProc(ec, *this); });
+}
+
+void Report::updateReadings()
+{
+    auto numElements = std::accumulate(
+        metrics.begin(), metrics.end(), 0u, [](auto sum, const auto& metric) {
+            return sum + metric->getReadings().size();
+        });
+
+    readingsCache.resize(numElements);
+
+    auto it = readingsCache.begin();
+
+    for (const auto& metric : metrics)
+    {
+        for (const auto& reading : metric->getReadings())
+        {
+            *(it++) = std::make_tuple(reading.id, reading.metadata,
+                                      reading.value, reading.timestamp);
+        }
+    }
+
+    std::get<0>(readings) = std::time(0);
+    std::get<1>(readings) = readingsCache;
+    reportIface->signal_property("Readings");
 }