|
5 | 5 | import sys |
6 | 6 | from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer |
7 | 7 | from threading import Thread |
| 8 | +from unittest.mock import patch |
8 | 9 |
|
9 | 10 | import httpcore |
10 | 11 | import httpx |
|
16 | 17 |
|
17 | 18 | @pytest.fixture(autouse=True) |
18 | 19 | def clean_env(monkeypatch): |
| 20 | + if hasattr(transport, "_log_keepalive_unavailable"): |
| 21 | + transport._log_keepalive_unavailable.cache_clear() |
19 | 22 | for suffix in ("", "_IDLE", "_INTERVAL", "_COUNT"): |
20 | 23 | monkeypatch.delenv("UNSTRUCTURED_CLIENT_TCP_KEEPALIVE" + suffix, raising=False) |
21 | 24 | monkeypatch.setenv("NO_PROXY", "*") |
@@ -50,6 +53,43 @@ def test_unit_invalid_value(monkeypatch, caplog, suffix, default, value): |
50 | 53 | assert "using default" in caplog.text |
51 | 54 |
|
52 | 55 |
|
| 56 | +@pytest.mark.parametrize("suffix,maximum,default", [ |
| 57 | + ("IDLE", 32767, 60), ("INTERVAL", 32767, 30), ("COUNT", 127, 5), |
| 58 | +]) |
| 59 | +@pytest.mark.parametrize("above_maximum", [False, True]) |
| 60 | +def test_unit_value_bounds(monkeypatch, caplog, suffix, maximum, default, above_maximum): |
| 61 | + monkeypatch.setenv("UNSTRUCTURED_CLIENT_TCP_KEEPALIVE_" + suffix, |
| 62 | + str(maximum + int(above_maximum))) |
| 63 | + expected = default if above_maximum else maximum |
| 64 | + assert getattr(transport.resolve_tcp_keepalive(), suffix.lower()) == expected |
| 65 | + assert ("using default" in caplog.text) == above_maximum |
| 66 | + |
| 67 | + |
| 68 | +@pytest.mark.parametrize("asynchronous", [False, True]) |
| 69 | +def test_unit_missing_proxy_helper_client_options(monkeypatch, asynchronous): |
| 70 | + monkeypatch.setattr(transport, "get_environment_proxies", None) |
| 71 | + if asynchronous: |
| 72 | + options = {"verify": False, "cert": None, "limits": httpx.Limits(max_connections=3)} |
| 73 | + with patch.object(httpx, "AsyncClient") as constructor: |
| 74 | + transport.create_async_http_client(timeout=42, transport_options=options) |
| 75 | + constructor.assert_called_once_with(timeout=42, **options) |
| 76 | + else: |
| 77 | + with patch.object(httpx, "Client") as constructor: |
| 78 | + transport.create_http_client() |
| 79 | + constructor.assert_called_once_with() |
| 80 | + |
| 81 | + |
| 82 | +def test_unit_missing_proxy_helper_logs_once(monkeypatch, caplog): |
| 83 | + monkeypatch.setattr(transport, "get_environment_proxies", None) |
| 84 | + caplog.set_level("DEBUG", logger=transport.logger.name) |
| 85 | + with transport.create_http_client(): |
| 86 | + pass |
| 87 | + asyncio.run(transport.create_async_http_client().aclose()) |
| 88 | + messages = [record for record in caplog.records if "TCP keepalive is unavailable" in record.message] |
| 89 | + assert len(messages) == 1 |
| 90 | + assert messages[0].levelname == "DEBUG" |
| 91 | + |
| 92 | + |
53 | 93 | def test_unit_custom_values(monkeypatch): |
54 | 94 | for suffix, value in (("IDLE", "5"), ("INTERVAL", "6"), ("COUNT", "7")): |
55 | 95 | monkeypatch.setenv("UNSTRUCTURED_CLIENT_TCP_KEEPALIVE_" + suffix, value) |
@@ -81,15 +121,20 @@ def test_unit_supplied_clients_untouched(): |
81 | 121 | asyncio.run(asynchronous.aclose()) |
82 | 122 |
|
83 | 123 |
|
| 124 | +@pytest.mark.parametrize("missing_proxy_helper", [False, True]) |
84 | 125 | @pytest.mark.parametrize("asynchronous", [False, True]) |
85 | | -def test_unit_environment_proxy_routes(monkeypatch, asynchronous): |
| 126 | +def test_unit_environment_proxy_routes(monkeypatch, asynchronous, missing_proxy_helper): |
| 127 | + if missing_proxy_helper: |
| 128 | + monkeypatch.setattr(transport, "get_environment_proxies", None) |
86 | 129 | monkeypatch.setenv("HTTPS_PROXY", "http://127.0.0.1:8123") |
87 | 130 | monkeypatch.setenv("NO_PROXY", "excluded.example") |
88 | 131 | client = transport.create_async_http_client() if asynchronous else transport.create_http_client() |
89 | 132 | proxied = client._transport_for_url(httpx.URL("https://api.example")) |
90 | 133 | assert isinstance(proxied._pool, httpcore.AsyncHTTPProxy if asynchronous else httpcore.HTTPProxy) |
91 | 134 | assert proxied._pool._proxy_url.host == b"127.0.0.1" |
92 | | - assert proxied._pool._socket_options == transport.resolve_tcp_keepalive().socket_options() |
| 135 | + if missing_proxy_helper: |
| 136 | + assert client._transport._pool._socket_options is None |
| 137 | + assert proxied._pool._socket_options is None |
93 | 138 | assert client._transport_for_url(httpx.URL("https://excluded.example")) is client._transport |
94 | 139 | if asynchronous: |
95 | 140 | asyncio.run(client.aclose()) |
|
0 commit comments