diff --git a/.github/workflows/ci-tests.yml b/.github/workflows/ci-tests.yml index 7373ac5a..d06092cc 100644 --- a/.github/workflows/ci-tests.yml +++ b/.github/workflows/ci-tests.yml @@ -12,12 +12,13 @@ on: workflow_dispatch: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref_name }} cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: pytester: runs-on: ${{ matrix.os }} + timeout-minutes: 30 strategy: fail-fast: false matrix: @@ -50,4 +51,4 @@ jobs: uv pip list - name: Run tests - run: pytest tests/ -v --disable-warnings --color=yes + run: pytest tests/ -v --color=yes -n 2 --dist=loadfile diff --git a/requires_test.txt b/requires_test.txt index 550bab9c..f3b71b4e 100644 --- a/requires_test.txt +++ b/requires_test.txt @@ -1,4 +1,5 @@ pytest ==8.3.2 +pytest-xdist ==3.6.1 mygene ==3.2.2 scvi-tools >=1.1.0, <1.3.0 diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..801594e8 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +""" +Pytest configuration and fixtures for TDC tests. + +This conftest.py ensures shared directories are cleaned before test execution +to prevent race conditions and shared state issues in parallel testing. +""" + +import os +import shutil +from contextlib import suppress + +import pytest + + +@pytest.fixture(scope="session", autouse=True) +def cleanup_shared_directories(): + """ + Clean up shared ./data and ./oracle directories before test session starts. + + This fixture runs automatically before any tests to ensure a clean state, + preventing race conditions when tests run in parallel with pytest-xdist. + + With pytest-xdist, session-scoped fixtures run once per worker process, + but since all workers share the same working directory, we need to be + careful about race conditions. The --dist=loadfile strategy helps by + grouping tests by file to the same worker. + """ + # Get the root directory where tests are run from + root_dir = os.getcwd() + + # Clean up before tests start + for directory in ["data", "oracle"]: + dir_path = os.path.join(root_dir, directory) + with suppress(FileNotFoundError): + shutil.rmtree(dir_path) + + # Let tests run + yield + + # Optional: Clean up after tests complete + # Commented out to allow inspection of test artifacts + # for directory in ["data", "oracle"]: + # dir_path = os.path.join(root_dir, directory) + # with suppress(FileNotFoundError): + # shutil.rmtree(dir_path)