netx/tests/mcp_remote/topology/test_compact_bbox.py
oliver 52679a7cfc MCP: serve tools from the API process over Streamable HTTP at /mcp
- netx_api/mcp_remote: ops / topology / bizMonitor tools, Bearer auth,
  per-tool RBAC filtering, ?groups= filter, readOnlyHint and group meta.
- Mount the official MCP Streamable HTTP app at /mcp (stateless);
  AuthAuditMiddleware is pure ASGI and skips /mcp.
- Let uvicorn chunk MCP responses; some Windows LSPs rewrite
  Content-Length replies on */mcp* paths into broken chunked framing.
- NETX_MCP_ALLOWED_HOSTS opts into DNS-rebinding checks (off by default
  so LAN and reverse-proxy hosts work; Bearer is the gate).
- Remove the three stdio Python MCP packages; tests moved to /mcp,
  including real-TCP framing regressions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-16 21:52:08 +08:00

40 lines
1.7 KiB
Python

"""Tests for gated compact_bbox."""
from __future__ import annotations
from netx_api.mcp_remote.topology.layout_metrics import count_edge_crossings
from netx_api.mcp_remote.topology.layout_ops.compact_bbox import compact_bbox
from netx_api.mcp_remote.topology.layout_ops.graph_util import build_state_from_nodes_edges
from netx_api.mcp_remote.topology.layout_ops.orbit_sweep import _has_any_footprint_overlap
def test_compact_bbox_shrinks_without_raising_crossings():
# Two portals + a far leaf; shrink should pull leaf inward.
nodes = [
{"fabric_node_id": "p1", "name": "P1", "x": 0.0, "y": 0.0},
{"fabric_node_id": "p2", "name": "P2", "x": 1000.0, "y": 0.0},
{"fabric_node_id": "a", "name": "A", "x": 500.0, "y": 0.0},
{"fabric_node_id": "leaf", "name": "Leaf", "x": 500.0, "y": 4000.0},
]
edges = [
{"a_fabric_node_id": "p1", "b_fabric_node_id": "a"},
{"a_fabric_node_id": "a", "b_fabric_node_id": "p2"},
{"a_fabric_node_id": "a", "b_fabric_node_id": "leaf"},
]
st = build_state_from_nodes_edges(nodes, edges)
g0 = count_edge_crossings(st.positions, st.links)
op = compact_bbox(
st,
portal_ids=["p1", "p2"],
min_scale=0.7,
step=0.05,
max_clearance_slack=50,
)
assert op.params.get("accepted") is True
assert op.params.get("scale", 1.0) < 1.0
assert abs(op.state.positions["p1"][0] - 0.0) < 1e-6
assert abs(op.state.positions["p2"][0] - 1000.0) < 1e-6
assert op.state.positions["leaf"][1] < 4000.0
g1 = count_edge_crossings(op.state.positions, op.state.links)
assert g1 <= g0
assert not _has_any_footprint_overlap(op.state.positions, op.state.names)