@@ -61,6 +61,8 @@ public class RateLimiterTest extends FirebasePerformanceTestBase {
61
61
private static final Rate TWO_TOKENS_PER_MINUTE = new Rate (2 , 1 , MINUTES );
62
62
private static final Rate FOUR_TOKENS_PER_MINUTE = new Rate (4 , 1 , MINUTES );
63
63
private static final Rate TWO_TOKENS_PER_SECOND = new Rate (2 , 1 , SECONDS );
64
+ private static final Rate THREE_TOKENS_PER_SECOND = new Rate (3 , 1 , SECONDS );
65
+ private static final Rate TEN_TOKENS_PER_SECOND = new Rate (10 , 1 , SECONDS );
64
66
65
67
@ Before
66
68
public void setUp () {
@@ -125,7 +127,7 @@ public void testRateLimitImpl() {
125
127
126
128
/** An edge test case for Token Bucket algorithm. */
127
129
@ Test
128
- public void testRateLimitImplWithIrregularTimeIntervals () {
130
+ public void testRateLimiterImplWithIrregularTimeIntervals () {
129
131
130
132
makeConfigResolverReturnDefaultValues ();
131
133
@@ -165,7 +167,8 @@ public void testRateLimitImplWithIrregularTimeIntervals() {
165
167
}
166
168
167
169
@ Test
168
- public void testRateLimitImplWithLongTimeGapBetweenEvents_doesNotAccumulateTokensOrCauseBurst () {
170
+ public void
171
+ testRateLimiterImplWithLongTimeGapBetweenEvents_doesNotAccumulateTokensOrCauseBurst () {
169
172
170
173
makeConfigResolverReturnDefaultValues ();
171
174
@@ -206,6 +209,97 @@ public void testRateLimitImplWithLongTimeGapBetweenEvents_doesNotAccumulateToken
206
209
assertThat (limiter .check (metric )).isFalse ();
207
210
}
208
211
212
+ @ Test
213
+ public void testRateLimiterImplWithBursts_rateLessThanCapacity_doesNotAllowMoreThanCapacity () {
214
+
215
+ makeConfigResolverReturnDefaultValues ();
216
+
217
+ // Make Config Resolver returns default value for resource sampling rate.
218
+ when (mockConfigResolver .getTraceSamplingRate ()).thenReturn (1.0f );
219
+ when (mockConfigResolver .getNetworkRequestSamplingRate ()).thenReturn (1.0f );
220
+
221
+ // allow 3 logs per second. token bucket capacity is 4.
222
+ RateLimiterImpl limiter =
223
+ new RateLimiterImpl (THREE_TOKENS_PER_SECOND , 4 , mClock , mockConfigResolver , NETWORK , false );
224
+ PerfMetric metric = PerfMetric .getDefaultInstance ();
225
+
226
+ // clock is 0, token count starts at 4, none should be replenished
227
+ assertThat (limiter .check (metric )).isTrue ();
228
+ assertThat (limiter .check (metric )).isTrue ();
229
+ assertThat (limiter .check (metric )).isTrue ();
230
+ assertThat (limiter .check (metric )).isTrue ();
231
+ assertThat (limiter .check (metric )).isFalse ();
232
+ assertThat (limiter .check (metric )).isFalse ();
233
+
234
+ // clock is 1 second, 3 events should be allowed within the second
235
+ currentTime = currentTime .plusSeconds (1 );
236
+ assertThat (limiter .check (metric )).isTrue ();
237
+ assertThat (limiter .check (metric )).isTrue ();
238
+ assertThat (limiter .check (metric )).isTrue ();
239
+ assertThat (limiter .check (metric )).isFalse ();
240
+
241
+ // the first burst has finished, and there are 1 event per second for the next 3 seconds
242
+ currentTime = currentTime .plusSeconds (1 );
243
+ assertThat (limiter .check (metric )).isTrue ();
244
+ currentTime = currentTime .plusSeconds (1 );
245
+ assertThat (limiter .check (metric )).isTrue ();
246
+ currentTime = currentTime .plusSeconds (1 );
247
+ assertThat (limiter .check (metric )).isTrue ();
248
+
249
+ // after 10 seconds, the second burst is here, but capacity = 4 events are allowed
250
+ currentTime = currentTime .plusSeconds (10 );
251
+ assertThat (limiter .check (metric )).isTrue ();
252
+ assertThat (limiter .check (metric )).isTrue ();
253
+ assertThat (limiter .check (metric )).isTrue ();
254
+ assertThat (limiter .check (metric )).isTrue ();
255
+ assertThat (limiter .check (metric )).isFalse ();
256
+ assertThat (limiter .check (metric )).isFalse ();
257
+ assertThat (limiter .check (metric )).isFalse ();
258
+ }
259
+
260
+ @ Test
261
+ public void testRateLimiterImplWithBursts_rateMoreThanCapacity_doesNotAllowMoreThanCapacity () {
262
+
263
+ makeConfigResolverReturnDefaultValues ();
264
+
265
+ // Make Config Resolver returns default value for resource sampling rate.
266
+ when (mockConfigResolver .getTraceSamplingRate ()).thenReturn (1.0f );
267
+ when (mockConfigResolver .getNetworkRequestSamplingRate ()).thenReturn (1.0f );
268
+
269
+ // allow 3 logs per second. token bucket capacity is 2.
270
+ RateLimiterImpl limiter =
271
+ new RateLimiterImpl (THREE_TOKENS_PER_SECOND , 2 , mClock , mockConfigResolver , NETWORK , false );
272
+ PerfMetric metric = PerfMetric .getDefaultInstance ();
273
+
274
+ // clock is 0, token count starts at 2, none should be replenished
275
+ assertThat (limiter .check (metric )).isTrue ();
276
+ assertThat (limiter .check (metric )).isTrue ();
277
+ assertThat (limiter .check (metric )).isFalse ();
278
+ assertThat (limiter .check (metric )).isFalse ();
279
+
280
+ // clock is 1 second, 2 events should be allowed within the second due to capacity cap
281
+ currentTime = currentTime .plusSeconds (1 );
282
+ assertThat (limiter .check (metric )).isTrue ();
283
+ assertThat (limiter .check (metric )).isTrue ();
284
+ assertThat (limiter .check (metric )).isFalse ();
285
+ assertThat (limiter .check (metric )).isFalse ();
286
+
287
+ // the first burst has finished, and there are 1 event per second for the next 3 seconds
288
+ currentTime = currentTime .plusSeconds (1 );
289
+ assertThat (limiter .check (metric )).isTrue ();
290
+ currentTime = currentTime .plusSeconds (1 );
291
+ assertThat (limiter .check (metric )).isTrue ();
292
+ currentTime = currentTime .plusSeconds (1 );
293
+ assertThat (limiter .check (metric )).isTrue ();
294
+
295
+ // the second burst is here, but only capacity = 2 events are allowed
296
+ currentTime = currentTime .plusSeconds (10 );
297
+ assertThat (limiter .check (metric )).isTrue ();
298
+ assertThat (limiter .check (metric )).isTrue ();
299
+ assertThat (limiter .check (metric )).isFalse ();
300
+ assertThat (limiter .check (metric )).isFalse ();
301
+ }
302
+
209
303
/**
210
304
* Inside class RateLimiter, there is one RateLimiterImpl instance for TraceMetric object, and one
211
305
* RateLimiterImpl instance for NetworkRequestMetric object, each RateLimiterImpl instance is a
0 commit comments