threshold: use absolute value for D-Bus

Use the absolute value for threshold rather than percentage value.
This involves passing the total value from the metric collection so it
can be used in percentage calculation within health metric logic.

Change-Id: I46240aee54117c70637f9fbf882018f0eac520b2
Signed-off-by: Jagpal Singh Gill <paligill@gmail.com>
diff --git a/health_metric.cpp b/health_metric.cpp
index a160025..4c391cd 100644
--- a/health_metric.cpp
+++ b/health_metric.cpp
@@ -104,7 +104,7 @@
         if (threshold == thresholds.end())
         {
             bound_map_t bounds;
-            bounds.emplace(bound, value.value);
+            bounds.emplace(bound, std::numeric_limits<double>::quiet_NaN());
             thresholds.emplace(type, bounds);
         }
         else
@@ -138,23 +138,26 @@
 }
 
 void HealthMetric::checkThreshold(ThresholdIntf::Type type,
-                                  ThresholdIntf::Bound bound, double value)
+                                  ThresholdIntf::Bound bound, MValue value)
 {
     auto threshold = std::make_tuple(type, bound);
     auto thresholds = ThresholdIntf::value();
 
     if (thresholds.contains(type) && thresholds[type].contains(bound))
     {
-        auto thresholdValue = thresholds[type][bound];
+        auto tConfig = config.thresholds.at(threshold);
+        auto thresholdValue = tConfig.value / 100 * value.total;
+        thresholds[type][bound] = thresholdValue;
+        ThresholdIntf::value(thresholds);
         auto assertions = ThresholdIntf::asserted();
-        if (didThresholdViolate(bound, thresholdValue, value))
+        if (didThresholdViolate(bound, thresholdValue, value.current))
         {
             if (!assertions.contains(threshold))
             {
                 assertions.insert(threshold);
                 ThresholdIntf::asserted(assertions);
-                ThresholdIntf::assertionChanged(type, bound, true, value);
-                auto tConfig = config.thresholds.at(threshold);
+                ThresholdIntf::assertionChanged(type, bound, true,
+                                                value.current);
                 if (tConfig.log)
                 {
                     error(
@@ -170,7 +173,7 @@
         {
             assertions.erase(threshold);
             ThresholdIntf::asserted(assertions);
-            ThresholdIntf::assertionChanged(type, bound, false, value);
+            ThresholdIntf::assertionChanged(type, bound, false, value.current);
             if (config.thresholds.find(threshold)->second.log)
             {
                 info(
@@ -182,7 +185,7 @@
     }
 }
 
-void HealthMetric::checkThresholds(double value)
+void HealthMetric::checkThresholds(MValue value)
 {
     if (!ThresholdIntf::value().empty())
     {
@@ -205,7 +208,7 @@
     {
         history.pop_front();
     }
-    history.push_back(value.user);
+    history.push_back(value.current);
 
     if (history.size() < config.windowSize)
     {
@@ -217,7 +220,7 @@
     double average = (std::accumulate(history.begin(), history.end(), 0.0)) /
                      history.size();
     ValueIntf::value(average);
-    checkThresholds(value.monitor);
+    checkThresholds(value);
 }
 
 void HealthMetric::create(const paths_t& bmcPaths)
diff --git a/health_metric.hpp b/health_metric.hpp
index 01f6836..e79fce1 100644
--- a/health_metric.hpp
+++ b/health_metric.hpp
@@ -28,10 +28,10 @@
 
 struct MValue
 {
-    /** @brief Value for end user consumption */
-    double user;
-    /** @brief Value for threshold monitor */
-    double monitor;
+    /** @brief Current value of metric */
+    double current;
+    /** @brief Total value of metric */
+    double total;
 };
 
 class HealthMetric : public MetricIntf
@@ -61,9 +61,9 @@
     void initProperties();
     /** @brief Check specified threshold for the given value */
     void checkThreshold(ThresholdIntf::Type type, ThresholdIntf::Bound bound,
-                        double value);
+                        MValue value);
     /** @brief Check all thresholds for the given value */
-    void checkThresholds(double value);
+    void checkThresholds(MValue value);
     /** @brief Get the object path for the given subtype */
     auto getPath(SubType subType) -> std::string;
     /** @brief D-Bus bus connection */
diff --git a/health_metric_collection.cpp b/health_metric_collection.cpp
index 552a2c3..ae7d593 100644
--- a/health_metric_collection.cpp
+++ b/health_metric_collection.cpp
@@ -103,8 +103,7 @@
               std::to_underlying(config.subType), "VALUE",
               (double)activePercValue);
         /* For CPU, both user and monitor uses percentage values */
-        metrics[config.subType]->update(
-            MValue(activePercValue, activePercValue));
+        metrics[config.subType]->update(MValue(activePercValue, 100));
     }
     return true;
 }
@@ -150,21 +149,19 @@
         }
         else if (name.starts_with("Shmem"))
         {
-            memoryValues[MetricIntf::SubType::memoryShared] = value;
+            memoryValues[MetricIntf::SubType::memoryShared] += value;
         }
     }
 
     for (auto& config : configs)
     {
-        auto absoluteValue = memoryValues.at(config.subType);
-        auto memoryTotal = memoryValues.at(MetricIntf::SubType::memoryTotal);
-        double percentValue = (memoryTotal - absoluteValue) / memoryTotal * 100;
         // Convert kB to Bytes
-        absoluteValue = absoluteValue * 1024;
-        debug("Memory Metric {SUBTYPE}: {VALUE}, {PERCENT}", "SUBTYPE",
-              std::to_underlying(config.subType), "VALUE", absoluteValue,
-              "PERCENT", percentValue);
-        metrics[config.subType]->update(MValue(absoluteValue, percentValue));
+        auto value = memoryValues.at(config.subType) * 1024;
+        auto total = memoryValues.at(MetricIntf::SubType::memoryTotal) * 1024;
+        debug("Memory Metric {SUBTYPE}: {VALUE}, {TOTAL}", "SUBTYPE",
+              std::to_underlying(config.subType), "VALUE", value, "TOTAL",
+              total);
+        metrics[config.subType]->update(MValue(value, total));
     }
     return true;
 }
@@ -181,14 +178,12 @@
                   strerror(e), "PATH", config.path);
             continue;
         }
