From 8529c46f009008587501108a74029e6a72e6037b Mon Sep 17 00:00:00 2001 From: Hernan Ezequiel Di Giorgi Date: Sat, 18 Jul 2020 20:00:55 -0300 Subject: [PATCH] update tests - Use mockbin for redirections. - Mock synchronous requests too. --- ...questtest_httpx_test_test_behind_proxy.yml | 43 ------------------- ... => test_httpx_test_test_behind_proxy.yml} | 0 tests/integration/test_httpx.py | 23 +++++----- tox.ini | 11 ++--- vcr/patch.py | 7 ++- vcr/stubs/httpx_stubs.py | 19 ++++++++ 6 files changed, 40 insertions(+), 63 deletions(-) delete mode 100644 tests/integration/cassettes/DoSyncRequesttest_httpx_test_test_behind_proxy.yml rename tests/integration/cassettes/{DoAsyncRequesttest_httpx_test_test_behind_proxy.yml => test_httpx_test_test_behind_proxy.yml} (100%) diff --git a/tests/integration/cassettes/DoSyncRequesttest_httpx_test_test_behind_proxy.yml b/tests/integration/cassettes/DoSyncRequesttest_httpx_test_test_behind_proxy.yml deleted file mode 100644 index a9382c1..0000000 --- a/tests/integration/cassettes/DoSyncRequesttest_httpx_test_test_behind_proxy.yml +++ /dev/null @@ -1,43 +0,0 @@ -interactions: -- request: - body: null - headers: - accept: - - '*/*' - accept-encoding: - - gzip, deflate, br - connection: - - keep-alive - host: - - httpbin.org - user-agent: - - python-httpx/0.12.1 - method: GET - uri: https://localhost:8080/headers - response: - body: - string: "{\n \"headers\": {\n \"Accept\": \"*/*\", \n \"Accept-Encoding\"\ - : \"gzip, deflate, br\", \n \"Host\": \"httpbin.org\", \n \"User-Agent\"\ - : \"python-httpx/0.12.1\", \n \"X-Amzn-Trace-Id\": \"Root=1-5ea778ca-c402f3ae901e78b3435b0a0c\"\ - \n }\n}\n" - headers: - Access-Control-Allow-Credentials: - - 'true' - Access-Control-Allow-Origin: - - '*' - Connection: - - keep-alive - Content-Length: - - '226' - Content-Type: - - application/json - Date: - - Tue, 28 Apr 2020 00:28:58 GMT - Server: - - gunicorn/19.9.0 - Via: - - my_own_proxy - status: - code: 200 - message: OK -version: 1 diff --git a/tests/integration/cassettes/DoAsyncRequesttest_httpx_test_test_behind_proxy.yml b/tests/integration/cassettes/test_httpx_test_test_behind_proxy.yml similarity index 100% rename from tests/integration/cassettes/DoAsyncRequesttest_httpx_test_test_behind_proxy.yml rename to tests/integration/cassettes/test_httpx_test_test_behind_proxy.yml diff --git a/tests/integration/test_httpx.py b/tests/integration/test_httpx.py index 1d4eb9c..6e3d2fa 100644 --- a/tests/integration/test_httpx.py +++ b/tests/integration/test_httpx.py @@ -53,7 +53,7 @@ def yml(tmpdir, request): def test_status(tmpdir, scheme, do_request): - url = scheme + "://httpbin.org" + url = scheme + "://mockbin.org/request" with vcr.use_cassette(str(tmpdir.join("status.yaml"))): response = do_request()("GET", url) @@ -64,7 +64,7 @@ def test_status(tmpdir, scheme, do_request): def test_case_insensitive_headers(tmpdir, scheme, do_request): - url = scheme + "://httpbin.org" + url = scheme + "://mockbin.org/request" with vcr.use_cassette(str(tmpdir.join("whatever.yaml"))): do_request()("GET", url) @@ -120,7 +120,7 @@ def test_params_same_url_distinct_params(tmpdir, scheme, do_request): def test_redirect(tmpdir, do_request, yml): - url = "https://httpbin.org/redirect/2" + url = "https://mockbin.org/redirect/303/2" response = do_request()("GET", url) with vcr.use_cassette(yml): @@ -169,10 +169,7 @@ def test_simple_fetching(tmpdir, do_request, yml, url): def test_behind_proxy(do_request): # This is recorded because otherwise we should have a live proxy somewhere. yml = ( - os.path.dirname(os.path.realpath(__file__)) - + "/cassettes/" - + do_request.__name__ - + "test_httpx_test_test_behind_proxy.yml" + os.path.dirname(os.path.realpath(__file__)) + "/cassettes/" + "test_httpx_test_test_behind_proxy.yml" ) url = "https://httpbin.org/headers" proxy = "http://localhost:8080" @@ -225,16 +222,16 @@ def test_cookies(tmpdir, scheme, do_request): def test_relative_redirects(tmpdir, scheme, do_request): - url = scheme + "://httpbin.org" + url = scheme + "://mockbin.com/redirect/301?to=/redirect/301?to=/request" testfile = str(tmpdir.join("relative_redirects.yml")) with vcr.use_cassette(testfile): - response = do_request()("GET", url + "/redirect-to?url=/redirect-to?url=/get") - assert len(response.history) == 2 - assert response.json()["url"].endswith("get") + response = do_request()("GET", url) + assert len(response.history) == 2, response + assert response.json()["url"].endswith("request") with vcr.use_cassette(testfile) as cassette: - response = do_request()("GET", url + "/redirect-to?url=/redirect-to?url=/get") + response = do_request()("GET", url) assert len(response.history) == 2 - assert response.json()["url"].endswith("get") + assert response.json()["url"].endswith("request") assert cassette.play_count == 3 diff --git a/tox.ini b/tox.ini index def257e..f30a050 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,9 @@ skip_missing_interpreters=true envlist = cov-clean, lint, - {py35,py36,py37,py38}-{requests,httplib2,urllib3,tornado4,boto3,aiohttp,httpx}, - {pypy3}-{requests,httplib2,urllib3,tornado4,boto3,httpx}, + {py35,py36,py37,py38}-{requests,httplib2,urllib3,tornado4,boto3,aiohttp}, + {py36,py37,py38}-{httpx} + {pypy3}-{requests,httplib2,urllib3,tornado4,boto3}, cov-report @@ -79,10 +80,10 @@ deps = aiohttp: aiohttp aiohttp: pytest-asyncio aiohttp: pytest-aiohttp - httpx: httpx - httpx: pytest-asyncio + {py36,py37,py38}-{httpx}: httpx + {py36,py37,py38}-{httpx}: pytest-asyncio depends = - lint,{py35,py36,py37,py38,pypy3}-{requests,httplib2,urllib3,tornado4,boto3,httpx},{py35,py36,py37,py38}-{aiohttp}: cov-clean + lint,{py35,py36,py37,py38,pypy3}-{requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37,py38}-{aiohttp},{py36,py37,py38}-{httpx}: cov-clean cov-report: lint,{py35,py36,py37,py38,pypy3}-{requests,httplib2,urllib3,tornado4,boto3},{py35,py36,py37,py38}-{aiohttp} passenv = AWS_ACCESS_KEY_ID diff --git a/vcr/patch.py b/vcr/patch.py index db61ba6..a3683fb 100644 --- a/vcr/patch.py +++ b/vcr/patch.py @@ -99,7 +99,7 @@ try: except ImportError: # pragma: no cover pass else: - _HttpxClient_send = httpx.Client.send + _HttpxSyncClient_send = httpx.Client.send _HttpxAsyncClient_send = httpx.AsyncClient.send @@ -330,11 +330,14 @@ class CassettePatcherBuilder: except ImportError: # pragma: no cover return else: - from .stubs.httpx_stubs import async_vcr_send + from .stubs.httpx_stubs import async_vcr_send, sync_vcr_send new_async_client_send = async_vcr_send(self._cassette, _HttpxAsyncClient_send) yield httpx.AsyncClient, "send", new_async_client_send + new_sync_client_send = sync_vcr_send(self._cassette, _HttpxSyncClient_send) + yield httpx.Client, "send", new_sync_client_send + def _urllib3_patchers(self, cpool, stubs): http_connection_remover = ConnectionRemover( self._get_cassette_subclass(stubs.VCRRequestsHTTPConnection) diff --git a/vcr/stubs/httpx_stubs.py b/vcr/stubs/httpx_stubs.py index f2b99fd..c809389 100644 --- a/vcr/stubs/httpx_stubs.py +++ b/vcr/stubs/httpx_stubs.py @@ -136,3 +136,22 @@ def async_vcr_send(cassette, real_send): return _async_vcr_send(cassette, real_send, *args, **kwargs) return _inner_send + + +def _sync_vcr_send(cassette, real_send, *args, **kwargs): + vcr_request, response = _shared_vcr_send(cassette, real_send, *args, **kwargs) + if response: + # add cookies from response to session cookie store + args[0].cookies.extract_cookies(response) + return response + + real_response = real_send(*args, **kwargs) + return _record_responses(cassette, vcr_request, real_response) + + +def sync_vcr_send(cassette, real_send): + @functools.wraps(real_send) + def _inner_send(*args, **kwargs): + return _sync_vcr_send(cassette, real_send, *args, **kwargs) + + return _inner_send