summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc
parentInitial commit. (diff)
downloadfirefox-esr-upstream.tar.xz
firefox-esr-upstream.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc')
-rw-r--r--third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc192
1 files changed, 192 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc b/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc
new file mode 100644
index 0000000000..07dda5609e
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/rate_limiter_unittest.cc
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_base/rate_limiter.h"
+
+#include <memory>
+
+#include "rtc_base/event.h"
+#include "rtc_base/platform_thread.h"
+#include "system_wrappers/include/clock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+class RateLimitTest : public ::testing::Test {
+ public:
+ RateLimitTest()
+ : clock_(0), rate_limiter(new RateLimiter(&clock_, kWindowSizeMs)) {}
+ ~RateLimitTest() override {}
+
+ void SetUp() override { rate_limiter->SetMaxRate(kMaxRateBps); }
+
+ protected:
+ static constexpr int64_t kWindowSizeMs = 1000;
+ static constexpr uint32_t kMaxRateBps = 100000;
+ // Bytes needed to completely saturate the rate limiter.
+ static constexpr size_t kRateFillingBytes =
+ (kMaxRateBps * kWindowSizeMs) / (8 * 1000);
+ SimulatedClock clock_;
+ std::unique_ptr<RateLimiter> rate_limiter;
+};
+
+TEST_F(RateLimitTest, IncreasingMaxRate) {
+ // Fill rate, extend window to full size.
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+ clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1);
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+
+ // All rate consumed.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+
+ // Double the available rate and fill that too.
+ rate_limiter->SetMaxRate(kMaxRateBps * 2);
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes));
+
+ // All rate consumed again.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+}
+
+TEST_F(RateLimitTest, DecreasingMaxRate) {
+ // Fill rate, extend window to full size.
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+ clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1);
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+
+ // All rate consumed.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+
+ // Halve the available rate and move window so half of the data falls out.
+ rate_limiter->SetMaxRate(kMaxRateBps / 2);
+ clock_.AdvanceTimeMilliseconds(1);
+
+ // All rate still consumed.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+}
+
+TEST_F(RateLimitTest, ChangingWindowSize) {
+ // Fill rate, extend window to full size.
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+ clock_.AdvanceTimeMilliseconds(kWindowSizeMs - 1);
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+
+ // All rate consumed.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+
+ // Decrease window size so half of the data falls out.
+ rate_limiter->SetWindowSize(kWindowSizeMs / 2);
+ // Average rate should still be the same, so rate is still all consumed.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+
+ // Increase window size again. Now the rate is only half used (removed data
+ // points don't come back to life).
+ rate_limiter->SetWindowSize(kWindowSizeMs);
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes / 2));
+
+ // All rate consumed again.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+}
+
+TEST_F(RateLimitTest, SingleUsageAlwaysOk) {
+ // Using more bytes than can fit in a window is OK for a single packet.
+ EXPECT_TRUE(rate_limiter->TryUseRate(kRateFillingBytes + 1));
+}
+
+TEST_F(RateLimitTest, WindowSizeLimits) {
+ EXPECT_TRUE(rate_limiter->SetWindowSize(1));
+ EXPECT_FALSE(rate_limiter->SetWindowSize(0));
+ EXPECT_TRUE(rate_limiter->SetWindowSize(kWindowSizeMs));
+ EXPECT_FALSE(rate_limiter->SetWindowSize(kWindowSizeMs + 1));
+}
+
+static constexpr TimeDelta kMaxTimeout = TimeDelta::Seconds(30);
+
+class ThreadTask {
+ public:
+ explicit ThreadTask(RateLimiter* rate_limiter)
+ : rate_limiter_(rate_limiter) {}
+ virtual ~ThreadTask() {}
+
+ void Run() {
+ start_signal_.Wait(kMaxTimeout);
+ DoRun();
+ end_signal_.Set();
+ }
+
+ virtual void DoRun() = 0;
+
+ RateLimiter* const rate_limiter_;
+ rtc::Event start_signal_;
+ rtc::Event end_signal_;
+};
+
+TEST_F(RateLimitTest, MultiThreadedUsage) {
+ // Simple sanity test, with different threads calling the various methods.
+ // Runs a few simple tasks, each on its own thread, but coordinated with
+ // events so that they run in a serialized order. Intended to catch data
+ // races when run with tsan et al.
+
+ // Half window size, double rate -> same amount of bytes needed to fill rate.
+
+ class SetWindowSizeTask : public ThreadTask {
+ public:
+ explicit SetWindowSizeTask(RateLimiter* rate_limiter)
+ : ThreadTask(rate_limiter) {}
+ ~SetWindowSizeTask() override {}
+
+ void DoRun() override {
+ EXPECT_TRUE(rate_limiter_->SetWindowSize(kWindowSizeMs / 2));
+ }
+ } set_window_size_task(rate_limiter.get());
+ auto thread1 = rtc::PlatformThread::SpawnJoinable(
+ [&set_window_size_task] { set_window_size_task.Run(); }, "Thread1");
+
+ class SetMaxRateTask : public ThreadTask {
+ public:
+ explicit SetMaxRateTask(RateLimiter* rate_limiter)
+ : ThreadTask(rate_limiter) {}
+ ~SetMaxRateTask() override {}
+
+ void DoRun() override { rate_limiter_->SetMaxRate(kMaxRateBps * 2); }
+ } set_max_rate_task(rate_limiter.get());
+ auto thread2 = rtc::PlatformThread::SpawnJoinable(
+ [&set_max_rate_task] { set_max_rate_task.Run(); }, "Thread2");
+
+ class UseRateTask : public ThreadTask {
+ public:
+ UseRateTask(RateLimiter* rate_limiter, SimulatedClock* clock)
+ : ThreadTask(rate_limiter), clock_(clock) {}
+ ~UseRateTask() override {}
+
+ void DoRun() override {
+ EXPECT_TRUE(rate_limiter_->TryUseRate(kRateFillingBytes / 2));
+ clock_->AdvanceTimeMilliseconds((kWindowSizeMs / 2) - 1);
+ EXPECT_TRUE(rate_limiter_->TryUseRate(kRateFillingBytes / 2));
+ }
+
+ SimulatedClock* const clock_;
+ } use_rate_task(rate_limiter.get(), &clock_);
+ auto thread3 = rtc::PlatformThread::SpawnJoinable(
+ [&use_rate_task] { use_rate_task.Run(); }, "Thread3");
+
+ set_window_size_task.start_signal_.Set();
+ EXPECT_TRUE(set_window_size_task.end_signal_.Wait(kMaxTimeout));
+
+ set_max_rate_task.start_signal_.Set();
+ EXPECT_TRUE(set_max_rate_task.end_signal_.Wait(kMaxTimeout));
+
+ use_rate_task.start_signal_.Set();
+ EXPECT_TRUE(use_rate_task.end_signal_.Wait(kMaxTimeout));
+
+ // All rate consumed.
+ EXPECT_FALSE(rate_limiter->TryUseRate(1));
+}
+
+} // namespace webrtc