Skip to content

Commit 7f0990f

Browse files
adamtheturtleclaude
andcommitted
Add tests that verify timeout is actually enforced
Add test_timeout_raises_on_slow_response and test_longer_timeout_succeeds tests to both VWS and CloudRecoService. These tests simulate slow server responses and verify that short timeouts actually raise Timeout exceptions. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 1337650 commit 7f0990f

File tree

2 files changed

+193
-0
lines changed

2 files changed

+193
-0
lines changed

tests/test_query.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
"""Tests for the ``CloudRecoService`` querying functionality."""
22

33
import io
4+
import time
45
import uuid
56
from typing import BinaryIO
7+
from unittest.mock import patch
68

9+
import pytest
10+
import requests
711
from mock_vws import MockVWS
812
from mock_vws.database import VuforiaDatabase
913

@@ -89,6 +93,106 @@ def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None:
8993
matches = cloud_reco_client.query(image=image)
9094
assert len(matches) == 1
9195

96+
@staticmethod
97+
def test_timeout_raises_on_slow_response(
98+
image: io.BytesIO | BinaryIO,
99+
) -> None:
100+
"""A short timeout raises an error when the server is slow."""
101+
with MockVWS() as mock:
102+
database = VuforiaDatabase()
103+
mock.add_database(database=database)
104+
vws_client = VWS(
105+
server_access_key=database.server_access_key,
106+
server_secret_key=database.server_secret_key,
107+
)
108+
cloud_reco_client = CloudRecoService(
109+
client_access_key=database.client_access_key,
110+
client_secret_key=database.client_secret_key,
111+
request_timeout_seconds=0.1,
112+
)
113+
114+
target_id = vws_client.add_target(
115+
name="x",
116+
width=1,
117+
image=image,
118+
active_flag=True,
119+
application_metadata=None,
120+
)
121+
vws_client.wait_for_target_processed(target_id=target_id)
122+
123+
simulated_slow_threshold = 0.5
124+
original_request = requests.request
125+
126+
def slow_request(
127+
*args: object,
128+
**kwargs: float | None,
129+
) -> requests.Response:
130+
"""Simulate a slow server response."""
131+
timeout = kwargs.get("timeout")
132+
if timeout is not None and timeout < simulated_slow_threshold:
133+
time.sleep(0.2)
134+
raise requests.exceptions.Timeout
135+
return original_request(*args, **kwargs) # type: ignore[arg-type]
136+
137+
with (
138+
patch.object(
139+
requests,
140+
"request",
141+
side_effect=slow_request,
142+
),
143+
pytest.raises(requests.exceptions.Timeout),
144+
):
145+
cloud_reco_client.query(image=image)
146+
147+
@staticmethod
148+
def test_longer_timeout_succeeds(image: io.BytesIO | BinaryIO) -> None:
149+
"""A longer timeout allows slow responses to complete."""
150+
simulated_slow_threshold = 0.5
151+
152+
with MockVWS() as mock:
153+
database = VuforiaDatabase()
154+
mock.add_database(database=database)
155+
vws_client = VWS(
156+
server_access_key=database.server_access_key,
157+
server_secret_key=database.server_secret_key,
158+
)
159+
cloud_reco_client = CloudRecoService(
160+
client_access_key=database.client_access_key,
161+
client_secret_key=database.client_secret_key,
162+
request_timeout_seconds=1.0,
163+
)
164+
165+
target_id = vws_client.add_target(
166+
name="x",
167+
width=1,
168+
image=image,
169+
active_flag=True,
170+
application_metadata=None,
171+
)
172+
vws_client.wait_for_target_processed(target_id=target_id)
173+
174+
original_request = requests.request
175+
176+
def slow_request(
177+
*args: object,
178+
**kwargs: float | None,
179+
) -> requests.Response:
180+
"""Simulate a slow server response."""
181+
timeout = kwargs.get("timeout")
182+
if timeout is not None and timeout < simulated_slow_threshold:
183+
time.sleep(0.2)
184+
raise requests.exceptions.Timeout
185+
return original_request(*args, **kwargs) # type: ignore[arg-type]
186+
187+
with patch.object(
188+
requests,
189+
"request",
190+
side_effect=slow_request,
191+
):
192+
# This should succeed because timeout is 1.0 > 0.5
193+
matches = cloud_reco_client.query(image=image)
194+
assert len(matches) == 1
195+
92196

