@@ -187,4 +187,138 @@ public function testFlooding()
187187 $ this ->assertTrue ($ throttler ->check ('127.0.0.1 ' , $ rate , MINUTE , 0 ));
188188 $ this ->assertSame (10.0 , round ($ this ->cache ->get ('throttler_127.0.0.1 ' )));
189189 }
190+
191+ /**
192+ * @dataProvider tokenTimeUsecases
193+ */
194+ public function testTokenTimeCalculationUCs (int $ capacity , int $ seconds , array $ checkInputs ): void
195+ {
196+ $ key = 'testkey ' ;
197+ $ throttler = new Throttler ($ this ->cache );
198+
199+ // clear $key before test start
200+ $ throttler ->remove ($ key );
201+
202+ foreach ($ checkInputs as $ index => $ checkInput ) {
203+ $ throttler ->setTestTime ($ checkInput ['testTime ' ]);
204+ $ checkResult = $ throttler ->check ($ key , $ capacity , $ seconds , $ checkInput ['cost ' ]);
205+
206+ $ this ->assertSame ($ checkInput ['expectedCheckResult ' ], $ checkResult , "Input# {$ index }: Wrong check() result " );
207+ $ this ->assertSame ($ checkInput ['expectedTokenTime ' ], $ throttler ->getTokenTime (), "Input# {$ index }: Wrong tokenTime " );
208+ }
209+ }
210+
211+ public function tokenTimeUsecases (): array
212+ {
213+ return [
214+ '2 capacity / 200 seconds (100s refresh, 0.01 tokens/s) -> 5 checks, 1 cost each ' => [
215+ 'capacity ' => 2 ,
216+ 'seconds ' => 200 ,
217+ 'checkInputs ' => [
218+ [ // 2 -> 1
219+ 'testTime ' => 0 ,
220+ 'cost ' => 1 ,
221+ 'expectedCheckResult ' => true ,
222+ 'expectedTokenTime ' => 0 ,
223+ ],
224+ [ // +3s / 1.03 -> 0.03
225+ 'testTime ' => 3 ,
226+ 'cost ' => 1 ,
227+ 'expectedCheckResult ' => true ,
228+ 'expectedTokenTime ' => 0 ,
229+ ],
230+ [ // +0s / 0.03 -> 0.03 / (1 - 0.03) * 100 = 97
231+ 'testTime ' => 3 ,
232+ 'cost ' => 1 ,
233+ 'expectedCheckResult ' => false ,
234+ 'expectedTokenTime ' => 97 ,
235+ ],
236+ [ // +1m 32s / 0.95 -> 0.95 / (1 - 0.95) * 100 = 5
237+ 'testTime ' => 95 ,
238+ 'cost ' => 1 ,
239+ 'expectedCheckResult ' => false ,
240+ 'expectedTokenTime ' => 5 ,
241+ ],
242+ [ // +7s / 1.02 -> 0.02
243+ 'testTime ' => 102 ,
244+ 'cost ' => 1 ,
245+ 'expectedCheckResult ' => true ,
246+ 'expectedTokenTime ' => 0 ,
247+ ],
248+ [ // +13s / 0.15 / (1 - 0.15) * 100 = 85
249+ 'testTime ' => 115 ,
250+ 'cost ' => 1 ,
251+ 'expectedCheckResult ' => false ,
252+ 'expectedTokenTime ' => 85 ,
253+ ],
254+ ],
255+ ],
256+ '1 capacity / 3600 seconds (3600s refresh, 2.77e-4 tokens/s) -> 2 checks with 1 cost each ' => [
257+ 'capacity ' => 1 ,
258+ 'seconds ' => 3600 ,
259+ 'checkInputs ' => [
260+ [ // 1 -> 0
261+ 'testTime ' => 0 ,
262+ 'cost ' => 1 ,
263+ 'expectedCheckResult ' => true ,
264+ 'expectedTokenTime ' => 0 ,
265+ ],
266+ [ // +6m / 0.1 -> 0.1 / (1 - 0.1) * 3600 = 3240
267+ 'testTime ' => 360 ,
268+ 'cost ' => 1 ,
269+ 'expectedCheckResult ' => false ,
270+ 'expectedTokenTime ' => 3240 ,
271+ ],
272+ ],
273+ ],
274+ '10 capacity / 200 seconds (20s refresh, 0.05 tokens/s) -> 7 checks with different costs (RNG) ' => [
275+ 'capacity ' => 10 ,
276+ 'seconds ' => 200 ,
277+ 'checkInputs ' => [
278+ [ // -2t / 10 -> 8
279+ 'testTime ' => 0 ,
280+ 'cost ' => 2 ,
281+ 'expectedCheckResult ' => true ,
282+ 'expectedTokenTime ' => 0 ,
283+ ],
284+ [ // +19s -2t / 8.95 -> 6.95
285+ 'testTime ' => 19 ,
286+ 'cost ' => 2 ,
287+ 'expectedCheckResult ' => true ,
288+ 'expectedTokenTime ' => 0 ,
289+ ],
290+ [ // +16s -3t / 7.75 -> 4.75
291+ 'testTime ' => 35 ,
292+ 'cost ' => 3 ,
293+ 'expectedCheckResult ' => true ,
294+ 'expectedTokenTime ' => 0 ,
295+ ],
296+ [ // +4s -2t / 4.95 -> 2.95
297+ 'testTime ' => 39 ,
298+ 'cost ' => 2 ,
299+ 'expectedCheckResult ' => true ,
300+ 'expectedTokenTime ' => 0 ,
301+ ],
302+ [ // +13s -5t / 3.6 -> -1.4 (blow allowed)
303+ 'testTime ' => 52 ,
304+ 'cost ' => 5 ,
305+ 'expectedCheckResult ' => true ,
306+ 'expectedTokenTime ' => 0 ,
307+ ],
308+ [ // +2s -2t / -1.3 -> -1.3 / (1 - (-1.3)) * 20 = 46
309+ 'testTime ' => 54 ,
310+ 'cost ' => 2 ,
311+ 'expectedCheckResult ' => false ,
312+ 'expectedTokenTime ' => 46 ,
313+ ],
314+ [ // +7s -2t / -0.95 - -0.95 / (1 - (-0.95)) * 20 = 39
315+ 'testTime ' => 61 ,
316+ 'cost ' => 2 ,
317+ 'expectedCheckResult ' => false ,
318+ 'expectedTokenTime ' => 39 ,
319+ ],
320+ ],
321+ ],
322+ ];
323+ }
190324}
0 commit comments