Skip to content

Commit 4d7a0f9

Browse files
committed
coverage, fix http request blocker
1 parent f578fe1 commit 4d7a0f9

File tree

2 files changed

+48
-13
lines changed

2 files changed

+48
-13
lines changed

.github/workflows/ci.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,10 @@ jobs:
9090
run: |
9191
SECRET_VARS=$(aws secretsmanager get-secret-value --secret-id gh-actions/api-keys/judgeval --query SecretString --output text)
9292
export $(echo "$SECRET_VARS" | jq -r 'to_entries | .[] | "\(.key)=\(.value)"')
93-
pipenv run pytest ./e2etests
93+
pipenv run pytest --durations=0 --cov=. --cov-config=.coveragerc --cov-report=html ./e2etests
94+
95+
- name: Upload coverage HTML report
96+
uses: actions/upload-artifact@v4
97+
with:
98+
name: coverage-html
99+
path: htmlcov

src/tests/conftest.py

Lines changed: 41 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ def get_error_info():
1414
return inspect.getframeinfo(caller_frame)
1515

1616
def is_external_url(url):
17-
return isinstance(url, str) and url.startswith(('http://', 'https://'))
17+
return isinstance(url, str) and url.startswith(('http://', 'https://')) and not url.startswith('http://testserver') # FastAPI TestClient base url starts with http://testserver
1818

1919
# Store original methods
2020
original_requests = {
@@ -32,7 +32,8 @@ def is_external_url(url):
3232
'put': httpx.put,
3333
'delete': httpx.delete,
3434
'head': httpx.head,
35-
'patch': httpx.patch
35+
'patch': httpx.patch,
36+
'request': httpx.request
3637
}
3738

3839
original_httpx_client = {
@@ -63,7 +64,6 @@ def wrapper(*args, **kwargs):
6364
def make_blocked_httpx_module(method_name, original_func):
6465
def wrapper(*args, **kwargs):
6566
url = args[0] if args else kwargs.get('url', '')
66-
print("url:", url)
6767
if not is_external_url(url):
6868
filtered_kwargs = {k: v for k, v in kwargs.items() if v is not None}
6969
return original_func(*args, **filtered_kwargs)
@@ -77,34 +77,62 @@ def wrapper(*args, **kwargs):
7777

7878
def make_blocked_httpx_client(method_name, original_func):
7979
def wrapper(self, *args, **kwargs):
80-
url = args[0] if args else kwargs.get('url', '')
81-
print("url:", url)
82-
if not is_external_url(url):
80+
from httpx import URL
81+
82+
if method_name == "request" and len(args) >= 2:
83+
method, url_arg = args[0], args[1]
84+
else:
85+
url_arg = args[0] if args else kwargs.get('url', '')
86+
87+
if isinstance(url_arg, str) and hasattr(self, 'base_url') and self.base_url:
88+
full_url = URL(self.base_url).join(URL(url_arg))
89+
else:
90+
full_url = url_arg
91+
92+
if not is_external_url(str(full_url)):
8393
filtered_kwargs = {k: v for k, v in kwargs.items() if v is not None}
8494
return original_func(self, *args, **filtered_kwargs)
95+
8596
caller = get_error_info()
8697
raise RuntimeError(
87-
f"Blocked httpx.Client.{method_name.upper()} to {url}\n"
98+
f"Blocked httpx.Client.{method_name.upper()} to {full_url}\n"
8899
f"Called from: {caller.filename}:{caller.lineno} in {caller.function}\n"
89100
f"Please mock this request in your test."
90101
)
102+
91103
return wrapper
104+
92105

93106
def make_blocked_httpx_async_client(method_name, original_func):
94107
async def wrapper(self, *args, **kwargs):
95-
url = args[0] if args else kwargs.get('url', '')
96-
print("url:", url)
97-
if not is_external_url(url):
108+
from httpx import URL
109+
110+
# Extract method and url argument based on call signature
111+
if method_name == "request" and len(args) >= 2:
112+
method, url_arg = args[0], args[1]
113+
else:
114+
url_arg = args[0] if args else kwargs.get('url', '')
115+
116+
# Reconstruct full URL
117+
if isinstance(url_arg, str) and hasattr(self, 'base_url') and self.base_url:
118+
full_url = URL(self.base_url).join(URL(url_arg))
119+
else:
120+
full_url = url_arg
121+
122+
if not is_external_url(str(full_url)):
98123
filtered_kwargs = {k: v for k, v in kwargs.items() if v is not None}
99124
return await original_func(self, *args, **filtered_kwargs)
125+
100126
caller = get_error_info()
101127
raise RuntimeError(
102-
f"Blocked httpx.AsyncClient.{method_name.upper()} to {url}\n"
128+
f"Blocked httpx.AsyncClient.{method_name.upper()} to {full_url}\n"
103129
f"Called from: {caller.filename}:{caller.lineno} in {caller.function}\n"
104130
f"Please mock this request in your test."
105131
)
132+
106133
return wrapper
107134

135+
108136
def blocked_urllib(*args, **kwargs):
109137
url = args[0] if args else kwargs.get('url', '')
110138
if not is_external_url(url):
@@ -131,5 +159,6 @@ def blocked_urllib(*args, **kwargs):
131159
# Patch httpx.AsyncClient instance methods
132160
for method, original_func in original_httpx_async_client.items():
133161
monkeypatch.setattr(httpx.AsyncClient, method, make_blocked_httpx_async_client(method, original_func))
162+
134163
# Patch urllib
135-
monkeypatch.setattr(urllib.request, "urlopen", blocked_urllib)
164+
monkeypatch.setattr(urllib.request, "urlopen", blocked_urllib)

0 commit comments

Comments
 (0)