Skip to content

Commit c6334ab

Browse files
authored
[ML] Refactor tests that use CDataGatherer constructor (#2845)
This is a refactoring PR. It cleans up and refactors some unit tests. No functional changes have been made. It also fixes the linting issues from clang-tidy and SonarQube.
1 parent 8a713ef commit c6334ab

9 files changed

+1898
-2441
lines changed

lib/model/unittest/CDetectionRuleTest.cc

Lines changed: 281 additions & 475 deletions
Large diffs are not rendered by default.

lib/model/unittest/CEventRateDataGathererTest.cc

Lines changed: 517 additions & 819 deletions
Large diffs are not rendered by default.

lib/model/unittest/CEventRatePopulationDataGathererTest.cc

Lines changed: 191 additions & 200 deletions
Large diffs are not rendered by default.

lib/model/unittest/CHierarchicalResultsTest.cc

Lines changed: 216 additions & 237 deletions
Large diffs are not rendered by default.

lib/model/unittest/CMetricDataGathererTest.cc

Lines changed: 295 additions & 319 deletions
Large diffs are not rendered by default.

lib/model/unittest/CMetricPopulationDataGathererTest.cc

Lines changed: 254 additions & 289 deletions
Large diffs are not rendered by default.

lib/model/unittest/CModelDetailsViewTest.cc

Lines changed: 40 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,12 @@
2323
#include <model/CSearchKey.h>
2424

2525
#include "Mocks.h"
26+
#include "ModelTestHelpers.h"
2627

2728
#include <boost/test/unit_test.hpp>
2829

2930
#include <memory>
31+
#include <ranges>
3032
#include <vector>
3133

3234
BOOST_TEST_DONT_PRINT_LOG_VALUE(ml::model::CModelPlotData::TFeatureStrByFieldDataUMapUMapCItr);
@@ -35,115 +37,79 @@ BOOST_AUTO_TEST_SUITE(CModelDetailsViewTest)
3537

3638
using namespace ml;
3739

38-
namespace {
39-
40-
const std::string EMPTY_STRING;
41-
42-
} // unnamed
43-
4440
class CTestFixture {
4541
protected:
4642
model::CResourceMonitor m_ResourceMonitor;
4743
};
4844

4945
BOOST_FIXTURE_TEST_CASE(testModelPlot, CTestFixture) {
5046
using TDoubleVec = std::vector<double>;
51-
using TStrVec = std::vector<std::string>;
5247
using TMockModelPtr = std::unique_ptr<model::CMockModel>;
5348

54-
core_t::TTime bucketLength{600};
55-
model::CSearchKey key;
56-
model::SModelParams params{bucketLength};
49+
constexpr core_t::TTime bucketLength{600};
50+
const model::CSearchKey key;
51+
const model::SModelParams params{bucketLength};
5752
model_t::TFeatureVec features;
5853

5954
model::CAnomalyDetectorModel::TDataGathererPtr gatherer;
6055
TMockModelPtr model;
6156

6257
auto setupTest = [&]() {
63-
gatherer = std::make_shared<model::CDataGatherer>(
64-
model_t::analysisCategory(features[0]), model_t::E_None, params,
65-
EMPTY_STRING, EMPTY_STRING, "p", EMPTY_STRING, EMPTY_STRING,
66-
TStrVec{}, key, features, 0, 0);
67-
std::string person11{"p11"};
68-
std::string person12{"p12"};
69-
std::string person21{"p21"};
70-
std::string person22{"p22"};
71-
bool addedPerson{false};
72-
gatherer->addPerson(person11, m_ResourceMonitor, addedPerson);
73-
gatherer->addPerson(person12, m_ResourceMonitor, addedPerson);
74-
gatherer->addPerson(person21, m_ResourceMonitor, addedPerson);
75-
gatherer->addPerson(person22, m_ResourceMonitor, addedPerson);
76-
77-
model.reset(new model::CMockModel{params, gatherer, {/*we don't care about influence*/}});
78-
79-
maths::time_series::CTimeSeriesDecomposition trend;
80-
maths::common::CNormalMeanPrecConjugate prior{
58+
gatherer = model::CDataGathererBuilder(model_t::analysisCategory(features[0]),
59+
features, params, key, 0)
60+
.personFieldName("p")
61+
.buildSharedPtr();
62+
for (const std::vector<std::string> persons{"p11", "p12", "p21", "p22"};
63+
const auto& person : persons) {
64+
bool addedPerson{false};
65+
gatherer->addPerson(person, m_ResourceMonitor, addedPerson);
66+
}
67+
68+
const model::CMockModel::TFeatureInfluenceCalculatorCPtrPrVecVec influenceCalculators;
69+
model = std::make_unique<model::CMockModel>(params, gatherer, influenceCalculators);
70+
71+
const maths::time_series::CTimeSeriesDecomposition trend;
72+
const maths::common::CNormalMeanPrecConjugate prior{
8173
maths::common::CNormalMeanPrecConjugate::nonInformativePrior(maths_t::E_ContinuousData)};
82-
maths::common::CModelParams timeSeriesModelParams{
74+
const maths::common::CModelParams timeSeriesModelParams{
8375
bucketLength, 1.0, 0.001, 0.2, 6 * core::constants::HOUR, 24 * core::constants::HOUR};
84-
maths::time_series::CUnivariateTimeSeriesModel timeSeriesModel{
76+
const maths::time_series::CUnivariateTimeSeriesModel timeSeriesModel{
8577
timeSeriesModelParams, 0, trend, prior};
8678
model::CMockModel::TMathsModelUPtrVec models;
87-
models.emplace_back(timeSeriesModel.clone(0));
88-
models.emplace_back(timeSeriesModel.clone(1));
89-
models.emplace_back(timeSeriesModel.clone(2));
90-
models.emplace_back(timeSeriesModel.clone(3));
79+
for (int i = 0; i < 4; ++i) {
80+
models.emplace_back(timeSeriesModel.clone(i));
81+
}
9182
model->mockTimeSeriesModels(std::move(models));
9283
};
9384

94-
LOG_DEBUG(<< "Individual sum");
95-
{
96-
features.assign(1, model_t::E_IndividualSumByBucketAndPerson);
85+
auto testModelPlot = [&](model_t::EFeature feature, const TDoubleVec& values) {
86+
features.assign(1, feature);
9787
setupTest();
98-
99-
TDoubleVec values{2.0, 3.0, 0.0, 0.0};
10088
std::size_t pid{0};
10189
for (auto value : values) {
102-
model->mockAddBucketValue(model_t::E_IndividualSumByBucketAndPerson,
103-
pid++, 0, 0, {value});
90+
model->mockAddBucketValue(feature, pid++, 0, 0, {value});
10491
}
10592

10693
model::CModelPlotData plotData;
10794
model->details()->modelPlot(0, 90.0, {}, plotData);
10895
BOOST_TEST_REQUIRE(plotData.begin() != plotData.end());
109-
for (const auto& featureByFieldData : plotData) {
110-
BOOST_REQUIRE_EQUAL(values.size(), featureByFieldData.second.size());
111-
for (const auto& byFieldData : featureByFieldData.second) {
112-
BOOST_TEST_REQUIRE(gatherer->personId(byFieldData.first, pid));
113-
BOOST_REQUIRE_EQUAL(1, byFieldData.second.s_ValuesPerOverField.size());
114-
for (const auto& currentBucketValue : byFieldData.second.s_ValuesPerOverField) {
115-
BOOST_REQUIRE_EQUAL(values[pid], currentBucketValue.second);
96+
for (const auto & [ _, plotDataValues ] : plotData) {
97+
BOOST_REQUIRE_EQUAL(values.size(), plotDataValues.size());
98+
for (const auto & [ fst, snd ] : plotDataValues) {
99+
BOOST_TEST_REQUIRE(gatherer->personId(fst, pid));
100+
BOOST_REQUIRE_EQUAL(1, snd.s_ValuesPerOverField.size());
101+
for (const auto & [ field_name, val ] : snd.s_ValuesPerOverField) {
102+
BOOST_REQUIRE_EQUAL(values[pid], val);
116103
}
117104
}
118105
}
119-
}
120-
121-
LOG_DEBUG(<< "Individual count");
122-
{
123-
features.assign(1, model_t::E_IndividualCountByBucketAndPerson);
124-
setupTest();
106+
};
125107

126-
TDoubleVec values{0.0, 1.0, 3.0};
127-
std::size_t pid{0};
128-
for (auto value : values) {
129-
model->mockAddBucketValue(model_t::E_IndividualCountByBucketAndPerson,
130-
pid++, 0, 0, {value});
131-
}
108+
LOG_DEBUG(<< "Individual sum");
109+
testModelPlot(model_t::E_IndividualSumByBucketAndPerson, {2.0, 3.0, 0.0, 0.0});
132110

133-
model::CModelPlotData plotData;
134-
model->details()->modelPlot(0, 90.0, {}, plotData);
135-
BOOST_TEST_REQUIRE(plotData.begin() != plotData.end());
136-
for (const auto& featureByFieldData : plotData) {
137-
BOOST_REQUIRE_EQUAL(values.size(), featureByFieldData.second.size());
138-
for (const auto& byFieldData : featureByFieldData.second) {
139-
BOOST_TEST_REQUIRE(gatherer->personId(byFieldData.first, pid));
140-
BOOST_REQUIRE_EQUAL(1, byFieldData.second.s_ValuesPerOverField.size());
141-
for (const auto& currentBucketValue : byFieldData.second.s_ValuesPerOverField) {
142-
BOOST_REQUIRE_EQUAL(values[pid], currentBucketValue.second);
143-
}
144-
}
145-
}
146-
}
111+
LOG_DEBUG(<< "Individual count");
112+
testModelPlot(model_t::E_IndividualCountByBucketAndPerson, {0.0, 1.0, 3.0});
147113
}
148114

149115
BOOST_AUTO_TEST_SUITE_END()

lib/model/unittest/CRuleConditionTest.cc

Lines changed: 15 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@
1313

1414
#include <model/CAnomalyDetectorModel.h>
1515
#include <model/CDataGatherer.h>
16-
#include <model/CDetectionRule.h>
1716
#include <model/CRuleCondition.h>
1817
#include <model/CSearchKey.h>
1918
#include <model/ModelTypes.h>
2019
#include <model/SModelParams.h>
2120

2221
#include "Mocks.h"
22+
#include "ModelTestHelpers.h"
2323

2424
#include <boost/test/unit_test.hpp>
2525

@@ -31,41 +31,31 @@ BOOST_AUTO_TEST_SUITE(CRuleConditionTest)
3131
using namespace ml;
3232
using namespace model;
3333

34-
namespace {
35-
36-
using TStrVec = std::vector<std::string>;
37-
38-
const std::string EMPTY_STRING;
39-
}
40-
4134
BOOST_AUTO_TEST_CASE(testTimeContition) {
42-
core_t::TTime bucketLength = 100;
43-
core_t::TTime startTime = 100;
44-
CSearchKey key;
45-
SModelParams params(bucketLength);
46-
CAnomalyDetectorModel::TFeatureInfluenceCalculatorCPtrPrVecVec influenceCalculators;
35+
constexpr core_t::TTime bucketLength = 100;
36+
constexpr core_t::TTime startTime = 100;
37+
CSearchKey const key;
38+
SModelParams const params(bucketLength);
39+
const CAnomalyDetectorModel::TFeatureInfluenceCalculatorCPtrPrVecVec influenceCalculators;
4740

4841
model_t::TFeatureVec features;
4942
features.push_back(model_t::E_IndividualMeanByPerson);
50-
CAnomalyDetectorModel::TDataGathererPtr gathererPtr(std::make_shared<CDataGatherer>(
51-
model_t::E_Metric, model_t::E_None, params, EMPTY_STRING, EMPTY_STRING, EMPTY_STRING,
52-
EMPTY_STRING, EMPTY_STRING, TStrVec{}, key, features, startTime, 0));
43+
auto gathererPtr = CDataGathererBuilder(model_t::E_Metric, features, params, key, startTime)
44+
.buildSharedPtr();
5345

54-
CMockModel model(params, gathererPtr, influenceCalculators);
46+
CMockModel const model(params, gathererPtr, influenceCalculators);
5547

5648
{
5749
CRuleCondition condition;
5850
condition.appliesTo(CRuleCondition::E_Time);
5951
condition.op(CRuleCondition::E_GTE);
6052
condition.value(500);
6153

62-
model_t::CResultType resultType(model_t::CResultType::E_Final);
54+
model_t::CResultType const resultType(model_t::CResultType::E_Final);
6355
BOOST_TEST_REQUIRE(condition.test(model, model_t::E_IndividualCountByBucketAndPerson,
64-
resultType, std::size_t(0), std::size_t(1),
65-
core_t::TTime(450)) == false);
56+
resultType, 0, 1, 450) == false);
6657
BOOST_TEST_REQUIRE(condition.test(model, model_t::E_IndividualCountByBucketAndPerson,
67-
resultType, std::size_t(0),
68-
std::size_t(1), core_t::TTime(550)));
58+
resultType, 0, 1, 550));
6959
}
7060

7161
{
@@ -74,13 +64,11 @@ BOOST_AUTO_TEST_CASE(testTimeContition) {
7464
condition.op(CRuleCondition::E_LT);
7565
condition.value(600);
7666

77-
model_t::CResultType resultType(model_t::CResultType::E_Final);
67+
model_t::CResultType const resultType(model_t::CResultType::E_Final);
7868
BOOST_TEST_REQUIRE(condition.test(model, model_t::E_IndividualCountByBucketAndPerson,
79-
resultType, std::size_t(0), std::size_t(1),
80-
core_t::TTime(600)) == false);
69+
resultType, 0, 1, 600) == false);
8170
BOOST_TEST_REQUIRE(condition.test(model, model_t::E_IndividualCountByBucketAndPerson,
82-
resultType, std::size_t(0),
83-
std::size_t(1), core_t::TTime(599)));
71+
resultType, 0, 1, 599));
8472
}
8573
}
8674

