Added support for Enabled property

Enabled property is added so that user can select via dbus interface if
Readings are updated and signal on Readings update is emitted, moreover
Metric calculation on received sensor data is active only when Enabled
is set to true

Tested:
- New unit tests were created, ran all new and previous UTs, all passed
- Tested under QEMU by adding reports for single and multiple sensors,
  changing Enabled property and emitting signal of value change for
  sensors added into the report, checking if Readings is accordingly
  updated or not updated
- Verified persistency, if Enabled property is successfully stored and
  restored after Telemetry service restart and also checked if after the
  restart dependencies of Enabled (Readings, Metric calculation) are
  properly initiated

Signed-off-by: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com>
Change-Id: I29cf13693a48d15cb16d2ad6707f483f67f4879b
diff --git a/src/interfaces/metric.hpp b/src/interfaces/metric.hpp
index 62a8f44..57a2b68 100644
--- a/src/interfaces/metric.hpp
+++ b/src/interfaces/metric.hpp
@@ -16,6 +16,7 @@
     virtual ~Metric() = default;
 
     virtual void initialize() = 0;
+    virtual void deinitialize() = 0;
     virtual std::vector<MetricValue> getReadings() const = 0;
     virtual LabeledMetricParameters dumpConfiguration() const = 0;
 };
diff --git a/src/interfaces/report_factory.hpp b/src/interfaces/report_factory.hpp
index 182973d..970dd01 100644
--- a/src/interfaces/report_factory.hpp
+++ b/src/interfaces/report_factory.hpp
@@ -23,12 +23,13 @@
         convertMetricParams(boost::asio::yield_context& yield,
                             const ReadingParameters& metricParams) const = 0;
 
-    virtual std::unique_ptr<interfaces::Report> make(
-        const std::string& name, const std::string& reportingType,
-        bool emitsReadingsSignal, bool logToMetricReportsCollection,
-        Milliseconds period, ReportManager& reportManager,
-        JsonStorage& reportStorage,
-        std::vector<LabeledMetricParameters> labeledMetricParams) const = 0;
+    virtual std::unique_ptr<interfaces::Report>
+        make(const std::string& name, const std::string& reportingType,
+             bool emitsReadingsSignal, bool logToMetricReportsCollection,
+             Milliseconds period, ReportManager& reportManager,
+             JsonStorage& reportStorage,
+             std::vector<LabeledMetricParameters> labeledMetricParams,
+             bool enabled) const = 0;
 };
 
 } // namespace interfaces
diff --git a/src/interfaces/sensor.hpp b/src/interfaces/sensor.hpp
index 3e46317..65d3c21 100644
--- a/src/interfaces/sensor.hpp
+++ b/src/interfaces/sensor.hpp
@@ -44,6 +44,8 @@
 
     virtual Id id() const = 0;
     virtual void registerForUpdates(const std::weak_ptr<SensorListener>&) = 0;
+    virtual void
+        unregisterFromUpdates(const std::weak_ptr<SensorListener>&) = 0;
 };
 
 } // namespace interfaces
diff --git a/src/metric.cpp b/src/metric.cpp
index 04d3fe9..4290293 100644
--- a/src/metric.cpp
+++ b/src/metric.cpp
@@ -141,10 +141,17 @@
     }
 }
 
+void Metric::deinitialize()
+{
+    for (const auto& sensor : sensors)
+    {
+        sensor->unregisterFromUpdates(weak_from_this());
+    }
+}
+
 std::vector<MetricValue> Metric::getReadings() const
 {
     const auto timestamp = clock->timestamp();
-
     auto resultReadings = readings;
 
     for (size_t i = 0; i < resultReadings.size(); ++i)
diff --git a/src/metric.hpp b/src/metric.hpp
index dfed383..f053691 100644
--- a/src/metric.hpp
+++ b/src/metric.hpp
@@ -17,6 +17,7 @@
     ~Metric();
 
     void initialize() override;
+    void deinitialize() override;
     std::vector<MetricValue> getReadings() const override;
     void sensorUpdated(interfaces::Sensor&, uint64_t) override;
     void sensorUpdated(interfaces::Sensor&, uint64_t, double value) override;
diff --git a/src/report.cpp b/src/report.cpp
index 8a7297e..af19a91 100644
--- a/src/report.cpp
+++ b/src/report.cpp
@@ -17,14 +17,15 @@
                const Milliseconds intervalIn,
                interfaces::ReportManager& reportManager,
                interfaces::JsonStorage& reportStorageIn,
-               std::vector<std::shared_ptr<interfaces::Metric>> metricsIn) :
+               std::vector<std::shared_ptr<interfaces::Metric>> metricsIn,
+               const bool enabledIn) :
     name(reportName),
     path(reportDir + name), reportingType(reportingTypeIn),
     interval(intervalIn), emitsReadingsUpdate(emitsReadingsUpdateIn),
     logToMetricReportsCollection(logToMetricReportsCollectionIn),
     objServer(objServer), metrics(std::move(metricsIn)), timer(ioc),
     fileName(std::to_string(std::hash<std::string>{}(name))),
