diff --git a/ydb/core/control/immediate_control_board_sampler_ut.cpp b/ydb/core/control/immediate_control_board_sampler_ut.cpp new file mode 100644 index 000000000000..5df3cbe18bfd --- /dev/null +++ b/ydb/core/control/immediate_control_board_sampler_ut.cpp @@ -0,0 +1,62 @@ +#include "immediate_control_board_sampler.h" + +#include + +namespace NKikimr { + +Y_UNIT_TEST_SUITE(SamplingControlTests) { + ui32 RunTrials(TSampler& sampler, ui32 trials) { + ui32 cnt = 0; + for (ui32 i = 0; i < trials; ++i) { + if (sampler.Sample()) { + ++cnt; + } + } + return cnt; + } + + Y_UNIT_TEST(Simple) { + TControlWrapper control(500'000, 0, 1'000'000); + TSampler sampler(control, 42); + + auto samples = RunTrials(sampler, 100'000); + UNIT_ASSERT_GE(samples, 48'000); + UNIT_ASSERT_LE(samples, 52'000); + } + + Y_UNIT_TEST(EdgeCaseLower) { + TControlWrapper control(0, 0, 1'000'000); + TSampler sampler(control, 42); + + auto samples = RunTrials(sampler, 100'000); + UNIT_ASSERT_EQUAL(samples, 0); + } + + Y_UNIT_TEST(EdgeCaseUpper) { + TControlWrapper control(1'000'000, 0, 1'000'000); + TSampler sampler(control, 42); + + auto samples = RunTrials(sampler, 100'000); + UNIT_ASSERT_EQUAL(samples, 100'000); + } + + Y_UNIT_TEST(ChangingControl) { + TControlWrapper control(250'000, 0, 1'000'000); + TSampler sampler(control, 42); + + { + auto samples = RunTrials(sampler, 100'000); + UNIT_ASSERT_GE(samples, 23'000); + UNIT_ASSERT_LE(samples, 27'000); + } + + control = 750'000; + { + auto samples = RunTrials(sampler, 100'000); + UNIT_ASSERT_GE(samples, 73'000); + UNIT_ASSERT_LE(samples, 77'000); + } + } +} + +} // namespace NKikimr diff --git a/ydb/core/control/immediate_control_board_throttler_ut.cpp b/ydb/core/control/immediate_control_board_throttler_ut.cpp new file mode 100644 index 000000000000..3a5e40edf532 --- /dev/null +++ b/ydb/core/control/immediate_control_board_throttler_ut.cpp @@ -0,0 +1,126 @@ +#include "immediate_control_board_throttler.h" + +#include + +namespace NKikimr { + +class TTimeProviderMock : public ITimeProvider { +public: + TTimeProviderMock(TInstant now) : CurrentTime(now) {} + + void Advance(TDuration delta) { + CurrentTime += delta; + } + + TInstant Now() final { + return CurrentTime; + } + +private: + TInstant CurrentTime; +}; + +Y_UNIT_TEST_SUITE(ThrottlerControlTests) { + void CheckAtLeast(TThrottler& throttler, ui32 n) { + for (ui32 i = 0; i < n; ++i) { + UNIT_ASSERT(!throttler.Throttle()); + } + } + + void CheckExact(TThrottler& throttler, ui32 n) { + CheckAtLeast(throttler, n); + UNIT_ASSERT(throttler.Throttle()); + } + + Y_UNIT_TEST(Simple) { + TControlWrapper maxPerMinute(6, 0, 180); + TControlWrapper maxBurst(2, 0, 180); + + auto timeProvider = MakeIntrusive(TInstant::Now()); + + TThrottler throttler(maxPerMinute, maxBurst, timeProvider); + CheckExact(throttler, 3); + CheckExact(throttler, 0); + + timeProvider->Advance(TDuration::Seconds(9)); + CheckExact(throttler, 0); + timeProvider->Advance(TDuration::Seconds(1)); + CheckExact(throttler, 1); + + timeProvider->Advance(TDuration::Seconds(15)); + CheckExact(throttler, 1); + + timeProvider->Advance(TDuration::Seconds(15)); + CheckExact(throttler, 2); + } + + Y_UNIT_TEST(LongIdle) { + TControlWrapper maxPerMinute(10, 0, 180); + TControlWrapper maxBurst(2, 0, 180); + + auto timeProvider = MakeIntrusive(TInstant::Now()); + + TThrottler throttler(maxPerMinute, maxBurst, timeProvider); + CheckAtLeast(throttler, 3); + + timeProvider->Advance(TDuration::Hours(1)); + CheckExact(throttler, 3); + } + + Y_UNIT_TEST(Overflow) { + TControlWrapper maxPerMinute(6'000, 0, 6'000); + TControlWrapper maxBurst(6'000, 0, 6'000); + + auto timeProvider = MakeIntrusive(TInstant::Now()); + + TThrottler throttler(maxPerMinute, maxBurst, timeProvider); + CheckExact(throttler, 6'001); + + timeProvider->Advance(TDuration::Days(365 * 10)); + + CheckExact(throttler, 6'001); + } + + Y_UNIT_TEST(ChangingControls) { + TControlWrapper maxPerMinute(6, 0, 180); + TControlWrapper maxBurst(2, 0, 180); + + auto timeProvider = MakeIntrusive(TInstant::Now()); + + TThrottler throttler(maxPerMinute, maxBurst, timeProvider); + CheckExact(throttler, 3); + + maxBurst = 4; + CheckExact(throttler, 2); + + maxBurst = 0; + CheckExact(throttler, 0); + + timeProvider->Advance(TDuration::Seconds(9)); + CheckExact(throttler, 0); + timeProvider->Advance(TDuration::Seconds(1)); + CheckExact(throttler, 1); + + maxPerMinute = 12 * 60; + timeProvider->Advance(TDuration::Seconds(1)); + CheckExact(throttler, 1); + + maxBurst = 20; + + timeProvider->Advance(TDuration::Seconds(3)); + CheckExact(throttler, 21); + + maxBurst = 0; + timeProvider->Advance(TDuration::Seconds(59)); + CheckAtLeast(throttler, 1); + maxPerMinute = 1; + CheckExact(throttler, 0); + timeProvider->Advance(TDuration::Minutes(1)); + CheckExact(throttler, 1); + + maxBurst = 2; + CheckExact(throttler, 2); + } +} + +} // namespace NKikimr diff --git a/ydb/core/control/ut/ya.make b/ydb/core/control/ut/ya.make index 1e4885a42485..ede54f7d8c00 100644 --- a/ydb/core/control/ut/ya.make +++ b/ydb/core/control/ut/ya.make @@ -22,6 +22,8 @@ PEERDIR( SRCS( immediate_control_board_ut.cpp immediate_control_board_actor_ut.cpp + immediate_control_board_sampler_ut.cpp + immediate_control_board_throttler_ut.cpp ) END()