Skip to content

Commit ad54fda

Browse files
committed
added edge tests for proportions
1 parent 9c87146 commit ad54fda

File tree

1 file changed

+147
-29
lines changed

1 file changed

+147
-29
lines changed

test/rateLimiters/slidingWindowCounter.test.ts

Lines changed: 147 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ describe('Test TokenBucket Rate Limiter', () => {
104104
// tokens returned in processRequest is equal to the capacity
105105
// still available in the fixed window
106106

107+
// adds additional ms so that:
107108
// rolling window proportion: .99999...
108109
// 1 + 10 * .9 = 10 (floored)
109110
const result = await limiter.processRequest(user4, timestamp + WINDOW_SIZE + 1, 1);
@@ -123,7 +124,31 @@ describe('Test TokenBucket Rate Limiter', () => {
123124
expect(count.currentTokens).toBe(1);
124125
});
125126

126-
// three different tests within, with different rolling window proportions (.25, .5, .75)
127+
// five different tests within, with different rolling window proportions (0.01, .25, .5, .75, 1)
128+
test('rolling window at 100% allows requests under capacity', async () => {
129+
// 100% of rolling window present in previous fixed window
130+
// 1*60000 = 60000 (time after initial fixedWindowStart
131+
// to set rolling window at 100% of previous fixed window)
132+
133+
// to set initial fixedWindowStart
134+
await setTokenCountInClient(client, user4, 0, 0, timestamp);
135+
136+
// large request at very end of first fixed window
137+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, 8);
138+
139+
// 2 + 8 * 1 = 10, right at capacity (request should be allowed)
140+
// tokens until capacity: 0 (tokens property returned by processRequest method)
141+
const result = await limiter.processRequest(user4, timestamp + WINDOW_SIZE, 2);
142+
expect(result.tokens).toBe(0);
143+
expect(result.success).toBe(true);
144+
145+
// currentTokens (in current fixed window): 4
146+
// previousTokens (in previous fixed window): 8
147+
const count1 = await getWindowFromClient(client, user4);
148+
expect(count1.currentTokens).toBe(2);
149+
expect(count1.previousTokens).toBe(8);
150+
});
151+
127152
test('rolling window at 75% allows requests under capacity', async () => {
128153
// 75% of rolling window present in previous fixed window
129154
// 1.25*60000 = 75000 (time after initial fixedWindowStart
@@ -133,13 +158,17 @@ describe('Test TokenBucket Rate Limiter', () => {
133158
await setTokenCountInClient(client, user4, 0, 0, timestamp);
134159

135160
// large request at very end of first fixed window
136-
await limiter.processRequest(user4, timestamp + WINDOW_SIZE, 8);
161+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, 8);
137162

138163
// 4 + 8 * .75 = 10, right at capacity (request should be allowed)
139164
// tokens until capacity: 0 (tokens property returned by processRequest method)
140-
expect(
141-
(await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.25, 4)).tokens
142-
).toBe(0);
165+
const result = await limiter.processRequest(
166+
user4,
167+
timestamp + WINDOW_SIZE * 1.25,
168+
4
169+
);
170+
expect(result.tokens).toBe(0);
171+
expect(result.success).toBe(true);
143172

144173
// currentTokens (in current fixed window): 4
145174
// previousTokens (in previous fixed window): 8
@@ -157,13 +186,17 @@ describe('Test TokenBucket Rate Limiter', () => {
157186
await setTokenCountInClient(client, user4, 0, 0, timestamp);
158187

159188
// large request at very end of first fixed window
160-
await limiter.processRequest(user4, timestamp + WINDOW_SIZE, 8);
189+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, 8);
161190

162191
// 4 + 8 * .5 = 8, under capacity (request should be allowed)
163192
// tokens until capacity: 2 (tokens property returned by processRequest method)
164-
expect(
165-
(await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.5, 4)).tokens
166-
).toBe(2);
193+
const result = await limiter.processRequest(
194+
user4,
195+
timestamp + WINDOW_SIZE * 1.5,
196+
4
197+
);
198+
expect(result.tokens).toBe(2);
199+
expect(result.success).toBe(true);
167200

168201
// currentTokens (in current fixed window): 4
169202
// previousTokens (in previous fixed window): 8
@@ -181,20 +214,52 @@ describe('Test TokenBucket Rate Limiter', () => {
181214
await setTokenCountInClient(client, user4, 0, 0, timestamp);
182215

183216
// large request at very end of first fixed window
184-
await limiter.processRequest(user4, timestamp + WINDOW_SIZE, 8);
217+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, 8);
185218

186219
// 4 + 8 * .25 = 6, under capacity (request should be allowed)
187220
// tokens until capacity: 4 (tokens property returned by processRequest method)
188-
expect(
189-
(await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.75, 4)).tokens
190-
).toBe(4);
221+
const result = await limiter.processRequest(
222+
user4,
223+
timestamp + WINDOW_SIZE * 1.75,
224+
4
225+
);
226+
expect(result.tokens).toBe(4);
227+
expect(result.success).toBe(true);
191228

192229
// currentTokens (in current fixed window): 4
193230
// previousTokens (in previous fixed window): 8
194231
const count = await getWindowFromClient(client, user4);
195232
expect(count.currentTokens).toBe(4);
196233
expect(count.previousTokens).toBe(8);
197234
});
235+
236+
test('rolling window at 1% allows requests under capacity', async () => {
237+
// 1% of rolling window present in previous fixed window
238+
// 0.01*60000 = 600 (time after initial fixedWindowStart
239+
// to set rolling window at 1% of previous fixed window)
240+
241+
// to set initial fixedWindowStart
242+
await setTokenCountInClient(client, user4, 0, 0, timestamp);
243+
244+
// large request at very end of first fixed window
245+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, 8);
246+
247+
// 10 + 8 * .01 = 10, right at capacity (request should be allowed)
248+
// tokens until capacity: 0 (tokens property returned by processRequest method)
249+
const result = await limiter.processRequest(
250+
user4,
251+
timestamp + WINDOW_SIZE * 1.99,
252+
4
253+
);
254+
expect(result.tokens).toBe(0);
255+
expect(result.success).toBe(true);
256+
257+
// currentTokens (in current fixed window): 4
258+
// previousTokens (in previous fixed window): 8
259+
const count1 = await getWindowFromClient(client, user4);
260+
expect(count1.currentTokens).toBe(4);
261+
expect(count1.previousTokens).toBe(8);
262+
});
198263
});
199264