-    reportStorage(reportStorageIn)
+    reportStorage(reportStorageIn), enabled(enabledIn)
 {
     readingParameters =
         toReadingParameters(utils::transform(metrics, [](const auto& metric) {
@@ -59,9 +60,12 @@
         scheduleTimer(interval);
     }
 
-    for (auto& metric : this->metrics)
+    if (enabled)
     {
-        metric->initialize();
+        for (auto& metric : this->metrics)
+        {
+            metric->initialize();
+        }
     }
 }
 
@@ -69,16 +73,50 @@
 {
     auto dbusIface = objServer->add_unique_interface(path, reportIfaceName);
     dbusIface->register_property_rw(
+        "Enabled", enabled, sdbusplus::vtable::property_::emits_change,
+        [this](bool newVal, const auto&) {
+            if (newVal != enabled)
+            {
+                if (true == newVal && "Periodic" == reportingType)
+                {
+                    scheduleTimer(interval);
+                }
+                if (newVal)
+                {
+                    for (auto& metric : metrics)
+                    {
+                        metric->initialize();
+                    }
+                }
+                else
+                {
+                    for (auto& metric : metrics)
+                    {
+                        metric->deinitialize();
+                    }
+                }
+
+                enabled = newVal;
+                persistency = storeConfiguration();
+            }
+            return true;
+        },
+        [this](const auto&) { return enabled; });
+    dbusIface->register_property_rw(
         "Interval", interval.count(),
         sdbusplus::vtable::property_::emits_change,
         [this](uint64_t newVal, auto&) {
-            Milliseconds newValT(newVal);
-            if (newValT < ReportManager::minInterval)
+            if (Milliseconds newValT{newVal};
+                newValT >= ReportManager::minInterval)
             {
-                return false;
+                if (newValT != interval)
+                {
+                    interval = newValT;
+                    persistency = storeConfiguration();
+                }
+                return true;
             }
-            interval = newValT;
-            return true;
+            return false;
         },
         [this](const auto&) { return interval.count(); });
     dbusIface->register_property_rw(
@@ -158,22 +196,24 @@
 
 void Report::updateReadings()
 {
-    using ReadingsValue = std::tuple_element_t<1, Readings>;
-    std::get<ReadingsValue>(cachedReadings).clear();
-
-    for (const auto& metric : metrics)
+    if (!enabled)
     {
-        for (const auto& reading : metric->getReadings())
-        {
-            std::get<1>(cachedReadings)
-                .emplace_back(reading.id, reading.metadata, reading.value,
-                              reading.timestamp);
-        }
+        return;
     }
 
     using ReadingsTimestamp = std::tuple_element_t<0, Readings>;
-    std::get<ReadingsTimestamp>(cachedReadings) = std::time(0);
+    using ReadingsValue = std::tuple_element_t<1, Readings>;
 
+    std::get<ReadingsValue>(cachedReadings).clear();
+    for (const auto& metric : metrics)
+    {
+        for (const auto& [id, meta, val, timestamp] : metric->getReadings())
+        {
+            std::get<ReadingsValue>(cachedReadings)
+                .emplace_back(id, meta, val, timestamp);
+        }
+    }
+    std::get<ReadingsTimestamp>(cachedReadings) = std::time(0);
     std::swap(readings, cachedReadings);
 
     reportIface->signal_property("Readings");
@@ -185,6 +225,7 @@
     {
         nlohmann::json data;
 
+        data["Enabled"] = enabled;
         data["Version"] = reportVersion;
         data["Name"] = name;
         data["ReportingType"] = reportingType;
diff --git a/src/report.hpp b/src/report.hpp
index 92293a0..26cc130 100644
--- a/src/report.hpp
+++ b/src/report.hpp
@@ -23,7 +23,8 @@
            const bool logToMetricReportsCollection, const Milliseconds period,
            interfaces::ReportManager& reportManager,
            interfaces::JsonStorage& reportStorage,
-           std::vector<std::shared_ptr<interfaces::Metric>> metrics);
+           std::vector<std::shared_ptr<interfaces::Metric>> metrics,
+           const bool enabled);
     ~Report() = default;
 
     Report(const Report&) = delete;
@@ -68,6 +69,7 @@
 
     interfaces::JsonStorage::FilePath fileName;
     interfaces::JsonStorage& reportStorage;
+    bool enabled;
 
   public:
     static constexpr const char* reportIfaceName =
diff --git a/src/report_factory.cpp b/src/report_factory.cpp
index 091739c..3d86521 100644
--- a/src/report_factory.cpp
+++ b/src/report_factory.cpp
@@ -21,7 +21,8 @@
     bool emitsReadingsSignal, bool logToMetricReportsCollection,
     Milliseconds period, interfaces::ReportManager& reportManager,
     interfaces::JsonStorage& reportStorage,
-    std::vector<LabeledMetricParameters> labeledMetricParams) const
+    std::vector<LabeledMetricParameters> labeledMetricParams,
+    bool enabled) const
 {
     std::vector<std::shared_ptr<interfaces::Metric>> metrics = utils::transform(
         labeledMetricParams,
@@ -41,7 +42,7 @@
     return std::make_unique<Report>(
         bus->get_io_context(), objServer, name, reportingType,
         emitsReadingsSignal, logToMetricReportsCollection, period,
-        reportManager, reportStorage, std::move(metrics));
+        reportManager, reportStorage, std::move(metrics), enabled);
 }
 
 Sensors ReportFactory::getSensors(
diff --git a/src/report_factory.hpp b/src/report_factory.hpp
index 1160a6f..69f6349 100644
--- a/src/report_factory.hpp
+++ b/src/report_factory.hpp
@@ -24,8 +24,8 @@
              bool emitsReadingsSignal, bool logToMetricReportsCollection,
              Milliseconds period, interfaces::ReportManager& reportManager,
              interfaces::JsonStorage& reportStorage,
-             std::vector<LabeledMetricParameters> labeledMetricParams)
-            const override;
+             std::vector<LabeledMetricParameters> labeledMetricParams,
+             bool enabled) const override;
 
   private:
     Sensors getSensors(
diff --git a/src/report_manager.cpp b/src/report_manager.cpp
index e40d9a4..c8103a6 100644
--- a/src/report_manager.cpp
+++ b/src/report_manager.cpp
@@ -56,12 +56,14 @@
                                     const bool logToMetricReportsCollection,
                                     const uint64_t interval,
                                     ReadingParametersPastVersion metricParams) {
+                    constexpr auto enabledDefault = true;
                     return addReport(yield, reportName, reportingType,
                                      emitsReadingsUpdate,
                                      logToMetricReportsCollection,
                                      Milliseconds(interval),
                                      convertToReadingParameters(
-                                         std::move(metricParams)))
+                                         std::move(metricParams)),
+                                     enabledDefault)
                         .getPath();
                 });
 
