diff --git a/.circleci/continue-config.yml b/.circleci/continue-config.yml index c13366ea..e3f13632 100644 --- a/.circleci/continue-config.yml +++ b/.circleci/continue-config.yml @@ -38,7 +38,7 @@ jobs: name: Run tests command: | mkdir -p test-results - uv run pytest tests/ -v --junitxml=test-results/results.xml + uv run pytest tests/ -v -n auto --junitxml=test-results/results.xml - store_test_results: path: test-results noop-job: diff --git a/pyproject.toml b/pyproject.toml index 559569fc..8ec956b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -57,6 +57,8 @@ dev = [ "pre-commit", "pytest-repeat>=0.9.4", "taskipy", + "pytest-forked>=1.6.0", + "pytest-xdist>=3.8.0", ] examples = [ diff --git a/tests/v2/backends/simp_driver/test_http.py b/tests/v2/backends/simp_driver/test_http.py index 1ec6ef7c..de5fe8f8 100644 --- a/tests/v2/backends/simp_driver/test_http.py +++ b/tests/v2/backends/simp_driver/test_http.py @@ -15,6 +15,7 @@ """Tests for simp_driver/http.py (SimpHttpDriver).""" import multiprocessing +import os import time import pytest @@ -23,6 +24,14 @@ from mplang.v2.dialects import simp from mplang.v2.edsl.context import pop_context, push_context +# Skip when running with pytest-xdist (parallel workers) +# These tests use multiprocessing which conflicts with xdist's process model +_is_xdist_worker = os.environ.get("PYTEST_XDIST_WORKER") is not None +pytestmark = pytest.mark.skipif( + _is_xdist_worker, + reason="HTTP tests use fork() which conflicts with pytest-xdist workers", +) + def run_worker(rank: int, world_size: int, port: int, endpoints: list[str]) -> None: """Run a single worker server.""" diff --git a/tests/v2/backends/simp_worker/test_http.py b/tests/v2/backends/simp_worker/test_http.py index 80ed4043..716ccafd 100644 --- a/tests/v2/backends/simp_worker/test_http.py +++ b/tests/v2/backends/simp_worker/test_http.py @@ -16,6 +16,7 @@ import logging import multiprocessing +import os import time import httpx @@ -30,6 +31,14 @@ from mplang.v2.dialects import simp, tensor from mplang.v2.edsl.context import pop_context, push_context +# Skip when running with pytest-xdist (parallel workers) +# These tests use multiprocessing which conflicts with xdist's process model +_is_xdist_worker = os.environ.get("PYTEST_XDIST_WORKER") is not None +pytestmark = pytest.mark.skipif( + _is_xdist_worker, + reason="HTTP tests use multiprocessing which can conflict with pytest-xdist workers", +) + logging.basicConfig(level=logging.DEBUG) diff --git a/uv.lock b/uv.lock index d2c6228a..ca0ad502 100644 --- a/uv.lock +++ b/uv.lock @@ -407,6 +407,15 @@ epy = [ { name = "typing-extensions" }, ] +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec" }, +] + [[package]] name = "fastapi" version = "0.124.0" @@ -905,7 +914,9 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-benchmark" }, { name = "pytest-cov" }, + { name = "pytest-forked" }, { name = "pytest-repeat" }, + { name = "pytest-xdist" }, { name = "ruff" }, { name = "taskipy" }, ] @@ -945,7 +956,9 @@ dev = [ { name = "pytest-asyncio" }, { name = "pytest-benchmark" }, { name = "pytest-cov" }, + { name = "pytest-forked", specifier = ">=1.6.0" }, { name = "pytest-repeat", specifier = ">=0.9.4" }, + { name = "pytest-xdist", specifier = ">=3.8.0" }, { name = "ruff" }, { name = "taskipy" }, ] @@ -1547,6 +1560,19 @@ wheels = [ { url = "https://mirrors.aliyun.com/pypi/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861" }, ] +[[package]] +name = "pytest-forked" +version = "1.6.0" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +dependencies = [ + { name = "py" }, + { name = "pytest" }, +] +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/8c/c9/93ad2ba2413057ee694884b88cf7467a46c50c438977720aeac26e73fdb7/pytest-forked-1.6.0.tar.gz", hash = "sha256:4dafd46a9a600f65d822b8f605133ecf5b3e1941ebb3588e943b4e3eb71a5a3f" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/f4/af/9c0bda43e486a3c9bf1e0f876d0f241bc3f229d7d65d09331a0868db9629/pytest_forked-1.6.0-py3-none-any.whl", hash = "sha256:810958f66a91afb1a1e2ae83089d8dc1cd2437ac96b12963042fbb9fb4d16af0" }, +] + [[package]] name = "pytest-repeat" version = "0.9.4" @@ -1559,6 +1585,19 @@ wheels = [ { url = "https://mirrors.aliyun.com/pypi/packages/73/d4/8b706b81b07b43081bd68a2c0359fe895b74bf664b20aca8005d2bb3be71/pytest_repeat-0.9.4-py3-none-any.whl", hash = "sha256:c1738b4e412a6f3b3b9e0b8b29fcd7a423e50f87381ad9307ef6f5a8601139f3" }, ] +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://mirrors.aliyun.com/pypi/simple/" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://mirrors.aliyun.com/pypi/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1" } +wheels = [ + { url = "https://mirrors.aliyun.com/pypi/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88" }, +] + [[package]] name = "python-dateutil" version = "2.9.0.post0"