Skip to content

Commit 26ff8ae

Browse files
authored
test: do not use deprecated and removed APIs of httpx (#47)
* test: do not use deprecated and removed APIs of `httpx` - `proxies` => `mounts` - `app` => `transport` * docs(CHANGELOG): update `CHANGELOG.md`
1 parent a45086a commit 26ff8ae

File tree

4 files changed

+48
-38
lines changed

4 files changed

+48
-38
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- `Fixed` for any bug fixes.
1717
- `Security` in case of vulnerabilities.
1818
- `[YANKED]` for deprecated releases.
19+
- `Internal` for internal changes. Only for maintainers.
1920

2021
<!-- Refer to: https://github.com/olivierlacan/keep-a-changelog/blob/main/CHANGELOG.md -->
2122
<!-- Refer to: https://github.com/gradio-app/gradio/blob/main/CHANGELOG.md -->
@@ -26,6 +27,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2627

2728
- [#30](https://github.com/WSH032/fastapi-proxy-lib/pull/30) - fix(internal): use `websocket` in favor of `websocket_route`. Thanks [@WSH032](https://github.com/WSH032)!
2829

30+
### Internal
31+
32+
- [#47](https://github.com/WSH032/fastapi-proxy-lib/pull/47) - test: do not use deprecated and removed APIs of httpx. Thanks [@WSH032](https://github.com/WSH032)!
33+
2934
## [0.1.0] - 2023-12-01
3035

3136
### Security

tests/test_core_lib.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from fastapi_proxy_lib.core.http import ReverseHttpProxy
1414
from fastapi_proxy_lib.fastapi.app import forward_http_app, reverse_http_app
1515
from fastapi_proxy_lib.fastapi.router import RouterHelper
16+
from httpx import ASGITransport
1617
from starlette.responses import JSONResponse
1718

1819
from .tool import DEFAULT_URL
@@ -70,7 +71,9 @@ async def _() -> JSONResponse:
7071
# }
7172
# }
7273

73-
client = httpx.AsyncClient(app=app, base_url="http://www.example.com")
74+
client = httpx.AsyncClient(
75+
transport=ASGITransport(app), base_url="http://www.example.com"
76+
)
7477
resp = await client.get("http://www.example.com/exception")
7578
assert resp.status_code == 0
7679
assert resp.json()["detail"] == test_err_msg

tests/test_http.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import httpx
55
import pytest
66
from fastapi_proxy_lib.core.tool import default_proxy_filter
7+
from httpx import ASGITransport
78
from typing_extensions import override
89

910
from .conftest import AppFactoryFixture, LifeAppDataclass4Test
@@ -32,7 +33,8 @@ async def tool_4_test_fixture( # pyright: ignore[reportIncompatibleMethodOverri
3233
) -> Tool4TestFixture:
3334
"""目标服务器请参考`tests.app.echo_http_app.get_app`."""
3435
client_for_conn_to_target_server = httpx.AsyncClient(
35-
app=echo_http_test_model.app, base_url=DEFAULT_TARGET_SERVER_BASE_URL
36+
transport=ASGITransport(echo_http_test_model.app),
37+
base_url=DEFAULT_TARGET_SERVER_BASE_URL,
3638
)
3739

3840
reverse_http_app = await reverse_http_app_fct(
@@ -41,7 +43,8 @@ async def tool_4_test_fixture( # pyright: ignore[reportIncompatibleMethodOverri
4143
)
4244

4345
client_for_conn_to_proxy_server = httpx.AsyncClient(
44-
app=reverse_http_app, base_url=DEFAULT_PROXY_SERVER_BASE_URL
46+
transport=ASGITransport(reverse_http_app),
47+
base_url=DEFAULT_PROXY_SERVER_BASE_URL,
4548
)
4649

4750
get_request = echo_http_test_model.get_request
@@ -198,7 +201,8 @@ async def test_bad_url_request(
198201
)
199202

200203
client_for_conn_to_proxy_server = httpx.AsyncClient(
201-
app=reverse_http_app, base_url=DEFAULT_PROXY_SERVER_BASE_URL
204+
transport=ASGITransport(reverse_http_app),
205+
base_url=DEFAULT_PROXY_SERVER_BASE_URL,
202206
)
203207

204208
r = await client_for_conn_to_proxy_server.get(DEFAULT_PROXY_SERVER_BASE_URL)
@@ -252,15 +256,17 @@ async def tool_4_test_fixture( # pyright: ignore[reportIncompatibleMethodOverri
252256
) -> Tool4TestFixture:
253257
"""目标服务器请参考`tests.app.echo_http_app.get_app`."""
254258
client_for_conn_to_target_server = httpx.AsyncClient(
255-
app=echo_http_test_model.app, base_url=DEFAULT_TARGET_SERVER_BASE_URL
259+
transport=ASGITransport(echo_http_test_model.app),
260+
base_url=DEFAULT_TARGET_SERVER_BASE_URL,
256261
)
257262

258263
forward_http_app = await forward_http_app_fct(
259264
client=client_for_conn_to_target_server, proxy_filter=default_proxy_filter
260265
)
261266

262267
client_for_conn_to_proxy_server = httpx.AsyncClient(
263-
app=forward_http_app, base_url=DEFAULT_PROXY_SERVER_BASE_URL
268+
transport=ASGITransport(forward_http_app),
269+
base_url=DEFAULT_PROXY_SERVER_BASE_URL,
264270
)
265271

266272
get_request = echo_http_test_model.get_request
@@ -310,7 +316,8 @@ async def test_bad_url_request(
310316
)
311317

312318
client_for_conn_to_proxy_server = httpx.AsyncClient(
313-
app=forward_http_app, base_url=DEFAULT_PROXY_SERVER_BASE_URL
319+
transport=ASGITransport(forward_http_app),
320+
base_url=DEFAULT_PROXY_SERVER_BASE_URL,
314321
)
315322

316323
# 错误的无法发出请求的URL
@@ -356,7 +363,8 @@ async def connect_error_mock_handler(
356363
)
357364

358365
client_for_conn_to_proxy_server = httpx.AsyncClient(
359-
app=forward_http_app, base_url=DEFAULT_PROXY_SERVER_BASE_URL
366+
transport=ASGITransport(forward_http_app),
367+
base_url=DEFAULT_PROXY_SERVER_BASE_URL,
360368
)
361369

362370
r = await client_for_conn_to_proxy_server.get(

tests/test_ws.py

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import pytest
1212
import uvicorn
1313
from fastapi_proxy_lib.fastapi.app import reverse_ws_app as get_reverse_ws_app
14-
from httpx_ws import aconnect_ws
14+
from httpx_ws import AsyncWebSocketSession, aconnect_ws
1515
from starlette import websockets as starlette_websockets_module
1616
from typing_extensions import override
1717

@@ -33,7 +33,7 @@
3333
# # https://github.com/encode/uvicorn/discussions/2105
3434
WS_BACKENDS_NEED_BE_TESTED = ("websockets",)
3535

36-
# https://www.python-httpx.org/advanced/#http-proxying
36+
# https://www.python-httpx.org/advanced/transports/#no-proxy-support
3737
NO_PROXIES: Dict[Any, Any] = {"all://": None}
3838

3939

@@ -81,18 +81,20 @@ def _subprocess_run_httpx_ws(
8181
kwargs_async_client = kwargs_async_client or {}
8282
kwargs_aconnect_ws = kwargs_aconnect_ws or {}
8383

84-
kwargs_async_client.pop("proxies", None)
84+
kwargs_async_client.pop("mounts", None)
8585
kwargs_aconnect_ws.pop("client", None)
8686

8787
async def run():
8888
_exit_stack = AsyncExitStack()
89-
_temp_client = httpx.AsyncClient(proxies=NO_PROXIES, **kwargs_async_client)
90-
_ = await _exit_stack.enter_async_context(
91-
aconnect_ws(
89+
_temp_client = httpx.AsyncClient(mounts=NO_PROXIES, **kwargs_async_client)
90+
# it's `httpx-ws` typing issue, so ignore it
91+
_ws_session: AsyncWebSocketSession = (
92+
aconnect_ws( # pyright: ignore[reportAssignmentType]
9293
client=_temp_client,
9394
**kwargs_aconnect_ws,
9495
)
9596
)
97+
_ = await _exit_stack.enter_async_context(_ws_session)
9698
queue.put("done")
9799
queue.close()
98100
while True: # run forever
@@ -125,7 +127,7 @@ async def tool_4_test_fixture( # pyright: ignore[reportIncompatibleMethodOverri
125127

126128
target_server_base_url = str(target_ws_server.contx_socket_url)
127129

128-
client_for_conn_to_target_server = httpx.AsyncClient(proxies=NO_PROXIES)
130+
client_for_conn_to_target_server = httpx.AsyncClient(mounts=NO_PROXIES)
129131

130132
reverse_ws_app = get_reverse_ws_app(
131133
client=client_for_conn_to_target_server, base_url=target_server_base_url
@@ -140,7 +142,7 @@ async def tool_4_test_fixture( # pyright: ignore[reportIncompatibleMethodOverri
140142

141143
proxy_server_base_url = str(proxy_ws_server.contx_socket_url)
142144

143-
client_for_conn_to_proxy_server = httpx.AsyncClient(proxies=NO_PROXIES)
145+
client_for_conn_to_proxy_server = httpx.AsyncClient(mounts=NO_PROXIES)
144146

145147
return Tool4TestFixture(
146148
client_for_conn_to_target_server=client_for_conn_to_target_server,
@@ -210,7 +212,7 @@ async def test_ws_proxy(self, tool_4_test_fixture: Tool4TestFixture) -> None:
210212

211213
aconnect_ws_subprocess_queue: "Queue[str]" = Queue()
212214

213-
kwargs_async_client = {"proxies": NO_PROXIES}
215+
kwargs_async_client = {"mounts": NO_PROXIES}
214216
kwargs_aconnect_ws = {"url": proxy_server_base_url + "do_nothing"}
215217
kwargs = {
216218
"kwargs_async_client": kwargs_async_client,
@@ -270,7 +272,7 @@ async def test_target_server_shutdown_abnormally(
270272
await asyncio.sleep(0.1)
271273
target_server_base_url = subprocess_queue.get()
272274

273-
client_for_conn_to_target_server = httpx.AsyncClient(proxies=NO_PROXIES)
275+
client_for_conn_to_target_server = httpx.AsyncClient(mounts=NO_PROXIES)
274276

275277
reverse_ws_app = get_reverse_ws_app(
276278
client=client_for_conn_to_target_server, base_url=target_server_base_url
@@ -285,31 +287,23 @@ async def test_target_server_shutdown_abnormally(
285287

286288
async with aconnect_ws(
287289
proxy_server_base_url + "do_nothing",
288-
httpx.AsyncClient(proxies=NO_PROXIES),
289-
) as ws0, aconnect_ws(
290-
proxy_server_base_url + "do_nothing",
291-
httpx.AsyncClient(proxies=NO_PROXIES),
292-
) as ws1:
290+
httpx.AsyncClient(mounts=NO_PROXIES),
291+
) as ws:
292+
loop = asyncio.get_running_loop()
293+
293294
# force shutdown target server
294295
target_ws_server_subprocess.terminate()
295296
target_ws_server_subprocess.kill()
296-
# https://pytest-cov.readthedocs.io/en/latest/subprocess-support.html#if-you-use-multiprocessing-process
297-
target_ws_server_subprocess.join() # dont forget this, pytest-cov requires this
298297

299-
with pytest.raises(httpx_ws.WebSocketDisconnect) as exce:
300-
await ws0.receive()
301-
assert exce.value.code == 1011
302-
303-
loop = asyncio.get_running_loop()
298+
start = loop.time()
304299

305-
seconde_ws_recv_start = loop.time()
306300
with pytest.raises(httpx_ws.WebSocketDisconnect) as exce:
307-
await ws1.receive()
301+
await ws.receive()
308302
assert exce.value.code == 1011
309-
seconde_ws_recv_end = loop.time()
310303

311-
# HACK: 由于收到关闭代码需要40s,目前无法确定是什么原因,
312-
# 所以目前会同时测试两个客户端的连接,
313-
# 只要第二个客户端不是在之前40s基础上又重复40s,就暂时没问题,
314-
# 因为这模拟了多个客户端进行连接的情况。
315-
assert (seconde_ws_recv_end - seconde_ws_recv_start) < 2
304+
end = loop.time()
305+
# we require the proxy server to send 1011 in 60s
306+
assert end - start < 60
307+
308+
# https://pytest-cov.readthedocs.io/en/latest/subprocess-support.html#if-you-use-multiprocessing-process
309+
target_ws_server_subprocess.join() # dont forget this, pytest-cov requires this

0 commit comments

Comments
 (0)