Projeto do Agent Contas ORACLE
This commit is contained in:
111
tests/migration/test_framework_native_structure.py
Normal file
111
tests/migration/test_framework_native_structure.py
Normal file
@@ -0,0 +1,111 @@
|
||||
from __future__ import annotations
|
||||
import pytest
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
from agent_framework.workflows import FileWorkflowRepository
|
||||
from app.domain.contas import ContasDomainService
|
||||
from app.domain.contas.workflow_actions import build_contas_workflow_actions
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def test_domain_does_not_import_langgraph_directly():
|
||||
violations = []
|
||||
for base in (ROOT / "app", ROOT / "mcp"):
|
||||
for path in base.rglob("*.py"):
|
||||
text = path.read_text(encoding="utf-8", errors="ignore")
|
||||
if re.search(r"(^|\n)\s*(from\s+langgraph|import\s+langgraph)", text):
|
||||
violations.append(str(path.relative_to(ROOT)))
|
||||
assert not violations
|
||||
|
||||
|
||||
def test_official_templates_use_framework_state_graph():
|
||||
for rel in (
|
||||
"agent_framework_oci/templates/agent_template_backend/app/workflows/agent_graph.py",
|
||||
"agent_framework_oci/templates/agent_template_backend_day_zero/app/workflows/agent_graph.py",
|
||||
):
|
||||
text = (ROOT / rel).read_text(encoding="utf-8")
|
||||
assert "FrameworkStateGraph" in text
|
||||
assert "from langgraph.graph" not in text
|
||||
|
||||
|
||||
def test_all_active_workflow_actions_registered(monkeypatch):
|
||||
monkeypatch.setenv("TIM_USE_MOCK_GATEWAY", "true")
|
||||
registry = build_contas_workflow_actions(ContasDomainService())
|
||||
registered = set(registry._actions)
|
||||
repo = FileWorkflowRepository(ROOT / "workflows")
|
||||
active = []
|
||||
required = set()
|
||||
for marker in sorted((ROOT / "workflows").glob("*.active.yaml")):
|
||||
name = marker.name.removesuffix(".active.yaml")
|
||||
definition = repo.get_active(name)
|
||||
active.append((name, definition.version))
|
||||
required.update(node.action for node in definition.nodes)
|
||||
assert len(active) == 10
|
||||
assert required <= registered, sorted(required - registered)
|
||||
|
||||
|
||||
def test_guardrail_config_declares_all_execution_stages():
|
||||
raw = yaml.safe_load((ROOT / "config" / "guardrails.yaml").read_text(encoding="utf-8"))
|
||||
assert raw.get("input")
|
||||
assert raw.get("output")
|
||||
assert raw.get("retrieval")
|
||||
assert raw.get("tool")
|
||||
|
||||
|
||||
def test_contestacao_workflow_encerra_imediatamente_quando_cval_bloqueia():
|
||||
import yaml
|
||||
from pathlib import Path
|
||||
wf = yaml.safe_load((Path(__file__).parents[2] / "workflows" / "contestacao_tool.v2.yaml").read_text())
|
||||
edges = wf["edges"]
|
||||
blocked = [e for e in edges if e.get("from") == "abrir_contestacao_cliente" and e.get("to") == "END"]
|
||||
assert blocked
|
||||
assert blocked[0]["priority"] == 1
|
||||
assert blocked[0]["when"] == {"eq": ["$.vars.abrir_contestacao_cliente.success", False]}
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_workflow_runtime_preserva_snapshot_parcial_quando_action_posterior_falha(tmp_path, monkeypatch):
|
||||
from types import SimpleNamespace
|
||||
from agent_framework.workflows.models import WorkflowDefinition, WorkflowNode
|
||||
from agent_framework.workflows.runtime import WorkflowRuntime
|
||||
|
||||
class Repo:
|
||||
def get_active(self, name):
|
||||
return WorkflowDefinition(name=name, version=1, start="a", nodes=[WorkflowNode(id="a", action="noop")], edges=[])
|
||||
class Graph:
|
||||
async def ainvoke(self, initial, config=None):
|
||||
raise RuntimeError("API contestacao indisponivel")
|
||||
async def aget_state(self, config=None):
|
||||
return SimpleNamespace(values={
|
||||
"nodes": {"registrar_protocolo": {"protocolo_id": "PRT-123"}},
|
||||
"trace": [{"node": "registrar_protocolo", "status": "COMPLETED"}],
|
||||
"input": {"msisdn": "119"},
|
||||
})
|
||||
runtime = WorkflowRuntime(Repo()) # type: ignore[arg-type]
|
||||
monkeypatch.setattr(runtime, "_compile", lambda definition: Graph())
|
||||
result = await runtime.arun("contestacao_tool", {"msisdn": "119"}, execution_id="exec-1")
|
||||
assert result.status == "FAILED"
|
||||
assert result.output["registrar_protocolo"]["protocolo_id"] == "PRT-123"
|
||||
assert result.trace == [{"node": "registrar_protocolo", "status": "COMPLETED"}]
|
||||
assert result.state["input"]["msisdn"] == "119"
|
||||
|
||||
|
||||
def test_agent_workflow_init_realmente_inicializa_router_agentes_e_graph():
|
||||
import ast
|
||||
from pathlib import Path
|
||||
source = (Path(__file__).parents[2] / "app" / "workflows" / "agent_graph.py").read_text()
|
||||
tree = ast.parse(source)
|
||||
cls = next(n for n in tree.body if isinstance(n, ast.ClassDef) and n.name == "AgentWorkflow")
|
||||
init = next(n for n in cls.body if isinstance(n, (ast.FunctionDef, ast.AsyncFunctionDef)) and n.name == "__init__")
|
||||
assigned = set()
|
||||
for node in ast.walk(init):
|
||||
if isinstance(node, ast.Assign):
|
||||
for target in node.targets:
|
||||
if isinstance(target, ast.Attribute) and isinstance(target.value, ast.Name) and target.value.id == "self":
|
||||
assigned.add(target.attr)
|
||||
assert {"router", "faturas", "vas", "contestacao", "suporte_contas", "graph"} <= assigned
|
||||
Reference in New Issue
Block a user