diff --git a/requirements/dev.txt b/requirements/dev.txt index 3f8a5a398a6..b4a55fb9a52 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -12,6 +12,8 @@ aiosignal==1.1.2 # via -r requirements/base.txt alabaster==0.7.12 # via sphinx +apipkg==1.5 + # via execnet appdirs==1.4.4 # via # black @@ -66,6 +68,8 @@ distlib==0.3.1 # via virtualenv docutils==0.16 # via sphinx +execnet==1.7.1 + # via pytest-xdist filelock==3.0.12 # via virtualenv flake8-pyi==20.10.0 @@ -137,7 +141,9 @@ pluggy==0.13.1 pre-commit==2.9.3 # via -r requirements/lint.txt py==1.10.0 - # via pytest + # via + # pytest + # pytest-forked pycares==3.1.1 # via aiodns pycodestyle==2.6.0 @@ -158,13 +164,19 @@ pyparsing==2.4.7 # via packaging pytest-cov==2.10.1 # via -r requirements/test.txt +pytest-forked==1.3.0 + # via pytest-xdist pytest-mock==3.5.1 # via -r requirements/test.txt +pytest-xdist==2.2.0 ; python_version >= "3.8" or sys_platform == "win32" + # via -r requirements/test.txt pytest==6.1.2 # via # -r requirements/test.txt # pytest-cov + # pytest-forked # pytest-mock + # pytest-xdist python-dateutil==2.8.1 # via freezegun pytz==2020.5 diff --git a/requirements/test.txt b/requirements/test.txt index 858de22b155..f5257be02cb 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -9,6 +9,7 @@ mypy-extensions==0.4.3; implementation_name=="cpython" pytest==6.2.1 pytest-cov==2.11.1 pytest-mock==3.5.1 +pytest-xdist==2.2.0; python_version>="3.8" or sys_platform == "win32" re-assert==1.1.0 setuptools-git==1.2 trustme==0.6.0; platform_machine!="i686" # no 32-bit wheels diff --git a/setup.cfg b/setup.cfg index 971cee3e3ef..aeef2a71aa8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -36,6 +36,11 @@ omit = site-packages [tool:pytest] addopts = + # `pytest-xdist`: + #--numprocesses=auto + # ^ this is being added dynamically by tests._pytest_plugin instead + # Ref: https://github.com/pytest-dev/pytest-xdist/issues/620 + # show 10 slowest invocations: --durations=10 @@ -50,6 +55,9 @@ addopts = # `pytest-cov`: --cov=aiohttp + + # pre-load an in-tree plugin + -p tests._pytest_plugin filterwarnings = error ignore:module 'ssl' has no attribute 'OP_NO_COMPRESSION'. The Python interpreter is compiled against OpenSSL < 1.0.0. Ref. https.//docs.python.org/3/library/ssl.html#ssl.OP_NO_COMPRESSION:UserWarning diff --git a/tests/_pytest_plugin.py b/tests/_pytest_plugin.py new file mode 100644 index 00000000000..5ef2576c4c5 --- /dev/null +++ b/tests/_pytest_plugin.py @@ -0,0 +1,37 @@ +"""An early plugin enabling pytest-xdist in supported envs.""" + +from contextlib import suppress +from sys import platform +from typing import TYPE_CHECKING, List + +try: + from asyncio import ThreadedChildWatcher +except ImportError: + SUPPORTS_XDIST = platform == "win32" +else: + SUPPORTS_XDIST = True + del ThreadedChildWatcher + + +if TYPE_CHECKING: + from _pytest.config import Config + from _pytest.config.argparsing import Parser + + +def pytest_load_initial_conftests( + early_config: "Config", + parser: "Parser", + args: List[str], +) -> None: + """Auto-enable pytest-xdist when supported and not disabled.""" + if not SUPPORTS_XDIST: + return + + with suppress(ValueError): + p_pos = args.index("no:xdist") - 1 + if p_pos >= 0: + # NOTE: allow disabling xdist with `-p no:xdist` + return + + xdist_args = "-n", "auto" + args[:0] = xdist_args # Prepend to allow user-supplied overrides diff --git a/tests/test_loop.py b/tests/test_loop.py index 3211b756702..af19f9567c2 100644 --- a/tests/test_loop.py +++ b/tests/test_loop.py @@ -7,13 +7,14 @@ from aiohttp import web from aiohttp.test_utils import AioHTTPTestCase, unittest_run_loop +from tests._pytest_plugin import SUPPORTS_XDIST # type: ignore[import] @pytest.mark.skipif( platform.system() == "Windows", reason="the test is not valid for Windows" ) async def test_subprocess_co(loop: Any) -> None: - assert threading.current_thread() is threading.main_thread() + assert threading.current_thread() is threading.main_thread() or SUPPORTS_XDIST proc = await asyncio.create_subprocess_shell( "exit 0", stdin=asyncio.subprocess.DEVNULL,