Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ jobs:
test:
needs: changes
runs-on: ${{ needs.changes.outputs.runner == 'korvid-runners' && 'korvid-runners' || 'ubuntu-latest' }}
# The full suite under coverage takes 39-46 minutes on Python 3.12 (#454).
# In one process the suite under coverage took 39-46 minutes on Python
# 3.12 (#454); it now runs on four xdist workers (#468), and the limit
# stays as headroom for a loaded runner.
timeout-minutes: 60
strategy:
matrix:
Expand All @@ -159,7 +161,7 @@ jobs:
- run: uvx deptry src/
# A docs-only change still gets a full suite run, on one version.
- if: needs.changes.outputs.code == 'true' || matrix.python-version == '3.12'
run: uv run pytest --cov --cov-fail-under=80
run: uv run pytest -n 4 --cov --cov-fail-under=80

windows-test:
needs: changes
Expand Down Expand Up @@ -199,7 +201,7 @@ jobs:
# The docs landing harness ran above in a fresh process; do not execute
# it a second time in the long-lived Windows pytest process.
- if: needs.changes.outputs.code == 'true'
run: uv run pytest -q --ignore=tests/windows/test_native_terminal.py --ignore=tests/test_docs_landing_behavior.py --deselect=tests/core/test_audit.py::test_concurrent_appends_across_instances --randomly-seed=${{ github.run_id }}
run: uv run pytest -n 4 -q --ignore=tests/windows/test_native_terminal.py --ignore=tests/test_docs_landing_behavior.py --deselect=tests/core/test_audit.py::test_concurrent_appends_across_instances --randomly-seed=${{ github.run_id }}

pre-commit:
needs: changes
Expand Down
2 changes: 1 addition & 1 deletion docs/dev/quality-gates.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ gate wastes more time than it saves.
| job | what it establishes |
|---|---|
| `changes` | classifies the diff so a docs-only change skips redundant test legs |
| `test` (3.11, 3.12, 3.13) | ruff, `ruff format --check`, mypy, `tach`, `deptry`, `pytest --cov --cov-fail-under=80` |
| `test` (3.11, 3.12, 3.13) | ruff, `ruff format --check`, mypy, `tach`, `deptry`, `pytest -n 4 --cov --cov-fail-under=80` (four xdist workers; coverage is combined across them) |
| `windows-test` (3.12) | OS-specific behaviour — path handling, terminal, keyring |
| `pre-commit` | the layer-1 hooks over every file |
| `security` | `pip-audit` on the locked runtime resolution **including every extra**, `zizmor` on the workflows |
Expand Down
3 changes: 3 additions & 0 deletions tests/k8s/test_pulse.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,9 @@ async def refresh(
("gzip", gzip.compress(b'{"items": []}') + b"trailing"),
("br", b"unsupported"),
],
# Named, not derived from the payload: a gzip header carries the time it
# was written, and xdist aborts when its workers collect different IDs.
ids=["gzip-not-compressed", "gzip-truncated", "gzip-trailing-bytes", "br-unsupported"],
)
async def test_invalid_compression_fails_closed_and_closes_response(
pulse: ModuleType, encoding: str, payload: bytes
Expand Down
59 changes: 58 additions & 1 deletion tests/test_ci_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import json
import os
import shlex
import shutil
import subprocess
from collections.abc import Mapping
Expand Down Expand Up @@ -72,7 +73,9 @@
WINDOWS_SEED = "${{ github.run_id }}"
CI_JOB_TIMEOUTS = {
"changes": 10,
# The full suite under coverage takes 39-46 minutes on Python 3.12 (#454).
# In one process the suite under coverage took 39-46 minutes on Python
# 3.12 (#454); it now runs on four xdist workers (#468), and the limit
# stays as headroom for a loaded runner.
"test": 60,
"windows-test": 45,
"pre-commit": 20,
Expand Down Expand Up @@ -431,6 +434,60 @@ def test_windows_pytest_processes_print_and_share_one_deterministic_seed() -> No
assert sum(run.count("--randomly-seed=") for run in runs) == 2


def test_the_full_suite_runs_on_four_xdist_workers() -> None:
"""In one process the suite took the 3.12 coverage job past 45 minutes
(#454); four workers run it, with the same coverage, in under a third of
the time (#468). A fixed count rather than `auto`: a korvid-runners pod
requests one CPU on a shared eight-vCPU node."""
jobs = _jobs(CI_WORKFLOW)
linux_suite = [run for run in _run_steps(jobs["test"]) if run.startswith("uv run pytest")]
windows_suite = [
run
for run in _run_steps(jobs["windows-test"])
if run.startswith("uv run pytest")
and "--ignore=tests/windows/test_native_terminal.py" in run
]

assert linux_suite == ["uv run pytest -n 4 --cov --cov-fail-under=80"]
assert len(windows_suite) == 1
assert windows_suite[0].startswith("uv run pytest -n 4 -q ")
assert _xdist_worker_counts(windows_suite[0]) == ["4"]


def _xdist_worker_counts(run: str) -> list[str]:
"""Every worker count `run` passes to pytest-xdist, in order.

xdist takes the last of repeated `-n` options, so a pin has to see all of
them, in each spelling pytest accepts.
"""
tokens = shlex.split(run)
counts: list[str] = []
for index, token in enumerate(tokens):
if token in ("-n", "--numprocesses"):
counts.append(tokens[index + 1] if index + 1 < len(tokens) else "")
elif token.startswith("--numprocesses="):
counts.append(token.partition("=")[2])
elif token.startswith("-n") and not token.startswith("--"):
counts.append(token[2:])
return counts


@pytest.mark.parametrize(
("run", "counts"),
[
("uv run pytest -n 4 -q", ["4"]),
("uv run pytest -n 4 -q --ignore=tests/x.py -n 1", ["4", "1"]),
("uv run pytest -n4 -q", ["4"]),
("uv run pytest --numprocesses 4", ["4"]),
("uv run pytest --numprocesses=4 -n 2", ["4", "2"]),
("uv run pytest -q --no-header", []),
],
ids=["spaced", "repeated", "attached", "long", "long-then-short", "none"],
)
def test_the_worker_count_check_sees_every_n_option(run: str, counts: list[str]) -> None:
assert _xdist_worker_counts(run) == counts


def test_experimental_ty_job_is_honestly_advisory() -> None:
job = _jobs(CI_WORKFLOW)["ty-experimental"]
Comment thread
hellices marked this conversation as resolved.
runs = _run_steps(job)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_platforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def test_ci_workflow_defines_the_required_windows_test_job() -> None:
assert "uv sync --locked --dev --all-extras" in runs
audit_regression = "tests/core/test_audit.py::test_concurrent_appends_across_instances"
full_suite = (
"uv run pytest -q --ignore=tests/windows/test_native_terminal.py"
"uv run pytest -n 4 -q --ignore=tests/windows/test_native_terminal.py"
" --ignore=tests/test_docs_landing_behavior.py"
f" --deselect={audit_regression}"
" --randomly-seed=${{ github.run_id }}"
Expand Down Expand Up @@ -268,7 +268,7 @@ def test_ci_windows_docs_harness_runs_once_in_fresh_process() -> None:
f"uv run pytest -p no:tach tests/windows/test_native_terminal.py {audit_regression} -q"
)
full_suite = (
"uv run pytest -q --ignore=tests/windows/test_native_terminal.py"
"uv run pytest -n 4 -q --ignore=tests/windows/test_native_terminal.py"
" --ignore=tests/test_docs_landing_behavior.py"
f" --deselect={audit_regression}"
" --randomly-seed=${{ github.run_id }}"
Expand Down
Loading