blob: 236e3b04ef0a71bb341ae48fb50415759cef0f0a [file] [log] [blame]
// Copyright 2021 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 "src/connectivity/bluetooth/core/bt-host/public/pw_bluetooth_sapphire/internal/host/common/retire_log.h"
#include <algorithm>
#include <numeric>
#include <random>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
namespace bt::internal {
namespace {
// Retire 101 entries where the fields in the range [starting_value,
// starting_value + 100]
void Retire101Elements(RetireLog& retire_log, int starting_value = 0) {
std::vector<int> values(101);
std::iota(values.begin(), values.end(), starting_value);
constexpr int kSeed = 4;
std::shuffle(values.begin(), values.end(), std::default_random_engine(kSeed));
for (auto value : values) {
retire_log.Retire(value, std::chrono::milliseconds(value));
}
}
TEST(RetireLogDeathTest, InitializationLimits) {
ASSERT_DEATH_IF_SUPPORTED({ RetireLog retire_log(0, 100); }, "min_depth");
ASSERT_DEATH_IF_SUPPORTED(
{ RetireLog retire_log(101, 100); }, "min_depth.*max_depth");
ASSERT_DEATH_IF_SUPPORTED(
{ RetireLog retire_log(1, size_t{1} << 60); }, "max_depth");
}
TEST(RetireLogDeathTest, ComputeQuantileLimits) {
RetireLog retire_log(1, 100);
retire_log.Retire(1, std::chrono::seconds(1));
ASSERT_DEATH_IF_SUPPORTED(
{
[[maybe_unused]] auto _ =
retire_log.ComputeByteCountQuantiles(std::array{-1.});
},
"0");
ASSERT_DEATH_IF_SUPPORTED(
{
[[maybe_unused]] auto _ =
retire_log.ComputeByteCountQuantiles(std::array{2.});
},
"1");
}
TEST(RetireLogTest, QuantileCallBeforeRetiringYieldsNothing) {
RetireLog retire_log(1, 100);
EXPECT_EQ(0U, retire_log.depth());
auto result = retire_log.ComputeAgeQuantiles(std::array{.5});
EXPECT_FALSE(result.has_value());
}
TEST(RetireLogTest, QuantileCallsAfterDepthOneYieldsTheResult) {
RetireLog retire_log(1, 100);
constexpr pw::chrono::SystemClock::duration kTestDuration =
std::chrono::milliseconds(10);
retire_log.Retire(0, kTestDuration);
auto result = retire_log.ComputeAgeQuantiles(std::array{.5});
ASSERT_TRUE(result.has_value());
EXPECT_THAT(*result, testing::Each(testing::Eq(kTestDuration)));
}
TEST(RetireLogTest, ComputeQuantiles) {
RetireLog retire_log(1, 101);
Retire101Elements(retire_log);
auto result = retire_log.ComputeByteCountQuantiles(
std::array{0., .001, .5, .754, .99, 1.});
ASSERT_TRUE(result.has_value());
// Cutting at extremes yields the min and max entries while cutting in the
// middle yields the median. Cutting between entry values yields the nearest
// (by distribution) logged value.
EXPECT_THAT(*result, testing::ElementsAre(0, 0, 50, 76, 99, 100));
}
TEST(RetireLogTest, ComputeQuantilesExactBoundaryIsHighBiased) {
RetireLog retire_log(2, 2);
retire_log.Retire(0, {});
retire_log.Retire(1, {});
auto result = retire_log.ComputeByteCountQuantiles(std::array{.5});
ASSERT_TRUE(result.has_value());
// Cutting at exactly between two entries yields the higher sample
EXPECT_THAT(*result, testing::ElementsAre(1));
}
TEST(RetireLogTest, ComputeQuantilesOutOfOrderPartitions) {
RetireLog retire_log(1, 101);
Retire101Elements(retire_log);
auto result = retire_log.ComputeByteCountQuantiles(std::array{.75, .25, .5});
ASSERT_TRUE(result.has_value());
EXPECT_THAT(*result, testing::ElementsAre(75, 25, 50));
}
// Check that cutting at the same point more than once works
TEST(RetireLogTest, ComputeSameQuantileTwice) {
RetireLog retire_log(1, 101);
Retire101Elements(retire_log);
auto result =
retire_log.ComputeByteCountQuantiles(std::array{0., 0., 1., 1.});
ASSERT_TRUE(result.has_value());
EXPECT_THAT(*result, testing::ElementsAre(0, 0, 100, 100));
}
TEST(RetireLogTest, RetiringPastMaxDepthReplacesPreviousEntries) {
RetireLog retire_log(1, 101);
Retire101Elements(retire_log, /*starting_value=*/0);
Retire101Elements(retire_log, /*starting_value=*/10);
EXPECT_EQ(101U, retire_log.depth());
auto result = retire_log.ComputeByteCountQuantiles(std::array{0., .5, 1.});
ASSERT_TRUE(result.has_value());
EXPECT_THAT(*result, testing::ElementsAre(10, 60, 110));
}
} // namespace
} // namespace bt::internal