From d78311a923d377c2facd9fbb570216c3b2d1f3c4 Mon Sep 17 00:00:00 2001 From: earayu Date: Mon, 27 Apr 2026 19:41:26 +0800 Subject: [PATCH] test(e2e-http): parametrize compose runner by VECTOR_DB_TYPE / GRAPH_DB_TYPE + 2-combo CI matrix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The compose runner ran a single fixed backend shape (Qdrant + PG-graph), so the HTTP E2E suite only proved one of the two production deployment shapes actually boots end-to-end. Connector-level swap correctness is covered by tests/integration/compat (matrixed in compat-test.yml), but that doesn't exercise the full FastAPI lifespan against the alternate backends. Changes: - runners/compose/up.sh: accept VECTOR_DB_TYPE (qdrant|pgvector) and GRAPH_DB_TYPE (postgresql|neo4j|nebula); validate, idempotently rewrite .env so the api container picks them up, activate matching --profile. Defaults preserve historical behavior (qdrant + postgresql). qdrant is always included in the service set because the api container's depends_on requires it healthy regardless of vector backend selection. - envs/docker.env.overrides: set PGVECTOR_DATABASE_URL to the same DSN as DATABASE_URL — required when VECTOR_DB_TYPE=pgvector, harmless when qdrant. - Makefile: add test-http-smoke-compose-{lite,full} shortcuts for the two shapes (Lite = pgvector + postgresql, Full = qdrant + neo4j). - .github/workflows/e2e-http-smoke.yml: convert e2e-http-smoke job to a fail-fast=false matrix over [lite, full]. Provider-aware job is unchanged (defaults), since LLM-provider coverage is orthogonal to graph backend choice and the matrix would double API-cost. --- .github/workflows/e2e-http-smoke.yml | 24 ++++++++++-- Makefile | 14 +++++++ envs/docker.env.overrides | 1 + tests/e2e_http/runners/compose/up.sh | 58 ++++++++++++++++++++++++++-- 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/.github/workflows/e2e-http-smoke.yml b/.github/workflows/e2e-http-smoke.yml index c36f0f61c..179ec04ed 100644 --- a/.github/workflows/e2e-http-smoke.yml +++ b/.github/workflows/e2e-http-smoke.yml @@ -15,6 +15,24 @@ jobs: timeout-minutes: 45 permissions: contents: read + strategy: + fail-fast: false + # Two deployment-shape combos. Connector-level "swap one DB" coverage + # already lives in compat-test.yml's matrix (Qdrant/pgvector, + # PG/Neo4j/Nebula); this matrix exists to prove the full HTTP stack + # boots and runs end-to-end under each shape. + matrix: + combo: + - name: lite + vector: pgvector + graph: postgresql + - name: full + vector: qdrant + graph: neo4j + name: e2e-http-smoke (${{ matrix.combo.name }}) + env: + VECTOR_DB_TYPE: ${{ matrix.combo.vector }} + GRAPH_DB_TYPE: ${{ matrix.combo.graph }} steps: - uses: actions/checkout@v4 @@ -53,7 +71,7 @@ jobs: if: failure() uses: actions/upload-artifact@v4 with: - name: e2e-http-bootstrap-artifacts + name: e2e-http-bootstrap-artifacts-${{ matrix.combo.name }} path: tests/e2e_http/bootstrap/.generated if-no-files-found: ignore # The bootstrap directory name starts with "." — actions/upload-artifact@v4 @@ -64,8 +82,8 @@ jobs: - name: Dump Compose diagnostics on failure if: failure() run: | - docker compose -f docker-compose.yml ps || true - docker compose -f docker-compose.yml logs --no-color api postgres redis qdrant es || true + docker compose --profile neo4j --profile nebula -f docker-compose.yml ps || true + docker compose --profile neo4j --profile nebula -f docker-compose.yml logs --no-color || true - name: Stop Compose stack if: always() diff --git a/Makefile b/Makefile index 6046f3d05..4f5bb85b2 100644 --- a/Makefile +++ b/Makefile @@ -51,6 +51,7 @@ help: @printf " make test-http-full Run full HTTP suite against an existing target\n" @printf " make test-http-up-compose / test-http-down-compose\n" @printf " make test-http-smoke-compose / test-http-full-compose\n" + @printf " make test-http-smoke-compose-lite / test-http-smoke-compose-full (DB-combo shortcuts)\n" @printf " make test-http-up-k8s / test-http-down-k8s\n" @printf " make test-http-smoke-k8s / test-http-full-k8s\n\n" @printf "Build / API\n" @@ -204,6 +205,7 @@ add-license: .PHONY: test-all test-unit test-integration test-e2e test-e2e-perf \ test-http-bootstrap test-http-smoke test-http-full \ test-http-up-compose test-http-down-compose test-http-smoke-compose test-http-full-compose \ + test-http-smoke-compose-lite test-http-smoke-compose-full \ test-http-up-k8s test-http-down-k8s test-http-smoke-k8s test-http-full-k8s test-all: test-unit test-integration test-e2e @@ -275,6 +277,18 @@ test-http-smoke-compose: test-http-full-compose: @./tests/e2e_http/scripts/run_compose_full.sh +# Backend-combo shortcuts. Lite = single-PG (pgvector + PG-graph) for the +# ApeRAG-Lite deployment; Full = Qdrant vector + Neo4j graph for the +# distributed deployment. Connector-level swap correctness is covered by +# tests/integration/compat/* (see test-compat-graph / test-compat-vector). +test-http-smoke-compose-lite: + @VECTOR_DB_TYPE=pgvector GRAPH_DB_TYPE=postgresql \ + ./tests/e2e_http/scripts/run_compose_smoke.sh + +test-http-smoke-compose-full: + @VECTOR_DB_TYPE=qdrant GRAPH_DB_TYPE=neo4j \ + ./tests/e2e_http/scripts/run_compose_smoke.sh + test-http-up-k8s: @./tests/e2e_http/runners/k8s/up.sh diff --git a/envs/docker.env.overrides b/envs/docker.env.overrides index 1d23d510e..9d79d15c8 100644 --- a/envs/docker.env.overrides +++ b/envs/docker.env.overrides @@ -8,6 +8,7 @@ NEBULA_USERNAME=root NEBULA_PASSWORD=nebula CELERY_BROKER_URL=redis://default:password@aperag-redis:6379/0 DATABASE_URL="postgresql://postgres:postgres@aperag-postgres:5432/postgres" +PGVECTOR_DATABASE_URL="postgresql://postgres:postgres@aperag-postgres:5432/postgres" VECTOR_DB_CONTEXT={"url":"http://aperag-qdrant", "port":6333, "distance":"Cosine", "timeout": 1000} ES_HOST=http://aperag-es:9200 MEMORY_REDIS_URL=redis://default:password@aperag-redis:6379 diff --git a/tests/e2e_http/runners/compose/up.sh b/tests/e2e_http/runners/compose/up.sh index cebe56869..c4d12b9db 100755 --- a/tests/e2e_http/runners/compose/up.sh +++ b/tests/e2e_http/runners/compose/up.sh @@ -5,19 +5,71 @@ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../../.." && pwd)" cd "${ROOT_DIR}" E2E_BASE_URL="${E2E_BASE_URL:-http://127.0.0.1:8000}" -E2E_COMPOSE_SERVICES="${E2E_COMPOSE_SERVICES:-postgres redis qdrant es api}" E2E_HEALTH_ATTEMPTS="${E2E_HEALTH_ATTEMPTS:-90}" E2E_HEALTH_SLEEP_SECONDS="${E2E_HEALTH_SLEEP_SECONDS:-2}" +# Backend selection. Defaults preserve historical behavior (Qdrant + PG-graph). +VECTOR_DB_TYPE="${VECTOR_DB_TYPE:-qdrant}" +GRAPH_DB_TYPE="${GRAPH_DB_TYPE:-postgresql}" + +case "${VECTOR_DB_TYPE}" in + qdrant|pgvector) ;; + *) + echo "VECTOR_DB_TYPE must be one of: qdrant, pgvector (got '${VECTOR_DB_TYPE}')" >&2 + exit 2 + ;; +esac + +case "${GRAPH_DB_TYPE}" in + postgresql|neo4j|nebula) ;; + *) + echo "GRAPH_DB_TYPE must be one of: postgresql, neo4j, nebula (got '${GRAPH_DB_TYPE}')" >&2 + exit 2 + ;; +esac + +# Always include qdrant in the service set: the api container's depends_on +# requires it healthy regardless of which vector backend is selected. Leaving +# qdrant idle in pgvector mode is cheap and avoids docker-compose surgery. +DEFAULT_SERVICES="postgres redis qdrant es api" +E2E_COMPOSE_SERVICES="${E2E_COMPOSE_SERVICES:-${DEFAULT_SERVICES}}" + +profile_flags=() +case "${GRAPH_DB_TYPE}" in + neo4j) profile_flags=(--profile neo4j) ;; + nebula) profile_flags=(--profile nebula) ;; +esac + if [[ ! -f "${ROOT_DIR}/.env" ]]; then cp "${ROOT_DIR}/envs/env.template" "${ROOT_DIR}/.env" fi -docker compose -f docker-compose.yml up -d --build ${E2E_COMPOSE_SERVICES} +# Idempotently set or append a KEY=VALUE in .env so the api container's +# env_file pickup reflects the selected backends. +update_env_var() { + local key="$1" + local value="$2" + local file="${ROOT_DIR}/.env" + if grep -qE "^${key}=" "${file}"; then + awk -v k="${key}" -v v="${value}" 'BEGIN{FS=OFS="="} $1==k{print k"="v; next} {print}' \ + "${file}" > "${file}.tmp" + mv "${file}.tmp" "${file}" + else + printf '\n%s=%s\n' "${key}" "${value}" >> "${file}" + fi +} + +update_env_var VECTOR_DB_TYPE "${VECTOR_DB_TYPE}" +update_env_var GRAPH_DB_TYPE "${GRAPH_DB_TYPE}" + +echo "Compose runner starting (vector=${VECTOR_DB_TYPE}, graph=${GRAPH_DB_TYPE}, profiles='${profile_flags[*]:-}')" + +# `${array[@]+"${array[@]}"}` is the set -u-safe expansion for an empty array. +docker compose ${profile_flags[@]+"${profile_flags[@]}"} -f docker-compose.yml up -d --build ${E2E_COMPOSE_SERVICES} for ((i = 1; i <= E2E_HEALTH_ATTEMPTS; i++)); do if curl --silent --show-error --fail "${E2E_BASE_URL}/health" >/dev/null; then - echo "Compose runner ready at ${E2E_BASE_URL}" + echo "Compose runner ready at ${E2E_BASE_URL} (vector=${VECTOR_DB_TYPE}, graph=${GRAPH_DB_TYPE})" exit 0 fi sleep "${E2E_HEALTH_SLEEP_SECONDS}"