#include "util/prometheus/Label.hpp" #include "util/prometheus/MetricBase.hpp" #include "util/prometheus/MetricBuilder.hpp" #include "util/prometheus/MetricsFamily.hpp" #include "util/prometheus/OStream.hpp" #include #include #include #include #include #include #include #include using namespace util::prometheus; struct MetricsFamilyTest : ::testing::Test { struct MetricMock : MetricBase { using MetricBase::MetricBase; MOCK_METHOD(void, serializeValue, (OStream&), (const)); }; using MetricStrictMock = ::testing::StrictMock; struct MetricBuilderImplMock : MetricBuilderInterface { std::unique_ptr operator()( std::string metricName, std::string labelsString, MetricType metricType, std::vector const& buckets ) override { return buildInt(std::move(metricName), std::move(labelsString), metricType, buckets); } std::unique_ptr operator()( std::string metricName, std::string labelsString, MetricType metricType, std::vector const& buckets ) override { return buildDouble(std::move(metricName), std::move(labelsString), metricType, buckets); } MOCK_METHOD( std::unique_ptr, buildInt, (std::string, std::string, MetricType, std::vector const&) ); MOCK_METHOD( std::unique_ptr, buildDouble, (std::string, std::string, MetricType, std::vector const&) ); }; ::testing::StrictMock metricBuilderMock; std::string const name{"name"}; std::string const description{"description"}; MetricType const type{MetricType::CounterInt}; MetricsFamily metricsFamily{name, description, type, metricBuilderMock}; }; TEST_F(MetricsFamilyTest, getters) { EXPECT_EQ(metricsFamily.name(), name); EXPECT_EQ(metricsFamily.type(), type); } TEST_F(MetricsFamilyTest, getMetric) { Labels const labels{{{"label1", "value1"}}}; std::string const labelsString = labels.serialize(); EXPECT_CALL(metricBuilderMock, buildInt(name, labelsString, type, std::vector{})) .WillOnce(::testing::Return(std::make_unique(name, labelsString))); auto& metric = metricsFamily.getMetric(labels); EXPECT_EQ(metric.name(), name); EXPECT_EQ(metric.labelsString(), labelsString); auto* metricMock = dynamic_cast(&metric); ASSERT_NE(metricMock, nullptr); EXPECT_EQ(&metricsFamily.getMetric(labels), &metric); Labels const labels2{{{"label1", "value2"}}}; std::string const labels2String = labels2.serialize(); EXPECT_CALL(metricBuilderMock, buildInt(name, labels2String, type, std::vector{})) .WillOnce(::testing::Return(std::make_unique(name, labels2String))); auto& metric2 = metricsFamily.getMetric(labels2); EXPECT_EQ(metric2.name(), name); EXPECT_EQ(metric2.labelsString(), labels2String); auto* metric2Mock = dynamic_cast(&metric2); ASSERT_NE(metric2Mock, nullptr); EXPECT_EQ(&metricsFamily.getMetric(labels2), &metric2); EXPECT_NE(&metric, &metric2); EXPECT_CALL(*metricMock, serializeValue(::testing::_)).WillOnce([](OStream& s) { s << "metric"; }); EXPECT_CALL(*metric2Mock, serializeValue(::testing::_)).WillOnce([](OStream& s) { s << "metric2"; }); OStream stream{false}; stream << metricsFamily; auto const serialized = std::move(stream).data(); auto const expected = fmt::format( "# HELP {0} {1}\n# TYPE {0} {2}\nmetric\nmetric2\n\n", name, description, toString(type) ); auto const anotherExpected = fmt::format( "# HELP {0} {1}\n# TYPE {0} {2}\nmetric2\nmetric\n\n", name, description, toString(type) ); EXPECT_TRUE(serialized == expected || serialized == anotherExpected); }