Skip to content

Commit bdf5869

Browse files
mpk-droidclaude
andauthored
RHAIENG-4029: add tier-2 integration test for agentic RAG agent (#101)
* feat(agentic_rag): add tier-2 integration deployment test Add integration test that builds, deploys, and health-checks the LangGraph Agentic RAG agent on OpenShift. Unlike tier-1 agents, this test validates RAG-specific env vars (EMBEDDING_MODEL, VECTOR_STORE_ID, EMBEDDING_DIMENSION, VECTOR_STORE_PROVIDER) are present before attempting deployment, and writes them to .env so the Helm deploy target passes them through to the pod. Also fixes the `make test` target to ignore the integration directory, preventing import errors when running unit tests locally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: add env var comment and redact VECTOR_STORE_ID in integration logs Clarify why agent.yaml-optional vars are required in the integration test, and extend _REDACT_PATTERNS to cover VECTOR_STORE_ID which may contain connection strings with credentials. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit review feedback Validate EMBEDDING_DIMENSION as int before writing to .env, and add quoted-format redaction pattern for VECTOR_STORE_ID to cover Helm --set usage in deployment logs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: address teammate review feedback - Move helpers (_write_env_file, INTERNAL_REGISTRY) and fixtures (agent_dir, agent_name, deployed_agent) to conftest.py so the test file contains only test functions (andrewdonheiser) - Add broad `except Exception` fallback in deployed_agent fixture so unexpected errors surface clearly in CI (andrewdonheiser) - Wrap EMBEDDING_DIMENSION int() cast with try/except and pytest.fail for a clear error message (tarun-etikala) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address CodeRabbit review feedback - Use module import for shared fixtures to avoid F811 lint collision with fixture argument names - Move yield outside exception handlers so test assertion failures aren't masked as "deployment errors" Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: sort imports to satisfy ruff I001 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 84444c9 commit bdf5869

5 files changed

Lines changed: 119 additions & 1 deletion

File tree

agents/langgraph/agentic_rag/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ CONTAINER_CLI := $(shell command -v podman 2>/dev/null || command -v docker 2>/
66
MODEL ?= llama3.1:8b
77
OLLAMA_EMBEDDING_MODEL ?= embeddinggemma:latest
88

9-
.PHONY: init re-init env ollama llama-server run-app run-app-fresh run-cli load-docs build push build-openshift deploy undeploy test dry-run help
9+
.PHONY: init re-init env ollama llama-server run-app run-app-fresh run-cli load-docs build push build-openshift deploy undeploy test test-integration dry-run help
1010

1111
help: ## Show this help
1212
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-14s %s\n", $$1, $$2}'
@@ -184,3 +184,8 @@ undeploy: ## Remove deployment from cluster
184184

185185
test: ## Run unit tests
186186
uv run --extra dev python -m pytest tests/ --ignore=tests/integration --ignore=tests/behavioral $(PYTEST_ARGS)
187+
188+
test-integration: ## Run integration deployment test
189+
PYTHONPATH=$$(git rev-parse --show-toplevel)/tests \
190+
uv run --extra dev python -m pytest tests/integration/test_deployment.py \
191+
-v --tb=long --junitxml=results.xml

agents/langgraph/agentic_rag/tests/integration/__init__.py

Whitespace-only changes.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
from __future__ import annotations
2+
3+
import logging
4+
import os
5+
6+
import integration.conftest # noqa: F401 — re-exports cluster_auth, repo_root
7+
import pytest
8+
from integration.utils import (
9+
MakeTargetError,
10+
RouteNotFoundError,
11+
get_route,
12+
load_agent_name,
13+
run_make,
14+
)
15+
16+
logger = logging.getLogger(__name__)
17+
18+
INTERNAL_REGISTRY = "image-registry.openshift-image-registry.svc:5000"
19+
20+
# Optional per agent.yaml but required here to ensure RAG-capable deployment.
21+
_REQUIRED_ENV = ("BASE_URL", "MODEL_ID", "EMBEDDING_MODEL", "VECTOR_STORE_ID")
22+
23+
24+
@pytest.fixture(scope="module")
25+
def agent_dir(repo_root):
26+
return repo_root / "agents" / "langgraph" / "agentic_rag"
27+
28+
29+
@pytest.fixture(scope="module")
30+
def agent_name(agent_dir):
31+
return load_agent_name(agent_dir)
32+
33+
34+
def _write_env_file(agent_dir, container_image):
35+
"""Write a .env file with both base and RAG-specific env vars."""
36+
missing = [v for v in _REQUIRED_ENV if v not in os.environ]
37+
if missing:
38+
pytest.fail(
39+
f"Missing required env vars for tier-2 RAG agent: {', '.join(missing)}. "
40+
"Set them in the CI workflow or export locally."
41+
)
42+
43+
raw_dim = os.environ.get("EMBEDDING_DIMENSION", "768")
44+
try:
45+
embedding_dim = int(raw_dim)
46+
except ValueError:
47+
pytest.fail(f"EMBEDDING_DIMENSION must be an integer, got: {raw_dim!r}")
48+
49+
env_path = agent_dir / ".env"
50+
env_path.write_text(
51+
f"API_KEY={os.environ.get('API_KEY', 'not-needed')}\n"
52+
f"BASE_URL={os.environ['BASE_URL']}\n"
53+
f"MODEL_ID={os.environ['MODEL_ID']}\n"
54+
f"CONTAINER_IMAGE={container_image}\n"
55+
f"EMBEDDING_MODEL={os.environ['EMBEDDING_MODEL']}\n"
56+
f"EMBEDDING_DIMENSION={embedding_dim}\n"
57+
f"VECTOR_STORE_ID={os.environ['VECTOR_STORE_ID']}\n"
58+
f"VECTOR_STORE_PROVIDER={os.environ.get('VECTOR_STORE_PROVIDER', 'milvus')}\n"
59+
)
60+
return env_path
61+
62+
63+
@pytest.fixture(scope="module")
64+
def deployed_agent(cluster_auth, agent_dir, agent_name):
65+
namespace = cluster_auth["namespace"]
66+
container_image = f"{INTERNAL_REGISTRY}/{namespace}/{agent_name}:latest"
67+
env_path = _write_env_file(agent_dir, container_image)
68+
69+
deployed = False
70+
try:
71+
try:
72+
logger.info("Building image on cluster via build-openshift...")
73+
run_make("build-openshift", cwd=agent_dir, timeout=600)
74+
75+
logger.info("Deploying to cluster...")
76+
run_make("deploy", cwd=agent_dir, timeout=300)
77+
deployed = True
78+
79+
route_url = get_route(agent_name, namespace=namespace)
80+
logger.info("Agent deployed at %s", route_url)
81+
except (MakeTargetError, RouteNotFoundError) as exc:
82+
pytest.fail(f"Deployment failed: {exc}")
83+
except Exception as exc:
84+
pytest.fail(f"Unexpected error during deployment setup: {exc}")
85+
86+
yield route_url
87+
88+
finally:
89+
if deployed:
90+
logger.info("Tearing down deployment...")
91+
try:
92+
run_make("undeploy", cwd=agent_dir, timeout=120)
93+
except MakeTargetError:
94+
logger.warning(
95+
"Cleanup failed — manual undeploy may be needed", exc_info=True
96+
)
97+
env_path.unlink(missing_ok=True)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from __future__ import annotations
2+
3+
import pytest
4+
from integration.utils import health_check
5+
6+
7+
@pytest.mark.integration
8+
def test_health_endpoint(deployed_agent):
9+
route_url = deployed_agent
10+
result = health_check(f"{route_url}/health", retries=12, backoff=5.0)
11+
12+
assert result["status"] == "healthy"
13+
assert result["agent_initialized"] is True

tests/integration/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ def load_agent_name(agent_dir: str | Path) -> str:
2525
re.compile(r'(apiKey:\s*")[^"]*"'),
2626
re.compile(r'(--set\s+secrets\.apiKey=")[^"]*"'),
2727
re.compile(r"(--set\s+secrets\.apiKey=)\S+"),
28+
re.compile(r"(VECTOR_STORE_ID=)\S+"),
29+
re.compile(r'(--set\s+env\.VECTOR_STORE_ID=")[^"]*"'),
30+
re.compile(r"(--set\s+env\.VECTOR_STORE_ID=)\S+"),
2831
]
2932

3033

0 commit comments

Comments
 (0)