| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- # -*- coding: utf-8 -*-
- """
- Tests für Satellite Capability System.
- """
- import asyncio
- import pytest
- from datetime import datetime
- from trixy_core.satellite.capability import (
- CapabilityDiscovery,
- DiscoveryConfig,
- CapabilityProbe,
- CapabilityRegistry,
- Capability,
- CapabilityInfo,
- CapabilityState,
- )
- from trixy_core.satellite.capability.discovery import SimpleProbe, ProbeResult
- class TestCapabilityInfo:
- """Tests für CapabilityInfo."""
- def test_info_creation(self):
- """Testet Info-Erstellung."""
- info = CapabilityInfo(
- id="audio.input",
- name="Mikrofon",
- description="Audio-Eingang",
- category="audio",
- )
- assert info.id == "audio.input"
- assert info.name == "Mikrofon"
- assert info.category == "audio"
- def test_info_defaults(self):
- """Testet Standard-Werte."""
- info = CapabilityInfo(id="test", name="Test")
- assert info.description == ""
- assert info.category == ""
- assert info.required_features == []
- class TestCapability:
- """Tests für Capability."""
- @pytest.fixture
- def cap_info(self):
- """Erstellt CapabilityInfo."""
- return CapabilityInfo(
- id="audio.input",
- name="Mikrofon",
- category="audio",
- )
- def test_capability_creation(self, cap_info):
- """Testet Capability-Erstellung."""
- cap = Capability(
- info=cap_info,
- state=CapabilityState.AVAILABLE,
- )
- assert cap.id == "audio.input"
- assert cap.state == CapabilityState.AVAILABLE
- assert cap.is_available
- def test_capability_states(self, cap_info):
- """Testet Capability-Zustände."""
- cap = Capability(info=cap_info)
- cap.state = CapabilityState.UNKNOWN
- assert not cap.is_available
- assert not cap.is_degraded
- cap.state = CapabilityState.AVAILABLE
- assert cap.is_available
- cap.state = CapabilityState.DEGRADED
- assert cap.is_degraded
- def test_update_state(self, cap_info):
- """Testet State-Update."""
- cap = Capability(info=cap_info)
- cap.update_state(CapabilityState.UNAVAILABLE, "Gerät nicht gefunden")
- assert cap.state == CapabilityState.UNAVAILABLE
- assert cap.error_message == "Gerät nicht gefunden"
- assert cap.last_checked is not None
- def test_to_dict(self, cap_info):
- """Testet Dictionary-Konvertierung."""
- cap = Capability(
- info=cap_info,
- state=CapabilityState.AVAILABLE,
- satellite_id="sat-001",
- )
- d = cap.to_dict()
- assert d["id"] == "audio.input"
- assert d["state"] == "AVAILABLE"
- assert d["satellite_id"] == "sat-001"
- class TestCapabilityRegistry:
- """Tests für CapabilityRegistry."""
- @pytest.fixture
- def registry(self):
- """Erstellt Registry."""
- return CapabilityRegistry()
- @pytest.fixture
- def audio_info(self):
- """Erstellt Audio-CapabilityInfo."""
- return CapabilityInfo(
- id="audio.input",
- name="Mikrofon",
- category="audio",
- )
- def test_define_capability(self, registry, audio_info):
- """Testet Capability-Definition."""
- registry.define_capability(audio_info)
- assert registry.capability_count == 1
- assert registry.get_definition("audio.input") == audio_info
- def test_register_capability(self, registry, audio_info):
- """Testet Capability-Registrierung."""
- cap = Capability(info=audio_info, state=CapabilityState.AVAILABLE)
- registry.register("sat-001", cap)
- assert registry.satellite_count == 1
- assert registry.has_capability("sat-001", "audio.input")
- def test_unregister_capability(self, registry, audio_info):
- """Testet Capability-Entfernung."""
- cap = Capability(info=audio_info)
- registry.register("sat-001", cap)
- assert registry.unregister("sat-001", "audio.input")
- assert not registry.has_capability("sat-001", "audio.input")
- def test_unregister_all_satellite(self, registry, audio_info):
- """Testet Entfernung aller Capabilities eines Satellites."""
- cap = Capability(info=audio_info)
- registry.register("sat-001", cap)
- assert registry.unregister("sat-001")
- assert "sat-001" not in registry
- def test_update_state(self, registry, audio_info):
- """Testet State-Update über Registry."""
- cap = Capability(info=audio_info)
- registry.register("sat-001", cap)
- assert registry.update_state(
- "sat-001",
- "audio.input",
- CapabilityState.UNAVAILABLE,
- "Fehler",
- )
- updated = registry.get("sat-001", "audio.input")
- assert updated.state == CapabilityState.UNAVAILABLE
- def test_get_capability(self, registry, audio_info):
- """Testet Capability-Abruf."""
- cap = Capability(info=audio_info, state=CapabilityState.AVAILABLE)
- registry.register("sat-001", cap)
- result = registry.get("sat-001", "audio.input")
- assert result == cap
- def test_get_all_capabilities(self, registry, audio_info):
- """Testet Abruf aller Capabilities."""
- cap1 = Capability(
- info=audio_info,
- state=CapabilityState.AVAILABLE,
- )
- cap2 = Capability(
- info=CapabilityInfo("display.screen", "Bildschirm"),
- state=CapabilityState.AVAILABLE,
- )
- registry.register("sat-001", cap1)
- registry.register("sat-001", cap2)
- caps = registry.get_all("sat-001")
- assert len(caps) == 2
- def test_get_available_capabilities(self, registry, audio_info):
- """Testet Abruf verfügbarer Capabilities."""
- cap1 = Capability(info=audio_info, state=CapabilityState.AVAILABLE)
- cap2 = Capability(
- info=CapabilityInfo("display.screen", "Bildschirm"),
- state=CapabilityState.UNAVAILABLE,
- )
- registry.register("sat-001", cap1)
- registry.register("sat-001", cap2)
- available = registry.get_available("sat-001")
- assert len(available) == 1
- assert available[0].id == "audio.input"
- def test_has_capability(self, registry, audio_info):
- """Testet Capability-Prüfung."""
- cap = Capability(info=audio_info, state=CapabilityState.AVAILABLE)
- registry.register("sat-001", cap)
- assert registry.has_capability("sat-001", "audio.input")
- assert not registry.has_capability("sat-001", "unknown")
- assert not registry.has_capability("unknown", "audio.input")
- def test_has_capability_require_available(self, registry, audio_info):
- """Testet Capability-Prüfung mit Verfügbarkeit."""
- cap = Capability(info=audio_info, state=CapabilityState.UNAVAILABLE)
- registry.register("sat-001", cap)
- # Mit require_available=True
- assert not registry.has_capability("sat-001", "audio.input", True)
- # Mit require_available=False
- assert registry.has_capability("sat-001", "audio.input", False)
- def test_has_all_capabilities(self, registry):
- """Testet Prüfung mehrerer Capabilities."""
- cap1 = Capability(
- info=CapabilityInfo("cap1", "Cap 1"),
- state=CapabilityState.AVAILABLE,
- )
- cap2 = Capability(
- info=CapabilityInfo("cap2", "Cap 2"),
- state=CapabilityState.AVAILABLE,
- )
- registry.register("sat-001", cap1)
- registry.register("sat-001", cap2)
- assert registry.has_all_capabilities("sat-001", ["cap1", "cap2"])
- assert not registry.has_all_capabilities("sat-001", ["cap1", "cap3"])
- def test_has_any_capability(self, registry):
- """Testet Prüfung auf mindestens eine Capability."""
- cap = Capability(
- info=CapabilityInfo("cap1", "Cap 1"),
- state=CapabilityState.AVAILABLE,
- )
- registry.register("sat-001", cap)
- assert registry.has_any_capability("sat-001", ["cap1", "cap2"])
- assert not registry.has_any_capability("sat-001", ["cap3", "cap4"])
- def test_find_satellites_with(self, registry, audio_info):
- """Testet Satellite-Suche nach Capability."""
- cap = Capability(info=audio_info, state=CapabilityState.AVAILABLE)
- registry.register("sat-001", cap)
- registry.register("sat-002", cap)
- satellites = registry.find_satellites_with("audio.input")
- assert len(satellites) == 2
- assert "sat-001" in satellites
- assert "sat-002" in satellites
- def test_find_satellites_with_all(self, registry):
- """Testet Satellite-Suche nach mehreren Capabilities."""
- cap1 = Capability(
- info=CapabilityInfo("cap1", "Cap 1"),
- state=CapabilityState.AVAILABLE,
- )
- cap2 = Capability(
- info=CapabilityInfo("cap2", "Cap 2"),
- state=CapabilityState.AVAILABLE,
- )
- registry.register("sat-001", cap1)
- registry.register("sat-001", cap2)
- registry.register("sat-002", cap1) # Nur cap1
- satellites = registry.find_satellites_with_all(["cap1", "cap2"])
- assert satellites == ["sat-001"]
- def test_get_by_category(self, registry):
- """Testet Abruf nach Kategorie."""
- cap1 = Capability(
- info=CapabilityInfo("audio.in", "In", category="audio"),
- )
- cap2 = Capability(
- info=CapabilityInfo("audio.out", "Out", category="audio"),
- )
- cap3 = Capability(
- info=CapabilityInfo("display", "Display", category="display"),
- )
- registry.register("sat-001", cap1)
- registry.register("sat-001", cap2)
- registry.register("sat-001", cap3)
- audio_caps = registry.get_by_category("sat-001", "audio")
- assert len(audio_caps) == 2
- def test_on_change_callback(self, registry, audio_info):
- """Testet Änderungs-Callback."""
- changes = []
- def on_change(sat_id, cap):
- changes.append((sat_id, cap.id))
- registry.on_change(on_change)
- cap = Capability(info=audio_info)
- registry.register("sat-001", cap)
- assert ("sat-001", "audio.input") in changes
- def test_get_summary(self, registry, audio_info):
- """Testet Zusammenfassung."""
- cap = Capability(info=audio_info, state=CapabilityState.AVAILABLE)
- registry.register("sat-001", cap)
- summary = registry.get_summary()
- assert summary["satellite_count"] == 1
- assert summary["total_capabilities"] == 1
- assert summary["available_capabilities"] == 1
- class TestDiscoveryConfig:
- """Tests für DiscoveryConfig."""
- def test_default_config(self):
- """Testet Standard-Konfiguration."""
- config = DiscoveryConfig()
- assert config.probe_timeout == 10.0
- assert config.probe_concurrency == 5
- assert config.auto_discover is True
- class TestProbeResult:
- """Tests für ProbeResult."""
- def test_result_creation(self):
- """Testet Result-Erstellung."""
- result = ProbeResult(
- capability_id="audio.input",
- success=True,
- state=CapabilityState.AVAILABLE,
- )
- assert result.capability_id == "audio.input"
- assert result.success
- assert result.state == CapabilityState.AVAILABLE
- class TestCapabilityDiscovery:
- """Tests für CapabilityDiscovery."""
- @pytest.fixture
- def registry(self):
- """Erstellt Registry."""
- return CapabilityRegistry()
- @pytest.fixture
- def send_func(self):
- """Erstellt Mock-Send-Funktion."""
- responses = {}
- async def send(sat_id, message):
- return responses.get(sat_id, {"available": False})
- send.responses = responses
- return send
- @pytest.fixture
- def discovery(self, registry, send_func):
- """Erstellt Discovery-Instanz."""
- config = DiscoveryConfig(
- probe_timeout=1.0,
- probe_concurrency=2,
- )
- return CapabilityDiscovery(
- registry=registry,
- send_func=send_func,
- config=config,
- )
- def test_register_probe(self, discovery):
- """Testet Probe-Registrierung."""
- info = CapabilityInfo("test", "Test")
- probe = SimpleProbe(info)
- discovery.register_probe(probe)
- assert discovery.probe_count == 1
- assert discovery.registry.get_definition("test") is not None
- def test_unregister_probe(self, discovery):
- """Testet Probe-Entfernung."""
- info = CapabilityInfo("test", "Test")
- probe = SimpleProbe(info)
- discovery.register_probe(probe)
- assert discovery.unregister_probe("test")
- assert discovery.probe_count == 0
- @pytest.mark.asyncio
- async def test_discover_capability(self, discovery, send_func):
- """Testet einzelne Capability-Discovery."""
- info = CapabilityInfo("audio.input", "Mikrofon")
- probe = SimpleProbe(info)
- discovery.register_probe(probe)
- send_func.responses["sat-001"] = {
- "available": True,
- "parameters": {"channels": 2},
- }
- result = await discovery.discover_capability("sat-001", "audio.input")
- assert result is not None
- assert result.success
- assert result.state == CapabilityState.AVAILABLE
- @pytest.mark.asyncio
- async def test_discover_satellite(self, discovery, send_func):
- """Testet vollständige Satellite-Discovery."""
- info1 = CapabilityInfo("cap1", "Cap 1")
- info2 = CapabilityInfo("cap2", "Cap 2")
- discovery.register_probe(SimpleProbe(info1))
- discovery.register_probe(SimpleProbe(info2))
- send_func.responses["sat-001"] = {"available": True}
- results = await discovery.discover_satellite("sat-001")
- assert len(results) == 2
- assert all(r.success for r in results)
- @pytest.mark.asyncio
- async def test_discover_specific_capabilities(self, discovery, send_func):
- """Testet Discovery spezifischer Capabilities."""
- info1 = CapabilityInfo("cap1", "Cap 1")
- info2 = CapabilityInfo("cap2", "Cap 2")
- discovery.register_probe(SimpleProbe(info1))
- discovery.register_probe(SimpleProbe(info2))
- send_func.responses["sat-001"] = {"available": True}
- results = await discovery.discover_satellite("sat-001", ["cap1"])
- assert len(results) == 1
- assert results[0].capability_id == "cap1"
- @pytest.mark.asyncio
- async def test_discover_all(self, discovery, send_func):
- """Testet Discovery für mehrere Satellites."""
- info = CapabilityInfo("cap1", "Cap 1")
- discovery.register_probe(SimpleProbe(info))
- send_func.responses["sat-001"] = {"available": True}
- send_func.responses["sat-002"] = {"available": False}
- results = await discovery.discover_all(["sat-001", "sat-002"])
- assert "sat-001" in results
- assert "sat-002" in results
- def test_needs_rediscovery(self, discovery):
- """Testet Rediscovery-Prüfung."""
- assert discovery.needs_rediscovery("sat-001")
- discovery._last_discovery["sat-001"] = datetime.now()
- assert not discovery.needs_rediscovery("sat-001")
- def test_get_stats(self, discovery):
- """Testet Statistik-Abruf."""
- info = CapabilityInfo("test", "Test")
- discovery.register_probe(SimpleProbe(info))
- stats = discovery.get_stats()
- assert stats["probe_count"] == 1
- assert "config" in stats
|