Refactor metadata returned by Readings property

Reading metadata is now JSON containg SensorDbusPath and SensorRedfishUri.
It is returned only if JSON metadata was provided during Report creation,
otherwise old behavior is maintained.

Additionally, json.hpp was removed as LabeledTupple is now used for
serialization and deserialization of metric and reading metadata.

Testing done:
- Unit test is passing as metric is returning proper metadata.
- Redfish get on redfish/v1/TelemetryService/MetricReports is containing
  MetricDefinition property, which utilizes SensorDbusPath metadata..
  Done on custom version of bmcweb.

Change-Id: I1b2cc4440d03e0fe45151b630f4e439839ed8589
Signed-off-by: Szymon Dompke <szymon.dompke@intel.com>
diff --git a/src/metric.cpp b/src/metric.cpp
index 6734d28..9dd4e67 100644
--- a/src/metric.cpp
+++ b/src/metric.cpp
@@ -1,7 +1,7 @@
 #include "metric.hpp"
 
 #include "types/report_types.hpp"
-#include "utils/json.hpp"
+#include "utils/labeled_tuple.hpp"
 #include "utils/transform.hpp"
 
 #include <algorithm>
@@ -68,22 +68,29 @@
 
 void Metric::tryUnpackJsonMetadata()
 {
+    using MetricMetadata =
+        utils::LabeledTuple<std::tuple<std::vector<std::string>>,
+                            utils::tstring::MetricProperties>;
+
+    using ReadingMetadata =
+        utils::LabeledTuple<std::tuple<std::string, std::string>,
+                            utils::tstring::SensorDbusPath,
+                            utils::tstring::SensorRedfishUri>;
     try
     {
-        const nlohmann::json parsedMetadata = nlohmann::json::parse(metadata);
-        if (const auto metricProperties =
-                utils::readJson<std::vector<std::string>>(parsedMetadata,
-                                                          "MetricProperties"))
+        const MetricMetadata parsedMetadata =
+            nlohmann::json::parse(metadata).get<MetricMetadata>();
+
+        if (readings.size() == parsedMetadata.at_index<0>().size())
         {
-            if (readings.size() == metricProperties->size())
+            for (size_t i = 0; i < readings.size(); ++i)
             {
-                for (size_t i = 0; i < readings.size(); ++i)
-                {
-                    readings[i].metadata = (*metricProperties)[i];
-                }
+                ReadingMetadata readingMetadata{
+                    sensors[i]->id().path, parsedMetadata.at_index<0>()[i]};
+                readings[i].metadata = readingMetadata.dump();
             }
         }
     }
-    catch (const nlohmann::json::parse_error& e)
+    catch (const nlohmann::json::parse_error&)
     {}
 }
diff --git a/src/utils/json.hpp b/src/utils/json.hpp
deleted file mode 100644
index 2ae606f..0000000
--- a/src/utils/json.hpp
+++ /dev/null
@@ -1,63 +0,0 @@
-#pragma once
-
-#include <nlohmann/json.hpp>
-
-#include <string_view>
-
-namespace utils
-{
-
-template <class T>
-struct is_vector : std::false_type
-{};
-
-template <class T>
-struct is_vector<std::vector<T>> : std::true_type
-{};
-
-template <class T>
-constexpr bool is_vector_v = is_vector<T>::value;
-
-template <class T>
-std::optional<T> readJson(const nlohmann::json& json)
-{
-    if constexpr (is_vector_v<T>)
-    {
-        if (json.is_array())
-        {
-            auto result = T{};
-            for (const auto& item : json.items())
-            {
-                if (auto val = readJson<typename T::value_type>(item.value()))
-                {
-                    result.emplace_back(*val);
-                }
-            }
-            return result;
-        }
-    }
-    else
-    {
-        if (const T* val = json.get_ptr<const T*>())
-        {
-            return *val;
-        }
-    }
-
-    return std::nullopt;
-}
-
-template <class T>
-std::optional<T> readJson(const nlohmann::json& json, std::string_view key)
-{
-    auto it = json.find(key);
-    if (it != json.end())
-    {
-        const nlohmann::json& subJson = *it;
-        return readJson<T>(subJson);
-    }
-
-    return std::nullopt;
-}
-
-} // namespace utils
diff --git a/src/utils/labeled_tuple.hpp b/src/utils/labeled_tuple.hpp
index a224141..398e4be 100644
--- a/src/utils/labeled_tuple.hpp
+++ b/src/utils/labeled_tuple.hpp
@@ -81,6 +81,11 @@
         from_json_all(j, std::make_index_sequence<sizeof...(Args)>());
     }
 
+    std::string dump() const
+    {
+        return to_json().dump();
+    }
+
     template <size_t Idx>
     const auto& at_index() const
     {
diff --git a/src/utils/tstring.hpp b/src/utils/tstring.hpp
index 8f9701a..f0bc679 100644
--- a/src/utils/tstring.hpp
+++ b/src/utils/tstring.hpp
@@ -128,5 +128,29 @@
     }
 };
 
+struct MetricProperties
+{
+    static std::string str()
+    {
+        return "MetricProperties";
+    }
+};
+
+struct SensorDbusPath
+{
+    static std::string str()
+    {
+        return "SensorDbusPath";
+    }
+};
+
+struct SensorRedfishUri
+{
+    static std::string str()
+    {
+        return "SensorRedfishUri";
+    }
+};
+
 } // namespace tstring
 } // namespace utils
diff --git a/tests/src/test_metric.cpp b/tests/src/test_metric.cpp
index 9006962..6c68513 100644
--- a/tests/src/test_metric.cpp
+++ b/tests/src/test_metric.cpp
@@ -71,15 +71,22 @@
 
 TEST_F(TestMetric, parsesSensorMetadata)
 {
+    using ReadingMetadata =
+        utils::LabeledTuple<std::tuple<std::string, std::string>,
+                            utils::tstring::SensorDbusPath,
+                            utils::tstring::SensorRedfishUri>;
+
     nlohmann::json metadata;
     metadata["MetricProperties"] = {"sensor1", "sensor2"};
 
     sensorMocks = makeSensorMocks(2);
     sut = makeSut(params.metadata(metadata.dump()));
 
-    EXPECT_THAT(sut->getReadings(),
-                ElementsAre(MetricValue{"id", "sensor1", 0., 0u},
-                            MetricValue{"id", "sensor2", 0., 0u}));
+    EXPECT_THAT(
+        sut->getReadings(),
+        ElementsAre(
+            MetricValue{"id", ReadingMetadata("", "sensor1").dump(), 0., 0u},
+            MetricValue{"id", ReadingMetadata("", "sensor2").dump(), 0., 0u}));
 }
 
 TEST_F(TestMetric, parsesSensorMetadataWhenMoreMetadataThanSensors)