Skip to content

Commit 569facc

Browse files
test: add rate limit tests
1 parent 4462a32 commit 569facc

2 files changed

Lines changed: 156 additions & 0 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ markers = [
5959
"parsing_file_sync",
6060
"profile",
6161
"quicksilver",
62+
"rate_limit",
6263
"scoring",
6364
"searching",
6465
"tagging",

tests/test_rate_limit.py

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
from hrflow.core.rate_limit import rate_limiter
2+
import pytest
3+
from time import time
4+
5+
@pytest.mark.rate_limit
6+
def test_rate_limit_no_params():
7+
i = 0
8+
9+
@rate_limiter
10+
def increment():
11+
nonlocal i
12+
i += 1
13+
14+
start_time = time()
15+
for round in range(5):
16+
increment()
17+
assert i == round + 1, ("The sub function wrapper with rate limiting must have",
18+
"a side effect, but the result is inconsistent with what it should be")
19+
20+
end_time = time()
21+
duration = end_time - start_time
22+
23+
assert duration < 1, "5 calls should be less than 1 second"
24+
25+
@pytest.mark.rate_limit
26+
def test_rate_limit_no_params_and_with_function_params():
27+
i = 0
28+
memory = None
29+
30+
@rate_limiter
31+
def increment(round : int):
32+
nonlocal i
33+
nonlocal memory
34+
35+
i += 1
36+
memory = round
37+
38+
39+
start_time = time()
40+
for round in range(5):
41+
increment(round)
42+
assert i == round + 1, ("The sub function wrapper with rate limiting must have",
43+
"a side effect, but the result is inconsistent with what it should be")
44+
assert memory == round, ("The sub function wrapper with rate limiting must",
45+
"have a side effect, but the result is inconsistent with what it should be")
46+
47+
end_time = time()
48+
duration = end_time - start_time
49+
50+
assert duration < 1, "5 calls should be less than 1 second"
51+
52+
@pytest.mark.rate_limit
53+
def test_rate_limit_sleep_per_req_and_with_function_params():
54+
min_sleep_per_request = 1 # second(s)
55+
delta_duration = 0.1
56+
i = 0
57+
memory = None
58+
59+
@rate_limiter
60+
def increment(round : int):
61+
nonlocal i
62+
nonlocal memory
63+
64+
i += 1
65+
memory = round
66+
67+
68+
global_start_time = time()
69+
round_count = 5
70+
for round in range(round_count):
71+
round_start_time = time()
72+
increment(round, min_sleep_per_request=min_sleep_per_request)
73+
assert i == round + 1, ("The sub function wrapper with rate limiting must have",
74+
"a side effect, but the result is inconsistent with what it should be")
75+
assert memory == round, ("The sub function wrapper with rate limiting must",
76+
"have a side effect, but the result is inconsistent with what it should be")
77+
round_duration = time() - round_start_time
78+
assert round_duration + delta_duration >= min_sleep_per_request, (
79+
"function call must be more than {min_sleep_per_request} second"
80+
)
81+
82+
end_time = time()
83+
global_duration = end_time - global_start_time
84+
85+
assert global_duration + delta_duration >= min_sleep_per_request*round_count, (
86+
"5 calls should be more than 5 seconds"
87+
)
88+
89+
@pytest.mark.rate_limit
90+
def test_rate_limit_with_rpm():
91+
SECONDS_IN_MINUTE = 60
92+
max_requests_per_minute = 5 # second(s)
93+
num_requests = 8
94+
delta_duration = 0.1
95+
i = 0
96+
97+
@rate_limiter
98+
def increment():
99+
# less than 0.1 second function
100+
nonlocal i
101+
i += 1
102+
103+
for round in range(num_requests):
104+
print(round)
105+
round_start_time = time()
106+
increment(max_requests_per_minute=max_requests_per_minute)
107+
assert i == round + 1, ("The sub function wrapper with rate limiting must have",
108+
"a side effect, but the result is inconsistent with what it should be")
109+
110+
round_duration = time() - round_start_time
111+
if round != 0 and round % max_requests_per_minute == 0:
112+
assert round_duration + delta_duration >= SECONDS_IN_MINUTE, (
113+
f"unexpected more than {max_requests_per_minute} req per minute"
114+
)
115+
else:
116+
assert round_duration <= delta_duration, (
117+
f"function call must be less than {delta_duration} second(s)"
118+
)
119+
120+
@pytest.mark.rate_limit
121+
def test_rate_limit_with_rpm_and_sleep_per_req():
122+
SECONDS_IN_MINUTE = 60
123+
min_sleep_per_request = 1 # second(s)
124+
max_requests_per_minute = 5 # second(s)
125+
num_requests = 8
126+
delta_duration = 0.1
127+
i = 0
128+
129+
@rate_limiter
130+
def increment():
131+
# less than 0.1 second function
132+
nonlocal i
133+
i += 1
134+
135+
for round in range(num_requests):
136+
print(round)
137+
round_start_time = time()
138+
increment(
139+
max_requests_per_minute=max_requests_per_minute,
140+
min_sleep_per_request=min_sleep_per_request
141+
)
142+
assert i == round + 1, ("The sub function wrapper with rate limiting must have",
143+
"a side effect, but the result is inconsistent with what it should be")
144+
145+
round_duration = time() - round_start_time
146+
if round != 0 and round % max_requests_per_minute == 0:
147+
normilized_duration = round_duration + delta_duration \
148+
+ min_sleep_per_request*max_requests_per_minute
149+
assert normilized_duration >= SECONDS_IN_MINUTE, (
150+
f"unexpected more than {max_requests_per_minute} req per minute"
151+
)
152+
else:
153+
assert round_duration + delta_duration >= min_sleep_per_request, (
154+
"function call must be more than {min_sleep_per_request} second"
155+
)

0 commit comments

Comments
 (0)