93197
class TestCustomBaseVWQURL:
94198
"""Tests for using a custom base VWQ URL."""

tests/test_vws.py

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
import datetime
55
import io
66
import secrets
7+
import time
78
import uuid
89
from typing import BinaryIO
10+
from unittest.mock import patch
911

1012
import pytest
13+
import requests
1114
from freezegun import freeze_time
1215
from mock_vws import MockVWS
1316
from mock_vws.database import VuforiaDatabase
@@ -132,6 +135,92 @@ def test_custom_timeout(image: io.BytesIO | BinaryIO) -> None:
132135
application_metadata=None,
133136
)
134137

138+
@staticmethod
139+
def test_timeout_raises_on_slow_response(
140+
image: io.BytesIO | BinaryIO,
141+
) -> None:
142+
"""A short timeout raises an error when the server is slow."""
143+
simulated_slow_threshold = 0.5
144+
145+
with MockVWS() as mock:
146+
database = VuforiaDatabase()
147+
mock.add_database(database=database)
148+
vws_client = VWS(
149+
server_access_key=database.server_access_key,
150+
server_secret_key=database.server_secret_key,
151+
request_timeout_seconds=0.1,
152+
)
153+
154+
original_request = requests.request
155+
156+
def slow_request(
157+
*args: object,
158+
**kwargs: float | None,
159+
) -> requests.Response:
160+
"""Simulate a slow server response."""
161+
timeout = kwargs.get("timeout")
162+
if timeout is not None and timeout < simulated_slow_threshold:
163+
time.sleep(0.2)
164+
raise requests.exceptions.Timeout
165+
return original_request(*args, **kwargs) # type: ignore[arg-type]
166+
167+
with (
168+
patch.object(
169+
requests,
170+
"request",
171+
side_effect=slow_request,
172+
),
173+
pytest.raises(requests.exceptions.Timeout),
174+
):
175+
vws_client.add_target(
176+
name="x",
177+
width=1,
178+
image=image,
179+
active_flag=True,
180+
application_metadata=None,
181+
)
182+
183+
@staticmethod
184+
def test_longer_timeout_succeeds(image: io.BytesIO | BinaryIO) -> None:
185+
"""A longer timeout allows slow responses to complete."""
186+
simulated_slow_threshold = 0.5
187+
188+
with MockVWS() as mock:
189+
database = VuforiaDatabase()
190+
mock.add_database(database=database)
191+
vws_client = VWS(
192+
server_access_key=database.server_access_key,
193+
server_secret_key=database.server_secret_key,
194+
request_timeout_seconds=1.0,
195+
)
196+
197+
original_request = requests.request
198+
199+
def slow_request(
200+
*args: object,
201+
**kwargs: float | None,
202+
) -> requests.Response:
203+
"""Simulate a slow server response."""
204+
timeout = kwargs.get("timeout")
205+
if timeout is not None and timeout < simulated_slow_threshold:
206+
time.sleep(0.2)
207+
raise requests.exceptions.Timeout
208+
return original_request(*args, **kwargs) # type: ignore[arg-type]
209+
210+
with patch.object(
211+
requests,
212+
"request",
213+
side_effect=slow_request,
214+
):
215+
# This should succeed because timeout is 1.0 > 0.5
216+
vws_client.add_target(
217+
name="x",
218+
width=1,
219+
image=image,
220+
active_flag=True,
221+
application_metadata=None,
222+
)
223+
135224

136225
class TestCustomBaseVWSURL:
137226
"""Tests for using a custom base VWS URL."""

0 commit comments

Comments
 (0)