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