Skip to content

Commit c50dc28

Browse files
authored
test: replace pytest-httpbin with custom fixture (#467)
1 parent c389865 commit c50dc28

6 files changed

Lines changed: 74 additions & 726 deletions

File tree

pyproject.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@ dependencies = ["pytest>=7.0.0"]
2828
[dependency-groups]
2929
dev = [
3030
"coverage[toml] >= 7.9",
31-
"pytest-httpbin >= 2.1.0",
32-
"pytest-randomly >= 3.15.0",
33-
"requests >= 2.32.4",
34-
"starlette >= 0.47.1",
3531
"httpx >= 0.28.1",
3632
"mypy >= 1.20",
33+
"pytest-randomly >= 3.15.0",
34+
"starlette >= 0.47.1",
3735
]
3836

3937
[project.urls]

tests/conftest.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import socket
2+
import threading
3+
from dataclasses import dataclass
4+
from http.server import BaseHTTPRequestHandler, HTTPServer
25

36
import pytest
47

@@ -9,3 +12,36 @@
912
not hasattr(socket, "AF_UNIX"),
1013
reason="Skip any platform that does not support AF_UNIX",
1114
)
15+
16+
17+
class _SimpleHandler(BaseHTTPRequestHandler):
18+
def do_GET(self) -> None:
19+
self.send_response(200)
20+
self.send_header("Content-Type", "text/plain")
21+
self.end_headers()
22+
self.wfile.write(b"OK")
23+
24+
def log_message(self, format, *args) -> None:
25+
pass # suppress request logging during tests
26+
27+
28+
@dataclass
29+
class _ServerInfo:
30+
host: str
31+
port: int
32+
33+
@property
34+
def url(self) -> str:
35+
return f"http://{self.host}:{self.port}"
36+
37+
38+
@pytest.fixture(scope="session")
39+
def httpserver() -> _ServerInfo:
40+
"""A lightweight local HTTP server for testing socket connections."""
41+
server = HTTPServer(("127.0.0.1", 0), _SimpleHandler)
42+
host, port = server.server_address
43+
thread = threading.Thread(target=server.serve_forever)
44+
thread.daemon = True
45+
thread.start()
46+
yield _ServerInfo(host=host, port=port)
47+
server.shutdown()

tests/test_combinations.py

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,36 @@
33
from .conftest import unix_sockets_only
44

55

6-
def test_parametrize_with_socket_enabled_and_allow_hosts(pytester, httpbin):
6+
def test_parametrize_with_socket_enabled_and_allow_hosts(pytester, httpserver):
77
"""This is a complex test that demonstrates the use of `parametrize`,
88
`enable_socket` fixture, allow_hosts CLI flag.
99
10-
TODO: This test makes real http calls. httpbin only provides a single IP.
11-
Is there a better way to express multiple **working** IPs?
12-
1310
From: https://github.com/miketheman/pytest-socket/issues/56
1411
"""
1512
pytester.makepyfile(f"""
13+
import socket
1614
import pytest
17-
import requests
15+
from urllib.request import urlopen
1816
1917
2018
@pytest.mark.parametrize(
21-
"url",
22-
[
23-
"https://google.com",
24-
"https://amazon.com",
25-
"https://www.microsoft.com",
26-
],
19+
"host",
20+
["google.com", "www.amazon.com", "www.microsoft.com"],
2721
)
28-
def test_domain(url, socket_enabled):
29-
requests.get(url)
22+
def test_domain(host, socket_enabled):
23+
# Just verify socket creation and connect aren't blocked
24+
sock = socket.create_connection((host, 443), timeout=5)
25+
sock.close()
3026
3127
def test_localhost_works():
32-
requests.get("{httpbin.url}/")
28+
urlopen("{httpserver.url}/")
3329
3430
def test_remote_not_allowed_fails():
35-
requests.get("http://172.1.1.1/")
31+
urlopen("http://172.1.1.1/")
3632
""")
3733
pytester.makeini(f"""
3834
[pytest]
39-
addopts = --disable-socket --allow-hosts={httpbin.host}
35+
addopts = --disable-socket --allow-hosts={httpserver.host}
4036
""")
4137
result = pytester.runpytest()
4238
result.assert_outcomes(passed=4, failed=1)
@@ -47,7 +43,7 @@ def test_remote_not_allowed_fails():
4743

4844

4945
@unix_sockets_only
50-
def test_combine_unix_and_allow_hosts(pytester, httpbin):
46+
def test_combine_unix_and_allow_hosts(pytester, httpserver):
5147
"""Test combination of disable, allow-unix and allow-hosts.
5248
5349
From https://github.com/miketheman/pytest-socket/issues/78
@@ -66,9 +62,9 @@ def test_unix_connect():
6662
6763
def test_inet_connect():
6864
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
69-
sock.connect(('{httpbin.host}', {httpbin.port}))
65+
sock.connect(('{httpserver.host}', {httpserver.port}))
7066
""")
7167
result = pytester.runpytest(
72-
"--disable-socket", "--allow-unix-socket", f"--allow-hosts={httpbin.host}"
68+
"--disable-socket", "--allow-unix-socket", f"--allow-hosts={httpserver.host}"
7369
)
7470
result.assert_outcomes(passed=2)

tests/test_precedence.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,16 @@ def test_socket_disabled():
125125
assert_socket_blocked(result, passed=1, failed=1)
126126

127127

