This commit is contained in:
Ashwin Bharambe 2025-11-04 17:10:40 -08:00
parent 02fd375965
commit 8adf6d2fe5
5 changed files with 64 additions and 54 deletions

View file

@ -165,3 +165,14 @@ jobs:
echo "::error::Full mypy failed. Reproduce locally with 'uv run pre-commit run mypy-full --hook-stage manual --all-files'." echo "::error::Full mypy failed. Reproduce locally with 'uv run pre-commit run mypy-full --hook-stage manual --all-files'."
fi fi
exit $status exit $status
- name: Check if any unused recordings
run: |
set -e
PYTHONPATH=$PWD uv run ./scripts/cleanup_recordings.py --delete
changes=$(git status --short tests/integration | grep 'recordings' || true)
if [ -n "$changes" ]; then
echo "::error::Unused integration recordings detected. Run 'PYTHONPATH=$(pwd) uv run ./scripts/cleanup_recordings.py --delete' locally and commit the deletions."
echo "$changes"
exit 1
fi

View file

@ -9,7 +9,7 @@
Clean up unused test recordings based on CI test collection. Clean up unused test recordings based on CI test collection.
This script: This script:
1. Resolves the CI test matrix by combining the default CI_MATRIX with scheduled overrides 1. Reads CI matrix definitions from tests/integration/ci_matrix.json (default + scheduled overrides)
2. Uses pytest --collect-only with --json-report to gather all test IDs that run in CI 2. Uses pytest --collect-only with --json-report to gather all test IDs that run in CI
3. Compares against existing recordings to identify unused ones 3. Compares against existing recordings to identify unused ones
4. Optionally deletes unused recordings 4. Optionally deletes unused recordings
@ -34,45 +34,43 @@ from collections import defaultdict
from pathlib import Path from pathlib import Path
REPO_ROOT = Path(__file__).parent.parent REPO_ROOT = Path(__file__).parent.parent
from tests.integration.suites import CI_MATRIX # noqa: E402
# Additional scheduled CI configurations (keep in sync with scripts/generate_ci_matrix.py) # Load CI matrix from JSON file
ADDITIONAL_CI_CONFIGS = [ CI_MATRIX_FILE = REPO_ROOT / "tests/integration/ci_matrix.json"
{"suite": "base", "setup": "vllm"}, # Weekly vLLM coverage with open(CI_MATRIX_FILE) as f:
] _matrix_config = json.load(f)
DEFAULT_CI_MATRIX: list[dict[str, str]] = _matrix_config["default"]
SCHEDULED_MATRICES: dict[str, list[dict[str, str]]] = _matrix_config.get("schedules", {})
def load_ci_configs() -> list[dict[str, str]]: def _unique_configs(entries):
"""Return all (suite, setup) combinations exercised in CI."""
configs: list[dict[str, str]] = []
seen: set[tuple[str, str]] = set() seen: set[tuple[str, str]] = set()
for entry in entries:
def add(entry: dict[str, str]) -> None: suite = entry["suite"]
suite = entry.get("suite") setup = entry["setup"]
setup = entry.get("setup")
if not suite or not setup:
raise RuntimeError(f"Invalid CI matrix entry: {entry}")
key = (suite, setup) key = (suite, setup)
if key in seen: if key in seen:
return continue
seen.add(key) seen.add(key)
configs.append({"suite": suite, "setup": setup}) yield {"suite": suite, "setup": setup}
for entry in CI_MATRIX:
add(entry)
for entry in ADDITIONAL_CI_CONFIGS:
add(entry)
return configs
def collect_ci_tests(ci_configs: list[dict[str, str]]): def iter_all_ci_configs() -> list[dict[str, str]]:
"""Return unique CI configs across default and scheduled matrices."""
combined = list(DEFAULT_CI_MATRIX)
for configs in SCHEDULED_MATRICES.values():
combined.extend(configs)
return list(_unique_configs(combined))
def collect_ci_tests():
"""Collect all test IDs that would run in CI using --collect-only with JSON output.""" """Collect all test IDs that would run in CI using --collect-only with JSON output."""
all_test_ids = set() all_test_ids = set()
configs = iter_all_ci_configs()
for config in ci_configs: for config in configs:
print(f"Collecting tests for suite={config['suite']}, setup={config['setup']}...") print(f"Collecting tests for suite={config['suite']}, setup={config['setup']}...")
# Create a temporary file for JSON report # Create a temporary file for JSON report
@ -135,7 +133,7 @@ def collect_ci_tests(ci_configs: list[dict[str, str]]):
os.unlink(json_report_file) os.unlink(json_report_file)
print(f"\nTotal unique test IDs collected: {len(all_test_ids)}") print(f"\nTotal unique test IDs collected: {len(all_test_ids)}")
return all_test_ids return all_test_ids, configs
def get_base_test_id(test_id: str) -> str: def get_base_test_id(test_id: str) -> str:
@ -247,14 +245,14 @@ def main():
print("Recording Cleanup Utility") print("Recording Cleanup Utility")
print("=" * 60) print("=" * 60)
ci_configs = load_ci_configs() ci_configs = iter_all_ci_configs()
print(f"\nDetected CI configurations: {len(ci_configs)}") print(f"\nDetected CI configurations: {len(ci_configs)}")
for config in ci_configs: for config in ci_configs:
print(f" - suite={config['suite']}, setup={config['setup']}") print(f" - suite={config['suite']}, setup={config['setup']}")
# Collect test IDs from CI configurations # Collect test IDs from CI configurations
ci_test_ids = collect_ci_tests(ci_configs) ci_test_ids, _ = collect_ci_tests()
if args.manifest: if args.manifest:
with open(args.manifest, "w") as f: with open(args.manifest, "w") as f:

View file

@ -6,20 +6,22 @@
# the root directory of this source tree. # the root directory of this source tree.
""" """
Generate CI test matrix from suites.py with schedule/input overrides. Generate CI test matrix from ci_matrix.json with schedule/input overrides.
This script is used by .github/workflows/integration-tests.yml to generate This script is used by .github/workflows/integration-tests.yml to generate
the test matrix dynamically based on the CI_MATRIX definition in suites.py. the test matrix dynamically based on the CI_MATRIX definition.
""" """
import json import json
import sys
from pathlib import Path from pathlib import Path
# Add tests/integration to path CI_MATRIX_FILE = Path(__file__).parent.parent / "tests/integration/ci_matrix.json"
sys.path.insert(0, str(Path(__file__).parent.parent / "tests/integration"))
from suites import CI_MATRIX with open(CI_MATRIX_FILE) as f:
matrix_config = json.load(f)
DEFAULT_MATRIX = matrix_config["default"]
SCHEDULE_MATRICES: dict[str, list[dict[str, str]]] = matrix_config.get("schedules", {})
def generate_matrix(schedule="", test_setup=""): def generate_matrix(schedule="", test_setup=""):
@ -33,15 +35,15 @@ def generate_matrix(schedule="", test_setup=""):
Returns: Returns:
Matrix configuration as JSON string Matrix configuration as JSON string
""" """
# Weekly vllm test on Sunday # Weekly scheduled test matrices
if schedule == "1 0 * * 0": if schedule and schedule in SCHEDULE_MATRICES:
matrix = [{"suite": "base", "setup": "vllm"}] matrix = SCHEDULE_MATRICES[schedule]
# Manual input for specific setup # Manual input for specific setup
elif test_setup == "ollama-vision": elif test_setup == "ollama-vision":
matrix = [{"suite": "vision", "setup": "ollama-vision"}] matrix = [{"suite": "vision", "setup": "ollama-vision"}]
# Default: use CI_MATRIX from suites.py # Default: use JSON-defined matrix
else: else:
matrix = CI_MATRIX matrix = DEFAULT_MATRIX
# GitHub Actions expects {"include": [...]} format # GitHub Actions expects {"include": [...]} format
return json.dumps({"include": matrix}) return json.dumps({"include": matrix})

View file

@ -0,0 +1,12 @@
{
"default": [
{"suite": "base", "setup": "ollama"},
{"suite": "vision", "setup": "ollama-vision"},
{"suite": "responses", "setup": "gpt"}
],
"schedules": {
"1 0 * * 0": [
{"suite": "base", "setup": "vllm"}
]
}
}

View file

@ -180,16 +180,3 @@ SUITE_DEFINITIONS: dict[str, Suite] = {
default_setup="ollama-vision", default_setup="ollama-vision",
), ),
} }
# CI test matrix - single source of truth for continuous integration test configurations
# This is used by:
# - .github/workflows/integration-tests.yml (CI jobs)
# - scripts/cleanup_recordings.py (unused recording cleanup)
#
# Each entry defines a (suite, setup) pair that runs in CI.
# Note: Special test configurations (vllm weekly tests, manual inputs) are handled in the CI workflow.
CI_MATRIX = [
{"suite": "base", "setup": "ollama"},
{"suite": "vision", "setup": "ollama-vision"},
{"suite": "responses", "setup": "gpt"},
]