diff --git a/.github/workflows/agent-deployment-test.yaml b/.github/workflows/agent-deployment-test.yaml index cc043741..04ef48e1 100644 --- a/.github/workflows/agent-deployment-test.yaml +++ b/.github/workflows/agent-deployment-test.yaml @@ -59,6 +59,7 @@ jobs: agent: - { name: langgraph-react-agent, dir: agents/langgraph/react_agent } - { name: langgraph-hitl-agent, dir: agents/langgraph/human_in_the_loop } + - { name: crewai-websearch-agent, dir: agents/crewai/websearch_agent } env: API_KEY: ${{ vars.API_KEY }} BASE_URL: ${{ vars.BASE_URL }} diff --git a/.gitignore b/.gitignore index 9c9ca733..dab428e9 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ STATUS.md .e2e-workdir evals/evalhub_adapter/eval-*.yaml evals/evalhub_adapter/provider-*.json +results.xml diff --git a/agents/crewai/websearch_agent/Makefile b/agents/crewai/websearch_agent/Makefile index d609cd9d..820a7534 100644 --- a/agents/crewai/websearch_agent/Makefile +++ b/agents/crewai/websearch_agent/Makefile @@ -5,7 +5,7 @@ VALUES_FILE := values.yaml CONTAINER_CLI := $(shell command -v podman 2>/dev/null || command -v docker 2>/dev/null) MODEL ?= llama3.1:8b -.PHONY: init re-init env ollama llama-server run-app run-app-fresh run-cli build push build-openshift deploy undeploy test dry-run help +.PHONY: init re-init env ollama llama-server run-app run-app-fresh run-cli build push build-openshift deploy undeploy test test-integration dry-run help help: ## Show this help @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " %-12s %s\n", $$1, $$2}' @@ -168,4 +168,9 @@ undeploy: ## Remove deployment from cluster helm uninstall $(AGENT_NAME) test: ## Run tests - uv run --extra dev python -m pytest tests/ + uv run --extra dev python -m pytest tests/ --ignore=tests/integration + +test-integration: ## Run integration deployment test + PYTHONPATH=$$(git rev-parse --show-toplevel)/tests \ + uv run --extra dev python -m pytest tests/integration/test_deployment.py \ + -v --tb=long --junitxml=results.xml diff --git a/agents/crewai/websearch_agent/pyproject.toml b/agents/crewai/websearch_agent/pyproject.toml index 77796cb5..d671845c 100644 --- a/agents/crewai/websearch_agent/pyproject.toml +++ b/agents/crewai/websearch_agent/pyproject.toml @@ -17,6 +17,7 @@ dependencies = [ [project.optional-dependencies] dev = [ + "httpx>=0.27", "pytest>=9.0.2", ] tracing = [ diff --git a/agents/crewai/websearch_agent/tests/integration/__init__.py b/agents/crewai/websearch_agent/tests/integration/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/agents/crewai/websearch_agent/tests/integration/conftest.py b/agents/crewai/websearch_agent/tests/integration/conftest.py new file mode 100644 index 00000000..e1144084 --- /dev/null +++ b/agents/crewai/websearch_agent/tests/integration/conftest.py @@ -0,0 +1,2 @@ +# Re-export shared integration fixtures so pytest discovers them. +from integration.conftest import cluster_auth, repo_root # noqa: F401 diff --git a/agents/crewai/websearch_agent/tests/integration/test_deployment.py b/agents/crewai/websearch_agent/tests/integration/test_deployment.py new file mode 100644 index 00000000..564bd538 --- /dev/null +++ b/agents/crewai/websearch_agent/tests/integration/test_deployment.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +import logging +import os + +import pytest +from integration.utils import ( + MakeTargetError, + RouteNotFoundError, + get_route, + health_check, + load_agent_name, + run_make, +) + +logger = logging.getLogger(__name__) + +INTERNAL_REGISTRY = "image-registry.openshift-image-registry.svc:5000" + + +@pytest.fixture(scope="module") +def agent_dir(repo_root): + return repo_root / "agents" / "crewai" / "websearch_agent" + + +@pytest.fixture(scope="module") +def agent_name(agent_dir): + return load_agent_name(agent_dir) + + +def _write_env_file(agent_dir, container_image): + """Write a .env file so Makefile targets can source it.""" + missing = [v for v in ("BASE_URL", "MODEL_ID") if v not in os.environ] + if missing: + pytest.fail( + f"Missing required env vars: {', '.join(missing)}. " + "Set them in the CI workflow or export locally." + ) + env_path = agent_dir / ".env" + env_path.write_text( + f"API_KEY={os.environ.get('API_KEY', 'not-needed')}\n" + f"BASE_URL={os.environ['BASE_URL']}\n" + f"MODEL_ID={os.environ['MODEL_ID']}\n" + f"CONTAINER_IMAGE={container_image}\n" + ) + return env_path + + +@pytest.fixture(scope="module") +def deployed_agent(cluster_auth, agent_dir, agent_name): + namespace = cluster_auth["namespace"] + container_image = f"{INTERNAL_REGISTRY}/{namespace}/{agent_name}:latest" + env_path = _write_env_file(agent_dir, container_image) + + deployed = False + try: + logger.info("Building image on cluster via build-openshift...") + run_make("build-openshift", cwd=agent_dir, timeout=600) + + logger.info("Deploying to cluster...") + run_make("deploy", cwd=agent_dir, timeout=300) + deployed = True + + route_url = get_route(agent_name, namespace=namespace) + logger.info("Agent deployed at %s", route_url) + + yield route_url + + except (MakeTargetError, RouteNotFoundError) as exc: + pytest.fail(f"Deployment failed: {exc}") + + finally: + if deployed: + logger.info("Tearing down deployment...") + try: + run_make("undeploy", cwd=agent_dir, timeout=120) + except MakeTargetError: + logger.warning( + "Cleanup failed — manual undeploy may be needed", exc_info=True + ) + env_path.unlink(missing_ok=True) + + +@pytest.mark.integration +def test_health_endpoint(deployed_agent): + route_url = deployed_agent + result = health_check(f"{route_url}/health", retries=12, backoff=5.0) + + assert result["status"] == "healthy" + assert result["agent_initialized"] is True