128-
def test_global_disable_and_allow_host(pytester, httpbin):
128+
def test_global_disable_and_allow_host(pytester, httpserver):
129129
"""Disable socket globally, but allow a specific host"""
130130
pytester.makepyfile(f"""
131131
from urllib.request import urlopen
132132
133133
def test_urlopen():
134-
assert urlopen("{httpbin.url}/")
134+
assert urlopen("{httpserver.url}/")
135135
136136
def test_urlopen_disabled():
137137
assert urlopen("https://google.com/")
138138
""")
139-
result = pytester.runpytest("--disable-socket", f"--allow-hosts={httpbin.host}")
139+
result = pytester.runpytest("--disable-socket", f"--allow-hosts={httpserver.host}")
140140
assert_socket_blocked(result, passed=1, failed=1)

tests/test_restrict_hosts.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ def assert_host_blocked(result, host):
5353

5454

5555
@pytest.fixture
56-
def assert_connect(httpbin, pytester):
56+
def assert_connect(httpserver, pytester):
5757
def assert_socket_connect(should_pass, **kwargs):
5858
# get the name of the calling function
5959
test_name = inspect.stack()[1][3]
6060

6161
mark = ""
62-
host = kwargs.get("host", httpbin.host)
62+
host = kwargs.get("host", httpserver.host)
6363
cli_arg = kwargs.get("cli_arg", None)
6464
code_template = kwargs.get("code_template", connect_code_template)
6565
mark_arg = kwargs.get("mark_arg", None)
@@ -70,7 +70,7 @@ def assert_socket_connect(should_pass, **kwargs):
7070
elif isinstance(mark_arg, list):
7171
hosts = '","'.join(mark_arg)
7272
mark = f'@pytest.mark.allow_hosts(["{hosts}"])'
73-
code = code_template.format(host, httpbin.port, test_name, mark)
73+
code = code_template.format(host, httpserver.port, test_name, mark)
7474
pytester.makepyfile(code)
7575

7676
if cli_arg:
@@ -253,62 +253,62 @@ def test_global_restrict_via_config_fail():
253253
assert_host_blocked(result, "127.0.0.1")
254254

255255

256-
def test_global_restrict_via_config_pass(pytester, httpbin):
256+
def test_global_restrict_via_config_pass(pytester, httpserver):
257257
pytester.makepyfile(f"""
258258
import socket
259259
260260
def test_global_restrict_via_config_pass():
261-
socket.socket().connect(('{httpbin.host}', {httpbin.port}))
261+
socket.socket().connect(('{httpserver.host}', {httpserver.port}))
262262
""")
263263
pytester.makeini(f"""
264264
[pytest]
265-
addopts = --allow-hosts={httpbin.host}
265+
addopts = --allow-hosts={httpserver.host}
266266
""")
267267
result = pytester.runpytest()
268268
result.assert_outcomes(passed=1)
269269

270270

271-
def test_test_isolation(pytester, httpbin):
271+
def test_test_isolation(pytester, httpserver):
272272
pytester.makepyfile(f"""
273273
import pytest
274274
import socket
275275
276-
@pytest.mark.allow_hosts('{httpbin.host}')
276+
@pytest.mark.allow_hosts('{httpserver.host}')
277277
def test_pass():
278-
socket.socket().connect(('{httpbin.host}', {httpbin.port}))
278+
socket.socket().connect(('{httpserver.host}', {httpserver.port}))
279279
280280
@pytest.mark.allow_hosts('2.2.2.2')
281281
def test_fail():
282-
socket.socket().connect(('{httpbin.host}', {httpbin.port}))
282+
socket.socket().connect(('{httpserver.host}', {httpserver.port}))
283283
284284
def test_pass_2():
285-
socket.socket().connect(('{httpbin.host}', {httpbin.port}))
285+
socket.socket().connect(('{httpserver.host}', {httpserver.port}))
286286
""")
287287
result = pytester.runpytest()
288288
result.assert_outcomes(passed=2, failed=1)
289-
assert_host_blocked(result, httpbin.host)
289+
assert_host_blocked(result, httpserver.host)
290290

291291

292-
def test_conflicting_cli_vs_marks(pytester, httpbin):
292+
def test_conflicting_cli_vs_marks(pytester, httpserver):
293293
pytester.makepyfile(f"""
294294
import pytest
295295
import socket
296296
297-
@pytest.mark.allow_hosts('{httpbin.host}')
297+
@pytest.mark.allow_hosts('{httpserver.host}')
298298
def test_pass():
299-
socket.socket().connect(('{httpbin.host}', {httpbin.port}))
299+
socket.socket().connect(('{httpserver.host}', {httpserver.port}))
300300
301301
@pytest.mark.allow_hosts('2.2.2.2')
302302
def test_fail():
303-
socket.socket().connect(('{httpbin.host}', {httpbin.port}))
303+
socket.socket().connect(('{httpserver.host}', {httpserver.port}))
304304
305305
def test_fail_2():
306-
socket.socket().connect(('2.2.2.2', {httpbin.port}))
306+
socket.socket().connect(('2.2.2.2', {httpserver.port}))
307307
""")
308308
result = pytester.runpytest("--allow-hosts=1.2.3.4")
309309
result.assert_outcomes(passed=1, failed=2)
310310
assert_host_blocked(result, "2.2.2.2")
311-
assert_host_blocked(result, httpbin.host)
311+
assert_host_blocked(result, httpserver.host)
312312

313313

314314
def test_normalize_allowed_hosts(getaddrinfo_hosts):

0 commit comments

Comments
 (0)