@@ -74,11 +76,12 @@
                        const bool logToMetricReportsCollection,
                        const uint64_t interval,
                        ReadingParameters metricParams) {
+                    constexpr auto enabledDefault = true;
                     return addReport(yield, reportName, reportingType,
                                      emitsReadingsUpdate,
                                      logToMetricReportsCollection,
                                      Milliseconds(interval),
-                                     std::move(metricParams))
+                                     std::move(metricParams), enabledDefault)
                         .getPath();
                 });
         });
@@ -169,28 +172,29 @@
     boost::asio::yield_context& yield, const std::string& reportName,
     const std::string& reportingType, const bool emitsReadingsUpdate,
     const bool logToMetricReportsCollection, Milliseconds interval,
-    ReadingParameters metricParams)
+    ReadingParameters metricParams, const bool enabled)
 {
     auto labeledMetricParams =
         reportFactory->convertMetricParams(yield, metricParams);
 
     return addReport(reportName, reportingType, emitsReadingsUpdate,
                      logToMetricReportsCollection, interval,
-                     std::move(labeledMetricParams));
+                     std::move(labeledMetricParams), enabled);
 }
 
 interfaces::Report& ReportManager::addReport(
     const std::string& reportName, const std::string& reportingType,
     const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
     Milliseconds interval,
-    std::vector<LabeledMetricParameters> labeledMetricParams)
+    std::vector<LabeledMetricParameters> labeledMetricParams,
+    const bool enabled)
 {
     verifyAddReport(reportName, reportingType, interval, labeledMetricParams);
 
     reports.emplace_back(
         reportFactory->make(reportName, reportingType, emitsReadingsUpdate,
                             logToMetricReportsCollection, interval, *this,
-                            *reportStorage, labeledMetricParams));
+                            *reportStorage, labeledMetricParams, enabled));
     return *reports.back();
 }
 
