xref: /aosp_15_r20/external/webrtc/rtc_base/rate_statistics_unittest.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/rate_statistics.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <cstdlib>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include "test/gtest.h"
16*d9f75844SAndroid Build Coastguard Worker 
17*d9f75844SAndroid Build Coastguard Worker namespace {
18*d9f75844SAndroid Build Coastguard Worker 
19*d9f75844SAndroid Build Coastguard Worker using webrtc::RateStatistics;
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker const int64_t kWindowMs = 500;
22*d9f75844SAndroid Build Coastguard Worker 
23*d9f75844SAndroid Build Coastguard Worker class RateStatisticsTest : public ::testing::Test {
24*d9f75844SAndroid Build Coastguard Worker  protected:
RateStatisticsTest()25*d9f75844SAndroid Build Coastguard Worker   RateStatisticsTest() : stats_(kWindowMs, 8000) {}
26*d9f75844SAndroid Build Coastguard Worker   RateStatistics stats_;
27*d9f75844SAndroid Build Coastguard Worker };
28*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,TestStrictMode)29*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, TestStrictMode) {
30*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
31*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
32*d9f75844SAndroid Build Coastguard Worker 
33*d9f75844SAndroid Build Coastguard Worker   const uint32_t kPacketSize = 1500u;
34*d9f75844SAndroid Build Coastguard Worker   const uint32_t kExpectedRateBps = kPacketSize * 1000 * 8;
35*d9f75844SAndroid Build Coastguard Worker 
36*d9f75844SAndroid Build Coastguard Worker   // Single data point is not enough for valid estimate.
37*d9f75844SAndroid Build Coastguard Worker   stats_.Update(kPacketSize, now_ms++);
38*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
39*d9f75844SAndroid Build Coastguard Worker 
40*d9f75844SAndroid Build Coastguard Worker   // Expecting 1200 kbps since the window is initially kept small and grows as
41*d9f75844SAndroid Build Coastguard Worker   // we have more data.
42*d9f75844SAndroid Build Coastguard Worker   stats_.Update(kPacketSize, now_ms);
43*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kExpectedRateBps, *stats_.Rate(now_ms));
44*d9f75844SAndroid Build Coastguard Worker 
45*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
46*d9f75844SAndroid Build Coastguard Worker   // Expecting 0 after init.
47*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
48*d9f75844SAndroid Build Coastguard Worker 
49*d9f75844SAndroid Build Coastguard Worker   const int kInterval = 10;
50*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < 100000; ++i) {
51*d9f75844SAndroid Build Coastguard Worker     if (i % kInterval == 0)
52*d9f75844SAndroid Build Coastguard Worker       stats_.Update(kPacketSize, now_ms);
53*d9f75844SAndroid Build Coastguard Worker 
54*d9f75844SAndroid Build Coastguard Worker     // Approximately 1200 kbps expected. Not exact since when packets
55*d9f75844SAndroid Build Coastguard Worker     // are removed we will jump 10 ms to the next packet.
56*d9f75844SAndroid Build Coastguard Worker     if (i > kInterval) {
57*d9f75844SAndroid Build Coastguard Worker       absl::optional<uint32_t> rate = stats_.Rate(now_ms);
58*d9f75844SAndroid Build Coastguard Worker       EXPECT_TRUE(static_cast<bool>(rate));
59*d9f75844SAndroid Build Coastguard Worker       uint32_t samples = i / kInterval + 1;
60*d9f75844SAndroid Build Coastguard Worker       uint64_t total_bits = samples * kPacketSize * 8;
61*d9f75844SAndroid Build Coastguard Worker       uint32_t rate_bps = static_cast<uint32_t>((1000 * total_bits) / (i + 1));
62*d9f75844SAndroid Build Coastguard Worker       EXPECT_NEAR(rate_bps, *rate, 22000u);
63*d9f75844SAndroid Build Coastguard Worker     }
64*d9f75844SAndroid Build Coastguard Worker     now_ms += 1;
65*d9f75844SAndroid Build Coastguard Worker   }
66*d9f75844SAndroid Build Coastguard Worker   now_ms += kWindowMs;
67*d9f75844SAndroid Build Coastguard Worker   // The window is 2 seconds. If nothing has been received for that time
68*d9f75844SAndroid Build Coastguard Worker   // the estimate should be 0.
69*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,IncreasingThenDecreasingBitrate)72*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, IncreasingThenDecreasingBitrate) {
73*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
74*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
75*d9f75844SAndroid Build Coastguard Worker   // Expecting 0 after init.
76*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
77*d9f75844SAndroid Build Coastguard Worker 
78*d9f75844SAndroid Build Coastguard Worker   stats_.Update(1000, ++now_ms);
79*d9f75844SAndroid Build Coastguard Worker   const uint32_t kExpectedBitrate = 8000000;
80*d9f75844SAndroid Build Coastguard Worker   // 1000 bytes per millisecond until plateau is reached.
81*d9f75844SAndroid Build Coastguard Worker   int prev_error = kExpectedBitrate;
82*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> bitrate;
83*d9f75844SAndroid Build Coastguard Worker   while (++now_ms < 10000) {
84*d9f75844SAndroid Build Coastguard Worker     stats_.Update(1000, now_ms);
85*d9f75844SAndroid Build Coastguard Worker     bitrate = stats_.Rate(now_ms);
86*d9f75844SAndroid Build Coastguard Worker     EXPECT_TRUE(static_cast<bool>(bitrate));
87*d9f75844SAndroid Build Coastguard Worker     int error = kExpectedBitrate - *bitrate;
88*d9f75844SAndroid Build Coastguard Worker     error = std::abs(error);
89*d9f75844SAndroid Build Coastguard Worker     // Expect the estimation error to decrease as the window is extended.
90*d9f75844SAndroid Build Coastguard Worker     EXPECT_LE(error, prev_error + 1);
91*d9f75844SAndroid Build Coastguard Worker     prev_error = error;
92*d9f75844SAndroid Build Coastguard Worker   }
93*d9f75844SAndroid Build Coastguard Worker   // Window filled, expect to be close to 8000000.
94*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kExpectedBitrate, *bitrate);
95*d9f75844SAndroid Build Coastguard Worker 
96*d9f75844SAndroid Build Coastguard Worker   // 1000 bytes per millisecond until 10-second mark, 8000 kbps expected.
97*d9f75844SAndroid Build Coastguard Worker   while (++now_ms < 10000) {
98*d9f75844SAndroid Build Coastguard Worker     stats_.Update(1000, now_ms);
99*d9f75844SAndroid Build Coastguard Worker     bitrate = stats_.Rate(now_ms);
100*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(kExpectedBitrate, *bitrate);
101*d9f75844SAndroid Build Coastguard Worker   }
102*d9f75844SAndroid Build Coastguard Worker 
103*d9f75844SAndroid Build Coastguard Worker   // Zero bytes per millisecond until 0 is reached.
104*d9f75844SAndroid Build Coastguard Worker   while (++now_ms < 20000) {
105*d9f75844SAndroid Build Coastguard Worker     stats_.Update(0, now_ms);
106*d9f75844SAndroid Build Coastguard Worker     absl::optional<uint32_t> new_bitrate = stats_.Rate(now_ms);
107*d9f75844SAndroid Build Coastguard Worker     if (static_cast<bool>(new_bitrate) && *new_bitrate != *bitrate) {
108*d9f75844SAndroid Build Coastguard Worker       // New bitrate must be lower than previous one.
109*d9f75844SAndroid Build Coastguard Worker       EXPECT_LT(*new_bitrate, *bitrate);
110*d9f75844SAndroid Build Coastguard Worker     } else {
111*d9f75844SAndroid Build Coastguard Worker       // 0 kbps expected.
112*d9f75844SAndroid Build Coastguard Worker       EXPECT_EQ(0u, *new_bitrate);
113*d9f75844SAndroid Build Coastguard Worker       break;
114*d9f75844SAndroid Build Coastguard Worker     }
115*d9f75844SAndroid Build Coastguard Worker     bitrate = new_bitrate;
116*d9f75844SAndroid Build Coastguard Worker   }
117*d9f75844SAndroid Build Coastguard Worker 
118*d9f75844SAndroid Build Coastguard Worker   // Zero bytes per millisecond until 20-second mark, 0 kbps expected.
119*d9f75844SAndroid Build Coastguard Worker   while (++now_ms < 20000) {
120*d9f75844SAndroid Build Coastguard Worker     stats_.Update(0, now_ms);
121*d9f75844SAndroid Build Coastguard Worker     EXPECT_EQ(0u, *stats_.Rate(now_ms));
122*d9f75844SAndroid Build Coastguard Worker   }
123*d9f75844SAndroid Build Coastguard Worker }
124*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,ResetAfterSilence)125*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, ResetAfterSilence) {
126*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
127*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
128*d9f75844SAndroid Build Coastguard Worker   // Expecting 0 after init.
129*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
130*d9f75844SAndroid Build Coastguard Worker 
131*d9f75844SAndroid Build Coastguard Worker   const uint32_t kExpectedBitrate = 8000000;
132*d9f75844SAndroid Build Coastguard Worker   // 1000 bytes per millisecond until the window has been filled.
133*d9f75844SAndroid Build Coastguard Worker   int prev_error = kExpectedBitrate;
134*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> bitrate;
135*d9f75844SAndroid Build Coastguard Worker   while (++now_ms < 10000) {
136*d9f75844SAndroid Build Coastguard Worker     stats_.Update(1000, now_ms);
137*d9f75844SAndroid Build Coastguard Worker     bitrate = stats_.Rate(now_ms);
138*d9f75844SAndroid Build Coastguard Worker     if (bitrate) {
139*d9f75844SAndroid Build Coastguard Worker       int error = kExpectedBitrate - *bitrate;
140*d9f75844SAndroid Build Coastguard Worker       error = std::abs(error);
141*d9f75844SAndroid Build Coastguard Worker       // Expect the estimation error to decrease as the window is extended.
142*d9f75844SAndroid Build Coastguard Worker       EXPECT_LE(error, prev_error + 1);
143*d9f75844SAndroid Build Coastguard Worker       prev_error = error;
144*d9f75844SAndroid Build Coastguard Worker     }
145*d9f75844SAndroid Build Coastguard Worker   }
146*d9f75844SAndroid Build Coastguard Worker   // Window filled, expect to be close to 8000000.
147*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kExpectedBitrate, *bitrate);
148*d9f75844SAndroid Build Coastguard Worker 
149*d9f75844SAndroid Build Coastguard Worker   now_ms += kWindowMs + 1;
150*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
151*d9f75844SAndroid Build Coastguard Worker   // Silence over window size should trigger auto reset for coming sample.
152*d9f75844SAndroid Build Coastguard Worker   stats_.Update(1000, now_ms);
153*d9f75844SAndroid Build Coastguard Worker   ++now_ms;
154*d9f75844SAndroid Build Coastguard Worker   stats_.Update(1000, now_ms);
155*d9f75844SAndroid Build Coastguard Worker   // We expect two samples of 1000 bytes, and that the bitrate is measured over
156*d9f75844SAndroid Build Coastguard Worker   // active window instead of full window, which is now_ms - first_timestamp + 1
157*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
158*d9f75844SAndroid Build Coastguard Worker 
159*d9f75844SAndroid Build Coastguard Worker   // Manual reset, add the same samples again.
160*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
161*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
162*d9f75844SAndroid Build Coastguard Worker   stats_.Update(1000, now_ms);
163*d9f75844SAndroid Build Coastguard Worker   ++now_ms;
164*d9f75844SAndroid Build Coastguard Worker   stats_.Update(1000, now_ms);
165*d9f75844SAndroid Build Coastguard Worker   // We expect two samples of 1000 bytes, and that the bitrate is measured over
166*d9f75844SAndroid Build Coastguard Worker   // 2 ms (window size has been reset) i.e. 2 * 8 * 1000 / 0.002 = 8000000.
167*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(kExpectedBitrate, *stats_.Rate(now_ms));
168*d9f75844SAndroid Build Coastguard Worker }
169*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,HandlesChangingWindowSize)170*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, HandlesChangingWindowSize) {
171*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
172*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
173*d9f75844SAndroid Build Coastguard Worker 
174*d9f75844SAndroid Build Coastguard Worker   // Sanity test window size.
175*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
176*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(stats_.SetWindowSize(kWindowMs + 1, now_ms));
177*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(stats_.SetWindowSize(0, now_ms));
178*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats_.SetWindowSize(1, now_ms));
179*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
180*d9f75844SAndroid Build Coastguard Worker 
181*d9f75844SAndroid Build Coastguard Worker   // Fill the buffer at a rate of 1 byte / millisecond (8 kbps).
182*d9f75844SAndroid Build Coastguard Worker   const int kBatchSize = 10;
183*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i <= kWindowMs; i += kBatchSize)
184*d9f75844SAndroid Build Coastguard Worker     stats_.Update(kBatchSize, now_ms += kBatchSize);
185*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
186*d9f75844SAndroid Build Coastguard Worker 
187*d9f75844SAndroid Build Coastguard Worker   // Halve the window size, rate should stay the same.
188*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats_.SetWindowSize(kWindowMs / 2, now_ms));
189*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
190*d9f75844SAndroid Build Coastguard Worker 
191*d9f75844SAndroid Build Coastguard Worker   // Double the window size again, rate should stay the same. (As the window
192*d9f75844SAndroid Build Coastguard Worker   // won't actually expand until new bit and bobs fall into it.
193*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats_.SetWindowSize(kWindowMs, now_ms));
194*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<uint32_t>(8000), *stats_.Rate(now_ms));
195*d9f75844SAndroid Build Coastguard Worker 
196*d9f75844SAndroid Build Coastguard Worker   // Fill the now empty half with bits it twice the rate.
197*d9f75844SAndroid Build Coastguard Worker   for (int i = 0; i < kWindowMs / 2; i += kBatchSize)
198*d9f75844SAndroid Build Coastguard Worker     stats_.Update(kBatchSize * 2, now_ms += kBatchSize);
199*d9f75844SAndroid Build Coastguard Worker 
200*d9f75844SAndroid Build Coastguard Worker   // Rate should have increase be 50%.
201*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(static_cast<uint32_t>((8000 * 3) / 2), *stats_.Rate(now_ms));
202*d9f75844SAndroid Build Coastguard Worker }
203*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,RespectsWindowSizeEdges)204*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, RespectsWindowSizeEdges) {
205*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
206*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
207*d9f75844SAndroid Build Coastguard Worker   // Expecting 0 after init.
208*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
209*d9f75844SAndroid Build Coastguard Worker 
210*d9f75844SAndroid Build Coastguard Worker   // One byte per ms, using one big sample.
211*d9f75844SAndroid Build Coastguard Worker   stats_.Update(kWindowMs, now_ms);
212*d9f75844SAndroid Build Coastguard Worker   now_ms += kWindowMs - 2;
213*d9f75844SAndroid Build Coastguard Worker   // Shouldn't work! (Only one sample, not full window size.)
214*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
215*d9f75844SAndroid Build Coastguard Worker 
216*d9f75844SAndroid Build Coastguard Worker   // Window size should be full, and the single data point should be accepted.
217*d9f75844SAndroid Build Coastguard Worker   ++now_ms;
218*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
219*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
220*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1000 * 8u, *bitrate);
221*d9f75844SAndroid Build Coastguard Worker 
222*d9f75844SAndroid Build Coastguard Worker   // Add another, now we have twice the bitrate.
223*d9f75844SAndroid Build Coastguard Worker   stats_.Update(kWindowMs, now_ms);
224*d9f75844SAndroid Build Coastguard Worker   bitrate = stats_.Rate(now_ms);
225*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
226*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(2 * 1000 * 8u, *bitrate);
227*d9f75844SAndroid Build Coastguard Worker 
228*d9f75844SAndroid Build Coastguard Worker   // Now that first sample should drop out...
229*d9f75844SAndroid Build Coastguard Worker   now_ms += 1;
230*d9f75844SAndroid Build Coastguard Worker   bitrate = stats_.Rate(now_ms);
231*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
232*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1000 * 8u, *bitrate);
233*d9f75844SAndroid Build Coastguard Worker }
234*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,HandlesZeroCounts)235*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, HandlesZeroCounts) {
236*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
237*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
238*d9f75844SAndroid Build Coastguard Worker   // Expecting 0 after init.
239*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
240*d9f75844SAndroid Build Coastguard Worker 
241*d9f75844SAndroid Build Coastguard Worker   stats_.Update(kWindowMs, now_ms);
242*d9f75844SAndroid Build Coastguard Worker   now_ms += kWindowMs - 1;
243*d9f75844SAndroid Build Coastguard Worker   stats_.Update(0, now_ms);
244*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
245*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
246*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(1000 * 8u, *bitrate);
247*d9f75844SAndroid Build Coastguard Worker 
248*d9f75844SAndroid Build Coastguard Worker   // Move window along so first data point falls out.
249*d9f75844SAndroid Build Coastguard Worker   ++now_ms;
250*d9f75844SAndroid Build Coastguard Worker   bitrate = stats_.Rate(now_ms);
251*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
252*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0u, *bitrate);
253*d9f75844SAndroid Build Coastguard Worker 
254*d9f75844SAndroid Build Coastguard Worker   // Move window so last data point falls out.
255*d9f75844SAndroid Build Coastguard Worker   now_ms += kWindowMs;
256*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
257*d9f75844SAndroid Build Coastguard Worker }
258*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,HandlesQuietPeriods)259*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, HandlesQuietPeriods) {
260*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
261*d9f75844SAndroid Build Coastguard Worker   stats_.Reset();
262*d9f75844SAndroid Build Coastguard Worker   // Expecting 0 after init.
263*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
264*d9f75844SAndroid Build Coastguard Worker 
265*d9f75844SAndroid Build Coastguard Worker   stats_.Update(0, now_ms);
266*d9f75844SAndroid Build Coastguard Worker   now_ms += kWindowMs - 1;
267*d9f75844SAndroid Build Coastguard Worker   absl::optional<uint32_t> bitrate = stats_.Rate(now_ms);
268*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
269*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0u, *bitrate);
270*d9f75844SAndroid Build Coastguard Worker 
271*d9f75844SAndroid Build Coastguard Worker   // Move window along so first data point falls out.
272*d9f75844SAndroid Build Coastguard Worker   ++now_ms;
273*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
274*d9f75844SAndroid Build Coastguard Worker 
275*d9f75844SAndroid Build Coastguard Worker   // Move window a long way out.
276*d9f75844SAndroid Build Coastguard Worker   // This will cause an automatic reset of the window
277*d9f75844SAndroid Build Coastguard Worker   // First data point won't give a valid result
278*d9f75844SAndroid Build Coastguard Worker   now_ms += 2 * kWindowMs;
279*d9f75844SAndroid Build Coastguard Worker   stats_.Update(0, now_ms);
280*d9f75844SAndroid Build Coastguard Worker   bitrate = stats_.Rate(now_ms);
281*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(static_cast<bool>(stats_.Rate(now_ms)));
282*d9f75844SAndroid Build Coastguard Worker   // Second data point gives valid result
283*d9f75844SAndroid Build Coastguard Worker   ++now_ms;
284*d9f75844SAndroid Build Coastguard Worker   stats_.Update(0, now_ms);
285*d9f75844SAndroid Build Coastguard Worker   bitrate = stats_.Rate(now_ms);
286*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(static_cast<bool>(bitrate));
287*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(0u, *bitrate);
288*d9f75844SAndroid Build Coastguard Worker }
289*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,HandlesBigNumbers)290*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, HandlesBigNumbers) {
291*d9f75844SAndroid Build Coastguard Worker   int64_t large_number = 0x100000000u;
292*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
293*d9f75844SAndroid Build Coastguard Worker   stats_.Update(large_number, now_ms++);
294*d9f75844SAndroid Build Coastguard Worker   stats_.Update(large_number, now_ms);
295*d9f75844SAndroid Build Coastguard Worker   EXPECT_TRUE(stats_.Rate(now_ms));
296*d9f75844SAndroid Build Coastguard Worker   EXPECT_EQ(large_number * RateStatistics::kBpsScale, *stats_.Rate(now_ms));
297*d9f75844SAndroid Build Coastguard Worker }
298*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,HandlesTooLargeNumbers)299*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, HandlesTooLargeNumbers) {
300*d9f75844SAndroid Build Coastguard Worker   int64_t very_large_number = std::numeric_limits<int64_t>::max();
301*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
302*d9f75844SAndroid Build Coastguard Worker   stats_.Update(very_large_number, now_ms++);
303*d9f75844SAndroid Build Coastguard Worker   stats_.Update(very_large_number, now_ms);
304*d9f75844SAndroid Build Coastguard Worker   // This should overflow the internal accumulator.
305*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(stats_.Rate(now_ms));
306*d9f75844SAndroid Build Coastguard Worker }
307*d9f75844SAndroid Build Coastguard Worker 
TEST_F(RateStatisticsTest,HandlesSomewhatLargeNumbers)308*d9f75844SAndroid Build Coastguard Worker TEST_F(RateStatisticsTest, HandlesSomewhatLargeNumbers) {
309*d9f75844SAndroid Build Coastguard Worker   int64_t very_large_number = std::numeric_limits<int64_t>::max();
310*d9f75844SAndroid Build Coastguard Worker   int64_t now_ms = 0;
311*d9f75844SAndroid Build Coastguard Worker   stats_.Update(very_large_number / 4, now_ms++);
312*d9f75844SAndroid Build Coastguard Worker   stats_.Update(very_large_number / 4, now_ms);
313*d9f75844SAndroid Build Coastguard Worker   // This should generate a rate of more than int64_t max, but still
314*d9f75844SAndroid Build Coastguard Worker   // accumulate less than int64_t overflow.
315*d9f75844SAndroid Build Coastguard Worker   EXPECT_FALSE(stats_.Rate(now_ms));
316*d9f75844SAndroid Build Coastguard Worker }
317*d9f75844SAndroid Build Coastguard Worker 
318*d9f75844SAndroid Build Coastguard Worker }  // namespace
319