summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc')
-rw-r--r--third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc318
1 files changed, 318 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc b/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc
new file mode 100644
index 0000000000..8f1a8384cf
--- /dev/null
+++ b/third_party/libwebrtc/rtc_base/rate_statistics_unittest.cc
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2012 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_statistics.h"
+
+#include <cstdlib>
+
+#include "test/gtest.h"
+
+namespace {
+
+using webrtc::RateStatistics;
+
+const int64_t kWindowMs = 500;
+
+class RateStatisticsTest : public ::testing::Test {
+ protected:
+ RateStatisticsTest() : stats_(kWindowMs, 8000) {}
+ RateStatistics stats_;
+};
+
+TEST_F(RateStatisticsTest, TestStrictMode) {
+ int64_t now_ms = 0;
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ const uint32_t kPacketSize = 1500u;
+ const uint32_t kExpectedRateBps = kPacketSize * 1000 * 8;
+
+ // Single data point is not enough for valid estimate.
+ stats_.Update(kPacketSize, now_ms++);
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ // Expecting 1200 kbps since the window is initially kept small and grows as
+ // we have more data.
+ stats_.Update(kPacketSize, now_ms);
+ EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms));
+
+ stats_.Reset();
+ // Expecting 0 after init.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ const int kInterval = 10;
+ for (int i = 0; i < 100000; ++i) {
+ if (i % kInterval == 0)
+ stats_.Update(kPacketSize, now_ms);
+
+ // Approximately 1200 kbps expected. Not exact since when packets
+ // are removed we will jump 10 ms to the next packet.
+ if (i > kInterval) {
+ absl::optional<uint32_t> rate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(rate));
+ uint32_t samples = i / kInterval + 1;
+ uint64_t total_bits = samples * kPacketSize * 8;
+ uint32_t rate_bps = static_cast<uint32_t>((1000 * total_bits) / (i + 1));
+ EXPECT_NEAR(rate_bps, *rate, 22000u);
+ }
+ now_ms += 1;
+ }
+ now_ms += kWindowMs;
+ // The window is 2 seconds. If nothing has been received for that time
+ // the estimate should be 0.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+}
+
+TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
+ int64_t now_ms = 0;
+ stats_.Reset();
+ // Expecting 0 after init.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ stats_.Update(1000, ++now_ms);
+ const uint32_t kExpectedBitrate = 8000000;
+ // 1000 bytes per millisecond until plateau is reached.
+ int prev_error = kExpectedBitrate;
+ absl::optional<uint32_t> bitrate;
+ while (++now_ms < 10000) {
+ stats_.Update(1000, now_ms);
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ int error = kExpectedBitrate - *bitrate;
+ error = std::abs(error);
+ // Expect the estimation error to decrease as the window is extended.
+ EXPECT_LE(error, prev_error + 1);
+ prev_error = error;
+ }
+ // Window filled, expect to be close to 8000000.
+ EXPECT_EQ(kExpectedBitrate, *bitrate);
+
+ // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected.
+ while (++now_ms < 10000) {
+ stats_.Update(1000, now_ms);
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_EQ(kExpectedBitrate, *bitrate);
+ }
+
+ // Zero bytes per millisecond until 0 is reached.
+ while (++now_ms < 20000) {
+ stats_.Update(0, now_ms);
+ absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
+ if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
+ // New bitrate must be lower than previous one.
+ EXPECT_LT(*new_bitrate, *bitrate);
+ } else {
+ // 0 kbps expected.
+ EXPECT_EQ(0u, *new_bitrate);
+ break;
+ }
+ bitrate = new_bitrate;
+ }
+
+ // Zero bytes per millisecond until 20-second mark, 0 kbps expected.
+ while (++now_ms < 20000) {
+ stats_.Update(0, now_ms);
+ EXPECT_EQ(0u, *stats_.Rate(now_ms));
+ }
+}
+
+TEST_F(RateStatisticsTest, ResetAfterSilence) {
+ int64_t now_ms = 0;
+ stats_.Reset();
+ // Expecting 0 after init.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ const uint32_t kExpectedBitrate = 8000000;
+ // 1000 bytes per millisecond until the window has been filled.
+ int prev_error = kExpectedBitrate;
+ absl::optional<uint32_t> bitrate;
+ while (++now_ms < 10000) {
+ stats_.Update(1000, now_ms);
+ bitrate = stats_.Rate(now_ms);
+ if (bitrate) {
+ int error = kExpectedBitrate - *bitrate;
+ error = std::abs(error);
+ // Expect the estimation error to decrease as the window is extended.
+ EXPECT_LE(error, prev_error + 1);
+ prev_error = error;
+ }
+ }
+ // Window filled, expect to be close to 8000000.
+ EXPECT_EQ(kExpectedBitrate, *bitrate);
+
+ now_ms += kWindowMs + 1;
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+ // Silence over window size should trigger auto reset for coming sample.
+ stats_.Update(1000, now_ms);
+ ++now_ms;
+ stats_.Update(1000, now_ms);
+ // We expect two samples of 1000 bytes, and that the bitrate is measured over
+ // active window instead of full window, which is now_ms - first_timestamp + 1
+ EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
+
+ // Manual reset, add the same samples again.
+ stats_.Reset();
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+ stats_.Update(1000, now_ms);
+ ++now_ms;
+ stats_.Update(1000, now_ms);
+ // We expect two samples of 1000 bytes, and that the bitrate is measured over
+ // 2 ms (window size has been reset) i.e. 2 * 8 * 1000 / 0.002 = 8000000.
+ EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
+}
+
+TEST_F(RateStatisticsTest, HandlesChangingWindowSize) {
+ int64_t now_ms = 0;
+ stats_.Reset();
+
+ // Sanity test window size.
+ EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
+ EXPECT_FALSE(stats_.SetWindowSize(kWindowMs + 1, now_ms));
+ EXPECT_FALSE(stats_.SetWindowSize(0, now_ms));
+ EXPECT_TRUE(stats_.SetWindowSize(1, now_ms));
+ EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
+
+ // Fill the buffer at a rate of 1 byte / millisecond (8 kbps).
+ const int kBatchSize = 10;
+ for (int i = 0; i <= kWindowMs; i += kBatchSize)
+ stats_.Update(kBatchSize, now_ms += kBatchSize);
+ EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
+
+ // Halve the window size, rate should stay the same.
+ EXPECT_TRUE(stats_.SetWindowSize(kWindowMs / 2, now_ms));
+ EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
+
+ // Double the window size again, rate should stay the same. (As the window
+ // won't actually expand until new bit and bobs fall into it.
+ EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
+ EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
+
+ // Fill the now empty half with bits it twice the rate.
+ for (int i = 0; i < kWindowMs / 2; i += kBatchSize)
+ stats_.Update(kBatchSize * 2, now_ms += kBatchSize);
+
+ // Rate should have increase be 50%.
+ EXPECT_EQ(static_cast<uint32_t>((8000 * 3) / 2), *stats_.Rate(now_ms));
+}
+
+TEST_F(RateStatisticsTest, RespectsWindowSizeEdges) {
+ int64_t now_ms = 0;
+ stats_.Reset();
+ // Expecting 0 after init.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ // One byte per ms, using one big sample.
+ stats_.Update(kWindowMs, now_ms);
+ now_ms += kWindowMs - 2;
+ // Shouldn't work! (Only one sample, not full window size.)
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ // Window size should be full, and the single data point should be accepted.
+ ++now_ms;
+ absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(1000 * 8u, *bitrate);
+
+ // Add another, now we have twice the bitrate.
+ stats_.Update(kWindowMs, now_ms);
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(2 * 1000 * 8u, *bitrate);
+
+ // Now that first sample should drop out...
+ now_ms += 1;
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(1000 * 8u, *bitrate);
+}
+
+TEST_F(RateStatisticsTest, HandlesZeroCounts) {
+ int64_t now_ms = 0;
+ stats_.Reset();
+ // Expecting 0 after init.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ stats_.Update(kWindowMs, now_ms);
+ now_ms += kWindowMs - 1;
+ stats_.Update(0, now_ms);
+ absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(1000 * 8u, *bitrate);
+
+ // Move window along so first data point falls out.
+ ++now_ms;
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(0u, *bitrate);
+
+ // Move window so last data point falls out.
+ now_ms += kWindowMs;
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+}
+
+TEST_F(RateStatisticsTest, HandlesQuietPeriods) {
+ int64_t now_ms = 0;
+ stats_.Reset();
+ // Expecting 0 after init.
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ stats_.Update(0, now_ms);
+ now_ms += kWindowMs - 1;
+ absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(0u, *bitrate);
+
+ // Move window along so first data point falls out.
+ ++now_ms;
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+
+ // Move window a long way out.
+ // This will cause an automatic reset of the window
+ // First data point won't give a valid result
+ now_ms += 2 * kWindowMs;
+ stats_.Update(0, now_ms);
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
+ // Second data point gives valid result
+ ++now_ms;
+ stats_.Update(0, now_ms);
+ bitrate = stats_.Rate(now_ms);
+ EXPECT_TRUE(static_cast<bool>(bitrate));
+ EXPECT_EQ(0u, *bitrate);
+}
+
+TEST_F(RateStatisticsTest, HandlesBigNumbers) {
+ int64_t large_number = 0x100000000u;
+ int64_t now_ms = 0;
+ stats_.Update(large_number, now_ms++);
+ stats_.Update(large_number, now_ms);
+ EXPECT_TRUE(stats_.Rate(now_ms));
+ EXPECT_EQ(large_number * RateStatistics::kBpsScale, *stats_.Rate(now_ms));
+}
+
+TEST_F(RateStatisticsTest, HandlesTooLargeNumbers) {
+ int64_t very_large_number = std::numeric_limits<int64_t>::max();
+ int64_t now_ms = 0;
+ stats_.Update(very_large_number, now_ms++);
+ stats_.Update(very_large_number, now_ms);
+ // This should overflow the internal accumulator.
+ EXPECT_FALSE(stats_.Rate(now_ms));
+}
+
+TEST_F(RateStatisticsTest, HandlesSomewhatLargeNumbers) {
+ int64_t very_large_number = std::numeric_limits<int64_t>::max();
+ int64_t now_ms = 0;
+ stats_.Update(very_large_number / 4, now_ms++);
+ stats_.Update(very_large_number / 4, now_ms);
+ // This should generate a rate of more than int64_t max, but still
+ // accumulate less than int64_t overflow.
+ EXPECT_FALSE(stats_.Rate(now_ms));
+}
+
+} // namespace