+        double value = buffer.f_bfree * buffer.f_frsize;
         double total = buffer.f_blocks * buffer.f_frsize;
-        double available = buffer.f_bfree * buffer.f_frsize;
-        double availablePercent = ((available / total) * 100);
-
-        debug("Storage Metric {SUBTYPE}: {TOTAL} {AVAIL} {AVAIL_PERCENT}",
-              "SUBTYPE", std::to_underlying(config.subType), "TOTAL", total,
-              "AVAIL", available, "AVAIL_PERCENT", availablePercent);
-        metrics[config.subType]->update(MValue(available, availablePercent));
+        debug("Storage Metric {SUBTYPE}: {VALUE}, {TOTAL}", "SUBTYPE",
+              std::to_underlying(config.subType), "VALUE", value, "TOTAL",
+              total);
+        metrics[config.subType]->update(MValue(value, total));
     }
     return true;
 }
diff --git a/test/test_health_metric.cpp b/test/test_health_metric.cpp
index 1fd0b15..ad93c24 100644
--- a/test/test_health_metric.cpp
+++ b/test/test_health_metric.cpp
@@ -88,9 +88,9 @@
     auto metric = std::make_unique<HealthMetric>(bus, Type::cpu, config,
                                                  paths_t());
     // Exceed the critical threshold
-    metric->update(MValue(1200, 95.0));
+    metric->update(MValue(1351, 1500));
     // Go below critical threshold but above warning threshold
-    metric->update(MValue(1200, 85.0));
+    metric->update(MValue(1399, 1500));
     // Go below warning threshold
-    metric->update(MValue(1200, 75.0));
+    metric->update(MValue(1199, 1500));
 }
diff --git a/test/test_health_metric_collection.cpp b/test/test_health_metric_collection.cpp
index dc15f07..19c2d49 100644
--- a/test/test_health_metric_collection.cpp
+++ b/test/test_health_metric_collection.cpp
@@ -116,10 +116,10 @@
         .WillRepeatedly(Invoke(
             [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
                 [[maybe_unused]] const char* interface, const char** names) {
-        // Test no signal generation for threshold init properties
-        const std::set<std::string> thresholdProperties = {"Value", "Asserted"};
-        EXPECT_THAT(thresholdProperties,
-                    testing::Not(testing::Contains(names[0])));
+        // Test signal generated for Value property set
+        EXPECT_STREQ("Value", names[0]);
+        // Test no signal generation for threshold asserted
+        EXPECT_STRNE("Asserted", names[0]);
         return 0;
     }));
 
@@ -150,7 +150,9 @@
         .WillRepeatedly(Invoke(
             [&]([[maybe_unused]] sd_bus* bus, [[maybe_unused]] const char* path,
                 [[maybe_unused]] const char* interface, const char** names) {
-        EXPECT_THAT("Asserted", StrEq(names[0]));
+        // Test signal generation for threshold properties set
+        const std::set<std::string> thresholdProperties = {"Value", "Asserted"};
+        EXPECT_THAT(thresholdProperties, testing::Contains(names[0]));
         return 0;
     }));