200265
describe('after a BLOCKED request...', () => {
@@ -214,15 +279,40 @@ describe('Test TokenBucket Rate Limiter', () => {
214279

215280
await setTokenCountInClient(client, user2, initRequest, 0, timestamp);
216281
// expect remaining tokens to be 4, b/c the 5 token request should be blocked
217-
expect(
218-
(await limiter.processRequest(user2, timestamp + WINDOW_SIZE, 5)).tokens
219-
).toBe(CAPACITY - initRequest);
282+
const result = await limiter.processRequest(user2, timestamp + WINDOW_SIZE - 1, 5);
283+
284+
expect(result.success).toBe(false);
285+
expect(result.tokens).toBe(CAPACITY - initRequest);
220286

221287
// expect current tokens in the window to still be 6
222288
expect((await getWindowFromClient(client, user2)).currentTokens).toBe(6);
223289
});
224290

225-
// 3 rolling window tests with different proportions (.25, .5, .75)
291+
// 5 rolling window tests with different proportions (.01, .25, .5, .75, 1)
292+
test('rolling window at 100% blocks requests over allowed limit set by formula', async () => {
293+
// 100% of rolling window present in previous fixed window
294+
// 1*60000 = 60000 (time after initial fixedWindowStart
295+
// to set rolling window at 100% of previous fixed window)
296+
297+
// to set initial fixedWindowStart
298+
await setTokenCountInClient(client, user4, 0, 0, timestamp);
299+
300+
const initRequest = 8;
301+
302+
// large request at very end of first fixed window
303+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, initRequest);
304+
305+
// 3 + 8 * 1 = 11, above capacity (request should be blocked)
306+
const result = await limiter.processRequest(user4, timestamp + WINDOW_SIZE, 3);
307+
expect(result.tokens).toBe(10);
308+
expect(result.success).toBe(false);
309+
310+
// currentTokens (in current fixed window): 0
311+
// previousTokens (in previous fixed window): 8
312+
const count1 = await getWindowFromClient(client, user4);
313+
expect(count1.currentTokens).toBe(0);
314+
expect(count1.previousTokens).toBe(initRequest);
315+
});
226316
test('rolling window at 75% blocks requests over allowed limit set by formula', async () => {
227317
// 75% of rolling window present in previous fixed window
228318
// 1.25*60000 = 75000 (time after initial fixedWindowStart
@@ -234,12 +324,16 @@ describe('Test TokenBucket Rate Limiter', () => {
234324
const initRequest = 8;
235325

236326
// large request at very end of first fixed window
237-
await limiter.processRequest(user4, timestamp + WINDOW_SIZE, initRequest);
327+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, initRequest);
238328

239329
// 5 + 8 * .75 = 11, above capacity (request should be blocked)
240-
expect(
241-
(await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.25, 5)).tokens
242-
).toBe(10);
330+
const result = await limiter.processRequest(
331+
user4,
332+
timestamp + WINDOW_SIZE * 1.25,
333+
5
334+
);
335+
expect(result.tokens).toBe(10);
336+
expect(result.success).toBe(false);
243337

244338
// currentTokens (in current fixed window): 0
245339
// previousTokens (in previous fixed window): 8
@@ -260,12 +354,12 @@ describe('Test TokenBucket Rate Limiter', () => {
260354
const initRequest = 8;
261355

262356
// large request at very end of first fixed window
263-
await limiter.processRequest(user4, timestamp + WINDOW_SIZE, initRequest);
357+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, initRequest);
264358

265359
// 7 + 8 * .5 = 11, over capacity (request should be blocked)
266-
expect(
267-
(await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.5, 7)).tokens
268-
).toBe(10);
360+
const result = await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.5, 7);
361+
expect(result.tokens).toBe(10);
362+
expect(result.success).toBe(false);
269363

270364
// currentTokens (in current fixed window): 0
271365
// previousTokens (in previous fixed window): 8
@@ -285,19 +379,43 @@ describe('Test TokenBucket Rate Limiter', () => {
285379
const initRequest = 8;
286380

287381
// large request at very end of first fixed window
288-
await limiter.processRequest(user4, timestamp + WINDOW_SIZE, initRequest);
382+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, initRequest);
289383

290384
// 9 + 8 * .25 = 11, over capacity (request should be blocked)
291-
expect(
292-
(await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.75, 9)).tokens
293-
).toBe(10);
385+
const result = await limiter.processRequest(user4, timestamp + WINDOW_SIZE * 1.75, 9);
386+
expect(result.tokens).toBe(10);
387+
expect(result.success).toBe(false);
294388

295389
// currentTokens (in current fixed window): 0
296390
// previousTokens (in previous fixed window): 8
297391
const count = await getWindowFromClient(client, user4);
298392
expect(count.currentTokens).toBe(0);
299393
expect(count.previousTokens).toBe(initRequest);
300394
});
395+
test('rolling window at 100% blocks requests over allowed limit set by formula', async () => {
396+
// 1% of rolling window present in previous fixed window
397+
// .01*60000 = 600 (time after initial fixedWindowStart
398+
// to set rolling window at 100% of previous fixed window)
399+
400+
// to set initial fixedWindowStart
401+
await setTokenCountInClient(client, user4, 0, 0, timestamp);
402+
403+
const initRequest = 8;
404+
405+
// large request at very end of first fixed window
406+
await limiter.processRequest(user4, timestamp + WINDOW_SIZE - 1, initRequest);
407+
408+
// 11 + 8 * .01 = 11, above capacity (request should be blocked)
409+
const result = await limiter.processRequest(user4, timestamp + WINDOW_SIZE, 11);
410+
expect(result.tokens).toBe(10);
411+
expect(result.success).toBe(false);
412+
413+
// currentTokens (in current fixed window): 0
414+
// previousTokens (in previous fixed window): 8
415+
const count1 = await getWindowFromClient(client, user4);
416+
expect(count1.currentTokens).toBe(0);
417+
expect(count1.previousTokens).toBe(initRequest);
418+
});
301419
});
302420

303421
describe('SlidingWindowCounter functions as expected', () => {

0 commit comments

Comments
 (0)