Add support for AppendLimit and ReportUpdates

Added 2 new properties for Report interface: AppendLimit and
ReportUpdates. They were also added as arguments to the future version
of AddReport method of ReportManager.

ReportUpdates property defines the report update behavior:
- Overwrite: Each report update overrides previous "Readings" property.
  "AppendLimit" set by user is not respected - "Readings" property size
  is equal to count of all sensor across all metrics defined in report.
- AppendWrapsWhenFull: New readings are appended until limit specified
  by "AppendLimit" is reached. Then oldest readings are overwritten by
  new ones.
- AppendStopsWhenFull: New readings are appended until limit specified
  by "AppendLimit" is reached. Then updates are stopped.
- NewReport: not supported yet and will be implemented in the future.

Please note that if ReportingType is set to OnRequest, those 2 new
properties are ignored, and Readings property will contain one reading
per defined sensor, across all metrics. They are still stored, which
means that if ReportingType will be changed in the runtime, those
properties will be respected.

Tested:
- Both new properties can be accessed from dbus.
- Both properties are reflected in Readings property.
- Old AddReport method is working as before the change.
- UTs are passing.

Signed-off-by: Szymon Dompke <szymon.dompke@intel.com>
Change-Id: I8a18f7e68215f0f6e5c403b533d2c4ff479df69e
diff --git a/tests/src/mocks/metric_mock.hpp b/tests/src/mocks/metric_mock.hpp
index a105aa0..268b681 100644
--- a/tests/src/mocks/metric_mock.hpp
+++ b/tests/src/mocks/metric_mock.hpp
@@ -20,4 +20,9 @@
     MOCK_METHOD(std::vector<MetricValue>, getReadings, (), (const, override));
     MOCK_METHOD(LabeledMetricParameters, dumpConfiguration, (),
                 (const, override));
+
+    uint64_t sensorCount() const override
+    {
+        return getReadings().size();
+    }
 };
diff --git a/tests/src/mocks/report_factory_mock.hpp b/tests/src/mocks/report_factory_mock.hpp
index e456429..f593883 100644
--- a/tests/src/mocks/report_factory_mock.hpp
+++ b/tests/src/mocks/report_factory_mock.hpp
@@ -35,7 +35,8 @@
             .WillByDefault(
                 WithArgs<1>(Invoke(&ReportFactoryMock::convertToLabeled)));
 
-        ON_CALL(*this, make(A<const std::string&>(), _, _, _, _, _, _, _, _))
+        ON_CALL(*this,
+                make(A<const std::string&>(), _, _, _, _, _, _, _, _, _, _))
             .WillByDefault(WithArgs<0>(Invoke([](const std::string& name) {
                 return std::make_unique<NiceMock<ReportMock>>(name);
             })));
@@ -47,9 +48,9 @@
 
     MOCK_METHOD(std::unique_ptr<interfaces::Report>, make,
                 (const std::string&, const std::string&, bool, bool,
-                 Milliseconds, interfaces::ReportManager&,
-                 interfaces::JsonStorage&, std::vector<LabeledMetricParameters>,
-                 bool),
+                 Milliseconds, uint64_t, const std::string&,
+                 interfaces::ReportManager&, interfaces::JsonStorage&,
+                 std::vector<LabeledMetricParameters>, bool),
                 (const, override));
 
     auto& expectMake(
@@ -65,12 +66,13 @@
                 make(params.reportName(), params.reportingType(),
                      params.emitReadingUpdate(),
                      params.logToMetricReportCollection(), params.interval(),
-                     rm, js, params.metricParameters(), params.enabled()));
+                     params.appendLimit(), params.reportUpdates(), rm, js,
+                     params.metricParameters(), params.enabled()));
         }
         else
         {
             using testing::_;
-            return EXPECT_CALL(*this, make(_, _, _, _, _, rm, js, _, _));
+            return EXPECT_CALL(*this, make(_, _, _, _, _, _, _, rm, js, _, _));
         }
     }
 };
