diff --git a/.env.example b/.env.example index 306e279..f6639e2 100644 --- a/.env.example +++ b/.env.example @@ -1,5 +1,6 @@ # Central app config (non-secret defaults) APP_CONFIG_PATH=config/app.toml +APEX_COMPOSE_PROJECT_NAME=apex # Postgres (secret) DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/postgres diff --git a/Justfile b/Justfile index 15d2e86..911bf9c 100644 --- a/Justfile +++ b/Justfile @@ -18,15 +18,15 @@ rust_log_server := "info,rag_server=debug,rag_core=debug,tower_http=debug" # Start Postgres + Qdrant up: - docker compose -f {{compose_file}} up -d + docker compose -p ${APEX_COMPOSE_PROJECT_NAME:-apex} -f {{compose_file}} up -d # Stop services down: - docker compose -f {{compose_file}} down + docker compose -p ${APEX_COMPOSE_PROJECT_NAME:-apex} -f {{compose_file}} down # Stop services and remove volumes down-v: - docker compose -f {{compose_file}} down -v + docker compose -p ${APEX_COMPOSE_PROJECT_NAME:-apex} -f {{compose_file}} down -v # ── Build ───────────────────────────────────────────────────────────── @@ -52,29 +52,29 @@ unit-test: # Integration tests and API smoke against local Postgres + Qdrant. # Starts Docker infra first and then runs the repo's non-provider integration suites. integration-test: up - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-client --test client_tests -- --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-cli --test e2e -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test health -- --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test health -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test health_degraded -- --ignored --nocapture --test-threads=1 - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test ingest -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test search -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test e2e -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_conversations -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_ingest -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_lifecycle -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_retrieval -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-client --test client_tests -- --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-cli --test e2e -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test health -- --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test health -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test health_degraded -- --ignored --nocapture --test-threads=1 + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test ingest -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test search -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test e2e -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_conversations -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_ingest -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_lifecycle -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-core --test integration_retrieval -- --ignored --nocapture # Offline benchmark for routed agentic search. agentic-eval: up - CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test agentic_eval -- --ignored --nocapture --test-threads=1 + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_itest}} cargo test -p rag-server --test agentic_eval -- --ignored --nocapture --test-threads=1 # Optional provider/native smoke tests. # These require extra local setup such as PDFium, Tesseract, or live LLM credentials. smoke-test: up - CARGO_TARGET_DIR={{target_dir_smoke}} cargo test -p rag-core --test integration_pdf -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_smoke}} cargo test -p rag-core --test integration_chat -- --ignored --nocapture - CARGO_TARGET_DIR={{target_dir_smoke}} cargo test -p rag-core --test smoke_llm -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_smoke}} cargo test -p rag-core --test integration_pdf -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_smoke}} cargo test -p rag-core --test integration_chat -- --ignored --nocapture + APEX_COMPOSE_PROJECT_NAME=${APEX_COMPOSE_PROJECT_NAME:-apex} CARGO_TARGET_DIR={{target_dir_smoke}} cargo test -p rag-core --test smoke_llm -- --ignored --nocapture # ── Server ──────────────────────────────────────────────────────────── diff --git a/crates/rag-server/tests/health_degraded.rs b/crates/rag-server/tests/health_degraded.rs index 3a1e896..29a5445 100644 --- a/crates/rag-server/tests/health_degraded.rs +++ b/crates/rag-server/tests/health_degraded.rs @@ -5,8 +5,37 @@ mod common; +use std::path::PathBuf; + use test_support::spawn_app; +const DEFAULT_COMPOSE_PROJECT_NAME: &str = "apex"; + +fn compose_project_name() -> String { + std::env::var("APEX_COMPOSE_PROJECT_NAME") + .unwrap_or_else(|_| DEFAULT_COMPOSE_PROJECT_NAME.to_string()) +} + +fn workspace_root() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../..").canonicalize().expect("workspace root") +} + +fn docker_compose_service(action: &str, service: &str) { + let compose_file = workspace_root().join("docker-compose.yml"); + let _ = std::process::Command::new("docker") + .current_dir(workspace_root()) + .args([ + "compose", + "-p", + &compose_project_name(), + "-f", + compose_file.to_str().expect("compose file path"), + action, + service, + ]) + .status(); +} + /// GET /readiness returns 503 when a dependency is unreachable. #[tokio::test] #[ignore] // requires `just up`; stops and restarts Qdrant container @@ -14,13 +43,13 @@ async fn readiness_degrades_gracefully() { let (app, _state) = common::full_app().await; let server = spawn_app(app).await.expect("spawn"); - // Stop Qdrant container. - let _ = std::process::Command::new("docker").args(["compose", "stop", "qdrant"]).status(); + // Stop Qdrant container from the shared local compose project. + docker_compose_service("stop", "qdrant"); let resp = reqwest::get(format!("{}/readiness", server.base_url())).await.expect("request"); // Restart Qdrant so other tests aren't affected. - let _ = std::process::Command::new("docker").args(["compose", "start", "qdrant"]).status(); + docker_compose_service("start", "qdrant"); // Wait for Qdrant to become responsive again before returning, // so tests in other binaries aren't affected. diff --git a/docs/howto/testing.md b/docs/howto/testing.md index bc06131..7f5f9a9 100644 --- a/docs/howto/testing.md +++ b/docs/howto/testing.md @@ -88,6 +88,11 @@ This command starts local services first: just up ``` +`just up` uses a shared local Docker Compose project (`apex`) so multiple repo +worktrees reuse the same Postgres/Qdrant stack instead of racing for host ports. +The health-degraded integration test also targets this shared project when +stopping/starting Qdrant. + Then it runs the repo's integration targets, including: - `crates/rag-client/tests/client_tests.rs` @@ -364,7 +369,7 @@ Check services: ```bash just up -docker compose ps +docker compose -p apex ps ``` ### Ignored tests do not run