Drop dependency on the abandoned python-lazy-fixture II.

This commit is contained in:
Jakub Roztocil 2024-03-04 18:05:26 +01:00
parent 3524ccf0ba
commit db16bbee96
5 changed files with 80 additions and 172 deletions

View File

@ -2,6 +2,7 @@ import socket
import pytest import pytest
from pytest_httpbin import certs from pytest_httpbin import certs
from pytest_httpbin.serve import Server as PyTestHttpBinServer
from .utils import ( # noqa from .utils import ( # noqa
HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN, HTTPBIN_WITH_CHUNKED_SUPPORT_DOMAIN,
@ -19,8 +20,10 @@ from .utils.plugins_cli import ( # noqa
interface, interface,
) )
from .utils.http_server import http_server, localhost_http_server # noqa from .utils.http_server import http_server, localhost_http_server # noqa
# noinspection PyUnresolvedReferences
from .fixtures import pytest_lazy_fixture
# Patch to support `url = str(server)` in addition to `url = server + '/foo'`.
PyTestHttpBinServer.__str__ = lambda self: self.url
@pytest.fixture(scope='function', autouse=True) @pytest.fixture(scope='function', autouse=True)
@ -72,8 +75,15 @@ def _remote_httpbin_available():
@pytest.fixture @pytest.fixture
def remote_httpbin(_remote_httpbin_available): def remote_httpbin(_remote_httpbin_available):
if _remote_httpbin_available: if _remote_httpbin_available:
return 'http://' + REMOTE_HTTPBIN_DOMAIN class Server(str):
"""Look like `pytest_httpbin.serve.Server` but only provide URL info."""
@property
def url(self):
return self
return Server('http://' + REMOTE_HTTPBIN_DOMAIN)
pytest.skip(f'{REMOTE_HTTPBIN_DOMAIN} not resolvable') pytest.skip(f'{REMOTE_HTTPBIN_DOMAIN} not resolvable')

View File

@ -1,99 +0,0 @@
"""
Replacement for the abandoned `pytest.lazy_fixture` <https://github.com/TvoroG/pytest-lazy-fixture>
Based on <https://github.com/TvoroG/pytest-lazy-fixture/issues/65#issuecomment-1914581161>
"""
import dataclasses
import typing
import pytest
@dataclasses.dataclass
class LazyFixture:
"""Lazy fixture dataclass."""
name: str
def lazy_fixture(name: str) -> LazyFixture:
"""Mark a fixture as lazy."""
return LazyFixture(name)
# NOTE: Mimic the original API
pytest.lazy_fixture = lazy_fixture
def is_lazy_fixture(value: object) -> bool:
"""Check whether a value is a lazy fixture."""
return isinstance(value, LazyFixture)
def pytest_make_parametrize_id(
config: pytest.Config,
val: object,
argname: str,
) -> str | None:
"""Inject lazy fixture parametrized id.
Reference:
- https://bit.ly/48Off6r
Args:
config (pytest.Config): pytest configuration.
value (object): fixture value.
argname (str): automatic parameter name.
Returns:
str: new parameter id.
"""
if is_lazy_fixture(val):
return typing.cast(LazyFixture, val).name
return None
@pytest.hookimpl(tryfirst=True)
def pytest_fixture_setup(
fixturedef: pytest.FixtureDef,
request: pytest.FixtureRequest,
) -> object | None:
"""Lazy fixture setup hook.
This hook will never take over a fixture setup but just simply will
try to resolve recursively any lazy fixture found in request.param.
Reference:
- https://bit.ly/3SyvsXJ
Args:
fixturedef (pytest.FixtureDef): fixture definition object.
request (pytest.FixtureRequest): fixture request object.
Returns:
object | None: fixture value or None otherwise.
"""
if hasattr(request, "param") and request.param:
request.param = _resolve_lazy_fixture(request.param, request)
return None
def _resolve_lazy_fixture(__val: object, request: pytest.FixtureRequest) -> object:
"""Lazy fixture resolver.
Args:
__val (object): fixture value object.
request (pytest.FixtureRequest): pytest fixture request object.
Returns:
object: resolved fixture value.
"""
if isinstance(__val, list | tuple):
return tuple(_resolve_lazy_fixture(v, request) for v in __val)
if isinstance(__val, typing.Mapping):
return {k: _resolve_lazy_fixture(v, request) for k, v in __val.items()}
if not is_lazy_fixture(__val):
return __val
lazy_obj = typing.cast(LazyFixture, __val)
return request.getfixturevalue(lazy_obj.name)

