32c7336bf6
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
4.6 KiB
Python
141 lines
4.6 KiB
Python
"""Tests para discover_local_services."""
|
|
|
|
import os
|
|
import socket
|
|
import sys
|
|
|
|
import yaml
|
|
|
|
# El modulo hoja se importa por su nombre directo; aseguramos que su directorio
|
|
# esta en sys.path para poder correr el test desde cualquier cwd.
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from discover_local_services import discover_local_services
|
|
|
|
NORMALIZED_KEYS = {
|
|
"name", "subdomain", "port", "health_path", "title", "icon", "category",
|
|
"rewrite_host", "up",
|
|
}
|
|
|
|
|
|
def _write_manifest(tmp_path, services):
|
|
manifest = {
|
|
"dashboard_subdomain": "home",
|
|
"glance_port": 8585,
|
|
"services": services,
|
|
}
|
|
path = tmp_path / "local_services.yaml"
|
|
path.write_text(yaml.safe_dump(manifest), encoding="utf-8")
|
|
return str(path)
|
|
|
|
|
|
def test_golden_service_up_with_all_keys(tmp_path):
|
|
# Abrimos un socket real en un puerto efímero para simular un servicio vivo.
|
|
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
listener.bind(("127.0.0.1", 0))
|
|
listener.listen(1)
|
|
port = listener.getsockname()[1]
|
|
try:
|
|
manifest = _write_manifest(tmp_path, [
|
|
{
|
|
"name": "metabase",
|
|
"subdomain": "metabase",
|
|
"port": port,
|
|
"health_path": "/api/health",
|
|
"title": "Metabase",
|
|
"icon": "si:metabase",
|
|
"category": "Datos",
|
|
},
|
|
])
|
|
result = discover_local_services(manifest, include_registry=False)
|
|
assert len(result) == 1
|
|
svc = result[0]
|
|
# Todas las claves normalizadas presentes.
|
|
assert set(svc.keys()) == NORMALIZED_KEYS
|
|
assert svc["up"] is True
|
|
assert svc["name"] == "metabase"
|
|
assert svc["port"] == port
|
|
assert svc["health_path"] == "/api/health"
|
|
finally:
|
|
listener.close()
|
|
|
|
|
|
def test_edge_closed_port_is_down(tmp_path):
|
|
# Tomamos un puerto efímero y lo cerramos inmediatamente -> debe estar down.
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.bind(("127.0.0.1", 0))
|
|
closed_port = s.getsockname()[1]
|
|
s.close()
|
|
|
|
manifest = _write_manifest(tmp_path, [
|
|
{
|
|
"name": "ghost",
|
|
"subdomain": "ghost",
|
|
"port": closed_port,
|
|
"health_path": "/",
|
|
"title": "Ghost",
|
|
"icon": "",
|
|
"category": "Otros",
|
|
},
|
|
])
|
|
result = discover_local_services(manifest, include_registry=False)
|
|
assert len(result) == 1
|
|
assert result[0]["up"] is False
|
|
|
|
|
|
def test_defaults_derived_for_missing_fields(tmp_path):
|
|
# Servicio mínimo: solo name + port. El resto debe derivarse con defaults.
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.bind(("127.0.0.1", 0))
|
|
closed_port = s.getsockname()[1]
|
|
s.close()
|
|
|
|
manifest = _write_manifest(tmp_path, [
|
|
{"name": "barebones", "port": closed_port},
|
|
])
|
|
result = discover_local_services(manifest, include_registry=False)
|
|
svc = result[0]
|
|
assert set(svc.keys()) == NORMALIZED_KEYS
|
|
assert svc["title"] == "barebones" # derivado de name
|
|
assert svc["icon"] == "" # default
|
|
assert svc["category"] == "Otros" # default
|
|
assert svc["health_path"] == "/" # default
|
|
assert svc["subdomain"] == "barebones" # derivado de name
|
|
assert svc["up"] is False
|
|
|
|
|
|
def test_empty_manifest_returns_empty_list(tmp_path):
|
|
manifest = _write_manifest(tmp_path, [])
|
|
result = discover_local_services(manifest, include_registry=False)
|
|
assert result == []
|
|
|
|
|
|
def test_rewrite_host_passthrough_desde_manifiesto(tmp_path):
|
|
# Un servicio con rewrite_host: true en el manifiesto debe propagar
|
|
# rewrite_host == True; uno sin la clave debe dar rewrite_host == False.
|
|
listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
listener.bind(("127.0.0.1", 0))
|
|
listener.listen(1)
|
|
port = listener.getsockname()[1]
|
|
try:
|
|
manifest = _write_manifest(tmp_path, [
|
|
{
|
|
"name": "jupyter",
|
|
"subdomain": "jupyter",
|
|
"port": port,
|
|
"rewrite_host": True,
|
|
},
|
|
{
|
|
"name": "metabase",
|
|
"subdomain": "metabase",
|
|
"port": port,
|
|
# sin clave rewrite_host -> default False
|
|
},
|
|
])
|
|
result = discover_local_services(manifest, include_registry=False)
|
|
by_name = {s["name"]: s for s in result}
|
|
assert by_name["jupyter"]["rewrite_host"] is True
|
|
assert by_name["metabase"]["rewrite_host"] is False
|
|
finally:
|
|
listener.close()
|