blob: f5a0127a404fc478e101d38cf30b218596b739f6 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <float.h>
#include <math.h>
#include <stdint.h>
#include <unistd.h>
#include <cobalt-client/cpp/metric-options.h>
#include <unittest/unittest.h>
namespace cobalt_client {
namespace {
bool TestLocal() {
BEGIN_TEST;
MetricOptions options;
options.SetMode(MetricOptions::Mode::kLocal);
ASSERT_TRUE(options.IsLocal());
ASSERT_FALSE(options.IsRemote());
ASSERT_FALSE(options.IsLazy());
END_TEST;
}
bool TestRemote() {
BEGIN_TEST;
MetricOptions options;
options.SetMode(MetricOptions::Mode::kRemote);
EXPECT_TRUE(options.IsRemote());
EXPECT_FALSE(options.IsLocal());
EXPECT_FALSE(options.IsLazy());
END_TEST;
}
bool TestLocalAndRemote() {
BEGIN_TEST;
MetricOptions options;
options.SetMode(MetricOptions::Mode::kRemoteAndLocal);
EXPECT_TRUE(options.IsRemote());
EXPECT_TRUE(options.IsLocal());
EXPECT_FALSE(options.IsLazy());
END_TEST;
}
bool TestLazy() {
BEGIN_TEST;
MetricOptions options;
options.SetMode(MetricOptions::Mode::kLazy);
EXPECT_TRUE(options.IsLazy());
EXPECT_FALSE(options.IsRemote());
EXPECT_FALSE(options.IsLocal());
END_TEST;
}
bool TestMakeExponentialOptions() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::CustomizedExponential(
/*bucket_count*/ 3, /*base*/ 4, /*scalar*/ 2, /*min*/ -10);
ASSERT_EQ(options.base, 4);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, -12);
ASSERT_EQ(options.type, HistogramOptions::Type::kExponential);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestMakeExponentialOptionsMaxOnly() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Exponential(
/*bucket_count*/ 3, /*max*/ 14);
ASSERT_EQ(options.base, 2);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, -2);
// We should be greater than the predecessor of max_value,
// which means that our max would fit in the overflow bucket.
ASSERT_LT(nextafter(options.max_value, 0), 24);
ASSERT_EQ(options.type, HistogramOptions::Type::kExponential);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestMakeExponentialOptionsMaxOnly2() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Exponential(
/*bucket_count*/ 12, /*max*/ (4096 - 1) * 10);
ASSERT_EQ(options.base, 2);
// We scale by 11, instead of 10, because 12 buckets
// can represent at mos 2^12 -1 = 4095, which would
// leave 4096 in the overflow bucket.
ASSERT_EQ(options.scalar, 10);
ASSERT_EQ(options.offset, -10);
// We should be greater than the predecessor of max_value,
// which means that our max would fit in the overflow bucket.
ASSERT_LT(nextafter(options.max_value, 0), 40950);
ASSERT_EQ(options.type, HistogramOptions::Type::kExponential);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestMakeExponentialOptionsMinAndMaxOnly() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Exponential(
/*bucket_count*/ 3, /*min*/ 10, /*max*/ 24);
ASSERT_EQ(options.base, 2);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, 8);
ASSERT_LT(nextafter(options.max_value, 0), 24);
ASSERT_EQ(options.type, HistogramOptions::Type::kExponential);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestMakeExponentialOptionsMaxContainedInLastBucket() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Exponential(
/*bucket_count*/ 3, /*min*/ 10, /*max*/ 23);
ASSERT_EQ(options.base, 2);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, 8);
// |max_value| should be greater than our max, which means that
// our max fits in the last non overflow bucket.
ASSERT_GT(options.max_value, 23);
ASSERT_EQ(options.type, HistogramOptions::Type::kExponential);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestExponentialInvalidBase() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::CustomizedExponential(
/*bucket_count*/ 1, /*base*/ 0, /*scalar*/ 2, /*min*/ -10);
ASSERT_FALSE(options.IsValid());
END_TEST;
}
bool TestExponentialInvalidScalar() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::CustomizedExponential(
/*bucket_count*/ 1, /*base*/ 1, /*scalar*/ 0, /*min*/ -10);
ASSERT_FALSE(options.IsValid());
END_TEST;
}
// Verify correct buckect assignment along the boundaries and points within the bucket for
// exponential bucket width.
bool TestExponentialMap() {
BEGIN_TEST;
// This generates the following histogram:
// | | | | | |
// -inf 5 8 14 26 +inf
HistogramOptions options = HistogramOptions::CustomizedExponential(
/*bucket_count*/ 3, /*base*/ 2, /*scalar*/ 3, /*min*/ 5);
// Bucket count differs in 2, due to underflow and overflow additional buckets.
EXPECT_EQ(options.map_fn(/*value*/ 4, /*bucket_count*/ 5, options), 0);
EXPECT_EQ(options.map_fn(nextafter(5, 4), 5, options), 0);
EXPECT_EQ(options.map_fn(5, 5, options), 1);
EXPECT_EQ(options.map_fn(7.5, 5, options), 1);
EXPECT_EQ(options.map_fn(nextafter(8, 7), 5, options), 1);
EXPECT_EQ(options.map_fn(8, 5, options), 2);
EXPECT_EQ(options.map_fn(12, 5, options), 2);
EXPECT_EQ(options.map_fn(nextafter(12, 11), 5, options), 2);
EXPECT_EQ(options.map_fn(14, 5, options), 3);
EXPECT_EQ(options.map_fn(18, 5, options), 3);
EXPECT_EQ(options.map_fn(nextafter(26, 25), 5, options), 3);
EXPECT_EQ(options.map_fn(26, 5, options), 4);
END_TEST;
}
bool TestExponentialReverseMap() {
BEGIN_TEST;
// This generates the following histogram:
// | | | | | |
// -inf 5 8 14 26 +inf
HistogramOptions options = HistogramOptions::CustomizedExponential(
/*bucket_count*/ 3, /*base*/ 2, /*scalar*/ 3, /*min*/ 5);
EXPECT_EQ(options.reverse_map_fn(/*bucket_index*/ 0, 3, options), -DBL_MAX);
// Bucket count differs in 2, due to underflow and overflow additional buckets.
EXPECT_EQ(options.reverse_map_fn(1, 5, options), 5);
EXPECT_EQ(options.reverse_map_fn(2, 5, options), 8);
EXPECT_EQ(options.reverse_map_fn(3, 5, options), 14);
EXPECT_EQ(options.reverse_map_fn(4, 5, options), 26);
END_TEST;
}
bool TestMakeLinearOptions() {
BEGIN_TEST;
HistogramOptions options =
HistogramOptions::CustomizedLinear(/*bucket_count*/ 3, /*scalar*/ 2, /*min*/ -10);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, -10);
ASSERT_EQ(options.type, HistogramOptions::Type::kLinear);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
ASSERT_TRUE(options.IsValid());
END_TEST;
}
bool TestMakeLinearOptionsMaxOnly() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Linear(/*bucket_count*/ 3, /*max*/ 15);
ASSERT_EQ(options.scalar, 5);
ASSERT_EQ(options.offset, 0);
ASSERT_EQ(options.type, HistogramOptions::Type::kLinear);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestMakeLinearOptionsMinAndMaxOnly() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Linear(/*bucket_count*/ 3, /*min*/ 9, /*max*/ 15);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, 9);
ASSERT_EQ(options.type, HistogramOptions::Type::kLinear);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestMakeLinearOptionsMaxContainedInLastBucket() {
BEGIN_TEST;
HistogramOptions options = HistogramOptions::Linear(/*bucket_count*/ 3, /*min*/ 9, /*max*/ 14);
ASSERT_EQ(options.scalar, 2);
ASSERT_EQ(options.offset, 9);
ASSERT_GT(options.max_value, 14);
ASSERT_EQ(options.type, HistogramOptions::Type::kLinear);
ASSERT_TRUE(options.map_fn);
ASSERT_NOT_NULL(options.map_fn);
ASSERT_NOT_NULL(options.reverse_map_fn);
END_TEST;
}
bool TestLinearInvalidScalar() {
BEGIN_TEST;
HistogramOptions options =
HistogramOptions::CustomizedLinear(/*bucket_count*/ 1, /*scalar*/ 0, /*min*/ -10);
ASSERT_FALSE(options.IsValid());
END_TEST;
}
// Verify correct bucket assignment along the boundaries and points within the bucket for
// linear bucket width.
bool TestLinearMap() {
BEGIN_TEST;
// This generates the following histogram:
// | | | | | |
// -inf -10 -8 -6 -4 +inf
HistogramOptions options =
HistogramOptions::CustomizedLinear(/*bucket_count*/ 3, /*scalar*/ 2, /*min*/ -10);
// bucket count differs in 2 due to underflow and overflow additional buckets.
EXPECT_EQ(options.map_fn(/*value*/ -15, 5, options), 0);
EXPECT_EQ(options.map_fn(nextafter(-10.0, -11), 5, options), 0);
EXPECT_EQ(options.map_fn(-10.0, 5, options), 1);
EXPECT_EQ(options.map_fn(-9.0, 5, options), 1);
EXPECT_EQ(options.map_fn(-8.0, 5, options), 2);
EXPECT_EQ(options.map_fn(-7.0, 5, options), 2);
EXPECT_EQ(options.map_fn(-6.0, 5, options), 3);
EXPECT_EQ(options.map_fn(-5.0, 5, options), 3);
EXPECT_EQ(options.map_fn(nexttoward(-4.0, -5.0), 5, options), 3);
EXPECT_EQ(options.map_fn(-4.0, 5, options), 4);
END_TEST;
}
bool TestLinearReverseMap() {
BEGIN_TEST;
// This generates the following histogram:
// | | | | | |
// -inf -10 -8 -6 -4 +inf
HistogramOptions options =
HistogramOptions::CustomizedLinear(/*bucket_count*/ 3, /*scalar*/ 2, /*min*/ -10);
// bucket count differs in 2 due to underflow and overflow additional buckets.
EXPECT_EQ(options.reverse_map_fn(/*bucket_index*/ 0, 3, options), -DBL_MAX);
EXPECT_EQ(options.reverse_map_fn(1, 5, options), -10);
EXPECT_EQ(options.reverse_map_fn(2, 5, options), -8);
EXPECT_EQ(options.reverse_map_fn(3, 5, options), -6);
EXPECT_EQ(options.reverse_map_fn(4, 5, options), -4);
END_TEST;
}
BEGIN_TEST_CASE(MetricOptionsTest)
RUN_TEST(TestLocal)
RUN_TEST(TestRemote)
RUN_TEST(TestLocalAndRemote)
RUN_TEST(TestLazy)
END_TEST_CASE(MetricOptionsTest)
BEGIN_TEST_CASE(HistogramOptionsTest)
RUN_TEST(TestMakeExponentialOptions)
RUN_TEST(TestMakeExponentialOptionsMaxOnly)
RUN_TEST(TestMakeExponentialOptionsMaxOnly2)
RUN_TEST(TestMakeExponentialOptionsMinAndMaxOnly)
RUN_TEST(TestMakeExponentialOptionsMaxContainedInLastBucket)
RUN_TEST(TestExponentialInvalidBase)
RUN_TEST(TestExponentialInvalidScalar)
RUN_TEST(TestExponentialMap)
RUN_TEST(TestExponentialReverseMap)
RUN_TEST(TestMakeLinearOptions)
RUN_TEST(TestMakeLinearOptionsMaxOnly)
RUN_TEST(TestMakeLinearOptionsMinAndMaxOnly)
RUN_TEST(TestMakeLinearOptionsMaxContainedInLastBucket)
RUN_TEST(TestLinearInvalidScalar)
RUN_TEST(TestLinearMap)
RUN_TEST(TestLinearReverseMap)
END_TEST_CASE(HistogramOptionsTest)
} // namespace
} // namespace cobalt_client