-
Notifications
You must be signed in to change notification settings - Fork 9.6k
chore: add scripts/dev/test.sh — chunked FIFO local test wrapper (~1.75x faster) #2719
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
+493
−0
Closed
Changes from 4 commits
Commits
Show all changes
37 commits
Select commit
Hold shift + click to select a range
cea63ef
parrallel tests
LahkLeKey 155f22d
Merge pull request #1 from LahkLeKey/feat/parallel-test-suite
LahkLeKey 9bf891c
fix(test): keep xdist wrapper-only and harden collection
LahkLeKey 9449e24
fix(test): forward runtime passthrough and validate cursor
LahkLeKey e317e4e
fix(test): harden chunk sizing and resume behavior
LahkLeKey e72b5b4
fix(test): use -q instead of -qq for pytest collect-only to preserve …
LahkLeKey 2caac75
(copilot-commit-suggestion) Potential fix for pull request finding
LahkLeKey 2227434
chore: harden fast-test cursor handling
LahkLeKey dcd1475
chore: harden fast-test portability
LahkLeKey 533e7a7
chore: harden fast-test collection
LahkLeKey 91e873a
chore: tune fast-test output
LahkLeKey e55ca41
chore: harden fast-test locking
LahkLeKey 4a73eef
chore: stream fast-test chunks
LahkLeKey aeb476e
chore: harden fast-test fd handling
LahkLeKey 500c843
chore: fix fast-test help and lock
LahkLeKey f711540
chore: tighten fast-test locks
LahkLeKey f5e0a01
chore: clarify fast-test resume
LahkLeKey ba75dab
chore: route fast-test logs to stderr
LahkLeKey ec06344
chore: harden fast-test argv sizing
LahkLeKey abb8cb5
chore: align test wrapper naming
LahkLeKey 48e53e1
chore: harden fast-test tempfiles
LahkLeKey 575547b
chore: harden fast-test cursor path
LahkLeKey 955d0e5
chore: harden pytest cache handling
LahkLeKey c10ae0d
chore: relax fast-test collection filter
LahkLeKey 92abcdc
chore: tighten fast-test path guards
LahkLeKey 6da8eb1
chore: force xdist and quiet collect
LahkLeKey 9df0085
chore: tighten fast-test xdist args
LahkLeKey e4a30f0
chore: harden cursor temp handling
LahkLeKey b0641b9
chore: tighten fast-test temp and lock
LahkLeKey c86a6d4
chore: speed up arg sizing
LahkLeKey 12a55ea
chore: harden cursor temp creation
LahkLeKey 6e4bae2
chore: fix help and cursor guard
LahkLeKey a00beb4
chore: harden cursor cleanup
LahkLeKey 15f2a06
chore: harden resume cursor access
LahkLeKey ef12855
chore: harden cursor read/write
LahkLeKey c9de4be
chore: harden lock file handling
LahkLeKey 16e34a0
chore: fix lock pid scope
LahkLeKey File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| #!/usr/bin/env bash | ||
| # Spec Kit local test wrapper — chunked FIFO dispatch over pytest-xdist. | ||
| # | ||
| # Design (matches the chunked-task / bounded-memory pattern): | ||
| # * Collect node ids once: `pytest --collect-only -q`. | ||
| # * Split the collection into fixed-size chunks (default 200 nodes). | ||
| # * Dispatch chunks sequentially as a FIFO queue; inside each chunk, | ||
| # pytest-xdist's `--dist=load` hands tests out one at a time to | ||
| # workers as they finish — natural FIFO progression with bounded | ||
| # in-flight memory. | ||
| # * Persist the cursor (next chunk index) to | ||
| # `.pytest_cache/fast-test-cursor` after every successful chunk so | ||
| # `--resume` continues exactly where a crash left off. | ||
| # * `--reset` clears the cursor; `--bench` reports wall-time only. | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| # | ||
| # Usage: | ||
| # scripts/dev/test.sh # full suite, chunked | ||
| # scripts/dev/test.sh --chunk-size 100 | ||
| # scripts/dev/test.sh --resume # continue from cursor | ||
| # scripts/dev/test.sh --reset # clear cursor | ||
| # scripts/dev/test.sh --bench # time only, no -v | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| # scripts/dev/test.sh -- tests/test_merge.py # pass-through to pytest | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" | ||
| CURSOR_FILE="$REPO_ROOT/.pytest_cache/fast-test-cursor" | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
LahkLeKey marked this conversation as resolved.
Outdated
|
||
|
|
||
| CHUNK_SIZE=200 | ||
| RESUME=0 | ||
| RESET=0 | ||
| BENCH=0 | ||
| PASSTHROUGH=() | ||
| RUNTIME_PASSTHROUGH=() | ||
|
|
||
| while (( $# )); do | ||
| case "$1" in | ||
| --chunk-size) CHUNK_SIZE="$2"; shift 2 ;; | ||
|
mnriem marked this conversation as resolved.
Outdated
|
||
| --resume) RESUME=1; shift ;; | ||
| --reset) RESET=1; shift ;; | ||
| --bench) BENCH=1; shift ;; | ||
| --) shift; PASSTHROUGH+=("$@"); break ;; | ||
| -h|--help) sed -n '2,22p' "$0"; exit 0 ;; | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| *) PASSTHROUGH+=("$1"); shift ;; | ||
| esac | ||
| done | ||
|
LahkLeKey marked this conversation as resolved.
|
||
|
|
||
| # Collection and execution do not share every pytest flag. Keep runtime | ||
| # passthrough aligned with user intent while stripping collect-only toggles. | ||
| for arg in "${PASSTHROUGH[@]}"; do | ||
| case "$arg" in | ||
| --collect-only|--co) ;; | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| *) RUNTIME_PASSTHROUGH+=("$arg") ;; | ||
| esac | ||
| done | ||
|
|
||
| if (( RESET )); then | ||
| rm -f "$CURSOR_FILE" | ||
| echo "[fast-test] cursor cleared" | ||
| exit 0 | ||
| fi | ||
|
LahkLeKey marked this conversation as resolved.
|
||
|
|
||
| cd "$REPO_ROOT" | ||
| mkdir -p "$(dirname "$CURSOR_FILE")" | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
|
|
||
| # 1. Collect node ids. | ||
| echo "[fast-test] collecting tests ..." | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| COLLECT_ERR="$(mktemp)" | ||
| COLLECT_OUT="$(mktemp)" | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| if ! uv run pytest --collect-only -qq "${PASSTHROUGH[@]}" >"$COLLECT_OUT" 2>"$COLLECT_ERR"; then | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| echo "[fast-test] test collection failed" >&2 | ||
| [[ -s "$COLLECT_ERR" ]] && { echo "--- collection stderr ---"; cat "$COLLECT_ERR"; } >&2 | ||
| rm -f "$COLLECT_ERR" "$COLLECT_OUT" | ||
| exit 1 | ||
| fi | ||
| mapfile -t NODES < <(grep -E '::' "$COLLECT_OUT" || true) | ||
|
mnriem marked this conversation as resolved.
Outdated
|
||
| rm -f "$COLLECT_ERR" "$COLLECT_OUT" | ||
| TOTAL="${#NODES[@]}" | ||
| if (( TOTAL == 0 )); then | ||
| echo "[fast-test] no tests collected" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| # 2. Determine starting cursor. | ||
| START=0 | ||
| if (( RESUME )) && [[ -f "$CURSOR_FILE" ]]; then | ||
| RAW_START="$(tr -d '[:space:]' < "$CURSOR_FILE")" | ||
| if [[ "$RAW_START" =~ ^[0-9]+$ ]]; then | ||
| START="$RAW_START" | ||
| (( START > TOTAL )) && START="$TOTAL" | ||
| echo "[fast-test] resuming from next test index: $START" | ||
| else | ||
|
LahkLeKey marked this conversation as resolved.
|
||
| echo "[fast-test] cursor file is invalid ('$RAW_START'); starting from 0" >&2 | ||
| fi | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| fi | ||
|
LahkLeKey marked this conversation as resolved.
LahkLeKey marked this conversation as resolved.
LahkLeKey marked this conversation as resolved.
|
||
|
|
||
| CHUNKS=$(( (TOTAL - START + CHUNK_SIZE - 1) / CHUNK_SIZE )) | ||
| echo "[fast-test] $TOTAL tests · chunk=$CHUNK_SIZE · $CHUNKS chunk(s) queued · workers=auto" | ||
|
mnriem marked this conversation as resolved.
Outdated
LahkLeKey marked this conversation as resolved.
Outdated
|
||
|
|
||
| # 3. FIFO dispatch. | ||
| T_START=$(date +%s) | ||
| i="$START" | ||
|
LahkLeKey marked this conversation as resolved.
|
||
| chunk_idx=0 | ||
| while (( i < TOTAL )); do | ||
| end=$(( i + CHUNK_SIZE )) | ||
| (( end > TOTAL )) && end="$TOTAL" | ||
| chunk_idx=$(( chunk_idx + 1 )) | ||
| echo "[fast-test] chunk $chunk_idx/$CHUNKS tests $((i+1))..$end" | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
|
|
||
| PYTEST_FLAGS=(-n auto --dist=load) | ||
| (( BENCH )) && PYTEST_FLAGS+=(-q) || PYTEST_FLAGS+=(--no-header -q) | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
|
|
||
| if ! uv run pytest "${PYTEST_FLAGS[@]}" "${RUNTIME_PASSTHROUGH[@]}" "${NODES[@]:i:CHUNK_SIZE}"; then | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| echo "[fast-test] chunk failed — cursor preserved at next test index $i (use --resume to retry)" | ||
| echo "$i" > "$CURSOR_FILE" | ||
| exit 1 | ||
| fi | ||
|
|
||
| i="$end" | ||
| echo "$i" > "$CURSOR_FILE" | ||
| done | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
|
|
||
| T_END=$(date +%s) | ||
| rm -f "$CURSOR_FILE" | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
| echo "[fast-test] all $TOTAL tests passed in $((T_END - T_START))s" | ||
|
LahkLeKey marked this conversation as resolved.
Outdated
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.