@@ -204,6 +208,7 @@
         std::optional<nlohmann::json> data = reportStorage->load(path);
         try
         {
+            bool enabled = data->at("Enabled").get<bool>();
             size_t version = data->at("Version").get<size_t>();
             if (version != Report::reportVersion)
             {
@@ -223,7 +228,7 @@
 
             addReport(name, reportingType, emitsReadingsSignal,
                       logToMetricReportsCollection, Milliseconds(interval),
-                      std::move(readingParameters));
+                      std::move(readingParameters), enabled);
         }
         catch (const std::exception& e)
         {
diff --git a/src/report_manager.hpp b/src/report_manager.hpp
index 1e6e15d..f056f78 100644
--- a/src/report_manager.hpp
+++ b/src/report_manager.hpp
@@ -43,18 +43,16 @@
         const std::string& reportName, const std::string& reportingType,
         Milliseconds interval,
         const std::vector<LabeledMetricParameters>& readingParams);
-    interfaces::Report& addReport(boost::asio::yield_context& yield,
-                                  const std::string& reportName,
-                                  const std::string& reportingType,
-                                  const bool emitsReadingsUpdate,
-                                  const bool logToMetricReportsCollection,
-                                  Milliseconds interval,
-                                  ReadingParameters metricParams);
+    interfaces::Report& addReport(
+        boost::asio::yield_context& yield, const std::string& reportName,
+        const std::string& reportingType, const bool emitsReadingsUpdate,
+        const bool logToMetricReportsCollection, Milliseconds interval,
+        ReadingParameters metricParams, const bool enabled);
     interfaces::Report& addReport(
         const std::string& reportName, const std::string& reportingType,
         const bool emitsReadingsUpdate, const bool logToMetricReportsCollection,
         Milliseconds interval,
-        std::vector<LabeledMetricParameters> metricParams);
+        std::vector<LabeledMetricParameters> metricParams, const bool enabled);
     void loadFromPersistent();
 
   public:
diff --git a/src/sensor.cpp b/src/sensor.cpp
index 26cadb7..f26a964 100644
--- a/src/sensor.cpp
+++ b/src/sensor.cpp
@@ -75,6 +75,22 @@
     }
 }
 
+void Sensor::unregisterFromUpdates(
+    const std::weak_ptr<interfaces::SensorListener>& weakListener)
+{
+    if (auto listener = weakListener.lock())
+    {
+        listeners.erase(
+            std::remove_if(
+                listeners.begin(), listeners.end(),
+                [listenerToUnregister = listener.get()](const auto& listener) {
+                    return (listener.expired() ||
+                            listener.lock().get() == listenerToUnregister);
+                }),
+            listeners.end());
+    }
+}
+
 void Sensor::updateValue(double newValue)
 {
     timestamp = std::time(0);
diff --git a/src/sensor.hpp b/src/sensor.hpp
index e3334a0..23c3d5c 100644
--- a/src/sensor.hpp
+++ b/src/sensor.hpp
@@ -28,6 +28,8 @@
     Id id() const override;
     void registerForUpdates(
         const std::weak_ptr<interfaces::SensorListener>& weakListener) override;
+    void unregisterFromUpdates(
+        const std::weak_ptr<interfaces::SensorListener>& weakListener) override;
 
   private:
     static std::optional<double> readValue(const ValueVariant& v);