mdns-termux/tests/test_cache.py

51 lines
1.7 KiB
Python
Raw Normal View History

feat: publisher-daemon (singleton + re-announce), sync-hosts, status/stop y tests Bloque de robustez operativa + integracion de sistema + calidad: Publisher como servicio (lib/mdns_tools/service.py): - `mdns publish --daemon`: daemon singleton con lock PID en ~/.cache/mdns/publisher.pid. Un segundo intento es rechazado -> evita el problema de "Termux SMB" duplicado (varios publishers compitiendo por el mismo nombre, que zeroconf renombra a "-2"). - Re-anuncio automatico al cambiar la IP local (WiFi<->datos, roaming): unregister + register con la nueva IP para que el registro no quede stale. - Apagado limpio: maneja SIGTERM ademas de SIGINT (loop en ticks de 1s) y envia goodbye packets para que los clientes borren la entrada al instante. - `mdns status` (running/host/ip/servicios/desde) y `mdns stop`. Integracion de sistema (lib/mdns_tools/hosts.py): - `mdns sync-hosts [--dry-run]`: escribe un bloque gestionado en $PREFIX/etc/hosts (o /etc/hosts) para que ping/curl/kubectl nativos resuelvan .local sin el wrapper `resolve`. Solo toca su propio bloque. Refactor publish.py: expone helpers reutilizables (local_ipv4, load_config, build_infos, register_all, unregister_all) que consume el daemon. Tests offline (tests/, pytest, 20 casos, sin red): - construccion/parseo de queries A, seleccion de IP ante multi-homing (rechazo de rangos virtuales), cache con TTL y familias, PTR reverse, render/strip del bloque de hosts. - pyproject.toml con metadata, deps, extras [test] y config de pytest. README: seccion de daemon, sync-hosts y tests; tabla RFC ampliada. bashrc.snippet: aliases mdns-up/status/down/hosts (consolidados). install.sh: fix de backticks; symlinks ya cubren mdns + lib via resolve(). Nota: publish.py (109) y service.py (110) exceden levemente las 100 lineas; se dejan como modulos cohesivos de responsabilidad unica, igual que el dispatcher CLI, para no fragmentar. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-07-20 17:59:10 +00:00
"""TTL-aware cache tests (isolated file via MDNS_CACHE_PATH)."""
import importlib
import time
def _fresh_cache(tmp_path, monkeypatch):
monkeypatch.setenv("MDNS_CACHE_PATH", str(tmp_path / "hosts.json"))
from mdns_tools import cache
importlib.reload(cache)
return cache
def test_put_get_roundtrip(tmp_path, monkeypatch):
cache = _fresh_cache(tmp_path, monkeypatch)
cache.put("dell.local", "192.168.1.17", ttl=120)
assert cache.get("dell.local") == "192.168.1.17"
def test_expired_returns_none_but_stale_available(tmp_path, monkeypatch):
cache = _fresh_cache(tmp_path, monkeypatch)
cache.put("x.local", "10.0.0.1", ttl=30)
# Force expiry by rewriting with a past timestamp.
data = cache._load()
data["x.local|v4"]["expires"] = time.time() - 1
cache._save(data)
assert cache.get("x.local") is None
assert cache.get_stale("x.local") == "10.0.0.1"
def test_families_are_separate(tmp_path, monkeypatch):
cache = _fresh_cache(tmp_path, monkeypatch)
cache.put("h.local", "192.168.1.9", family="v4")
cache.put("h.local", "fe80::9", family="v6")
assert cache.get("h.local", "v4") == "192.168.1.9"
assert cache.get("h.local", "v6") == "fe80::9"
def test_clear_specific_host(tmp_path, monkeypatch):
cache = _fresh_cache(tmp_path, monkeypatch)
cache.put("a.local", "1.1.1.1")
cache.put("b.local", "2.2.2.2")
assert cache.clear("a.local") == 1
assert cache.get("a.local") is None
assert cache.get("b.local") == "2.2.2.2"
def test_ttl_clamped_to_minimum(tmp_path, monkeypatch):
cache = _fresh_cache(tmp_path, monkeypatch)
cache.put("c.local", "3.3.3.3", ttl=1) # below floor
assert cache.all_entries()["c.local|v4"]["ttl"] >= 30