diff --git a/.circleci/config.yml b/.circleci/config.yml
index a93d62d0c39..0d442e32b0a 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -38,7 +38,7 @@ commands:
parameters:
category:
type: enum
- enum: ["backend", "client", "provider-harness", "redis-compat"]
+ enum: ["backend", "client"]
default: "backend"
steps:
- run:
@@ -160,7 +160,7 @@ commands:
exit 1
;;
esac
- curl -sSLf -o /tmp/rustup-init \
+ curl -sSLf --retry 3 --retry-all-errors --retry-max-time 120 --connect-timeout 15 --max-time 60 -o /tmp/rustup-init \
"https://static.rust-lang.org/rustup/archive/1.28.2/${RUSTUP_TRIPLE}/rustup-init"
echo "${RUSTUP_SHA256} /tmp/rustup-init" | sha256sum -c -
chmod +x /tmp/rustup-init
@@ -284,26 +284,6 @@ commands:
done
echo "fake OpenAI endpoint did not become ready" >&2
exit 1
- start_cost_center_service:
- description: "Start the stand-in cost center validation service (tests/store_model_in_db_tests/cost_center_service.py) on host port 9414 and wait until healthy. The proxy's team-metadata validator (team_metadata_validator_e2e.py, impl 'http') reaches it via TEAM_METADATA_VALIDATION_SERVICE_URL=http://host.docker.internal:9414/validate. Run after uv deps are synced."
- steps:
- - run:
- name: Start cost center validation service
- background: true
- command: |
- uv run --no-sync python tests/store_model_in_db_tests/cost_center_service.py --host 0.0.0.0 --port 9414
- - run:
- name: Wait for cost center validation service
- command: |
- for i in $(seq 1 30); do
- if curl -sf http://localhost:9414/health >/dev/null 2>&1; then
- echo "cost center validation service is up"
- exit 0
- fi
- sleep 1
- done
- echo "cost center validation service did not become ready" >&2
- exit 1
setup_litellm_enterprise_pip:
steps:
- run:
@@ -359,8 +339,15 @@ commands:
Add-Content -Path $PROFILE -Value "`$env:Path = `"$cargoBin;`$env:Path`""
}
setup_litellm_test_deps:
+ parameters:
+ checkout:
+ type: boolean
+ default: true
steps:
- - checkout
+ - when:
+ condition: << parameters.checkout >>
+ steps:
+ - checkout
- setup_google_dns
- install_uv
- install_rust
@@ -396,13 +383,28 @@ jobs:
shell: bash.exe
command: bash .circleci/scripts/path_filter.sh windows-release
- run:
- name: Install Python
+ name: Install Python 3.11.9 from python.org
+ no_output_timeout: 6m
command: |
- choco install python --version=3.11.0 -y --no-progress --force
- refreshenv
- python --version
- environment:
- CHOCOLATEY_CONFIRM_ALL: "true"
+ $ProgressPreference = "SilentlyContinue"
+ $installer = Join-Path $env:TEMP "python-3.11.9-amd64.exe"
+ Invoke-WebRequest -Uri https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe -OutFile $installer -TimeoutSec 120
+ $expected = "5ee42c4eee1e6b4464bb23722f90b45303f79442df63083f05322f1785f5fdde"
+ $actual = (Get-FileHash -Path $installer -Algorithm SHA256).Hash.ToLower()
+ if ($actual -ne $expected) {
+ throw "Python installer hash mismatch: expected $expected got $actual"
+ }
+ $arguments = "/quiet InstallAllUsers=1 PrependPath=1 Include_test=0 Include_doc=0 Include_launcher=0 TargetDir=C:\Python311"
+ $process = Start-Process -FilePath $installer -ArgumentList $arguments -PassThru
+ if (-not $process.WaitForExit(300000)) {
+ $process.Kill()
+ throw "Python installer did not finish within 5 minutes"
+ }
+ if ($process.ExitCode -ne 0) {
+ throw "Python installer exited with $($process.ExitCode)"
+ }
+ Remove-Item $installer
+ & C:\Python311\python.exe --version
- install_windows_toolchain
- run:
name: Record the Rust build environment for the release cargo cache key
@@ -425,7 +427,7 @@ jobs:
environment:
UV_HTTP_TIMEOUT: "300"
command: |
- $env:Path = "$HOME\.cargo\bin;$HOME\.local\bin;$env:Path"
+ $env:Path = "C:\Python311;C:\Python311\Scripts;$HOME\.cargo\bin;$HOME\.local\bin;$env:Path"
uv build --wheel --out-dir dist
if ($LASTEXITCODE -ne 0) {
exit $LASTEXITCODE
@@ -473,607 +475,6 @@ jobs:
command: |
python3 tests/windows_tests/check_windows_wheel_install.py --lengths-only
- auth_ui_unit_tests:
- docker:
- - &python312_image
- image: cimg/python:3.12@sha256:9c796c23c84e84a66a964acb508d39dc5433c81a47e07efd56dccbbc2427e07c
- auth:
- username: ${DOCKERHUB_USERNAME}
- password: ${DOCKERHUB_PASSWORD}
- - &postgres16_sidecar
- image: cimg/postgres:16.0@sha256:b125148bc76e8e8eee5eb3ad6020a3a14110a14e8192f1c645128afebe2e2f84
- environment:
- POSTGRES_USER: postgres
- POSTGRES_PASSWORD: postgres
- POSTGRES_DB: litellm_test
- working_directory: ~/project
- environment: &sidecar_database_url
- DATABASE_URL: "postgresql://postgres:postgres@localhost:5432/litellm_test"
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - save_cache:
- paths:
- - ~/.cache/uv
- key: v1-uv-cache-{{ checksum "uv.lock" }}
- - wait_for_service:
- url: tcp://localhost:5432
- timeout: "60"
- - run:
- name: Seed DB schema via prisma db push
- command: |
- set +e
- uv run --no-sync litellm --skip_server_startup --use_prisma_db_push
- set -e
- - run:
- name: Generate Prisma Client
- command: uv run --no-sync python -m prisma generate
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/proxy_admin_ui_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -v \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 2"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml auth_ui_unit_tests_coverage.xml
- mv .coverage auth_ui_unit_tests_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - auth_ui_unit_tests_coverage.xml
- - auth_ui_unit_tests_coverage
-
- llm_translation_testing:
- docker:
- - *python312_image
- working_directory: ~/project
- resource_class: xlarge
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - restore_cache:
- keys:
- - v1-uv-cache-{{ checksum "uv.lock" }}
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - save_cache:
- paths:
- - ~/.cache/uv
- key: v1-uv-cache-{{ checksum "uv.lock" }}
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- # Add --timeout to kill hanging tests after 120s (2 min)
- # Add --durations=20 to show 20 slowest tests for debugging
- # Subdirectories with dedicated jobs (maintain this list as new jobs are added)
- mkdir -p test-results
- # Glob excludes the realtime/ subdirectory since it has its own job
- TEST_FILES=$(circleci tests glob "tests/llm_translation/**/test_*.py" | grep -v "^tests/llm_translation/realtime/")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -v \
- --junitxml=test-results/junit.xml \
- --durations=20 \
- -n 4 \
- --timeout=120 --timeout_method=thread \
- --retries 2 --retry-delay 5 \
- --max-worker-restart=5"
- no_output_timeout: 15m
-
- # Store test results
- - store_test_results:
- path: test-results
- realtime_translation_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run realtime tests
- command: |
- # Add --timeout to kill hanging tests after 120s (2 min)
- # Add --durations=20 to show 20 slowest tests for debugging
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/llm_translation/realtime/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=20 \
- -n 4 \
- --timeout=120 --timeout_method=thread"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml realtime_translation_coverage.xml
- mv .coverage realtime_translation_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - realtime_translation_coverage.xml
- - realtime_translation_coverage
- guardrails_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- export LITELLM_LOG=WARNING
- uv run --no-sync python -m pytest --tb=short \
- -vv \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- --timeout=120 --timeout_method=thread \
- "tests/guardrails_tests/test_custom_guardrail.py::test_get_guardrail_dynamic_request_body_params"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml guardrails_coverage.xml
- mv .coverage guardrails_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - guardrails_coverage.xml
- - guardrails_coverage
-
- google_generate_content_endpoint_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/unified_google_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv -s \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- --retries 3 --retry-delay 5"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml google_generate_content_endpoint_coverage.xml
- mv .coverage google_generate_content_endpoint_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - google_generate_content_endpoint_coverage.xml
- - google_generate_content_endpoint_coverage
-
- ocr_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/ocr_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 4"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml ocr_coverage.xml
- mv .coverage ocr_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - ocr_coverage.xml
- - ocr_coverage
- search_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/search_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 4"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml search_coverage.xml
- mv .coverage search_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - search_coverage.xml
- - search_coverage
- batches_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/batches_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv -s \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 2"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml batches_coverage.xml
- mv .coverage batches_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - batches_coverage.xml
- - batches_coverage
- litellm_utils_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/litellm_utils_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv -s \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 2"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml litellm_utils_coverage.xml
- mv .coverage litellm_utils_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - litellm_utils_coverage.xml
- - litellm_utils_coverage
-
- pass_through_unit_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/pass_through_unit_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 4"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml pass_through_unit_tests_coverage.xml
- mv .coverage pass_through_unit_tests_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - pass_through_unit_tests_coverage.xml
- - pass_through_unit_tests_coverage
- image_gen_testing:
- docker:
- - *python312_image
- working_directory: ~/project
- resource_class: large
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/image_gen_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -v \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- -n 4"
- no_output_timeout: 15m
- # Store test results
- - store_test_results:
- path: test-results
- logging_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - setup_litellm_enterprise_pip
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- export LITELLM_LOG=WARNING
- TEST_FILES=$(circleci tests glob "tests/logging_callback_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- -n 4 \
- --junitxml=test-results/junit.xml \
- --durations=5 \
- --timeout=120 --timeout_method=thread"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml logging_coverage.xml || true
- mv .coverage logging_coverage || true
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - logging_coverage.xml
- - logging_coverage
- audio_testing:
- docker:
- - *python312_image
- working_directory: ~/project
-
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- # Run pytest and generate JUnit XML report
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/audio_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv -s \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
- - run:
- name: Rename the coverage files
- command: |
- mv coverage.xml audio_coverage.xml
- mv .coverage audio_coverage
-
- # Store test results
- - store_test_results:
- path: test-results
- - persist_to_workspace:
- root: .
- paths:
- - audio_coverage.xml
- - audio_coverage
helm_chart_testing:
machine:
image: ubuntu-2204:2024.04.1 # Use machine executor instead of docker
@@ -1133,11 +534,12 @@ jobs:
--set image.repository=litellm-ci \
--set image.tag=${IMAGE_TAG} \
--set image.pullPolicy=Never
- # Wait for pod to be ready
- echo "Waiting 30 seconds for pod to be ready..."
- sleep 30
+ if ! kubectl rollout status deployment/litellm --timeout=180s; then
+ kubectl describe pods -l app.kubernetes.io/name=litellm
+ kubectl logs -l app.kubernetes.io/name=litellm --tail=200
+ exit 1
+ fi
- # Print pod logs before running tests
echo "Printing pod logs..."
kubectl logs $(kubectl get pods -l app.kubernetes.io/name=litellm -o jsonpath="{.items[0].metadata.name}")
@@ -1240,7 +642,7 @@ jobs:
name: Run Basic Proxy Startup Tests (Health Readiness and Chat Completion)
command: |
mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/basic_proxy_startup_tests/**/test_*.py")
+ TEST_FILES=$(circleci tests glob "tests/integration/configuration/test_basic_proxy_startup.py")
echo "$TEST_FILES" | circleci tests run \
--verbose \
--command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
@@ -1251,199 +653,6 @@ jobs:
- store_test_results:
path: test-results
- build_and_test:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes
- - attach_workspace:
- at: ~/project
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - start_postgres
- - run:
- name: Load Docker Database Image
- command: |
- zstd -d litellm-docker-database.tar.zst --stdout | docker load
- docker tag litellm-docker-database:ci my-app:latest
- - start_openai_record_replay_proxy
- - start_fake_openai_endpoint
- - run:
- name: Run Docker container
- command: |
- docker run -d \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e USE_PRISMA_MIGRATE=True \
- -e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
- -e AZURE_API_KEY=$AZURE_API_KEY \
- -e REDIS_HOST=$REDIS_HOST \
- -e REDIS_PASSWORD=$REDIS_PASSWORD \
- -e REDIS_PORT=$REDIS_PORT \
- -e AZURE_FRANCE_API_KEY=$AZURE_FRANCE_API_KEY \
- -e AZURE_EUROPE_API_KEY=$AZURE_EUROPE_API_KEY \
- -e MISTRAL_API_KEY=$MISTRAL_API_KEY \
- -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
- -e GROQ_API_KEY=$GROQ_API_KEY \
- -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
- -e COHERE_API_KEY=$COHERE_API_KEY \
- -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
- -e AWS_REGION_NAME=$AWS_REGION_NAME \
- -e AUTO_INFER_REGION=True \
- -e OPENAI_API_KEY=$OPENAI_API_KEY \
- -e USE_DDTRACE=True \
- -e DD_API_KEY=$DD_API_KEY \
- -e DD_SITE=$DD_SITE \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e LANGFUSE_PROJECT1_PUBLIC=$LANGFUSE_PROJECT1_PUBLIC \
- -e LANGFUSE_PROJECT2_PUBLIC=$LANGFUSE_PROJECT2_PUBLIC \
- -e LANGFUSE_PROJECT1_SECRET=$LANGFUSE_PROJECT1_SECRET \
- -e LANGFUSE_PROJECT2_SECRET=$LANGFUSE_PROJECT2_SECRET \
- -e RECORDER_OPENAI_BASE_URL=http://host.docker.internal:8090/v1 \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/proxy_server_config.yaml:/app/config.yaml \
- my-app:latest \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- - run:
- name: Seed the routing strategy through /config/update
- command: |
- curl --noproxy '*' -sSf -X POST http://localhost:4000/config/update \
- -H "Authorization: Bearer $LITELLM_MASTER_KEY" -H 'Content-Type: application/json' \
- -d '{"router_settings": {"routing_strategy": "usage-based-routing-v2"}}'
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- # Original used `tests/*.py` (top-level only); the `--ignore=...`
- # flags were vestigial since shell globbing did not descend into
- # subdirectories. Replicate by globbing only top-level test files.
- TEST_FILES=$(circleci tests glob "tests/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -s -v \
- --junitxml=test-results/junit.xml \
- -n 4 \
- --durations=5"
- no_output_timeout: 15m
-
- # Store test results
- - store_test_results:
- path: test-results
- e2e_openai_endpoints:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - start_postgres
- - attach_workspace:
- at: ~/project
- - run:
- name: Load Docker Database Image
- command: |
- zstd -d litellm-docker-database.tar.zst --stdout | docker load
- docker images | grep litellm-docker-database
- - run:
- name: Run Docker container
- command: |
- docker run -d \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e AZURE_API_KEY=$AZURE_API_KEY \
- -e AZURE_API_BASE=$AZURE_API_BASE \
- -e AZURE_API_VERSION="2024-05-01-preview" \
- -e REDIS_HOST=$REDIS_HOST \
- -e REDIS_PASSWORD=$REDIS_PASSWORD \
- -e REDIS_PORT=$REDIS_PORT \
- -e AZURE_FRANCE_API_KEY=$AZURE_FRANCE_API_KEY \
- -e AZURE_EUROPE_API_KEY=$AZURE_EUROPE_API_KEY \
- -e MISTRAL_API_KEY=$MISTRAL_API_KEY \
- -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
- -e GROQ_API_KEY=$GROQ_API_KEY \
- -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
- -e COHERE_API_KEY=$COHERE_API_KEY \
- -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
- -e AWS_REGION_NAME=$AWS_REGION_NAME \
- -e AUTO_INFER_REGION=True \
- -e USE_DDTRACE=True \
- -e DD_API_KEY=$DD_API_KEY \
- -e DD_SITE=$DD_SITE \
- -e OPENAI_API_KEY=$OPENAI_API_KEY \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e LANGFUSE_PROJECT1_PUBLIC=$LANGFUSE_PROJECT1_PUBLIC \
- -e LANGFUSE_PROJECT2_PUBLIC=$LANGFUSE_PROJECT2_PUBLIC \
- -e LANGFUSE_PROJECT1_SECRET=$LANGFUSE_PROJECT1_SECRET \
- -e LANGFUSE_PROJECT2_SECRET=$LANGFUSE_PROJECT2_SECRET \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/litellm/proxy/example_config_yaml/oai_misc_config.yaml:/app/config.yaml \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/openai_endpoints_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -s -vv \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
-
- # Store test results
- - store_test_results:
- path: test-results
proxy_logging_guardrails_model_info_tests:
machine:
image: ubuntu-2204:2024.04.1
@@ -1474,66 +683,6 @@ jobs:
docker images | grep litellm-docker-database
- start_openai_record_replay_proxy
- start_fake_openai_endpoint
- - run:
- name: Run Docker container
- # intentionally give bad redis credentials here
- # the OTEL test - should get this as a trace
- command: |
- docker run -d \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e REDIS_HOST=$REDIS_HOST \
- -e REDIS_PASSWORD=$REDIS_PASSWORD \
- -e REDIS_PORT=$REDIS_PORT \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e OPENAI_API_KEY=$OPENAI_API_KEY \
- -e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e OTEL_EXPORTER="in_memory" \
- -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
- -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
- -e DEFAULT_NUM_WORKERS_LITELLM_PROXY=1 \
- -e USE_DDTRACE=True \
- -e DD_API_KEY=$DD_API_KEY \
- -e DD_SITE=$DD_SITE \
- -e AWS_REGION_NAME=$AWS_REGION_NAME \
- -e COHERE_API_KEY=$COHERE_API_KEY \
- -e RECORDER_COHERE_BASE_URL=http://host.docker.internal:8090/__recorder_upstream/api.cohere.com \
- -e GCS_FLUSH_INTERVAL="1" \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/litellm/proxy/example_config_yaml/otel_test_config.yaml:/app/config.yaml \
- -v $(pwd)/litellm/proxy/example_config_yaml/custom_guardrail.py:/app/custom_guardrail.py \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/otel_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -v \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
- # Clean up first container
- - run:
- name: Stop and remove first container
- command: |
- docker stop my-app
- docker rm my-app
-
# Second Docker Container Run with Different Config
# NOTE: We intentionally pass a "bad" license here. We need to ensure proxy starts and serves request even with bad license
- run:
@@ -1570,7 +719,7 @@ jobs:
name: Run second round of tests
command: |
mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/basic_proxy_startup_tests/**/test_*.py")
+ TEST_FILES=$(circleci tests glob "tests/integration/configuration/test_basic_proxy_startup.py")
echo "$TEST_FILES" | circleci tests run \
--verbose \
--command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
@@ -1582,385 +731,46 @@ jobs:
# Store test results
- store_test_results:
path: test-results
- proxy_multi_instance_tests:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - start_postgres
- - start_fake_openai_endpoint
- - attach_workspace:
- at: ~/project
- - run:
- name: Load Docker Database Image
- command: |
- zstd -d litellm-docker-database.tar.zst --stdout | docker load
- docker images | grep litellm-docker-database
- - run:
- name: Run Docker container 1
- # intentionally give bad redis credentials here
- # the OTEL test - should get this as a trace
- command: |
- docker run -d \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e REDIS_HOST=$REDIS_HOST \
- -e REDIS_PASSWORD=$REDIS_PASSWORD \
- -e REDIS_PORT=$REDIS_PORT \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e USE_DDTRACE=True \
- -e DD_API_KEY=$DD_API_KEY \
- -e DD_SITE=$DD_SITE \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/litellm/proxy/example_config_yaml/multi_instance_simple_config.yaml:/app/config.yaml \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Run Docker container 2
- command: |
- docker run -d \
- -p 4001:4001 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e REDIS_HOST=$REDIS_HOST \
- -e REDIS_PASSWORD=$REDIS_PASSWORD \
- -e REDIS_PORT=$REDIS_PORT \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e USE_DDTRACE=True \
- -e DD_API_KEY=$DD_API_KEY \
- -e DD_SITE=$DD_SITE \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app-2 \
- -v $(pwd)/litellm/proxy/example_config_yaml/multi_instance_simple_config.yaml:/app/config.yaml \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4001
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- - wait_for_service:
- url: http://localhost:4001
- timeout: "300"
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/multi_instance_e2e_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
- # Clean up first container
- # Store test results
- - store_test_results:
- path: test-results
-
- proxy_store_model_in_db_tests:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - start_postgres
- - start_fake_openai_endpoint
- - start_cost_center_service
- - attach_workspace:
- at: ~/project
- - run:
- name: Load Docker Database Image
- command: |
- zstd -d litellm-docker-database.tar.zst --stdout | docker load
- docker images | grep litellm-docker-database
- - run:
- name: Run Docker container
- # intentionally give bad redis credentials here
- # the OTEL test - should get this as a trace
- command: |
- docker run -d \
- --restart on-failure \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e STORE_MODEL_IN_DB="True" \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e FAKE_OPENAI_API_BASE=http://host.docker.internal:8190 \
- -e TEAM_METADATA_VALIDATION_SERVICE_URL=http://host.docker.internal:9414/validate \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/litellm/proxy/example_config_yaml/store_model_db_config.yaml:/app/config.yaml \
- -v $(pwd)/litellm/proxy/example_config_yaml/team_metadata_validator_e2e.py:/app/team_metadata_validator_e2e.py \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/store_model_in_db_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
- - run:
- name: Stop and remove containers
- command: |
- docker stop my-app || true
- docker rm my-app || true
- docker stop postgres-db || true
- docker rm postgres-db || true
- when: always
- - store_test_results:
- path: test-results
-
- proxy_pass_through_endpoint_tests:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - start_postgres
- - attach_workspace:
- at: ~/project
- - run:
- name: Load Docker Database Image
- command: |
- zstd -d litellm-docker-database.tar.zst --stdout | docker load
- docker images | grep litellm-docker-database
- - run:
- name: Run Docker container
- command: |
- docker run -d \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e OPENAI_API_KEY=$OPENAI_API_KEY \
- -e GEMINI_API_KEY=$GEMINI_API_KEY \
- -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
- -e ASSEMBLYAI_API_KEY=$ASSEMBLYAI_API_KEY \
- -e AZURE_API_KEY=$AZURE_API_KEY \
- -e AZURE_API_BASE=$AZURE_API_BASE \
- -e USE_DDTRACE=True \
- -e DD_API_KEY=$DD_API_KEY \
- -e DD_SITE=$DD_SITE \
- -e LITELLM_LICENSE=$LITELLM_LICENSE \
- -e LITELLM_USE_CHAT_COMPLETIONS_URL_FOR_ANTHROPIC_MESSAGES=true \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/litellm/proxy/example_config_yaml/pass_through_config.yaml:/app/config.yaml \
- -v $(pwd)/litellm/proxy/example_config_yaml/custom_auth_basic.py:/app/custom_auth_basic.py \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- # Install Node.js directly from nodejs.org with SHA256 verification,
- # instead of piping NodeSource's setup_24.x apt-repo installer into
- # sudo bash (which runs a mutable upstream script unattended).
- - install_node
-
- - run:
- name: Install Node.js test dependencies
- command: |
- cd tests/pass_through_tests
- npm ci
-
- - run:
- name: Run Vertex AI, Google AI Studio Node.js tests
- command: |
- cd tests/pass_through_tests
- NODE_OPTIONS=--experimental-vm-modules npx jest . --verbose
- no_output_timeout: 30m
- - run:
- name: Run tests
- command: |
- mkdir -p test-results
- TEST_FILES=$(circleci tests glob "tests/pass_through_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -v \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
-
- # Store test results
- - store_test_results:
- path: test-results
-
- proxy_e2e_anthropic_messages_tests:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes
- - setup_google_dns
- - install_uv
- - install_rust
- - run:
- name: Install Dependencies
- command: |
- uv sync --frozen --all-groups --all-extras --python 3.12
- - start_postgres
- - attach_workspace:
- at: ~/project
- - run:
- name: Load Docker Database Image
- command: |
- zstd -d litellm-docker-database.tar.zst --stdout | docker load
- docker images | grep litellm-docker-database
- - start_openai_record_replay_proxy
- - run:
- name: Run Docker container with test config
- command: |
- docker run -d \
- -p 4000:4000 \
- -e DATABASE_URL=postgresql://postgres:postgres@host.docker.internal:5432/circle_test \
- -e LITELLM_MASTER_KEY="$LITELLM_MASTER_KEY" \
- -e ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \
- -e RECORDER_ANTHROPIC_BASE_URL=http://host.docker.internal:8090/__recorder_upstream/api.anthropic.com \
- -e AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID \
- -e AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY \
- -e AWS_REGION_NAME="us-east-1" \
- -e LITELLM_LOCAL_ANTHROPIC_BETA_HEADERS="True" \
- -e LITELLM_LOG=ERROR \
- --add-host host.docker.internal:host-gateway \
- --name my-app \
- -v $(pwd)/tests/proxy_e2e_anthropic_messages_tests/test_config.yaml:/app/config.yaml \
- litellm-docker-database:ci \
- --config /app/config.yaml \
- --port 4000
- - run:
- name: Start outputting logs
- command: docker logs -f my-app
- background: true
- - wait_for_service:
- url: http://localhost:4000
- timeout: "300"
- - run:
- name: Run Claude Agent SDK E2E Tests
- command: |
- mkdir -p test-results
- export LITELLM_PROXY_URL="http://localhost:4000"
- export LITELLM_API_KEY="$LITELLM_MASTER_KEY"
- TEST_FILES=$(circleci tests glob "tests/proxy_e2e_anthropic_messages_tests/**/test_*.py")
- echo "$TEST_FILES" | circleci tests run \
- --verbose \
- --command="tr ' ' '\\n' | awk '/\\.py/ {print; next} {sub(/\\.[A-Z][^.]*$/, \"\"); gsub(/\\./, \"/\"); print \$0 \".py\"}' | xargs uv run --no-sync python -m pytest --tb=short \
- -vv -s \
- --junitxml=test-results/junit.xml \
- --durations=5"
- no_output_timeout: 15m
-
- # Store test results
- - store_test_results:
- path: test-results
-
- upload-coverage:
+ e2e_ui_build:
docker:
- - *python312_image
+ - image: cimg/python:3.12-browsers@sha256:b432899af01c9a311bf74f4f22e9ada2e5306d4b1b4383f8d29e1228a5844ef2
+ auth:
+ username: ${DOCKERHUB_USERNAME}
+ password: ${DOCKERHUB_PASSWORD}
+ resource_class: large
+ working_directory: ~/project
steps:
- checkout
- - skip_if_unrelated_changes
- - attach_workspace:
- at: .
- # Check file locations
+ - skip_if_unrelated_changes:
+ category: client
+ - setup_google_dns
+ - install_node
+ - restore_cache:
+ keys:
+ - ui-dashboard-node-deps-v1-{{ checksum "ui/litellm-dashboard/package-lock.json" }}
- run:
- name: Check coverage file location
+ name: Install dashboard dependencies
command: |
- echo "Current directory:"
- ls -la
- echo "\nContents of tests/llm_translation:"
- ls -la tests/llm_translation
- - install_uv
+ cd ui/litellm-dashboard
+ npm ci
+ - save_cache:
+ key: ui-dashboard-node-deps-v1-{{ checksum "ui/litellm-dashboard/package-lock.json" }}
+ paths:
+ - ui/litellm-dashboard/node_modules
- run:
- name: Combine Coverage
+ name: Build UI bundle
command: |
- uv tool run --from 'coverage[toml]==7.10.6' coverage combine realtime_translation_coverage ocr_coverage search_coverage logging_coverage audio_coverage pass_through_unit_tests_coverage batches_coverage google_generate_content_endpoint_coverage litellm_utils_coverage
- uv tool run --from 'coverage[toml]==7.10.6' coverage xml
- - codecov/upload:
- file: ./coverage.xml
- flags: circleci
+ cd ui/litellm-dashboard
+ npm run build
+ mkdir -p ../../ui-bundle
+ mv out ../../ui-bundle/out
+ find ../../ui-bundle/out -name '*.html' ! -name 'index.html' | while read -r f; do
+ d="${f%.html}"; mkdir -p "$d"; mv "$f" "$d/index.html"
+ done
+ - persist_to_workspace:
+ root: ~/project
+ paths:
+ - ui-bundle/out
e2e_ui_testing:
docker:
@@ -1973,7 +783,7 @@ jobs:
POSTGRES_USER: e2euser
POSTGRES_PASSWORD: e2epassword
POSTGRES_DB: litellm_e2e
- resource_class: large
+ resource_class: xlarge
working_directory: ~/project
environment:
DATABASE_URL: "postgresql://e2euser:e2epassword@localhost:5432/litellm_e2e"
@@ -1992,6 +802,8 @@ jobs:
printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- skip_if_unrelated_changes:
category: client
+ - attach_workspace:
+ at: ~/project
- setup_google_dns
- install_node
- install_uv
@@ -2010,7 +822,7 @@ jobs:
- ~/.cache/uv
- restore_cache:
keys:
- - ui-e2e-node-deps-v4-{{ checksum "ui/litellm-dashboard/package-lock.json" }}-{{ checksum "tests/e2e/ui/package-lock.json" }}
+ - ui-playwright-node-deps-v1-{{ checksum "tests/e2e/ui/package-lock.json" }}
- run:
name: Install Node dependencies and Playwright
# The cimg/python:3.12-browsers image already ships the Chromium system
@@ -2019,36 +831,19 @@ jobs:
# 5-10 minutes to the job and frequently stalls on flaky Ubuntu mirrors,
# so we install just the browser binary.
command: |
- cd ui/litellm-dashboard
- npm ci
- cd ../../tests/e2e/ui
+ cd tests/e2e/ui
npm ci
npx playwright install chromium
- save_cache:
- key: ui-e2e-node-deps-v4-{{ checksum "ui/litellm-dashboard/package-lock.json" }}-{{ checksum "tests/e2e/ui/package-lock.json" }}
+ key: ui-playwright-node-deps-v1-{{ checksum "tests/e2e/ui/package-lock.json" }}
paths:
- - ui/litellm-dashboard/node_modules
- tests/e2e/ui/node_modules
- ~/.cache/ms-playwright
- run:
- name: Build UI from source
- # Prior version used `cp -r out/ ../../litellm/proxy/_experimental/out/`.
- # GNU cp (used on CircleCI's Ubuntu image) interprets that as "copy the
- # source directory as a child of the destination" when the destination
- # already exists — silently creating `_experimental/out/out/` instead of
- # replacing the served bundle. The proxy continued serving whatever was
- # checked into `_experimental/out/*`, so this job was effectively testing
- # the pre-build bundle on every run. Replace-and-move guarantees the
- # freshly built bundle is what the proxy actually serves.
+ name: Use built UI bundle
command: |
- cd ui/litellm-dashboard
- npm run build
- rm -rf ../../litellm/proxy/_experimental/out
- mv out ../../litellm/proxy/_experimental/out
- # Restructure HTML so extensionless routes work (login.html -> login/index.html)
- find ../../litellm/proxy/_experimental/out -name '*.html' ! -name 'index.html' | while read -r f; do
- d="${f%.html}"; mkdir -p "$d"; mv "$f" "$d/index.html"
- done
+ rm -rf litellm/proxy/_experimental/out
+ cp -r ui-bundle/out litellm/proxy/_experimental/out
- wait_for_service:
url: tcp://localhost:5432
timeout: "30"
@@ -2115,7 +910,7 @@ jobs:
command: |
cd tests/e2e/ui
LITELLM_LICENSE="$LITELLM_LICENSE" \
- npx playwright test --config playwright.config.ts
+ npx playwright test --config playwright.config.ts --workers=3 --retries=0
no_output_timeout: 10m
- store_artifacts:
path: tests/e2e/ui/test-results
@@ -2153,6 +948,8 @@ jobs:
printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- skip_if_unrelated_changes:
category: client
+ - attach_workspace:
+ at: ~/project
- setup_google_dns
- install_node
- install_uv
@@ -2171,31 +968,23 @@ jobs:
- ~/.cache/uv
- restore_cache:
keys:
- - ui-e2e-node-deps-v4-{{ checksum "ui/litellm-dashboard/package-lock.json" }}-{{ checksum "tests/e2e/ui/package-lock.json" }}
+ - ui-playwright-node-deps-v1-{{ checksum "tests/e2e/ui/package-lock.json" }}
- run:
name: Install Node dependencies and Playwright
command: |
- cd ui/litellm-dashboard
- npm ci
- cd ../../tests/e2e/ui
+ cd tests/e2e/ui
npm ci
npx playwright install chromium
- save_cache:
- key: ui-e2e-node-deps-v4-{{ checksum "ui/litellm-dashboard/package-lock.json" }}-{{ checksum "tests/e2e/ui/package-lock.json" }}
+ key: ui-playwright-node-deps-v1-{{ checksum "tests/e2e/ui/package-lock.json" }}
paths:
- - ui/litellm-dashboard/node_modules
- tests/e2e/ui/node_modules
- ~/.cache/ms-playwright
- run:
- name: Build UI from source
+ name: Use built UI bundle
command: |
- cd ui/litellm-dashboard
- npm run build
- rm -rf ../../litellm/proxy/_experimental/out
- mv out ../../litellm/proxy/_experimental/out
- find ../../litellm/proxy/_experimental/out -name '*.html' ! -name 'index.html' | while read -r f; do
- d="${f%.html}"; mkdir -p "$d"; mv "$f" "$d/index.html"
- done
+ rm -rf litellm/proxy/_experimental/out
+ cp -r ui-bundle/out litellm/proxy/_experimental/out
- wait_for_service:
url: tcp://localhost:5432
timeout: "30"
@@ -2446,41 +1235,6 @@ jobs:
! docker exec my-app true 2>/dev/null || fail "container is still running"
echo "Proxy refused to serve (exit $exit_code) and never reached startup. Test passed."
- provider_replay_harness:
- docker:
- - *python312_image
- - image: redis@sha256:e2debfb7956fa12c7ddc79d7e645c8cf26b30c99a6e9161ea9bf4171e1668a5f
- working_directory: ~/project
- resource_class: medium
- environment:
- E2E_CACHE_TEST_REDIS_URL: redis://127.0.0.1:6379/0
- E2E_PROVIDER_CACHE: "0"
- E2E_FIXTURE_MODE: live
- steps:
- - checkout
- - run:
- name: Generate LiteLLM master key
- command: |
- key="$(openssl rand -hex 16)"
- printf 'export LITELLM_MASTER_KEY=sk-%s\n' "$key" >> "$BASH_ENV"
- - skip_if_unrelated_changes:
- category: provider-harness
- - setup_litellm_test_deps
- - wait_for_service:
- url: tcp://localhost:6379
- - run:
- name: Test provider capture and replay harness
- command: |
- mkdir -p test-results/provider-replay-harness
- uv run --no-sync pytest --tb=short -q --noconftest -o addopts= -o "pythonpath=tests/e2e tests/e2e_harness" -p no:rerunfailures \
- --junitxml=test-results/provider-replay-harness/junit.xml \
- tests/e2e_harness/test_provider_edge.py tests/e2e_harness/test_fixture_bundle.py \
- tests/e2e_harness/test_fixture_canonical.py tests/e2e_harness/test_fixture_mode.py \
- tests/code_coverage_tests/test_provider_replay_harness.py \
- tests/code_coverage_tests/test_provider_cache.py
- - store_test_results:
- path: test-results/provider-replay-harness
-
integration_contracts:
parameters:
suite:
@@ -2529,9 +1283,32 @@ jobs:
- run:
name: Build the candidate dashboard
command: cd ui/litellm-dashboard && NEXT_TELEMETRY_DISABLED=1 npm run build
+ - when:
+ condition:
+ equal: [mcp, << parameters.suite >>]
+ steps:
+ - run:
+ name: Install MCP SDK1 peer
+ command: |
+ uv venv --python 3.12 .venv-mcp-peer
+ uv pip install --python .venv-mcp-peer 'mcp==1.28.1' 'langchain-mcp-adapters==0.2.1'
+ echo "export MCP_TEST_PEER_PYTHON=$PWD/.venv-mcp-peer/bin/python" >> "$BASH_ENV"
+ - when:
+ condition:
+ equal: [sdk, << parameters.suite >>]
+ steps:
+ - run:
+ name: Install redis-server 7.2.16
+ command: |
+ mkdir -p /tmp/redis-bin
+ cid="$(docker create redis:7.2.16@sha256:0637954999d01b7c9ce9167db2da50656e2590d3b884f1c600c5f63bb6e6773c)"
+ docker cp "${cid}:/usr/local/bin/redis-server" /tmp/redis-bin/redis-server
+ docker rm "$cid"
+ /tmp/redis-bin/redis-server --version | grep -q 'v=7.2.16'
+ echo 'export PATH="/tmp/redis-bin:$PATH"' >> "$BASH_ENV"
- start_postgres:
image: postgres:16@sha256:e17e86066e5ef83e0952a9347f5c792b7ece00972e2aa787a6986f471b3dd3d5
- server_args: "-c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c pg_stat_statements.max=20000"
+ server_args: "-c max_connections=300 -c shared_preload_libraries=pg_stat_statements -c pg_stat_statements.track=all -c pg_stat_statements.max=20000"
- start_redis
- run:
name: Run owned integration contracts
@@ -2584,12 +1361,27 @@ jobs:
default: standard
shards:
type: integer
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: medium
+ docker:
+ - image: cimg/python:3.12@sha256:9c796c23c84e84a66a964acb508d39dc5433c81a47e07efd56dccbbc2427e07c
+ auth:
+ username: ${DOCKERHUB_USERNAME}
+ password: ${DOCKERHUB_PASSWORD}
+ resource_class: small
working_directory: ~/project
+ environment:
+ UV_PYTHON_DOWNLOADS: never
steps:
- - setup_litellm_test_deps
+ - checkout
+ - install_uv
+ - run:
+ name: Install the locked shard verifier and coverage dependencies
+ command: |
+ uv export --frozen --all-groups --all-extras --no-emit-project --no-emit-workspace --no-header --no-annotate \
+ | awk '/^[^ ]/ { keep = $0 ~ /^(annotated-types|coverage|pydantic|pydantic-core|typing-extensions|typing-inspection)==/ } keep' \
+ > /tmp/fan-in-requirements.txt
+ test "$(grep -c '^[^ ]' /tmp/fan-in-requirements.txt)" -eq 6
+ uv venv .venv --python 3.12
+ uv pip install --no-config --python .venv --require-hashes -r /tmp/fan-in-requirements.txt
- attach_workspace:
at: /tmp/integration-shards
- run:
@@ -2705,7 +1497,8 @@ jobs:
steps:
- checkout
- skip_if_unrelated_changes
- - setup_litellm_test_deps
+ - setup_litellm_test_deps:
+ checkout: false
- start_postgres:
db_name: litellm_test
image: postgres:16@sha256:e17e86066e5ef83e0952a9347f5c792b7ece00972e2aa787a6986f471b3dd3d5
@@ -2750,112 +1543,15 @@ jobs:
- store_artifacts:
path: test-results
- mcp_integration:
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- environment:
- COVERAGE_CORE: sysmon
- LITELLM_LOCAL_MODEL_COST_MAP: "True"
- steps:
- - checkout
- - skip_if_unrelated_changes
- - setup_litellm_test_deps
- - run:
- name: Generate Prisma client
- command: uv run --no-sync prisma generate --schema litellm/proxy/schema.prisma
- - run:
- name: Install MCP SDK1 peer
- command: |
- uv venv --python 3.12 .venv-mcp-peer
- uv pip install --python .venv-mcp-peer 'mcp==1.28.1' 'langchain-mcp-adapters==0.2.1'
- echo "export MCP_TEST_PEER_PYTHON=$PWD/.venv-mcp-peer/bin/python" >> "$BASH_ENV"
- - run:
- name: Run MCP integration tests
- command: |
- mkdir -p test-results
- env -u OPENAI_API_KEY -u ANTHROPIC_API_KEY \
- timeout --signal=TERM 20m uv run --no-sync pytest \
- tests/mcp_tests tests/unit/experimental_mcp_client tests/unit/proxy/_experimental/mcp_server \
- tests/unit/responses/mcp --tb=short -vv --maxfail=10 -n 2 --dist=loadscope --reruns 0 \
- --reruns-delay 1 --timeout=120 --rerun-except "from pytest-timeout" --durations=20 \
- --cov=./litellm --cov=./enterprise/litellm_enterprise --cov-report=xml:coverage.xml \
- --cov-config=pyproject.toml -o junit_family=xunit1 --junitxml=test-results/junit.xml
- - install_codecov_cli
- - run:
- name: Upload MCP integration coverage
- when: always
- command: |
- [ -f coverage.xml ] || { echo "no coverage.xml produced"; exit 1; }
- codecov upload-process --disable-search --fail-on-error -f coverage.xml \
- -F mcp-integration -C "$CIRCLE_SHA1" \
- -n "mcp-integration-${CIRCLE_BUILD_NUM}" --git-service github
- - store_test_results:
- path: test-results
- - store_artifacts:
- path: test-results
-
- redis_compat:
- parameters:
- redis_py:
- type: string
- machine:
- image: ubuntu-2204:2024.04.1
- resource_class: large
- working_directory: ~/project
- steps:
- - checkout
- - skip_if_unrelated_changes:
- category: redis-compat
- - setup_litellm_test_deps
- - run:
- name: Pin redis-py version
- command: |
- uv pip install "redis==<< parameters.redis_py >>"
- uv run --no-sync python -c "import redis; assert redis.__version__ == '<< parameters.redis_py >>', redis.__version__; print('redis-py', redis.__version__)"
- - run:
- name: Install redis-server 7.2.16
- command: |
- mkdir -p "$HOME/.local/bin"
- cid="$(docker create redis:7.2.16@sha256:0637954999d01b7c9ce9167db2da50656e2590d3b884f1c600c5f63bb6e6773c)"
- docker cp "${cid}":/usr/local/bin/redis-server "$HOME/.local/bin/redis-server"
- docker rm "$cid"
- redis-server --version | grep -q 'v=7.2.16'
- - run:
- name: Run Redis compatibility tests
- command: |
- mkdir -p test-results
- env -u CASSETTE_REDIS_URL -u AZURE_CLIENT_ID -u AZURE_CLIENT_SECRET -u AZURE_TENANT_ID \
- timeout --signal=TERM 15m uv run --no-sync pytest \
- tests/unit/test_redis.py tests/unit/caching/test_redis_connection_pool.py \
- tests/unit/caching/test_redis_cluster_cache.py tests/unit/caching/test_evicted_client_closer.py \
- tests/integration/sdk/test_redis_cluster_iam_auth.py::test_sync_cluster_authenticates_with_azure_credentials \
- tests/integration/sdk/test_redis_cluster_iam_auth.py::test_sync_cluster_authenticates_with_gcp_credentials \
- --tb=short -vv --reruns 2 --reruns-delay 1 --durations=20 --cov=./litellm \
- --cov-report=xml:coverage.xml -o junit_family=xunit1 --junitxml=test-results/junit.xml
- - when:
- condition:
- equal: ["5.3.1", << parameters.redis_py >>]
- steps:
- - install_codecov_cli
- - run:
- name: Upload Redis compatibility coverage
- when: always
- command: |
- [ -f coverage.xml ] || { echo "no coverage.xml produced"; exit 1; }
- codecov upload-process --disable-search --fail-on-error -f coverage.xml \
- -F redis-compat -C "$CIRCLE_SHA1" \
- -n "redis-compat-${CIRCLE_BUILD_NUM}" --git-service github
- - store_test_results:
- path: test-results
- - store_artifacts:
- path: test-results
-
workflows:
- migration_startup:
- when: << pipeline.parameters.run_migration_tests >>
- jobs: &migration_jobs
+ migration_startup_scheduled:
+ triggers:
+ - schedule:
+ cron: "17 0,6,12,18 * * *"
+ filters:
+ branches:
+ only: main
+ jobs:
- build_docker_database_image:
migration_qualification: true
- migration_startup_tests:
@@ -2880,33 +1576,11 @@ workflows:
suite: shaped
baseline: true
requires: [build_docker_database_image]
- migration_startup_scheduled:
- triggers:
- - schedule:
- cron: "17 0,6,12,18 * * *"
- filters:
- branches:
- only: main
- jobs: *migration_jobs
- routing_parity:
- when:
- not:
- equal: ["", << pipeline.parameters.routing_parity_base >>]
- jobs:
- - routing_parity:
- name: routing-parity-<< matrix.suite >>
- matrix:
- parameters:
- suite: [management, accounting, database, providers, extensions, cost, mcp]
integration:
- unless:
- or:
- - << pipeline.parameters.run_migration_tests >>
- - not:
- equal: ["", << pipeline.parameters.routing_parity_base >>]
jobs:
- integration_contracts:
name: integration-<< matrix.suite >>
+ filters: &integration_default_run not pipeline.parameters.run_migration_tests and pipeline.parameters.routing_parity_base == ""
matrix:
parameters:
suite: [sdk, cost, browser]
@@ -2916,185 +1590,178 @@ workflows:
suite: security
parallelism: 1
resource_class: xlarge
+ filters: *integration_default_run
- integration_contracts:
name: integration-management
suite: management
parallelism: 4
+ resource_class: xlarge
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-management-coverage
suite: management
shards: 4
requires: [integration-management]
+ filters: *integration_default_run
- integration_contracts:
name: integration-accounting
suite: accounting
parallelism: 4
+ resource_class: xlarge
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-accounting-coverage
suite: accounting
shards: 4
requires: [integration-accounting]
+ filters: *integration_default_run
- integration_contracts:
name: integration-providers
suite: providers
- parallelism: 8
+ parallelism: 4
+ resource_class: xlarge
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-providers-coverage
suite: providers
- shards: 8
+ shards: 4
requires:
- integration-providers
+ filters: *integration_default_run
- integration_contracts:
name: integration-database
suite: database
parallelism: 2
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-database-coverage
suite: database
shards: 2
requires: [integration-database]
+ filters: *integration_default_run
- integration_contracts:
name: integration-mcp
suite: mcp
- resource_class: xlarge
parallelism: 2
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-mcp-coverage
suite: mcp
shards: 2
requires:
- integration-mcp
+ filters: *integration_default_run
- integration_contracts:
name: integration-extensions
suite: extensions
parallelism: 8
+ resource_class: xlarge
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-extensions-coverage
suite: extensions
shards: 8
requires:
- integration-extensions
+ filters: *integration_default_run
- integration_contracts:
name: integration-management-replica
suite: management
mode: replica
parallelism: 4
+ resource_class: xlarge
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-management-replica-coverage
suite: management
mode: replica
shards: 4
requires: [integration-management-replica]
+ filters: *integration_default_run
- integration_contracts:
name: integration-database-replica
suite: database
mode: replica
parallelism: 2
+ filters: *integration_default_run
- integration_shard_coverage:
name: integration-database-replica-coverage
suite: database
mode: replica
shards: 2
requires: [integration-database-replica]
- - postgres_suite:
- name: proxy-behavior
- test_path: tests/proxy_behavior
- seed: true
- coverage_flag: lens-postgres
- timeout_minutes: 25
- - postgres_suite:
- name: proxy-security
- test_path: tests/proxy_security_tests
- seed: true
- timeout_minutes: 15
- - postgres_suite:
- name: schema-migration
- test_path: tests/proxy_migration_tests
- seed: false
- timeout_minutes: 20
- workers: 2
+ filters: *integration_default_run
- postgres_suite:
name: roi-database
test_path: tests/integration/database/test_roi_observed.py
seed: false
coverage_flag: roi-postgres
timeout_minutes: 10
- - mcp_integration:
- name: mcp-integration
- - redis_compat:
- name: redis-compat-<< matrix.redis_py >>
- matrix:
- parameters:
- redis_py:
- - "5.3.1"
- - "6.4.0"
- - "7.4.1"
- - "8.0.1"
- - windows_release_wheel
- - base_sdk_install
- build_and_test:
- unless:
- or:
- - << pipeline.parameters.run_migration_tests >>
- - not:
- equal: ["", << pipeline.parameters.routing_parity_base >>]
- jobs:
- - provider_replay_harness
- - auth_ui_unit_tests
- - build_docker_database_image
- - e2e_ui_testing
- - e2e_ui_testing_server_root_path
- - build_and_test:
- requires:
- - build_docker_database_image
- - e2e_openai_endpoints:
- requires:
- - build_docker_database_image
+ filters: *integration_default_run
+ - windows_release_wheel:
+ filters: *integration_default_run
+ - base_sdk_install:
+ filters: *integration_default_run
+ - build_docker_database_image:
+ filters: *integration_default_run
- proxy_logging_guardrails_model_info_tests:
requires:
- build_docker_database_image
- - proxy_multi_instance_tests:
- requires:
- - build_docker_database_image
- - proxy_store_model_in_db_tests:
- requires:
- - build_docker_database_image
- - proxy_pass_through_endpoint_tests:
- requires:
- - build_docker_database_image
- - proxy_e2e_anthropic_messages_tests:
- requires:
- - build_docker_database_image
- - llm_translation_testing
- - realtime_translation_testing
- - guardrails_testing
- - google_generate_content_endpoint_testing
- - ocr_testing
- - search_testing
- - batches_testing
- - litellm_utils_testing
- - pass_through_unit_testing
- - image_gen_testing
- - logging_testing
- - audio_testing
- - upload-coverage:
- requires:
- - realtime_translation_testing
- - google_generate_content_endpoint_testing
- - ocr_testing
- - search_testing
- - batches_testing
- - litellm_utils_testing
- - pass_through_unit_testing
- - image_gen_testing
- - logging_testing
- - audio_testing
+ filters: *integration_default_run
- db_migration_disable_update_check:
requires:
- build_docker_database_image
- - helm_chart_testing:
- requires:
- - build_docker_database_image
+ filters: *integration_default_run
- test_bad_database_url:
requires:
- build_docker_database_image
+ filters: *integration_default_run
+ - helm_chart_testing:
+ requires:
+ - build_docker_database_image
+ filters: *integration_default_run
+ - e2e_ui_build:
+ filters: *integration_default_run
+ - e2e_ui_testing:
+ requires: [e2e_ui_build]
+ filters: *integration_default_run
+ - e2e_ui_testing_server_root_path:
+ requires: [e2e_ui_build]
+ filters: *integration_default_run
+ - build_docker_database_image:
+ name: build_docker_database_image-migration
+ migration_qualification: true
+ filters: pipeline.parameters.run_migration_tests
+ - migration_startup_tests:
+ name: migration-startup
+ suite: startup
+ requires: [build_docker_database_image-migration]
+ filters: pipeline.parameters.run_migration_tests
+ - migration_startup_tests:
+ name: migration-recovery
+ suite: recovery
+ requires: [build_docker_database_image-migration]
+ filters: pipeline.parameters.run_migration_tests
+ - migration_startup_tests:
+ name: migration-legacy-and-pooling
+ suite: legacy
+ requires: [build_docker_database_image-migration]
+ filters: pipeline.parameters.run_migration_tests
+ - migration_startup_tests:
+ name: migration-upgrade
+ suite: upgrade
+ baseline: true
+ requires: [build_docker_database_image-migration]
+ filters: pipeline.parameters.run_migration_tests
+ - migration_startup_tests:
+ name: migration-upgrade-shaped
+ suite: shaped
+ baseline: true
+ requires: [build_docker_database_image-migration]
+ filters: pipeline.parameters.run_migration_tests
+ - routing_parity:
+ name: routing-parity-<< matrix.suite >>
+ matrix:
+ parameters:
+ suite: [management, accounting, database, providers, extensions, cost, mcp]
+ filters: pipeline.parameters.routing_parity_base != ""
diff --git a/.circleci/scripts/classify_changes.sh b/.circleci/scripts/classify_changes.sh
index 9fe2e99fb93..d2ab3478397 100755
--- a/.circleci/scripts/classify_changes.sh
+++ b/.circleci/scripts/classify_changes.sh
@@ -1,12 +1,11 @@
#!/usr/bin/env bash
set -uo pipefail
-category="${1:?usage: classify_changes.sh
-
+