Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 0 additions & 14 deletions .github/workflows/cicd-pull-request.yml

This file was deleted.

20 changes: 20 additions & 0 deletions .github/workflows/e2e-http-lite.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: E2E HTTP Lite

# ApeRAG-Lite deployment shape: pgvector + PG-graph (single-PG).
# Runs the smoke + provider-aware HTTP suite against this shape.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read

jobs:
e2e-http-compose:
if: ${{ !github.event.pull_request.draft }}
uses: ./.github/workflows/e2e-http-shape.yml
secrets: inherit
with:
shape: lite
20 changes: 20 additions & 0 deletions .github/workflows/e2e-http-qdrant-nebula.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: E2E HTTP Qdrant + Nebula

# Distributed deployment shape: Qdrant (vector) + Nebula (graph).
# Runs the smoke + provider-aware HTTP suite against this shape.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read

jobs:
e2e-http-compose:
if: ${{ !github.event.pull_request.draft }}
uses: ./.github/workflows/e2e-http-shape.yml
secrets: inherit
with:
shape: qdrant-nebula
20 changes: 20 additions & 0 deletions .github/workflows/e2e-http-qdrant-neo4j.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: E2E HTTP Qdrant + Neo4j

# Distributed deployment shape: Qdrant (vector) + Neo4j (graph).
# Runs the smoke + provider-aware HTTP suite against this shape.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
workflow_dispatch:

permissions:
contents: read

jobs:
e2e-http-compose:
if: ${{ !github.event.pull_request.draft }}
uses: ./.github/workflows/e2e-http-shape.yml
secrets: inherit
with:
shape: qdrant-neo4j
Original file line number Diff line number Diff line change
@@ -1,38 +1,33 @@
name: E2E HTTP
name: E2E HTTP (shape)

# Reusable workflow that runs the HTTP E2E suite (smoke + provider-aware)
# against a single deployment SHAPE. Top-level callers (e2e-http-lite.yml,
# e2e-http-full.yml) bind the shape so each shape produces its own status
# check, and adding a new shape is a one-line caller file.

on:
workflow_call:
# ``workflow_dispatch`` lets a diagnostic task fire the full suite against
# the current ref without opening a dummy PR. See task #11: after Phase A
# (log preservation) merges, Phase B (causation verdict) may need to
# replay the provider-aware suite on demand rather than waiting for a
# natural PR failure.
inputs:
shape:
description: "Deployment shape name (must match tests/e2e_http/shapes/<shape>.env)"
required: true
type: string
workflow_dispatch:
inputs:
shape:
description: "Deployment shape name (must match tests/e2e_http/shapes/<shape>.env)"
required: true
type: string
default: lite

jobs:
e2e-http-smoke:
runs-on: ubuntu-latest
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 }}
SHAPE: ${{ inputs.shape }}
steps:
- uses: actions/checkout@v4

