mirror of https://github.com/oxen-io/lokinet
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
342 lines
9.4 KiB
C++
342 lines
9.4 KiB
C++
#include <util/metrics_types.hpp>
|
|
|
|
#include <array>
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <gmock/gmock.h>
|
|
|
|
using namespace llarp;
|
|
using namespace ::testing;
|
|
|
|
struct MetricFormatSpecTestData
|
|
{
|
|
float m_scale;
|
|
const char *m_spec;
|
|
double m_value;
|
|
const char *m_expected;
|
|
};
|
|
|
|
struct MetricFormatSpecTest : public TestWithParam< MetricFormatSpecTestData >
|
|
{
|
|
};
|
|
|
|
TEST_P(MetricFormatSpecTest, print)
|
|
{
|
|
auto d = GetParam();
|
|
|
|
metrics::FormatSpec spec(d.m_scale, d.m_spec);
|
|
std::ostringstream stream;
|
|
metrics::FormatSpec::format(stream, d.m_value, spec);
|
|
|
|
ASSERT_EQ(d.m_expected, stream.str());
|
|
}
|
|
|
|
MetricFormatSpecTestData metricFormatTestData[] = {
|
|
MetricFormatSpecTestData{0.0, "", 1.5, ""},
|
|
MetricFormatSpecTestData{1.0, "%.4f", 1.5, "1.5000"},
|
|
MetricFormatSpecTestData{1.0, "%.0f", 2.0, "2"},
|
|
MetricFormatSpecTestData{1.0, "%.0f", 1.1, "1"},
|
|
MetricFormatSpecTestData{1.0, "%.0f", 1.5, "2"},
|
|
MetricFormatSpecTestData{1.0, "%.0f", 1.7, "2"},
|
|
MetricFormatSpecTestData{1.0, "%.0f", 3.0, "3"},
|
|
MetricFormatSpecTestData{2.0, "%.0f", 3.0, "6"},
|
|
MetricFormatSpecTestData{2.0, "%.1f", 1.1, "2.2"}};
|
|
|
|
INSTANTIATE_TEST_CASE_P(MetricsTypes, MetricFormatSpecTest,
|
|
ValuesIn(metricFormatTestData));
|
|
|
|
TEST(MetricsTypes, Format)
|
|
{
|
|
metrics::Format format;
|
|
|
|
format.setSpec(metrics::Publication::Type::Max,
|
|
metrics::FormatSpec(1.0, "%0.2f"));
|
|
format.setSpec(metrics::Publication::Type::Total,
|
|
metrics::FormatSpec(2.0, "%0.3f"));
|
|
|
|
ASSERT_EQ(nullptr, format.specFor(metrics::Publication::Type::Avg));
|
|
auto ptr = format.specFor(metrics::Publication::Type::Total);
|
|
ASSERT_NE(nullptr, ptr);
|
|
ASSERT_STREQ("%0.3f", ptr->m_format);
|
|
ASSERT_DOUBLE_EQ(2.0, ptr->m_scale);
|
|
ptr = format.specFor(metrics::Publication::Type::Max);
|
|
ASSERT_NE(nullptr, ptr);
|
|
ASSERT_STREQ("%0.2f", ptr->m_format);
|
|
ASSERT_DOUBLE_EQ(1.0, ptr->m_scale);
|
|
|
|
format.clear();
|
|
|
|
ASSERT_EQ(nullptr, format.specFor(metrics::Publication::Type::Total));
|
|
ASSERT_EQ(nullptr, format.specFor(metrics::Publication::Type::Max));
|
|
}
|
|
|
|
TEST(MetricsTypes, CatContainer)
|
|
{
|
|
std::array< metrics::CategoryContainer, 10 > containers;
|
|
{
|
|
metrics::Category c("A");
|
|
for(size_t i = 0; i < containers.size(); ++i)
|
|
{
|
|
c.registerContainer(&containers[i]);
|
|
metrics::CategoryContainer *next = (0 == i) ? 0 : &containers[i - 1];
|
|
ASSERT_EQ(&c, containers[i].m_category);
|
|
ASSERT_TRUE(containers[i].m_enabled);
|
|
ASSERT_EQ(next, containers[i].m_nextCategory);
|
|
}
|
|
|
|
for(size_t i = 0; i < containers.size(); ++i)
|
|
{
|
|
metrics::CategoryContainer *next = (0 == i) ? 0 : &containers[i - 1];
|
|
ASSERT_EQ(&c, containers[i].m_category);
|
|
ASSERT_TRUE(containers[i].m_enabled);
|
|
ASSERT_EQ(next, containers[i].m_nextCategory);
|
|
}
|
|
|
|
const std::atomic_bool *enabled = &c.enabledRaw();
|
|
|
|
c.enabled(false);
|
|
|
|
ASSERT_FALSE(*enabled);
|
|
ASSERT_EQ(&c.enabledRaw(), enabled);
|
|
|
|
for(size_t i = 0; i < containers.size(); ++i)
|
|
{
|
|
metrics::CategoryContainer *next = (0 == i) ? 0 : &containers[i - 1];
|
|
ASSERT_EQ(&c, containers[i].m_category);
|
|
ASSERT_FALSE(containers[i].m_enabled);
|
|
ASSERT_EQ(next, containers[i].m_nextCategory);
|
|
}
|
|
|
|
c.enabled(true);
|
|
|
|
ASSERT_TRUE(*enabled);
|
|
ASSERT_EQ(&c.enabledRaw(), enabled);
|
|
|
|
for(size_t i = 0; i < containers.size(); ++i)
|
|
{
|
|
metrics::CategoryContainer *next = (0 == i) ? 0 : &containers[i - 1];
|
|
ASSERT_EQ(&c, containers[i].m_category);
|
|
ASSERT_TRUE(containers[i].m_enabled);
|
|
ASSERT_EQ(next, containers[i].m_nextCategory);
|
|
}
|
|
}
|
|
for(const auto &container : containers)
|
|
{
|
|
ASSERT_THAT(container.m_category, IsNull());
|
|
ASSERT_FALSE(container.m_enabled);
|
|
ASSERT_THAT(container.m_nextCategory, IsNull());
|
|
}
|
|
}
|
|
|
|
TEST(MetricsTypes, Record)
|
|
{
|
|
metrics::Record r;
|
|
ASSERT_GT(r.min(), r.max());
|
|
}
|
|
|
|
TEST(MetricsTypes, Sample)
|
|
{
|
|
metrics::Category myCategory("MyCategory");
|
|
metrics::Description descA(&myCategory, "MetricA");
|
|
metrics::Description descB(&myCategory, "MetricB");
|
|
metrics::Description descC(&myCategory, "MetricC");
|
|
|
|
metrics::Id metricA(&descA);
|
|
metrics::Id metricB(&descB);
|
|
metrics::Id metricC(&descC);
|
|
|
|
absl::Time timeStamp = absl::Now();
|
|
metrics::Record recordA(metricA, 0, 0, 0, 0);
|
|
metrics::Record recordB(metricB, 1, 2, 3, 4);
|
|
metrics::Record recordC(metricC, 4, 3, 2, 1);
|
|
|
|
metrics::Record buffer1[] = {recordA, recordB};
|
|
std::vector< metrics::Record > buffer2;
|
|
buffer2.push_back(recordC);
|
|
|
|
metrics::Sample sample;
|
|
sample.sampleTime(timeStamp);
|
|
sample.pushGroup(buffer1, sizeof(buffer1) / sizeof(*buffer1),
|
|
absl::Seconds(1.0));
|
|
sample.pushGroup(buffer2.data(), buffer2.size(), absl::Seconds(2.0));
|
|
|
|
ASSERT_EQ(timeStamp, sample.sampleTime());
|
|
ASSERT_EQ(2u, sample.groupCount());
|
|
ASSERT_EQ(3u, sample.recordCount());
|
|
ASSERT_EQ(absl::Seconds(1), sample.group(0).samplePeriod());
|
|
ASSERT_EQ(buffer1, sample.group(0).records().data());
|
|
ASSERT_EQ(2, sample.group(0).size());
|
|
ASSERT_EQ(absl::Seconds(2), sample.group(1).samplePeriod());
|
|
ASSERT_EQ(buffer2.data(), sample.group(1).records().data());
|
|
ASSERT_EQ(1, sample.group(1).size());
|
|
|
|
for(auto sampleIt = sample.begin(); sampleIt != sample.end(); ++sampleIt)
|
|
{
|
|
;
|
|
for(auto groupIt = sampleIt->begin(); groupIt != sampleIt->end(); ++groupIt)
|
|
{
|
|
std::cout << *groupIt << std::endl;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct SampleTest
|
|
: public ::testing::TestWithParam< std::pair< absl::Time, std::string > >
|
|
{
|
|
metrics::Category cat_A;
|
|
metrics::Description DESC_A;
|
|
metrics::Description DESC_B;
|
|
metrics::Description DESC_C;
|
|
metrics::Description DESC_D;
|
|
metrics::Description DESC_E;
|
|
metrics::Description DESC_F;
|
|
metrics::Description DESC_G;
|
|
|
|
metrics::Id id_A;
|
|
metrics::Id id_B;
|
|
metrics::Id id_C;
|
|
metrics::Id id_D;
|
|
metrics::Id id_E;
|
|
metrics::Id id_F;
|
|
metrics::Id id_G;
|
|
|
|
std::vector< metrics::Record > recordBuffer;
|
|
|
|
SampleTest()
|
|
: cat_A("A", true)
|
|
, DESC_A(&cat_A, "A")
|
|
, DESC_B(&cat_A, "B")
|
|
, DESC_C(&cat_A, "C")
|
|
, DESC_D(&cat_A, "D")
|
|
, DESC_E(&cat_A, "E")
|
|
, DESC_F(&cat_A, "F")
|
|
, DESC_G(&cat_A, "G")
|
|
, id_A(&DESC_A)
|
|
, id_B(&DESC_B)
|
|
, id_C(&DESC_C)
|
|
, id_D(&DESC_D)
|
|
, id_E(&DESC_E)
|
|
, id_F(&DESC_F)
|
|
, id_G(&DESC_G)
|
|
{
|
|
recordBuffer.emplace_back(metrics::Id(0), 1, 1, 1, 1);
|
|
recordBuffer.emplace_back(id_A, 2, 2, 2, 2);
|
|
recordBuffer.emplace_back(id_B, 3, 3, 3, 3);
|
|
recordBuffer.emplace_back(id_C, 4, 4, 4, 4);
|
|
recordBuffer.emplace_back(id_D, 5, 5, 5, 5);
|
|
recordBuffer.emplace_back(id_E, 6, 6, 6, 6);
|
|
recordBuffer.emplace_back(id_F, 7, 7, 7, 7);
|
|
recordBuffer.emplace_back(id_G, 8, 8, 8, 8);
|
|
recordBuffer.emplace_back(id_A, 9, 9, 9, 9);
|
|
}
|
|
};
|
|
|
|
std::pair< std::vector< metrics::SampleGroup >, size_t >
|
|
generate(const std::string &specification,
|
|
const std::vector< metrics::Record > &recordBuffer)
|
|
{
|
|
const char *c = specification.c_str();
|
|
|
|
std::vector< metrics::SampleGroup > groups;
|
|
size_t size = 0;
|
|
|
|
const metrics::Record *head = recordBuffer.data();
|
|
const metrics::Record *current = head;
|
|
while(*c)
|
|
{
|
|
int numRecords = *(c + 1) - '0';
|
|
|
|
int elapsedTime = *(c + 3) - '0';
|
|
|
|
if(head + recordBuffer.size() < current + numRecords)
|
|
{
|
|
current = head;
|
|
}
|
|
groups.emplace_back(current, numRecords, absl::Seconds(elapsedTime));
|
|
|
|
size += numRecords;
|
|
current += numRecords;
|
|
c += 4;
|
|
}
|
|
return {groups, size};
|
|
}
|
|
|
|
TEST_P(SampleTest, basics)
|
|
{
|
|
absl::Time timestamp;
|
|
std::string spec;
|
|
|
|
std::tie(timestamp, spec) = GetParam();
|
|
|
|
std::vector< metrics::SampleGroup > groups;
|
|
size_t size;
|
|
std::tie(groups, size) = generate(spec, recordBuffer);
|
|
|
|
// Create the sample.
|
|
metrics::Sample sample;
|
|
sample.sampleTime(timestamp);
|
|
for(size_t j = 0; j < groups.size(); ++j)
|
|
{
|
|
sample.pushGroup(groups[j]);
|
|
}
|
|
|
|
// Test the sample.
|
|
ASSERT_EQ(timestamp, sample.sampleTime());
|
|
ASSERT_EQ(groups.size(), sample.groupCount());
|
|
ASSERT_EQ(size, sample.recordCount());
|
|
for(size_t j = 0; j < sample.groupCount(); ++j)
|
|
{
|
|
ASSERT_EQ(groups[j], sample.group(j));
|
|
}
|
|
}
|
|
|
|
TEST_P(SampleTest, append)
|
|
{
|
|
absl::Time timestamp;
|
|
std::string spec;
|
|
|
|
std::tie(timestamp, spec) = GetParam();
|
|
|
|
std::vector< metrics::SampleGroup > groups;
|
|
size_t size;
|
|
std::tie(groups, size) = generate(spec, recordBuffer);
|
|
|
|
// Create the sample.
|
|
metrics::Sample sample;
|
|
sample.sampleTime(timestamp);
|
|
|
|
std::for_each(groups.begin(), groups.end(), [&](const auto &group) {
|
|
sample.pushGroup(group.records(), group.samplePeriod());
|
|
});
|
|
|
|
// Test the sample.
|
|
ASSERT_EQ(timestamp, sample.sampleTime());
|
|
ASSERT_EQ(groups.size(), sample.groupCount());
|
|
ASSERT_EQ(size, sample.recordCount());
|
|
|
|
for(size_t j = 0; j < sample.groupCount(); ++j)
|
|
{
|
|
ASSERT_EQ(groups[j], sample.group(j));
|
|
}
|
|
}
|
|
|
|
absl::Time
|
|
fromYYMMDD(int year, int month, int day)
|
|
{
|
|
return absl::FromCivil(absl::CivilDay(year, month, day), absl::UTCTimeZone());
|
|
}
|
|
|
|
std::pair< absl::Time, std::string > sampleTestData[] = {
|
|
{fromYYMMDD(1900, 1, 1), ""},
|
|
{fromYYMMDD(1999, 1, 1), "R1E1"},
|
|
{fromYYMMDD(1999, 2, 1), "R2E2"},
|
|
{fromYYMMDD(2001, 9, 9), "R1E1R2E2"},
|
|
{fromYYMMDD(2001, 9, 9), "R3E3R3E3"},
|
|
{fromYYMMDD(2009, 9, 9), "R2E4R1E1"},
|
|
{fromYYMMDD(2001, 9, 9), "R1E1R2E2R3E3"},
|
|
{fromYYMMDD(2001, 9, 9), "R4E1R3E2R2E3R1E4"},
|
|
{fromYYMMDD(2001, 9, 9), "R1E1R2E2R1E1R2E2R1E1R2E1R1E2"}};
|
|
|
|
INSTANTIATE_TEST_CASE_P(MetricsTypes, SampleTest,
|
|
::testing::ValuesIn(sampleTestData));
|