From 6b3425ce88ac9a56c38e8c141d248f704ef9c936 Mon Sep 17 00:00:00 2001 From: Jonas Lundberg Date: Wed, 7 Jul 2021 11:38:49 +0200 Subject: [PATCH] Fix xfail marked tests (#153) * Fix xfail marked tests * Move remote test to separate test module --- tests/test_api.py | 30 ------------- tests/test_mock.py | 103 +++++++++++++++++++++++-------------------- tests/test_remote.py | 43 ++++++++++++++++++ 3 files changed, 97 insertions(+), 79 deletions(-) create mode 100644 tests/test_remote.py diff --git a/tests/test_api.py b/tests/test_api.py index c3859b0..3bae9bb 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -1,6 +1,5 @@ import asyncio import json as jsonlib -import os import re import socket from unittest import mock @@ -408,35 +407,6 @@ async def test_pass_through(client, using, route, expected): assert request.is_pass_through is expected -@pytest.mark.skipif( - os.environ.get("PASS_THROUGH") is None, reason="External pass-through disabled" -) -@pytest.mark.asyncio -@pytest.mark.parametrize("using", ["httpcore", "httpx"]) -async def test_external_pass_through(client, using): # pragma: nocover - with respx.mock(using=using) as respx_mock: - # Mock pass-through call - url = "https://httpbin.org/post" - route = respx_mock.post(url, json__foo="bar").pass_through() - - # Make external pass-through call - assert route.call_count == 0 - response = await client.post(url, json={"foo": "bar"}) - - assert response.content is not None - assert len(response.content) > 0 - assert "Content-Length" in response.headers - assert int(response.headers["Content-Length"]) > 0 - assert response.json()["json"] == {"foo": "bar"} - - assert respx_mock.calls.last.request.url == url - assert respx_mock.calls.last.response is None - - # TODO: Routed and recorded twice; AsyncConnectionPool + AsyncHTTPConnection - assert route.call_count == (2 if using == "httpcore" else 1) - assert respx_mock.calls.call_count == (2 if using == "httpcore" else 1) - - @respx.mock @pytest.mark.asyncio async def test_parallel_requests(client): diff --git a/tests/test_mock.py b/tests/test_mock.py index 8287f1b..324f199 100644 --- a/tests/test_mock.py +++ b/tests/test_mock.py @@ -1,4 +1,4 @@ -from contextlib import ExitStack as does_not_raise +from contextlib import ExitStack as does_not_raise, contextmanager import httpcore import httpx @@ -458,40 +458,44 @@ async def test_assert_all_mocked(client, assert_all_mocked, raises): assert respx_mock.calls.call_count == 0 -@pytest.mark.xfail(strict=False) @pytest.mark.asyncio -async def test_asgi(): # pragma: nocover - from respx.mocks import HTTPCoreMocker +async def test_asgi(): + @contextmanager + def mock_targets(): + from respx.mocks import HTTPCoreMocker + + try: + HTTPCoreMocker.add_targets( + "httpx._transports.asgi.ASGITransport", + "httpx._transports.wsgi.WSGITransport", + ) + with respx.mock(using="httpcore") as respx_mock: + yield respx_mock + finally: + HTTPCoreMocker.remove_targets( + "httpx._transports.asgi.ASGITransport", + "httpx._transports.wsgi.WSGITransport", + ) - try: - HTTPCoreMocker.add_targets( - "httpx._transports.asgi.ASGITransport", - "httpx._transports.wsgi.WSGITransport", - ) - async with respx.mock: - async with httpx.AsyncClient(app="fake-asgi") as client: - url = "https://foo.bar/" - jzon = {"status": "ok"} - headers = {"X-Foo": "bar"} - request = respx.get(url) % dict( - status_code=202, headers=headers, json=jzon - ) - response = await client.get(url) - assert request.called is True - assert response.status_code == 202 - assert response.headers == httpx.Headers( - { - "Content-Type": "application/json", - "Content-Length": "16", - **headers, - } - ) - assert response.json() == {"status": "ok"} - finally: - HTTPCoreMocker.remove_targets( - "httpx._transports.asgi.ASGITransport", - "httpx._transports.wsgi.WSGITransport", - ) + with mock_targets() as respx_mock: + async with httpx.AsyncClient(app="fake-asgi") as client: + url = "https://foo.bar/" + jzon = {"status": "ok"} + headers = {"X-Foo": "bar"} + request = respx_mock.get(url) % dict( + status_code=202, headers=headers, json=jzon + ) + response = await client.get(url) + assert request.called is True + assert response.status_code == 202 + assert response.headers == httpx.Headers( + { + "Content-Type": "application/json", + "Content-Length": "16", + **headers, + } + ) + assert response.json() == {"status": "ok"} def test_add_remove_targets(): @@ -503,20 +507,21 @@ def test_add_remove_targets(): assert HTTPCoreMocker.targets.count(target) == 1 pre_add_count = len(HTTPCoreMocker.targets) - HTTPCoreMocker.add_targets( - "httpx._transports.asgi.ASGITransport", - "httpx._transports.wsgi.WSGITransport", - ) - assert len(HTTPCoreMocker.targets) == pre_add_count + 2 - - HTTPCoreMocker.remove_targets("foobar") - assert len(HTTPCoreMocker.targets) == pre_add_count + 2 + try: + HTTPCoreMocker.add_targets( + "httpx._transports.asgi.ASGITransport", + "httpx._transports.wsgi.WSGITransport", + ) + assert len(HTTPCoreMocker.targets) == pre_add_count + 2 - HTTPCoreMocker.remove_targets( - "httpx._transports.asgi.ASGITransport", - "httpx._transports.wsgi.WSGITransport", - ) - assert len(HTTPCoreMocker.targets) == pre_add_count + HTTPCoreMocker.remove_targets("foobar") + assert len(HTTPCoreMocker.targets) == pre_add_count + 2 + finally: + HTTPCoreMocker.remove_targets( + "httpx._transports.asgi.ASGITransport", + "httpx._transports.wsgi.WSGITransport", + ) + assert len(HTTPCoreMocker.targets) == pre_add_count @pytest.mark.asyncio @@ -536,11 +541,11 @@ async def test_proxies(): assert response.json() == {"foo": "bar"} -@pytest.mark.xfail(strict=True) @pytest.mark.asyncio -async def test_uds(): # pragma: nocover +async def test_uds(): async with respx.mock: - async with httpx.AsyncClient(uds="/foo/bar.sock") as client: + uds = httpx.AsyncHTTPTransport(uds="/tmp/foobar.sock") + async with httpx.AsyncClient(transport=uds) as client: request = respx.get("https://foo.bar/") % 202 response = await client.get("https://foo.bar/") assert request.called is True diff --git a/tests/test_remote.py b/tests/test_remote.py new file mode 100644 index 0000000..0bdfa6e --- /dev/null +++ b/tests/test_remote.py @@ -0,0 +1,43 @@ +import os + +import pytest + +import respx + +pytestmark = pytest.mark.skipif( + os.environ.get("PASS_THROUGH") is None, reason="Remote pass-through disabled" +) + + +@pytest.mark.parametrize( + "using,client_lib,call_count", + [ + ("httpcore", "httpx", 2), # TODO: AsyncConnectionPool + AsyncHTTPConnection + ("httpx", "httpx", 1), + ], +) +def test_remote_pass_through(using, client_lib, call_count): # pragma: nocover + with respx.mock(using=using) as respx_mock: + # Mock pass-through calls + url = "https://httpbin.org/post" + route = respx_mock.post(url, json__foo="bar").pass_through() + + # Make external pass-through call + client = __import__(client_lib) + response = client.post(url, json={"foo": "bar"}) + + # Assert response is correct library model + assert isinstance(response, client.Response) + + assert response.status_code == 200 + assert response.content is not None + assert len(response.content) > 0 + assert "Content-Length" in response.headers + assert int(response.headers["Content-Length"]) > 0 + assert response.json()["json"] == {"foo": "bar"} + + assert respx_mock.calls.last.request.url == url + assert respx_mock.calls.last.response is None + + assert route.call_count == call_count + assert respx_mock.calls.call_count == call_count