Expand Down Expand Up @@ -71,7 +66,7 @@ jobs:
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e-http-bootstrap-artifacts-${{ matrix.combo.name }}
name: e2e-http-bootstrap-artifacts-${{ inputs.shape }}-smoke
path: tests/e2e_http/bootstrap/.generated
if-no-files-found: ignore
# The bootstrap directory name starts with "." — actions/upload-artifact@v4
Expand Down Expand Up @@ -122,6 +117,7 @@ jobs:
permissions:
contents: read
env:
SHAPE: ${{ inputs.shape }}
E2E_ALIBABACLOUD_API_KEY: ${{ secrets.E2E_ALIBABACLOUD_API_KEY }}
E2E_OPENROUTER_API_KEY: ${{ secrets.E2E_OPENROUTER_API_KEY }}
steps:
Expand Down Expand Up @@ -162,7 +158,7 @@ jobs:
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e-http-provider-bootstrap-artifacts
name: e2e-http-bootstrap-artifacts-${{ inputs.shape }}-provider
path: tests/e2e_http/bootstrap/.generated
if-no-files-found: ignore
include-hidden-files: true
Expand All @@ -176,7 +172,7 @@ jobs:
if: failure()
uses: actions/upload-artifact@v4
with:
name: e2e-http-provider-diagnostic-artifacts
name: e2e-http-provider-diagnostic-artifacts-${{ inputs.shape }}
path: tests/e2e_http/.diagnostic-artifacts
if-no-files-found: ignore
# ``.diagnostic-artifacts`` starts with a dot (hidden). v4 default skips
Expand All @@ -187,8 +183,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()
Expand Down
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +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-smoke-compose-{lite,qdrant-neo4j,qdrant-nebula} (per-shape 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"
Expand Down Expand Up @@ -205,7 +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-smoke-compose-lite test-http-smoke-compose-qdrant-neo4j test-http-smoke-compose-qdrant-nebula \
test-http-up-k8s test-http-down-k8s test-http-smoke-k8s test-http-full-k8s
test-all: test-unit test-integration test-e2e

Expand Down Expand Up @@ -286,8 +286,11 @@ test-http-full-compose:
test-http-smoke-compose-lite:
@SHAPE=lite ./tests/e2e_http/scripts/run_compose_smoke.sh

test-http-smoke-compose-full:
@SHAPE=full-neo4j ./tests/e2e_http/scripts/run_compose_smoke.sh
test-http-smoke-compose-qdrant-neo4j:
@SHAPE=qdrant-neo4j ./tests/e2e_http/scripts/run_compose_smoke.sh

test-http-smoke-compose-qdrant-nebula:
@SHAPE=qdrant-nebula ./tests/e2e_http/scripts/run_compose_smoke.sh

test-http-up-k8s:
@./tests/e2e_http/runners/k8s/up.sh
Expand Down
13 changes: 8 additions & 5 deletions tests/e2e_http/runners/compose/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ This runner is intentionally replaceable. The suite must remain runnable against
ApeRAG supports several real production deployment forms — different choices of vector backend (Qdrant or pgvector) and graph backend (PostgreSQL, Neo4j, or Nebula). Each named combination is a *shape*.

```
SHAPE=lite ./tests/e2e_http/runners/compose/up.sh
SHAPE=full-neo4j ./tests/e2e_http/runners/compose/up.sh
SHAPE=lite ./tests/e2e_http/runners/compose/up.sh
SHAPE=qdrant-neo4j ./tests/e2e_http/runners/compose/up.sh
SHAPE=qdrant-nebula ./tests/e2e_http/runners/compose/up.sh
```

Each shape file under `tests/e2e_http/shapes/<shape>.env` declares:
Expand All @@ -37,9 +38,11 @@ Adding a new shape = adding one new file. The runner / Makefile / CI all referen

### Available shapes (today)

- **lite** — single-PG ApeRAG-Lite: pgvector + PG-graph, no qdrant/neo4j containers
- **full-neo4j** — distributed: Qdrant + Neo4j
- **full-nebula** — distributed: Qdrant + Nebula
Shapes are named `<vector>-<graph>`, with **lite** as the special name for the single-PG (pgvector + PG-graph) ApeRAG-Lite deployment:

- **lite** — single-PG ApeRAG-Lite: pgvector + PG-graph, no qdrant/neo4j/nebula containers
- **qdrant-neo4j** — distributed: Qdrant + Neo4j
- **qdrant-nebula** — distributed: Qdrant + Nebula

### Backward compatibility

Expand Down
9 changes: 0 additions & 9 deletions tests/e2e_http/shapes/full-nebula.env

This file was deleted.

8 changes: 8 additions & 0 deletions tests/e2e_http/shapes/qdrant-nebula.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# SHAPE: qdrant-nebula — distributed deployment with Qdrant + Nebula.
#
# Same as qdrant-neo4j but with Nebula as the graph backend (activated
# via the "nebula" compose profile).
SHAPE_VECTOR_DB_TYPE=qdrant
SHAPE_GRAPH_DB_TYPE=nebula
SHAPE_COMPOSE_SERVICES="postgres redis es qdrant api"
SHAPE_COMPOSE_PROFILES="--profile nebula"
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SHAPE: full-neo4j — distributed deployment with Qdrant + Neo4j.
# SHAPE: qdrant-neo4j — distributed deployment with Qdrant + Neo4j.
#
# Postgres holds relational data only. Vector data lives in Qdrant.
# Graph data lives in Neo4j (activated via the "neo4j" compose profile).
Expand Down
22 changes: 19 additions & 3 deletions tests/unit_test/test_e2e_http_workflow_contract.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import re
from pathlib import Path

WORKFLOW_PATH = Path(".github/workflows/e2e-http-smoke.yml")
# After PR splitting the suite by deployment shape, the per-shape logic
# (smoke + provider-preflight + provider-aware) lives in the reusable
# `e2e-http-shape.yml` and per-shape callers (e2e-http-lite.yml etc.)
# bind it via workflow_call.
SHAPE_WORKFLOW_PATH = Path(".github/workflows/e2e-http-shape.yml")
SHAPE_CALLER_PATHS = [
Path(".github/workflows/e2e-http-lite.yml"),
Path(".github/workflows/e2e-http-qdrant-neo4j.yml"),
Path(".github/workflows/e2e-http-qdrant-nebula.yml"),
]


def _job_section(workflow_text: str, job_name: str) -> str:
Expand All @@ -14,8 +23,8 @@ def _job_section(workflow_text: str, job_name: str) -> str:
return match.group("body")


def test_e2e_http_workflow_splits_binding_smoke_from_provider_suite():
workflow_text = WORKFLOW_PATH.read_text()
def test_e2e_http_shape_workflow_splits_smoke_from_provider_suite():
workflow_text = SHAPE_WORKFLOW_PATH.read_text()

smoke_job = _job_section(workflow_text, "e2e-http-smoke")
provider_job = _job_section(workflow_text, "e2e-http-provider")
Expand All @@ -26,3 +35,10 @@ def test_e2e_http_workflow_splits_binding_smoke_from_provider_suite():
assert "provider-preflight" in workflow_text
assert "needs.provider-preflight.outputs.available == 'true'" in provider_job
assert "run_full.sh" in provider_job


def test_each_shape_caller_invokes_shape_workflow_with_a_shape_input():
for caller in SHAPE_CALLER_PATHS:
text = caller.read_text()
assert "uses: ./.github/workflows/e2e-http-shape.yml" in text, f"{caller} must invoke the shared shape workflow"
assert re.search(r"^\s+shape:\s+\S+", text, flags=re.MULTILINE), f"{caller} must pass a `shape` input"
Loading