diff --git a/tests/src/params/report_params.hpp b/tests/src/params/report_params.hpp
index cc71ce3..d68f3fb 100644
--- a/tests/src/params/report_params.hpp
+++ b/tests/src/params/report_params.hpp
@@ -75,6 +75,28 @@
         return enabledProperty;
     }
 
+    ReportParams& appendLimit(uint64_t val)
+    {
+        appendLimitProperty = val;
+        return *this;
+    }
+
+    uint64_t appendLimit() const
+    {
+        return appendLimitProperty;
+    }
+
+    ReportParams& reportUpdates(std::string val)
+    {
+        reportUpdatesProperty = val;
+        return *this;
+    }
+
+    std::string reportUpdates() const
+    {
+        return reportUpdatesProperty;
+    }
+
     ReportParams& metricParameters(std::vector<LabeledMetricParameters> val)
     {
         metricParametersProperty = std::move(val);
@@ -92,6 +114,8 @@
     bool emitReadingUpdateProperty = true;
     bool logToMetricReportCollectionProperty = true;
     Milliseconds intervalProperty = ReportManager::minInterval;
+    uint64_t appendLimitProperty = 123;
+    std::string reportUpdatesProperty = "Overwrite";
     std::vector<LabeledMetricParameters> metricParametersProperty{
         {LabeledMetricParameters{
              {LabeledSensorParameters{"Service",
diff --git a/tests/src/test_report.cpp b/tests/src/test_report.cpp
index ccdcce8..f09ddef 100644
--- a/tests/src/test_report.cpp
+++ b/tests/src/test_report.cpp
@@ -68,9 +68,11 @@
 
         return std::make_unique<Report>(
             DbusEnvironment::getIoc(), DbusEnvironment::getObjServer(),
-            params.reportName(), params.reportingType(),
+            params.reportName(), stringToReportingType(params.reportingType()),
             params.emitReadingUpdate(), params.logToMetricReportCollection(),
-            params.interval(), *reportManagerMock, storageMock,
+            params.interval(), params.appendLimit(),
+            stringToReportUpdates(params.reportUpdates()), *reportManagerMock,
+            storageMock,
             utils::convContainer<std::shared_ptr<interfaces::Metric>>(
                 metricMocks),
             params.enabled());
@@ -125,6 +127,10 @@
     EXPECT_THAT(getProperty<bool>(sut->getPath(), "Persistency"), Eq(true));
     EXPECT_THAT(getProperty<bool>(sut->getPath(), "EmitsReadingsUpdate"),
                 Eq(defaultParams.emitReadingUpdate()));
+    EXPECT_THAT(getProperty<uint64_t>(sut->getPath(), "AppendLimit"),
+                Eq(defaultParams.appendLimit()));
+    EXPECT_THAT(getProperty<std::string>(sut->getPath(), "ReportUpdates"),
+                Eq(defaultParams.reportUpdates()));
     EXPECT_THAT(
         getProperty<bool>(sut->getPath(), "LogToMetricReportsCollection"),
         Eq(defaultParams.logToMetricReportCollection()));
@@ -503,6 +509,113 @@
                             std::make_tuple("aa"s, "bb"s, 42.0, 74u)));
 }
 
+struct ReportUpdatesReportParams
+{
+    ReportParams reportParams;
+    std::vector<ReadingData> expectedReadings;
+    bool expectedEnabled;
+};
+
+class TestReportWithReportUpdatesAndLimit :
+    public TestReport,
+    public WithParamInterface<ReportUpdatesReportParams>
+{
+    void SetUp() override
+    {
+        sut = makeReport(ReportParams(GetParam().reportParams)
+                             .reportingType("Periodic")
+                             .interval(std::chrono::hours(1000)));
+    }
+};
+
+INSTANTIATE_TEST_SUITE_P(
+    _, TestReportWithReportUpdatesAndLimit,
+    Values(
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendWrapsWhenFull").appendLimit(5),
+            std::vector<ReadingData>{{std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                                      std::make_tuple("a"s, "b"s, 17.1, 114u),
+                                      std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                                      std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                                      std::make_tuple("a"s, "b"s, 17.1, 114u)}},
+            true},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendWrapsWhenFull").appendLimit(4),
+            std::vector<ReadingData>{
+                {std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                 std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
+            true},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendWrapsWhenFull").appendLimit(0),
+            std::vector<ReadingData>{}, true},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendStopsWhenFull").appendLimit(10),
+            std::vector<ReadingData>{
+                {std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                 std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                 std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                 std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
+            true},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendStopsWhenFull").appendLimit(5),
+            std::vector<ReadingData>{{std::make_tuple("a"s, "b"s, 17.1, 114u),
+                                      std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                                      std::make_tuple("a"s, "b"s, 17.1, 114u),
+                                      std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                                      std::make_tuple("a"s, "b"s, 17.1, 114u)}},
+            false},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendStopsWhenFull").appendLimit(4),
+            std::vector<ReadingData>{
+                {std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u),
+                 std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
+            false},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("AppendStopsWhenFull").appendLimit(0),
+            std::vector<ReadingData>{}, false},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("Overwrite").appendLimit(500),
+            std::vector<ReadingData>{
+                {std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
+            true},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("Overwrite").appendLimit(1),
+            std::vector<ReadingData>{
+                {std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
+            true},
+        ReportUpdatesReportParams{
+            ReportParams().reportUpdates("Overwrite").appendLimit(0),
+            std::vector<ReadingData>{
+                {std::make_tuple("a"s, "b"s, 17.1, 114u),
+                 std::make_tuple("aa"s, "bb"s, 42.0, 74u)}},
+            true}));
+
+TEST_P(TestReportWithReportUpdatesAndLimit,
+       readingsAreUpdatedAfterIntervalExpires)
+{
+    for (int i = 0; i < 4; i++)
+    {
+        sut->updateReadings();
+    }
+
+    const auto [timestamp, readings] =
+        getProperty<Readings>(sut->getPath(), "Readings");
+    const auto enabled = getProperty<bool>(sut->getPath(), "Enabled");
+
+    EXPECT_THAT(readings, ElementsAreArray(GetParam().expectedReadings));
+    EXPECT_EQ(enabled, GetParam().expectedEnabled);
+}
+
 class TestReportInitialization : public TestReport
 {
   public:
@@ -593,3 +706,11 @@
     makeMonitor();
     DbusEnvironment::sleepFor(defaultParams.interval() * 2);
 }
+
+TEST_F(TestReportInitialization, appendLimitDeducedProperly)
+{
+    sut = makeReport(
+        ReportParams().appendLimit(std::numeric_limits<uint64_t>::max()));
+    auto appendLimit = getProperty<uint64_t>(sut->getPath(), "AppendLimit");
+    EXPECT_EQ(appendLimit, 2ull);
+}
diff --git a/tests/src/test_report_manager.cpp b/tests/src/test_report_manager.cpp
index eeedd96..a740d95 100644
--- a/tests/src/test_report_manager.cpp
+++ b/tests/src/test_report_manager.cpp
@@ -60,9 +60,9 @@
             },
             DbusEnvironment::serviceName(), ReportManager::reportManagerPath,
             ReportManager::reportManagerIfaceName, "AddReportFutureVersion",
-            params.reportName(), params.reportingType(),
-            params.emitReadingUpdate(), params.logToMetricReportCollection(),
-            params.interval().count(),
+            params.reportName(), params.reportingType(), params.reportUpdates(),
+            params.appendLimit(), params.emitReadingUpdate(),
+            params.logToMetricReportCollection(), params.interval().count(),
             toReadingParameters(params.metricParameters()));
         return DbusEnvironment::waitForFuture(addReportPromise.get_future());
     }
@@ -336,6 +336,8 @@
         {"LogToMetricReportsCollection",
          reportParams.logToMetricReportCollection()},
         {"Interval", reportParams.interval().count()},
+        {"ReportUpdates", reportParams.reportUpdates()},
+        {"AppendLimit", reportParams.appendLimit()},
         {"ReadingParameters", reportParams.metricParameters()}};
 };