feat: Implement multi-node support with MQTT and mDNS for service discovery and coordination
This commit is contained in:
91
castle-api/tests/test_nodes.py
Normal file
91
castle-api/tests/test_nodes.py
Normal file
@@ -0,0 +1,91 @@
|
||||
"""Tests for nodes endpoints."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from castle_core.registry import DeployedComponent, NodeConfig, NodeRegistry
|
||||
|
||||
from castle_api.mesh import MeshStateManager
|
||||
|
||||
|
||||
class TestNodesList:
|
||||
"""GET /nodes endpoint tests."""
|
||||
|
||||
def test_returns_local_node(self, client: TestClient) -> None:
|
||||
"""Always returns the local node."""
|
||||
response = client.get("/nodes")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert len(data) >= 1
|
||||
local = data[0]
|
||||
assert local["hostname"] == "test-node"
|
||||
assert local["is_local"] is True
|
||||
assert local["online"] is True
|
||||
|
||||
def test_local_node_counts(self, client: TestClient) -> None:
|
||||
"""Local node has correct deployment counts."""
|
||||
response = client.get("/nodes")
|
||||
data = response.json()
|
||||
local = data[0]
|
||||
assert local["deployed_count"] == 1 # test-svc
|
||||
assert local["service_count"] == 1
|
||||
|
||||
def test_includes_remote_nodes(self, client: TestClient, registry_path: Path) -> None:
|
||||
"""Remote nodes from mesh state are included."""
|
||||
import castle_api.mesh as mesh_mod
|
||||
|
||||
original = mesh_mod.mesh_state
|
||||
try:
|
||||
mgr = MeshStateManager()
|
||||
remote_reg = NodeRegistry(
|
||||
node=NodeConfig(hostname="devbox", gateway_port=9000),
|
||||
deployed={
|
||||
"remote-svc": DeployedComponent(
|
||||
runner="python",
|
||||
run_cmd=["svc"],
|
||||
port=9050,
|
||||
category="service",
|
||||
),
|
||||
},
|
||||
)
|
||||
mgr.update_node("devbox", remote_reg)
|
||||
mesh_mod.mesh_state = mgr
|
||||
|
||||
# Also patch the reference in the nodes module
|
||||
import castle_api.nodes as nodes_mod
|
||||
|
||||
nodes_mod.mesh_state = mgr
|
||||
|
||||
response = client.get("/nodes")
|
||||
data = response.json()
|
||||
hostnames = [n["hostname"] for n in data]
|
||||
assert "devbox" in hostnames
|
||||
devbox = next(n for n in data if n["hostname"] == "devbox")
|
||||
assert devbox["is_local"] is False
|
||||
assert devbox["deployed_count"] == 1
|
||||
finally:
|
||||
mesh_mod.mesh_state = original
|
||||
import castle_api.nodes as nodes_mod2
|
||||
|
||||
nodes_mod2.mesh_state = original
|
||||
|
||||
|
||||
class TestNodeDetail:
|
||||
"""GET /nodes/{hostname} endpoint tests."""
|
||||
|
||||
def test_local_node_detail(self, client: TestClient) -> None:
|
||||
"""Returns local node detail with deployed components."""
|
||||
response = client.get("/nodes/test-node")
|
||||
assert response.status_code == 200
|
||||
data = response.json()
|
||||
assert data["hostname"] == "test-node"
|
||||
assert data["is_local"] is True
|
||||
assert len(data["deployed"]) == 1
|
||||
assert data["deployed"][0]["id"] == "test-svc"
|
||||
assert data["deployed"][0]["node"] == "test-node"
|
||||
|
||||
def test_unknown_node_returns_404(self, client: TestClient) -> None:
|
||||
"""Returns 404 for unknown hostname."""
|
||||
response = client.get("/nodes/nonexistent")
|
||||
assert response.status_code == 404
|
||||
Reference in New Issue
Block a user