lib/model/unittest/ModelTestHelpers.h

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include <model/CDataGatherer.h>
1919
#include <model/CSearchKey.h>
2020
#include <model/ModelTypes.h>
21-
#include <model/SModelParams.h>
2221

2322
#include <boost/test/unit_test.hpp>
2423

@@ -81,6 +80,95 @@ static void testGathererAttributes(const CDataGatherer& gatherer,
8180
BOOST_REQUIRE_EQUAL(startTime, gatherer.currentBucketStartTime());
8281
BOOST_REQUIRE_EQUAL(bucketLength, gatherer.bucketLength());
8382
}
83+
84+
class CDataGathererBuilder {
85+
public:
86+
using TFeatureVec = CDataGatherer::TFeatureVec;
87+
using TStrVec = CDataGatherer::TStrVec;
88+
89+
public:
90+
CDataGathererBuilder(model_t::EAnalysisCategory gathererType,
91+
const TFeatureVec& features,
92+
const SModelParams& params,
93+
const CSearchKey& searchKey,
94+
const core_t::TTime startTime)
95+
: m_Features(features), m_Params(params), m_StartTime(startTime),
96+
m_SearchKey(searchKey), m_GathererType(gathererType) {}
97+
98+
CDataGatherer build() const {
99+
return {m_GathererType,
100+
m_SummaryMode,
101+
m_Params,
102+
m_SummaryCountFieldName,
103+
m_PartitionFieldValue,
104+
m_PersonFieldName,
105+
m_AttributeFieldName,
106+
m_ValueFieldName,
107+
m_InfluenceFieldNames,
108+
m_SearchKey,
109+
m_Features,
110+
m_StartTime,
111+
m_SampleCountOverride};
112+
}
113+
114+
std::shared_ptr<CDataGatherer> buildSharedPtr() const {
115+
return std::make_shared<CDataGatherer>(
116+
m_GathererType, m_SummaryMode, m_Params, m_SummaryCountFieldName,
117+
m_PartitionFieldValue, m_PersonFieldName, m_AttributeFieldName,
118+
m_ValueFieldName, m_InfluenceFieldNames, m_SearchKey, m_Features,
119+
m_StartTime, m_SampleCountOverride);
120+
}
121+
122+
CDataGathererBuilder& partitionFieldValue(std::string_view partitionFieldValue) {
123+
m_PartitionFieldValue = partitionFieldValue;
124+
return *this;
125+
}
126+
127+
CDataGathererBuilder& personFieldName(std::string_view personFieldName) {
128+
m_PersonFieldName = personFieldName;
129+
return *this;
130+
}
131+
132+
CDataGathererBuilder& valueFieldName(std::string_view valueFieldName) {
133+
m_ValueFieldName = valueFieldName;
134+
return *this;
135+
}
136+
137+
CDataGathererBuilder& influenceFieldNames(const TStrVec& influenceFieldName) {
138+
m_InfluenceFieldNames = influenceFieldName;
139+
return *this;
140+
}
141+
142+
CDataGathererBuilder& attributeFieldName(std::string_view attributeFieldName) {
143+
m_AttributeFieldName = attributeFieldName;
144+
return *this;
145+
}
146+
147+
CDataGathererBuilder& gathererType(model_t::EAnalysisCategory gathererType) {
148+
m_GathererType = gathererType;
149+
return *this;
150+
}
151+
152+
CDataGathererBuilder& sampleCountOverride(std::size_t sampleCount) {
153+
m_SampleCountOverride = static_cast<int>(sampleCount);
154+
return *this;
155+
}
156+
157+
private:
158+
const TFeatureVec& m_Features;
159+
const SModelParams& m_Params;
160+
core_t::TTime m_StartTime;
161+
const CSearchKey& m_SearchKey;
162+
model_t::EAnalysisCategory m_GathererType;
163+
model_t::ESummaryMode m_SummaryMode{model_t::E_None};
164+
std::string m_SummaryCountFieldName{EMPTY_STRING};
165+
std::string m_PartitionFieldValue{EMPTY_STRING};
166+
std::string m_PersonFieldName{EMPTY_STRING};
167+
std::string m_AttributeFieldName{EMPTY_STRING};
168+
std::string m_ValueFieldName{EMPTY_STRING};
169+
TStrVec m_InfluenceFieldNames;
170+
int m_SampleCountOverride{0};
171+
};
84172
}
85173
}
86174

0 commit comments

Comments
 (0)