125 lines
4.3 KiB
YAML
125 lines
4.3 KiB
YAML
name: Tests
|
||
|
||
on:
|
||
push:
|
||
branches: [main]
|
||
paths-ignore:
|
||
- '**/*.md'
|
||
- 'docs/**'
|
||
pull_request:
|
||
branches: [main]
|
||
paths-ignore:
|
||
- '**/*.md'
|
||
- 'docs/**'
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
# Cancel in-progress runs for the same PR/branch
|
||
concurrency:
|
||
group: tests-${{ github.ref }}
|
||
cancel-in-progress: true
|
||
|
||
jobs:
|
||
test:
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 60
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||
|
||
- name: Install ripgrep (prebuilt binary)
|
||
run: |
|
||
set -euo pipefail
|
||
RG_VERSION=15.1.0
|
||
RG_SHA256=1c9297be4a084eea7ecaedf93eb03d058d6faae29bbc57ecdaf5063921491599
|
||
RG_TARBALL=ripgrep-${RG_VERSION}-x86_64-unknown-linux-musl.tar.gz
|
||
curl -sSfL -o "$RG_TARBALL" \
|
||
"https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${RG_TARBALL}"
|
||
echo "${RG_SHA256} ${RG_TARBALL}" | sha256sum -c -
|
||
tar -xzf "$RG_TARBALL"
|
||
sudo mv "ripgrep-${RG_VERSION}-x86_64-unknown-linux-musl/rg" /usr/local/bin/rg
|
||
rm -rf "$RG_TARBALL" "ripgrep-${RG_VERSION}-x86_64-unknown-linux-musl"
|
||
rg --version
|
||
|
||
- name: Install uv
|
||
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
|
||
|
||
- name: Set up Python 3.11
|
||
run: uv python install 3.11
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
uv venv .venv --python 3.11
|
||
source .venv/bin/activate
|
||
uv pip install -e ".[all,dev]"
|
||
|
||
- name: Run tests
|
||
# Per-file isolation via scripts/run_tests_parallel.py: discovers
|
||
# every test_*.py file under tests/ (excluding integration/ + e2e/),
|
||
# then runs `python -m pytest <file>` in a freshly-spawned subprocess
|
||
# with bounded parallelism. No xdist, no shared workers, no
|
||
# module-level state leakage between files.
|
||
#
|
||
# Why per-file (not per-test): per-test spawn cost (~250ms × 17k
|
||
# tests = 70min CPU minimum) blew the wall-clock budget. Per-file
|
||
# spawn (~250ms × ~850 files = ~3.5min) fits while still giving
|
||
# every file a fresh interpreter — the only isolation boundary
|
||
# that matters in practice (cross-file leakage was the original
|
||
# flake source; intra-file is the test author's responsibility).
|
||
#
|
||
# Why drop xdist entirely: xdist's persistent workers accumulate
|
||
# state across files, which is exactly the leakage we wanted to
|
||
# fix. ThreadPoolExecutor + subprocess.run is ~60 lines and does
|
||
# the job with cleaner semantics.
|
||
run: |
|
||
source .venv/bin/activate
|
||
python scripts/run_tests_parallel.py
|
||
env:
|
||
# Ensure tests don't accidentally call real APIs
|
||
OPENROUTER_API_KEY: ""
|
||
OPENAI_API_KEY: ""
|
||
NOUS_API_KEY: ""
|
||
|
||
e2e:
|
||
runs-on: ubuntu-latest
|
||
timeout-minutes: 15
|
||
steps:
|
||
- name: Checkout code
|
||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||
|
||
- name: Install ripgrep (prebuilt binary)
|
||
run: |
|
||
set -euo pipefail
|
||
RG_VERSION=15.1.0
|
||
RG_SHA256=1c9297be4a084eea7ecaedf93eb03d058d6faae29bbc57ecdaf5063921491599
|
||
RG_TARBALL=ripgrep-${RG_VERSION}-x86_64-unknown-linux-musl.tar.gz
|
||
curl -sSfL -o "$RG_TARBALL" \
|
||
"https://github.com/BurntSushi/ripgrep/releases/download/${RG_VERSION}/${RG_TARBALL}"
|
||
echo "${RG_SHA256} ${RG_TARBALL}" | sha256sum -c -
|
||
tar -xzf "$RG_TARBALL"
|
||
sudo mv "ripgrep-${RG_VERSION}-x86_64-unknown-linux-musl/rg" /usr/local/bin/rg
|
||
rm -rf "$RG_TARBALL" "ripgrep-${RG_VERSION}-x86_64-unknown-linux-musl"
|
||
rg --version
|
||
|
||
- name: Install uv
|
||
uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5
|
||
|
||
- name: Set up Python 3.11
|
||
run: uv python install 3.11
|
||
|
||
- name: Install dependencies
|
||
run: |
|
||
uv venv .venv --python 3.11
|
||
source .venv/bin/activate
|
||
uv pip install -e ".[all,dev]"
|
||
|
||
- name: Run e2e tests
|
||
run: |
|
||
source .venv/bin/activate
|
||
python -m pytest tests/e2e/ -v --tb=short
|
||
env:
|
||
OPENROUTER_API_KEY: ""
|
||
OPENAI_API_KEY: ""
|
||
NOUS_API_KEY: ""
|