11import { describe , expect , test } from "bun:test"
2- import { getRetryAfterDay , getRetryAfterHour } from "../src/routes/zen/util/rateLimiter"
2+ import { getRetryAfterDay } from "../src/routes/zen/util/rateLimiter"
33
44describe ( "getRetryAfterDay" , ( ) => {
55 test ( "returns full day at midnight UTC" , ( ) => {
@@ -17,76 +17,3 @@ describe("getRetryAfterDay", () => {
1717 expect ( getRetryAfterDay ( almost ) ) . toBe ( 1 )
1818 } )
1919} )
20-
21- describe ( "getRetryAfterHour" , ( ) => {
22- // 14:30:00 UTC — 30 minutes into the current hour
23- const now = Date . UTC ( 2026 , 0 , 15 , 14 , 30 , 0 , 0 )
24- const intervals = [ "2026011514" , "2026011513" , "2026011512" ]
25-
26- test ( "waits 3 hours when all usage is in current hour" , ( ) => {
27- const rows = [ { interval : "2026011514" , count : 10 } ]
28- // only current hour has usage — it won't leave the window for 3 hours from hour start
29- // 3 * 3600 - 1800 = 9000s
30- expect ( getRetryAfterHour ( rows , intervals , 10 , now ) ) . toBe ( 9000 )
31- } )
32-
33- test ( "waits 1 hour when dropping oldest interval is sufficient" , ( ) => {
34- const rows = [
35- { interval : "2026011514" , count : 2 } ,
36- { interval : "2026011512" , count : 10 } ,
37- ]
38- // total=12, drop oldest (-2h, count=10) -> 2 < 10
39- // hours = 3 - 2 = 1 -> 1 * 3600 - 1800 = 1800s
40- expect ( getRetryAfterHour ( rows , intervals , 10 , now ) ) . toBe ( 1800 )
41- } )
42-
43- test ( "waits 2 hours when usage spans oldest two intervals" , ( ) => {
44- const rows = [
45- { interval : "2026011513" , count : 8 } ,
46- { interval : "2026011512" , count : 5 } ,
47- ]
48- // total=13, drop -2h (5) -> 8, 8 >= 8, drop -1h (8) -> 0 < 8
49- // hours = 3 - 1 = 2 -> 2 * 3600 - 1800 = 5400s
50- expect ( getRetryAfterHour ( rows , intervals , 8 , now ) ) . toBe ( 5400 )
51- } )
52-
53- test ( "waits 1 hour when oldest interval alone pushes over limit" , ( ) => {
54- const rows = [
55- { interval : "2026011514" , count : 1 } ,
56- { interval : "2026011513" , count : 1 } ,
57- { interval : "2026011512" , count : 10 } ,
58- ]
59- // total=12, drop -2h (10) -> 2 < 10
60- // hours = 3 - 2 = 1 -> 1800s
61- expect ( getRetryAfterHour ( rows , intervals , 10 , now ) ) . toBe ( 1800 )
62- } )
63-
64- test ( "waits 2 hours when middle interval keeps total over limit" , ( ) => {
65- const rows = [
66- { interval : "2026011514" , count : 4 } ,
67- { interval : "2026011513" , count : 4 } ,
68- { interval : "2026011512" , count : 4 } ,
69- ]
70- // total=12, drop -2h (4) -> 8, 8 >= 5, drop -1h (4) -> 4 < 5
71- // hours = 3 - 1 = 2 -> 5400s
72- expect ( getRetryAfterHour ( rows , intervals , 5 , now ) ) . toBe ( 5400 )
73- } )
74-
75- test ( "rounds up to nearest second" , ( ) => {
76- const offset = Date . UTC ( 2026 , 0 , 15 , 14 , 30 , 0 , 500 )
77- const rows = [
78- { interval : "2026011514" , count : 2 } ,
79- { interval : "2026011512" , count : 10 } ,
80- ]
81- // hours=1 -> 3_600_000 - 1_800_500 = 1_799_500ms -> ceil(1799.5) = 1800
82- expect ( getRetryAfterHour ( rows , intervals , 10 , offset ) ) . toBe ( 1800 )
83- } )
84-
85- test ( "fallback returns time until next hour when rows are empty" , ( ) => {
86- // edge case: rows empty but function called (shouldn't happen in practice)
87- // loop drops all zeros, running stays 0 which is < any positive limit on first iteration
88- const rows : { interval : string ; count : number } [ ] = [ ]
89- // drop -2h (0) -> 0 < 1 -> hours = 3 - 2 = 1 -> 1800s
90- expect ( getRetryAfterHour ( rows , intervals , 1 , now ) ) . toBe ( 1800 )
91- } )
92- } )
0 commit comments