Files
OPNexus/backend/tests/test_dashboard.py
T
Julian Boldt e26b26eca6
Release / verify (push) Canceled after 0s
CI / checks (push) Canceled after 0s
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 0s
Release / test (push) Canceled after 0s
Release / publish (backend) (push) Canceled after 0s
Release / publish (frontend) (push) Canceled after 0s
Release / publish (proxy) (push) Canceled after 0s
Release v1.10.1-rc2
Siehe CHANGELOG.md
2026-10-07 09:34:26 +02:00

140 lines
5.4 KiB
Python

import uuid
from datetime import datetime, timedelta, timezone
import pytest
from app.database import SessionLocal
from app.models.alias import FirewallAlias
from app.models.alias_deployment import AliasDeployment
from app.models.host import OpnsenseHost
from app.models.host_operation import HostOperation
from app.models.policy_hierarchy_group import PolicyHierarchyGroup
from app.models.policy_hierarchy_rule import PolicyHierarchyRule
from app.models.policy_hierarchy_rule_deployment import PolicyHierarchyRuleDeployment
from app.models.rule import FirewallRule
from app.models.rule_deployment import RuleDeployment
@pytest.mark.asyncio
async def test_dashboard_summary_aggregates_pending_actions_across_kinds(client, respx_mock):
import httpx
respx_mock.get("https://fw-dash.test/api/diagnostics/interface/getVipStatus").mock(
return_value=httpx.Response(200, json={"rows": []})
)
resp = await client.post(
"/api/hosts",
json={"name": "fw-dash", "base_url": "https://fw-dash.test", "api_key": "k", "api_secret": "s"},
)
assert resp.status_code == 201, resp.text
host_id = uuid.UUID(resp.json()["id"])
async with SessionLocal() as db:
rule = FirewallRule(description="Test-Regel", interface="lan", direction="in")
db.add(rule)
await db.flush()
db.add(RuleDeployment(rule_id=rule.id, host_id=host_id, status="error", message="Zeitüberschreitung"))
group = PolicyHierarchyGroup(name="Zentrale")
db.add(group)
await db.flush()
hierarchy_rule = PolicyHierarchyRule(
hierarchy_group_id=group.id, rulebase="pre", description="Hierarchie-Regel",
interface="wan", direction="in",
)
db.add(hierarchy_rule)
await db.flush()
db.add(PolicyHierarchyRuleDeployment(policy_hierarchy_id=hierarchy_rule.id, host_id=host_id, status="pending"))
db.add(HostOperation(
host_id=host_id, host_name="fw-dash", actor="admin", action="update", status="submitted",
expires_at=datetime.now(timezone.utc) + timedelta(minutes=5), fingerprint="f", snapshot={},
))
await db.commit()
resp = await client.get("/api/dashboard")
assert resp.status_code == 200, resp.text
body = resp.json()
by_kind = {item["kind"]: item for item in body["pending_actions"]}
assert by_kind["rule"]["entity_name"] == "Test-Regel"
assert by_kind["rule"]["status"] == "error"
assert by_kind["rule"]["link"] == f"/rules?rule={rule.id}"
assert by_kind["policy_hierarchy"]["entity_name"] == "Hierarchie-Regel"
assert by_kind["policy_hierarchy"]["link"] == f"/policy-hierarchy?group={group.id}"
assert by_kind["host_operation"]["entity_name"] == "Firmware-Update"
assert by_kind["host_operation"]["host_name"] == "fw-dash"
host_names = {h["name"] for h in body["hosts"]}
assert "fw-dash" in host_names
@pytest.mark.asyncio
async def test_dashboard_excludes_settled_deployments(client, respx_mock):
import httpx
respx_mock.get("https://fw-settled.test/api/diagnostics/interface/getVipStatus").mock(
return_value=httpx.Response(200, json={"rows": []})
)
resp = await client.post(
"/api/hosts",
json={"name": "fw-settled", "base_url": "https://fw-settled.test", "api_key": "k", "api_secret": "s"},
)
host_id = uuid.UUID(resp.json()["id"])
async with SessionLocal() as db:
rule = FirewallRule(description="Erledigte Regel", interface="lan", direction="in")
db.add(rule)
await db.flush()
db.add(RuleDeployment(rule_id=rule.id, host_id=host_id, status="success"))
await db.commit()
resp = await client.get("/api/dashboard")
assert resp.status_code == 200
names = {item["entity_name"] for item in resp.json()["pending_actions"]}
assert "Erledigte Regel" not in names
@pytest.mark.asyncio
async def test_dashboard_includes_recent_activity(client):
from app.services import audit_service
await audit_service.persist(
kind="rule", action="deploy", status="success",
entity_id=str(uuid.uuid4()), entity_name="Audit-Regel", host_id=None, host_name=None, message="ok",
)
resp = await client.get("/api/dashboard")
assert resp.status_code == 200
names = {item["entity_name"] for item in resp.json()["recent_activity"]}
assert "Audit-Regel" in names
@pytest.mark.asyncio
async def test_dashboard_lists_stuck_alias_deployment(client, respx_mock):
import httpx
respx_mock.get("https://fw-alias.test/api/diagnostics/interface/getVipStatus").mock(
return_value=httpx.Response(200, json={"rows": []})
)
resp = await client.post(
"/api/hosts",
json={"name": "fw-alias", "base_url": "https://fw-alias.test", "api_key": "k", "api_secret": "s"},
)
host_id = uuid.UUID(resp.json()["id"])
async with SessionLocal() as db:
alias = FirewallAlias(name="Gitea", type="host", content="10.0.0.1", description="")
db.add(alias)
await db.flush()
db.add(AliasDeployment(alias_id=alias.id, host_id=host_id, status="revert_failed", message="Alias in use"))
await db.commit()
body = (await client.get("/api/dashboard")).json()
item = next(i for i in body["pending_actions"] if i["kind"] == "alias")
assert item["entity_name"] == "Gitea"
assert item["status"] == "revert_failed"
assert item["link"] == f"/aliases?alias={alias.id}"