Files
GTI_GERENCIADOR_FISCAL/central/tests/test_control_plane.py
T

74 lines
4.9 KiB
Python

from datetime import datetime, timedelta, timezone
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.pool import StaticPool
from sqlalchemy.orm import sessionmaker
from central.app.human_auth import create_admin, create_session, hash_password, verify_password
from central.app.main import create_app
from central.app.models import Agent, AgentEvent, AgentSnapshot, Base, Installation, Tenant
from central.app.events import purge_expired_events, record_event, sanitize_event
from central.app.installation_identity import compute_agent_health
from types import SimpleNamespace
def setup_db():
engine = create_engine("sqlite://", connect_args={"check_same_thread": False}, poolclass=StaticPool)
Base.metadata.create_all(engine)
return sessionmaker(bind=engine, expire_on_commit=False)
def seed(session_factory):
with session_factory() as session:
tenant = Tenant(name="Acme"); session.add(tenant); session.flush()
agent = Agent(tenant_id=tenant.id, name="agent", token_hash="x" * 64); session.add(agent); session.flush()
installation = Installation(agent_id=agent.id, tenant_id=tenant.id, installation_id="11111111-1111-4111-8111-111111111111", display_name="Acme ERP", hostname="srv-01", last_seen_at=datetime.now(timezone.utc)); session.add(installation); session.flush()
session.add(AgentSnapshot(installation_id=installation.id, total_products=10, fiscally_complete=8, safe_blocked=2, blockers={"CFOP": 2}))
admin = create_admin(session, "operator", "a-secure-password")
return agent.id, admin.id
def test_password_and_event_redaction_and_retention():
assert verify_password("a-secure-password", hash_password("a-secure-password"))
message, context = sanitize_event("password=bad token=secret", {"password": "bad", "nested": {"api_key": "key"}})
assert "bad" not in message and context["password"] == "[REDACTED]" and context["nested"]["api_key"] == "[REDACTED]"
session_factory = setup_db()
with session_factory() as session:
agent_id, _ = seed(session_factory)
installation = session.query(Installation).first()
old = record_event(session, tenant_id=installation.tenant_id, installation_id=installation.id, agent_id=agent_id, severity="INFO", event_type="HEARTBEAT", message="old", occurred_at=datetime.now(timezone.utc) - timedelta(days=100))
keep = record_event(session, tenant_id=installation.tenant_id, installation_id=installation.id, agent_id=agent_id, severity="CRITICAL", event_type="CONNECTION_ERROR", message="keep", occurred_at=datetime.now(timezone.utc) - timedelta(days=100), is_audit=True)
session.commit()
assert purge_expired_events(session, retention_days=90) == 1
assert session.get(AgentEvent, old.id) is None and session.get(AgentEvent, keep.id) is not None
def test_health_model_separates_safe_blocked_from_technical_failure():
now = datetime.now(timezone.utc)
recent = SimpleNamespace(last_seen_at=now, failed_products=0, last_job_status="COMPLETED")
blocked = SimpleNamespace(last_seen_at=now, failed_products=0, last_job_status="COMPLETED")
failed = SimpleNamespace(last_seen_at=now, failed_products=1, last_job_status="FAILED", agent_health="FAILED")
stale = SimpleNamespace(last_seen_at=now - timedelta(hours=2), failed_products=0, last_job_status="COMPLETED")
assert compute_agent_health(recent)[0] == "ONLINE"
assert compute_agent_health(blocked, supplemental=blocked)[0] == "ONLINE"
assert compute_agent_health(failed)[0] == "FAILED"
assert compute_agent_health(stale)[0] == "OFFLINE"
assert compute_agent_health(SimpleNamespace(last_seen_at=None))[0] == "UNKNOWN"
def test_human_login_and_dashboard_are_separate_from_agent_bearer():
session_factory = setup_db(); seed(session_factory)
client = TestClient(create_app(database_probe=lambda: True, session_factory=session_factory, bootstrap_token=None))
assert client.get("/", follow_redirects=False).status_code == 303
response = client.post("/login", data={"username": "operator", "password": "a-secure-password"}, follow_redirects=False)
assert response.status_code == 303
assert client.get("/v1/dashboard/summary").status_code == 200
assert TestClient(create_app(database_probe=lambda: True, session_factory=session_factory, bootstrap_token=None)).get("/v1/dashboard/summary", headers={"Authorization": "Bearer x"}).status_code == 401
assert client.get("/v1/agents").json()["items"][0]["installation_id"]
csrf = client.cookies.get("gti_csrf")
action = client.post("/v1/agents/1/actions/reprocess", json={"confirm": True, "csrf_token": csrf, "kind": "REPROCESS_ALL"})
assert action.status_code == 200 and action.json()["status"] == "PENDING"
denied = client.post("/v1/agents/1/actions/reprocess", json={"confirm": True, "csrf_token": "wrong", "kind": "REPROCESS_ALL"})
assert denied.status_code == 403