refactored: to utilise the google adk and production grade agent
Some checks failed
validation / verify (push) Failing after 10s
Some checks failed
validation / verify (push) Failing after 10s
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
212
tests/test_adk_architecture.py
Normal file
212
tests/test_adk_architecture.py
Normal file
@@ -0,0 +1,212 @@
|
||||
"""Comprehensive test suite for Google ADK Multi-Agent Architecture & PostgreSQL Persistence."""
|
||||
|
||||
import pytest
|
||||
import uuid
|
||||
from starlette.testclient import TestClient
|
||||
|
||||
from app.adk.agents import (
|
||||
DiscoveryAgent,
|
||||
ArchitectureDesignAgent,
|
||||
ValidationReviewAgent,
|
||||
PackagingAgent,
|
||||
OrchestratorLoopAgent,
|
||||
build_adk_multi_agent_system,
|
||||
)
|
||||
from app.adk.artifacts import PostgresArtifactRepository
|
||||
from app.adk.evaluation import ADKEvaluator
|
||||
from app.adk.runners import ADKAgentRunner
|
||||
from app.adk.sessions import PostgresSessionService
|
||||
from app.adk.tools import ADK_TOOLS
|
||||
from app.adk.workflows import create_gcp_adk_workflow
|
||||
from app.agent import app
|
||||
from app.config import get_settings
|
||||
from app.database import get_db_manager
|
||||
from app.skills.loader import SkillLoader
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def skill_loader():
|
||||
settings = get_settings()
|
||||
loader = SkillLoader(settings.SKILLS_DIR)
|
||||
loader.load_skills()
|
||||
return loader
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
return TestClient(app)
|
||||
|
||||
|
||||
def test_database_manager_operations():
|
||||
"""Verify PostgreSQL database manager schema initialization & CRUD operations."""
|
||||
db = get_db_manager()
|
||||
session_id = f"test-sess-{uuid.uuid4()}"
|
||||
execution_id = f"test-exec-{uuid.uuid4()}"
|
||||
|
||||
# 1. Save and retrieve session
|
||||
saved = db.save_session(session_id, "TestAgent", {"key": "value"})
|
||||
assert saved is True
|
||||
|
||||
session_data = db.get_session(session_id)
|
||||
assert session_data is not None
|
||||
assert session_data["agent_name"] == "TestAgent"
|
||||
assert session_data["state_data"]["key"] == "value"
|
||||
|
||||
# 2. Save workflow execution
|
||||
saved_exec = db.save_workflow_execution(
|
||||
execution_id=execution_id,
|
||||
session_id=session_id,
|
||||
status="completed",
|
||||
current_phase="package",
|
||||
loop_count=1,
|
||||
request_summary="Unit test workflow request",
|
||||
results={"passed": True},
|
||||
)
|
||||
assert saved_exec is True
|
||||
|
||||
# 3. Save artifact
|
||||
art_saved = db.save_artifact(
|
||||
artifact_id=f"art-{uuid.uuid4()}",
|
||||
execution_id=execution_id,
|
||||
artifact_type="markdown",
|
||||
file_path="docs/test.md",
|
||||
content="# Test Content",
|
||||
)
|
||||
assert art_saved is True
|
||||
|
||||
# 4. Record review log
|
||||
log_saved = db.record_orchestrator_log(
|
||||
log_id=f"log-{uuid.uuid4()}",
|
||||
execution_id=execution_id,
|
||||
iteration=1,
|
||||
review_status="APPROVED",
|
||||
reviewer_agent="ValidationReviewAgent",
|
||||
feedback="Passed all checks",
|
||||
)
|
||||
assert log_saved is True
|
||||
|
||||
|
||||
def test_adk_tools():
|
||||
"""Verify google.adk.tools wrappers."""
|
||||
assert len(ADK_TOOLS) == 6
|
||||
tool_names = [t.name for t in ADK_TOOLS]
|
||||
assert "validate_mermaid_diagram" in tool_names
|
||||
assert "validate_terraform_syntax" in tool_names
|
||||
assert "validate_repository_artifacts" in tool_names
|
||||
assert "developerknowledge_search_documents" in tool_names
|
||||
assert "developerknowledge_get_documents" in tool_names
|
||||
assert "developerknowledge_answer_query" in tool_names
|
||||
|
||||
|
||||
def test_adk_postgres_session_service():
|
||||
"""Verify PostgresSessionService creating, getting, and saving session state."""
|
||||
session_service = PostgresSessionService()
|
||||
session_id = f"adk-session-{uuid.uuid4()}"
|
||||
|
||||
sess = session_service.create_session("GCP_ADK_Agent", session_id=session_id)
|
||||
assert sess.session_id == session_id
|
||||
assert sess.agent_name == "GCP_ADK_Agent"
|
||||
|
||||
sess.state["counter"] = 42
|
||||
saved = session_service.save_session(sess)
|
||||
assert saved is True
|
||||
|
||||
fetched = session_service.get_session(session_id)
|
||||
assert fetched is not None
|
||||
assert fetched.state.get("counter") == 42
|
||||
|
||||
|
||||
def test_adk_orchestrator_loop_agent(skill_loader):
|
||||
"""Verify OrchestratorLoopAgent multi-agent loop review cycle."""
|
||||
orchestrator = build_adk_multi_agent_system(skill_loader, max_iterations=3)
|
||||
assert orchestrator.name == "OrchestratorLoopAgent"
|
||||
assert orchestrator.max_iterations == 3
|
||||
|
||||
initial_state = {
|
||||
"execution_id": str(uuid.uuid4()),
|
||||
"workflow_request": "Event-driven regional HTTP application",
|
||||
"target_dir": ".",
|
||||
"active_skills": [],
|
||||
}
|
||||
|
||||
final_state = orchestrator.execute(initial_state)
|
||||
assert final_state.get("validation_passed") is True
|
||||
assert final_state.get("loop_completed_successfully") is True
|
||||
assert len(final_state.get("active_skills", [])) == 5
|
||||
|
||||
|
||||
def test_adk_workflow_composition(skill_loader):
|
||||
"""Verify google.adk.workflows Workflow composition."""
|
||||
workflow = create_gcp_adk_workflow(skill_loader, max_iterations=2)
|
||||
assert workflow.name == "GCP_Solution_Architecture_Workflow"
|
||||
assert len(workflow.steps) == 1
|
||||
|
||||
initial_state = {
|
||||
"execution_id": str(uuid.uuid4()),
|
||||
"workflow_request": "Event-driven architecture test",
|
||||
"target_dir": ".",
|
||||
"active_skills": [],
|
||||
}
|
||||
|
||||
result = workflow.execute(initial_state)
|
||||
assert result.get("validation_passed") is True
|
||||
|
||||
|
||||
def test_adk_agent_runner():
|
||||
"""Verify ADKAgentRunner execution and artifact persistence."""
|
||||
runner = ADKAgentRunner()
|
||||
session_id = f"runner-session-{uuid.uuid4()}"
|
||||
|
||||
res = runner.run_execution(
|
||||
session_id=session_id,
|
||||
request_summary="High scale ingestion workflow",
|
||||
target_dir=".",
|
||||
)
|
||||
|
||||
assert res["status"] == "success"
|
||||
assert res["validation_passed"] is True
|
||||
assert "solution_guide" in res["artifacts"]
|
||||
|
||||
# Verify session persists in Postgres DB
|
||||
session_service = PostgresSessionService()
|
||||
sess = session_service.get_session(session_id)
|
||||
assert sess is not None
|
||||
|
||||
|
||||
def test_adk_evaluator():
|
||||
"""Verify ADKEvaluator executing benchmark cases."""
|
||||
evaluator = ADKEvaluator()
|
||||
case = {
|
||||
"id": "case-test",
|
||||
"workflow_request": "Event-driven regional HTTP application",
|
||||
"rubric": {
|
||||
"required_products": ["Cloud Run", "Pub/Sub", "Cloud Storage"],
|
||||
"requires_mermaid": True,
|
||||
"requires_terraform": True,
|
||||
"requires_guide_sections": ["Functional requirements", "Selected products"],
|
||||
},
|
||||
}
|
||||
|
||||
res = evaluator.evaluate_benchmark_case(case)
|
||||
assert res["passed"] is True
|
||||
assert res["percentage"] >= 80.0
|
||||
|
||||
|
||||
def test_starlette_session_api_endpoint(client):
|
||||
"""Verify Starlette API GET /sessions/{session_id} route."""
|
||||
session_id = f"api-sess-{uuid.uuid4()}"
|
||||
|
||||
# First run workflow to populate session
|
||||
payload = {
|
||||
"session_id": session_id,
|
||||
"request": "Test session retrieval route",
|
||||
}
|
||||
gen_resp = client.post("/generate", json=payload)
|
||||
assert gen_resp.status_code == 200
|
||||
|
||||
# Query session
|
||||
sess_resp = client.get(f"/sessions/{session_id}")
|
||||
assert sess_resp.status_code == 200
|
||||
sess_data = sess_resp.json()
|
||||
assert sess_data["session_id"] == session_id
|
||||
assert sess_data["agent_name"] == "OrchestratorLoopAgent"
|
||||
@@ -5,19 +5,36 @@ import unittest
|
||||
ROOT = pathlib.Path(__file__).parents[1]
|
||||
|
||||
|
||||
def get_artifact_text(filename):
|
||||
search_dirs = [
|
||||
ROOT / "deliverables" / "as-is",
|
||||
ROOT / "deliverables" / "target",
|
||||
ROOT / "deliverables" / "validation",
|
||||
ROOT / "deliverables" / "guides",
|
||||
ROOT / "deliverables",
|
||||
ROOT / "docs",
|
||||
ROOT,
|
||||
]
|
||||
for d in search_dirs:
|
||||
candidate = d / filename
|
||||
if candidate.is_file():
|
||||
return candidate.read_text(encoding="utf-8")
|
||||
raise FileNotFoundError(f"Artifact {filename} not found")
|
||||
|
||||
|
||||
class ArtifactTests(unittest.TestCase):
|
||||
def test_requirements_defer_products(self):
|
||||
text = (ROOT / "docs/requirements.md").read_text()
|
||||
text = get_artifact_text("requirements.md")
|
||||
self.assertIn("Product selection deferred:", text)
|
||||
self.assertIn("Open questions", text)
|
||||
|
||||
def test_architecture_has_products_and_flow(self):
|
||||
text = (ROOT / "docs/architecture.md").read_text()
|
||||
text = get_artifact_text("architecture.md")
|
||||
for product in ("Cloud Run", "Pub/Sub", "Cloud Storage", "Firestore"):
|
||||
self.assertIn(product, text)
|
||||
|
||||
def test_mermaid_is_flowchart(self):
|
||||
text = (ROOT / "architecture.mmd").read_text()
|
||||
text = get_artifact_text("architecture.mmd")
|
||||
self.assertTrue(text.startswith("flowchart"))
|
||||
self.assertIn("Cloud Run", text)
|
||||
|
||||
@@ -28,7 +45,7 @@ class ArtifactTests(unittest.TestCase):
|
||||
self.assertNotRegex(main, r"(?i)(password|secret|private_key)\\s*=")
|
||||
|
||||
def test_guide_packages_outputs(self):
|
||||
guide = (ROOT / "solution-architecture-guide.md").read_text()
|
||||
guide = get_artifact_text("solution-architecture-guide.md")
|
||||
for heading in ("Requirements", "Architecture", "Terraform", "Validation", "Verification"):
|
||||
self.assertIn(heading, guide)
|
||||
|
||||
|
||||
@@ -22,6 +22,8 @@ def test_agent_graph_execution():
|
||||
final_state = agent.invoke(initial_state)
|
||||
|
||||
assert final_state.get("current_phase") == "package"
|
||||
assert final_state.get("source_discovery_doc") is not None
|
||||
assert final_state.get("source_mermaid_diagram") is not None
|
||||
assert final_state.get("requirements_doc") is not None
|
||||
assert final_state.get("architecture_doc") is not None
|
||||
assert final_state.get("mermaid_diagram") is not None
|
||||
@@ -29,4 +31,4 @@ def test_agent_graph_execution():
|
||||
assert final_state.get("validation_results") is not None
|
||||
assert final_state.get("solution_guide") is not None
|
||||
assert final_state.get("validation_passed") is True
|
||||
assert len(final_state.get("active_skills", [])) == 4
|
||||
assert len(final_state.get("active_skills", [])) == 5
|
||||
|
||||
53
tests/test_mcp_developer_knowledge.py
Normal file
53
tests/test_mcp_developer_knowledge.py
Normal file
@@ -0,0 +1,53 @@
|
||||
"""Unit & Integration tests for Developer Knowledge MCP Client and Tools."""
|
||||
|
||||
import pytest
|
||||
from app.tools.mcp_developer_knowledge import (
|
||||
DeveloperKnowledgeMCPClient,
|
||||
developerknowledge_answer_query,
|
||||
developerknowledge_get_documents,
|
||||
developerknowledge_search_documents,
|
||||
get_mcp_client,
|
||||
)
|
||||
from app.adk.tools import mcp_search_tool, mcp_get_tool, mcp_answer_tool
|
||||
|
||||
|
||||
def test_mcp_client_search_documents():
|
||||
"""Verify DeveloperKnowledgeMCPClient search_documents method."""
|
||||
client = get_mcp_client()
|
||||
res = client.search_documents(query="Cloud Run", category="compute")
|
||||
assert res["source"] in ("live_mcp", "offline_fallback")
|
||||
assert "documents" in res or "data" in res
|
||||
|
||||
|
||||
def test_mcp_client_get_documents():
|
||||
"""Verify DeveloperKnowledgeMCPClient get_documents method."""
|
||||
client = get_mcp_client()
|
||||
res = client.get_documents(document_uri="https://cloud.google.com/run/docs/overview")
|
||||
assert res["source"] in ("live_mcp", "offline_fallback")
|
||||
assert "document" in res or "data" in res
|
||||
|
||||
|
||||
def test_mcp_client_answer_query():
|
||||
"""Verify DeveloperKnowledgeMCPClient answer_query method."""
|
||||
client = get_mcp_client()
|
||||
res = client.answer_query(query="Check Cloud Run release status")
|
||||
assert res["source"] in ("live_mcp", "offline_fallback")
|
||||
|
||||
|
||||
def test_langchain_mcp_tools():
|
||||
"""Verify LangChain @tool wrappers for Developer Knowledge MCP."""
|
||||
search_res = developerknowledge_search_documents.invoke({"query": "PubSub", "category": "messaging"})
|
||||
assert search_res is not None
|
||||
|
||||
get_res = developerknowledge_get_documents.invoke({"document_uri": "https://cloud.google.com/pubsub/docs"})
|
||||
assert get_res is not None
|
||||
|
||||
ans_res = developerknowledge_answer_query.invoke({"query": "What is the release status of Cloud Storage?"})
|
||||
assert ans_res is not None
|
||||
|
||||
|
||||
def test_adk_mcp_function_tools():
|
||||
"""Verify ADK FunctionTools for Developer Knowledge MCP."""
|
||||
assert mcp_search_tool.name == "developerknowledge_search_documents"
|
||||
assert mcp_get_tool.name == "developerknowledge_get_documents"
|
||||
assert mcp_answer_tool.name == "developerknowledge_answer_query"
|
||||
@@ -7,12 +7,13 @@ from app.config import get_settings
|
||||
|
||||
|
||||
def test_skill_loader_discovery():
|
||||
"""Verify SkillLoader discovers all 4 phase skills under app/skills/."""
|
||||
"""Verify SkillLoader discovers all phase skills under app/skills/."""
|
||||
settings = get_settings()
|
||||
loader = SkillLoader(settings.SKILLS_DIR)
|
||||
skills = loader.load_skills()
|
||||
|
||||
assert len(skills) >= 4
|
||||
assert len(skills) >= 5
|
||||
assert "source_discovery" in skills
|
||||
assert "requirements_discovery" in skills
|
||||
assert "architecture_design" in skills
|
||||
assert "validation_rules" in skills
|
||||
@@ -25,6 +26,10 @@ def test_skill_loader_by_phase():
|
||||
loader = SkillLoader(settings.SKILLS_DIR)
|
||||
loader.load_skills()
|
||||
|
||||
src_discover_skills = loader.get_skills_by_phase("source_discover")
|
||||
assert len(src_discover_skills) == 1
|
||||
assert src_discover_skills[0].name == "source_discovery"
|
||||
|
||||
discover_skills = loader.get_skills_by_phase("discover")
|
||||
assert len(discover_skills) == 1
|
||||
assert discover_skills[0].name == "requirements_discovery"
|
||||
|
||||
Reference in New Issue
Block a user