Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
51d9afa
Improve test infrastructure for parallel execution and better isolation
shaypal5 Feb 13, 2026
12bd858
clean up
shaypal5 Feb 28, 2026
00da69a
small fix
shaypal5 Feb 28, 2026
ac33217
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Feb 28, 2026
233d105
Fix ruff SIM108 lint error in conftest.py (#350)
Copilot Feb 28, 2026
1a1c5b9
Update tests/README.md
shaypal5 Feb 28, 2026
2d62c99
Update scripts/test-local.sh
shaypal5 Feb 28, 2026
123a794
documet flaky test marker in pyproject.toml
shaypal5 Feb 28, 2026
5f33ab1
Update pyproject.toml
shaypal5 Feb 28, 2026
a2032e5
Update tests/conftest.py
shaypal5 Feb 28, 2026
c4548e0
Update scripts/test-local.sh
shaypal5 Feb 28, 2026
52114a6
Update scripts/test-local.sh
shaypal5 Feb 28, 2026
5a9cd4d
Update scripts/test-local.sh
shaypal5 Feb 28, 2026
3cd6183
Update scripts/test-local.sh
shaypal5 Feb 28, 2026
00f22d6
Update scripts/test-local.sh
shaypal5 Feb 28, 2026
c30e2ca
Fix CI/CD Integration section in tests/README.md to match actual work…
Copilot Feb 28, 2026
78bd354
Fix SQL test module import path in parallel test fixture (#352)
Copilot Feb 28, 2026
12d6b2a
Extend isolated_cache_directory fixture to cover maxage-marked tests …
Copilot Feb 28, 2026
c4b2e31
Restore pytest-asyncio to base test requirements (#355)
Copilot Feb 28, 2026
4a4f2ca
Fix serial-mode regression in pickle cache file manipulation tests (#…
Copilot Mar 1, 2026
fd63d61
Apply suggestions from code review
Borda Mar 6, 2026
441ad80
Enable parallel test execution in CI with -n auto (#359)
Copilot Mar 6, 2026
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
10 changes: 5 additions & 5 deletions .github/workflows/ci-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ jobs:

- name: Unit tests (local)
if: matrix.backend == 'local'
run: pytest -m "not mongo and not sql and not redis and not s3" --cov=cachier --cov-report=term --cov-report=xml:cov.xml
run: pytest -m "not mongo and not sql and not redis and not s3" -n auto --cov=cachier --cov-report=term --cov-report=xml:cov.xml

- name: Setup docker (missing on MacOS)
if: runner.os == 'macOS' && matrix.backend == 'mongodb'
Expand Down Expand Up @@ -148,7 +148,7 @@ jobs:

- name: Unit tests (DB)
if: matrix.backend == 'mongodb'
run: pytest -m "mongo" --cov=cachier --cov-report=term --cov-report=xml:cov.xml
run: pytest -m "mongo" -n auto --cov=cachier --cov-report=term --cov-report=xml:cov.xml
- name: Speed eval
run: python tests/speed_eval.py

Expand All @@ -169,7 +169,7 @@ jobs:
if: matrix.backend == 'postgres'
env:
SQLALCHEMY_DATABASE_URL: postgresql+psycopg://testuser:testpass@localhost:5432/testdb
run: pytest -m sql --cov=cachier --cov-report=term --cov-report=xml:cov.xml
run: pytest -m sql -n auto --cov=cachier --cov-report=term --cov-report=xml:cov.xml

- name: Start Redis in docker
if: matrix.backend == 'redis'
Expand All @@ -183,11 +183,11 @@ jobs:

- name: Unit tests (Redis)
if: matrix.backend == 'redis'
run: pytest -m redis --cov=cachier --cov-report=term --cov-report=xml:cov.xml
run: pytest -m redis -n auto --cov=cachier --cov-report=term --cov-report=xml:cov.xml

- name: Unit tests (S3)
if: matrix.backend == 's3'
run: pytest -m s3 --cov=cachier --cov-report=term --cov-report=xml:cov.xml
run: pytest -m s3 -n auto --cov=cachier --cov-report=term --cov-report=xml:cov.xml

- name: Upload coverage to Codecov (non PRs)
continue-on-error: true
Expand Down
14 changes: 14 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ namespaces = false # to disable scanning PEP 420 namespaces (true by default)

# === Linting & Formatting ===

[tool.black]
line-length = 120

# --- ruff ---

[tool.ruff]
Expand Down Expand Up @@ -146,6 +149,7 @@ lint.per-file-ignores."tests/**" = [
"D401",
"S101",
"S105",
"S110",
"S311",
"S603",
]
Expand Down Expand Up @@ -188,6 +192,7 @@ addopts = [
"-v",
"-s",
"-W error",
# Note: parallel execution is opt-in via -n/--numprocesses (pytest-xdist)
]
markers = [
"mongo: test the MongoDB core",
Expand All @@ -199,6 +204,8 @@ markers = [
"maxage: test the max_age functionality",
"asyncio: marks tests as async",
"smoke: fast smoke tests with no external service dependencies",
"flaky: tests that are known to be flaky and should be retried",
"seriallocal: local core tests that should run serially",
]

[tool.coverage.report]
Expand All @@ -209,10 +216,17 @@ exclude_lines = [
"raise NotImplementedError", # Don't complain if tests don't hit defensive assertion code:
"if TYPE_CHECKING:", # Is only true when running mypy, not tests
]
# Parallel test execution configuration
# Use: pytest -n auto (for automatic worker detection)
# Or: pytest -n 4 (for specific number of workers)
# Memory tests are safe to run in parallel by default
# Pickle tests require isolation (handled by conftest.py fixture)

# --- coverage ---

[tool.coverage.run]
branch = true
parallel = true
# dynamic_context = "test_function"
omit = [
"tests/*",
Expand Down
85 changes: 84 additions & 1 deletion scripts/test-local.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ KEEP_RUNNING=false
SELECTED_CORES=""
INCLUDE_LOCAL_CORES=false
TEST_FILES=""
PARALLEL=false
PARALLEL_WORKERS="auto"

# Function to print colored messages
print_message() {
Expand Down Expand Up @@ -57,6 +59,8 @@ OPTIONS:
-k, --keep-running Keep containers running after tests
-h, --html-coverage Generate HTML coverage report
-f, --files Specify test files to run (can be used multiple times)
-p, --parallel Run tests in parallel using pytest-xdist
-w, --workers Number of parallel workers (default: auto)
--help Show this help message

EXAMPLES:
Expand All @@ -66,6 +70,8 @@ EXAMPLES:
$0 external -k # Run external backends, keep containers
$0 mongo memory -v # Run MongoDB and memory tests verbosely
$0 all -f tests/test_main.py -f tests/test_redis_core_coverage.py # Run specific test files
$0 memory pickle -p # Run local tests in parallel
$0 all -p -w 4 # Run all tests with 4 parallel workers

ENVIRONMENT:
You can also set cores via CACHIER_TEST_CORES environment variable:
Expand Down Expand Up @@ -103,6 +109,20 @@ while [[ $# -gt 0 ]]; do
usage
exit 0
;;
-p|--parallel)
PARALLEL=true
shift
;;
-w|--workers)
shift
if [[ $# -eq 0 ]] || [[ "$1" == -* ]]; then
print_message $RED "Error: -w/--workers requires a number argument"
usage
exit 1
fi
PARALLEL_WORKERS="$1"
shift
;;
-*)
print_message $RED "Unknown option: $1"
usage
Expand Down Expand Up @@ -234,6 +254,17 @@ check_dependencies() {
}
fi

# Check for pytest-xdist if parallel testing is requested
if [ "$PARALLEL" = true ]; then
if ! python -c "import xdist" 2>/dev/null; then
print_message $YELLOW "Installing pytest-xdist for parallel testing..."
pip install pytest-xdist || {
print_message $RED "Failed to install pytest-xdist"
exit 1
}
fi
fi

# Check MongoDB dependencies if testing MongoDB
if echo "$SELECTED_CORES" | grep -qw "mongo"; then
if ! python -c "import pymongo" 2>/dev/null; then
Expand Down Expand Up @@ -423,14 +454,20 @@ main() {
# Check and install dependencies
check_dependencies

# Check if we need Docker
# Check if we need Docker, and if we should run serial pickle tests
needs_docker=false
run_serial_local_tests=false
for core in $SELECTED_CORES; do
case $core in
mongo|redis|sql)
needs_docker=true
;;
esac
case $core in
pickle|all)
run_serial_local_tests=true
;;
esac
done

if [ "$needs_docker" = true ]; then
Expand Down Expand Up @@ -497,15 +534,31 @@ main() {
sql) test_sql ;;
esac
done
if [ -n "$pytest_markers" ]; then
pytest_markers="($pytest_markers) and not seriallocal"
else
pytest_markers="not seriallocal"
fi

# Run pytest
# Build pytest command
PYTEST_CMD="pytest"
# and the specific pytest command for running serial pickle tests
SERIAL_PYTEST_CMD="pytest -m seriallocal"
# Only add -n0 if pytest-xdist is available; otherwise, plain pytest is already serial
if python - << 'EOF' >/dev/null 2>&1
import xdist # noqa: F401
EOF
then
SERIAL_PYTEST_CMD="$SERIAL_PYTEST_CMD -n0"
fi

# Add test files if specified
if [ -n "$TEST_FILES" ]; then
PYTEST_CMD="$PYTEST_CMD $TEST_FILES"
print_message $BLUE "Test files specified: $TEST_FILES"
# and turn off serial local tests, so we run only selected files
run_serial_local_tests=false
fi

# Add markers if needed (only if no specific test files were given)
Expand All @@ -517,6 +570,10 @@ main() {

if [ "$selected_sorted" != "$all_sorted" ]; then
PYTEST_CMD="$PYTEST_CMD -m \"$pytest_markers\""
else
print_message $BLUE "Running all tests without markers since all cores are selected"
PYTEST_CMD="$PYTEST_CMD -m \"not seriallocal\""
run_serial_local_tests=true
fi
else
# When test files are specified, still apply markers if not running all cores
Expand All @@ -532,15 +589,41 @@ main() {
# Add verbose flag if needed
if [ "$VERBOSE" = true ]; then
PYTEST_CMD="$PYTEST_CMD -v"
SERIAL_PYTEST_CMD="$SERIAL_PYTEST_CMD -v"
fi

# Add parallel testing options if requested
if [ "$PARALLEL" = true ]; then
PYTEST_CMD="$PYTEST_CMD -n $PARALLEL_WORKERS"

# Show parallel testing info
if [ "$PARALLEL_WORKERS" = "auto" ]; then
print_message $BLUE "Running tests in parallel with automatic worker detection"
else
print_message $BLUE "Running tests in parallel with $PARALLEL_WORKERS workers"
fi

# Special note for pickle tests
if echo "$SELECTED_CORES" | grep -qw "pickle"; then
print_message $YELLOW "Note: Pickle tests will use isolated cache directories for parallel safety"
fi
fi

# Add coverage options
PYTEST_CMD="$PYTEST_CMD --cov=cachier --cov-report=$COVERAGE_REPORT"
SERIAL_PYTEST_CMD="$SERIAL_PYTEST_CMD --cov=cachier --cov-report=$COVERAGE_REPORT --cov-append"

# Print and run the command
print_message $BLUE "Running: $PYTEST_CMD"
eval $PYTEST_CMD

if [ "$run_serial_local_tests" = true ]; then
print_message $BLUE "Running serial local tests (pickle, memory) with: $SERIAL_PYTEST_CMD"
eval $SERIAL_PYTEST_CMD
else
print_message $BLUE "Skipping serial local tests (pickle, memory) since not requested"
fi

TEST_EXIT_CODE=$?

if [ $TEST_EXIT_CODE -eq 0 ]; then
Expand Down
Loading
Loading