View File

@ -2,54 +2,47 @@ import pytest
from .utils import http from .utils import http
def _stringify(fixture): @pytest.mark.parametrize('target_httpbin', [
return fixture + '' 'httpbin',
'remote_httpbin',
@pytest.mark.parametrize('instance', [
pytest.lazy_fixture('httpbin'),
pytest.lazy_fixture('remote_httpbin'),
]) ])
def test_explicit_user_set_cookie(httpbin, instance): def test_explicit_user_set_cookie(httpbin, target_httpbin, request):
# User set cookies ARE NOT persisted within redirects """User set cookies ARE NOT persisted within redirects when there is no session, even on the same domain."""
# when there is no session, even on the same domain. target_httpbin = request.getfixturevalue(target_httpbin)
r = http( r = http(
'--follow', '--follow',
httpbin + '/redirect-to', httpbin + '/redirect-to',
f'url=={_stringify(instance)}/cookies', f'url=={target_httpbin.url}/cookies',
'Cookie:a=b' 'Cookie:a=b'
) )
assert r.json == {'cookies': {}} assert r.json == {'cookies': {}}
@pytest.mark.parametrize('instance', [ @pytest.mark.parametrize('target_httpbin', [
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
]) ])
def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, instance): def test_explicit_user_set_cookie_in_session(tmp_path, httpbin, target_httpbin, request):
# User set cookies ARE persisted within redirects """User set cookies ARE persisted within redirects when there is A session, even on the same domain."""
# when there is A session, even on the same domain. target_httpbin = request.getfixturevalue(target_httpbin)
r = http( r = http(
'--follow', '--follow',
'--session', '--session',
str(tmp_path / 'session.json'), str(tmp_path / 'session.json'),
httpbin + '/redirect-to', httpbin + '/redirect-to',
f'url=={_stringify(instance)}/cookies', f'url=={target_httpbin}/cookies',
'Cookie:a=b' 'Cookie:a=b'
) )
assert r.json == {'cookies': {'a': 'b'}} assert r.json == {'cookies': {'a': 'b'}}
@pytest.mark.parametrize('instance', [ @pytest.mark.parametrize('target_httpbin', [
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
]) ])
def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance): def test_saved_user_set_cookie_in_session(tmp_path, httpbin, target_httpbin, request):
# User set cookies ARE persisted within redirects """User set cookies ARE persisted within redirects when there is A session, even on the same domain."""
# when there is A session, even on the same domain. target_httpbin = request.getfixturevalue(target_httpbin)
http( http(
'--follow', '--follow',
'--session', '--session',
@ -62,32 +55,33 @@ def test_saved_user_set_cookie_in_session(tmp_path, httpbin, instance):
'--session', '--session',
str(tmp_path / 'session.json'), str(tmp_path / 'session.json'),
httpbin + '/redirect-to', httpbin + '/redirect-to',
f'url=={_stringify(instance)}/cookies', f'url=={target_httpbin}/cookies',
) )
assert r.json == {'cookies': {'a': 'b'}} assert r.json == {'cookies': {'a': 'b'}}
@pytest.mark.parametrize('instance', [ @pytest.mark.parametrize('target_httpbin', [
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
]) ])
@pytest.mark.parametrize('session', [True, False]) @pytest.mark.parametrize('session', [True, False])
def test_explicit_user_set_headers(httpbin, tmp_path, instance, session): def test_explicit_user_set_headers(httpbin, tmp_path, target_httpbin, session, request):
# User set headers ARE persisted within redirects """
# even on different domains domain with or without User set headers ARE persisted within redirects even on different domains domain with or without an active session.
# an active session.
"""
target_httpbin = request.getfixturevalue(target_httpbin)
session_args = [] session_args = []
if session: if session:
session_args.extend([ session_args.extend([
'--session', '--session',
str(tmp_path / 'session.json') str(tmp_path / 'session.json')
]) ])
r = http( r = http(
'--follow', '--follow',
*session_args, *session_args,
httpbin + '/redirect-to', httpbin + '/redirect-to',
f'url=={_stringify(instance)}/get', f'url=={target_httpbin}/get',
'X-Custom-Header:value' 'X-Custom-Header:value'
) )
assert 'X-Custom-Header' in r.json['headers'] assert 'X-Custom-Header' in r.json['headers']
@ -95,16 +89,13 @@ def test_explicit_user_set_headers(httpbin, tmp_path, instance, session):
@pytest.mark.parametrize('session', [True, False]) @pytest.mark.parametrize('session', [True, False])
def test_server_set_cookie_on_redirect_same_domain(tmp_path, httpbin, session): def test_server_set_cookie_on_redirect_same_domain(tmp_path, httpbin, session):
# Server set cookies ARE persisted on the same domain """Server set cookies ARE persisted on the same domain when they are forwarded."""
# when they are forwarded.
session_args = [] session_args = []
if session: if session:
session_args.extend([ session_args.extend([
'--session', '--session',
str(tmp_path / 'session.json') str(tmp_path / 'session.json')
]) ])
r = http( r = http(
'--follow', '--follow',
*session_args, *session_args,
@ -136,8 +127,7 @@ def test_server_set_cookie_on_redirect_different_domain(tmp_path, http_server, h
def test_saved_session_cookies_on_same_domain(tmp_path, httpbin): def test_saved_session_cookies_on_same_domain(tmp_path, httpbin):
# Saved session cookies ARE persisted when making a new """Saved session cookies ARE persisted when making a new request to the same domain."""
# request to the same domain.
http( http(
'--session', '--session',
str(tmp_path / 'session.json'), str(tmp_path / 'session.json'),
@ -152,8 +142,7 @@ def test_saved_session_cookies_on_same_domain(tmp_path, httpbin):
def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_httpbin): def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_httpbin):
# Saved session cookies ARE persisted when making a new """Saved session cookies ARE persisted when making a new request to a different domain."""
# request to a different domain.
http( http(
'--session', '--session',
str(tmp_path / 'session.json'), str(tmp_path / 'session.json'),
@ -167,45 +156,49 @@ def test_saved_session_cookies_on_different_domain(tmp_path, httpbin, remote_htt
assert r.json == {'cookies': {}} assert r.json == {'cookies': {}}
@pytest.mark.parametrize('initial_domain, first_request_domain, second_request_domain, expect_cookies', [ @pytest.mark.parametrize(['initial_domain', 'first_request_domain', 'second_request_domain', 'expect_cookies'], [
( (
# Cookies are set by Domain A # Cookies are set by Domain A
# Initial domain is Domain A # Initial domain is Domain A
# Redirected domain is Domain A # Redirected domain is Domain A
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('httpbin'), 'httpbin',
True, True,
), ),
( (
# Cookies are set by Domain A # Cookies are set by Domain A
# Initial domain is Domain B # Initial domain is Domain B
# Redirected domain is Domain B # Redirected domain is Domain B
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
False, False,
), ),
( (
# Cookies are set by Domain A # Cookies are set by Domain A
# Initial domain is Domain A # Initial domain is Domain A
# Redirected domain is Domain B # Redirected domain is Domain B
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
False, False,
), ),
( (
# Cookies are set by Domain A # Cookies are set by Domain A
# Initial domain is Domain B # Initial domain is Domain B
# Redirected domain is Domain A # Redirected domain is Domain A
pytest.lazy_fixture('httpbin'), 'httpbin',
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
pytest.lazy_fixture('httpbin'), 'httpbin',
True, True,
), ),
]) ])
def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies): def test_saved_session_cookies_on_redirect(
tmp_path, initial_domain, first_request_domain, second_request_domain, expect_cookies, request):
initial_domain = request.getfixturevalue(initial_domain)
first_request_domain = request.getfixturevalue(first_request_domain)
second_request_domain = request.getfixturevalue(second_request_domain)
http( http(
'--session', '--session',
str(tmp_path / 'session.json'), str(tmp_path / 'session.json'),
@ -216,7 +209,7 @@ def test_saved_session_cookies_on_redirect(tmp_path, initial_domain, first_reque
str(tmp_path / 'session.json'), str(tmp_path / 'session.json'),
'--follow', '--follow',
first_request_domain + '/redirect-to', first_request_domain + '/redirect-to',
f'url=={_stringify(second_request_domain)}/cookies' f'url=={second_request_domain}/cookies'
) )
if expect_cookies: if expect_cookies:
expected_data = {'cookies': {'a': 'b'}} expected_data = {'cookies': {'a': 'b'}}

View File

@ -821,16 +821,17 @@ def test_session_multiple_headers_with_same_name(basic_session, httpbin):
'server, expected_cookies', 'server, expected_cookies',
[ [
( (
pytest.lazy_fixture('localhost_http_server'), 'localhost_http_server',
{'secure_cookie': 'foo', 'insecure_cookie': 'bar'} {'secure_cookie': 'foo', 'insecure_cookie': 'bar'}
), ),
( (
pytest.lazy_fixture('remote_httpbin'), 'remote_httpbin',
{'insecure_cookie': 'bar'} {'insecure_cookie': 'bar'}
) )
] ]
) )
def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies): def test_secure_cookies_on_localhost(mock_env, tmp_path, server, expected_cookies, request):
server = request.getfixturevalue(server)
session_path = tmp_path / 'session.json' session_path = tmp_path / 'session.json'
http( http(
'--session', str(session_path), '--session', str(session_path),

View File

@ -132,10 +132,10 @@ def test_check_updates_first_invocation(
@pytest.mark.parametrize( @pytest.mark.parametrize(
'should_issue_warning, build_channel', ['should_issue_warning', 'build_channel'],
[ [
(False, pytest.lazy_fixture('lower_build_channel')), (False, 'lower_build_channel'),
(True, pytest.lazy_fixture('higher_build_channel')), (True, 'higher_build_channel'),
], ],
) )
def test_check_updates_first_time_after_data_fetch( def test_check_updates_first_time_after_data_fetch(
@ -145,7 +145,9 @@ def test_check_updates_first_time_after_data_fetch(
static_fetch_data, static_fetch_data,
should_issue_warning, should_issue_warning,
build_channel, build_channel,
request,
): ):
request.getfixturevalue(build_channel)
http('fetch_updates', '--daemon', env=with_warnings) http('fetch_updates', '--daemon', env=with_warnings)
r = http(httpbin + '/get', env=with_warnings) r = http(httpbin + '/get', env=with_warnings)
@ -176,14 +178,15 @@ def test_cli_check_updates(
@pytest.mark.parametrize( @pytest.mark.parametrize(
"build_channel", [ 'build_channel', [
pytest.lazy_fixture("lower_build_channel"), 'lower_build_channel',
pytest.lazy_fixture("unknown_build_channel") 'unknown_build_channel',
] ]
) )
def test_cli_check_updates_not_shown( def test_cli_check_updates_not_shown(
static_fetch_data, build_channel static_fetch_data, build_channel, request
): ):
request.getfixturevalue(build_channel)
r = httpie('cli', 'check-updates') r = httpie('cli', 'check-updates')
assert r.exit_status == ExitStatus.SUCCESS assert r.exit_status == ExitStatus.SUCCESS
assert not check_update_warnings(r) assert not check_update_warnings(r)