| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493 |
- # -*- coding: utf-8 -*-
- """
- Unit-Tests für trixy_core.satellite.
- """
- import json
- import pytest
- from datetime import datetime
- from unittest.mock import MagicMock, AsyncMock
- from pathlib import Path
- from trixy_core.satellite.satellite import Satellite, ConnectionState, SatelliteSocket
- from trixy_core.satellite.satellite_manager import SatelliteManager
- from trixy_core.satellite.registration_manager import RegistrationManager, PendingRegistration
- class TestConnectionState:
- """Tests für ConnectionState."""
- def test_states_exist(self):
- """Testet, dass alle Zustände existieren."""
- assert hasattr(ConnectionState, "DISCONNECTED")
- assert hasattr(ConnectionState, "CONNECTING")
- assert hasattr(ConnectionState, "CONNECTED")
- assert hasattr(ConnectionState, "AUTHENTICATED")
- assert hasattr(ConnectionState, "DISCONNECTING")
- assert hasattr(ConnectionState, "ERROR")
- class TestSatellite:
- """Tests für Satellite-Klasse."""
- @pytest.fixture
- def satellite(self):
- """Erstellt einen Test-Satellite."""
- return Satellite(
- satellite_id="sat-test-123",
- room_id="wohnzimmer",
- mac_address="AA:BB:CC:DD:EE:FF",
- alias="Test Echo",
- ip_address="192.168.1.100"
- )
- def test_satellite_creation(self, satellite):
- """Testet die Satellite-Erstellung."""
- assert satellite.id == "sat-test-123"
- assert satellite.room_id == "wohnzimmer"
- assert satellite.mac_address == "AA:BB:CC:DD:EE:FF"
- assert satellite.alias == "Test Echo"
- assert satellite.ip_address == "192.168.1.100"
- def test_satellite_auto_id(self):
- """Testet die automatische ID-Generierung."""
- sat = Satellite(room_id="test")
- assert sat.id is not None
- assert len(sat.id) > 0
- def test_satellite_initial_state(self, satellite):
- """Testet den initialen Zustand."""
- assert satellite.state == ConnectionState.DISCONNECTED
- assert satellite.is_connected is False
- def test_satellite_is_connected(self, satellite):
- """Testet is_connected für verschiedene Zustände."""
- satellite.state = ConnectionState.CONNECTED
- assert satellite.is_connected is True
- satellite.state = ConnectionState.AUTHENTICATED
- assert satellite.is_connected is True
- satellite.state = ConnectionState.DISCONNECTED
- assert satellite.is_connected is False
- def test_set_connected(self, satellite):
- """Testet set_connected."""
- satellite.set_connected()
- assert satellite.state == ConnectionState.CONNECTED
- assert satellite.connected_at is not None
- assert satellite.last_heartbeat is not None
- def test_update_heartbeat(self, satellite):
- """Testet update_heartbeat."""
- satellite.update_heartbeat()
- assert satellite.last_heartbeat is not None
- def test_conversation_id(self, satellite):
- """Testet conversation_id."""
- assert satellite.conversation_id is None
- assert satellite.has_active_conversation is False
- satellite.conversation_id = "conv-123"
- assert satellite.conversation_id == "conv-123"
- assert satellite.has_active_conversation is True
- def test_version(self, satellite):
- """Testet version."""
- satellite.version = "1.0.0"
- assert satellite.version == "1.0.0"
- def test_metadata(self, satellite):
- """Testet metadata."""
- satellite.metadata["custom"] = "value"
- assert satellite.metadata["custom"] == "value"
- def test_to_dict(self, satellite):
- """Testet to_dict."""
- satellite.set_connected()
- data = satellite.to_dict()
- assert data["id"] == "sat-test-123"
- assert data["room_id"] == "wohnzimmer"
- assert data["mac_address"] == "AA:BB:CC:DD:EE:FF"
- assert data["state"] == "CONNECTED"
- @pytest.mark.asyncio
- async def test_disconnect(self, satellite):
- """Testet disconnect."""
- satellite.set_connected()
- satellite.conversation_id = "conv-123"
- await satellite.disconnect("Test reason")
- assert satellite.state == ConnectionState.DISCONNECTED
- assert satellite.conversation_id is None
- def test_repr(self, satellite):
- """Testet __repr__."""
- repr_str = repr(satellite)
- assert "Satellite" in repr_str
- assert "sat-test-123" in repr_str
- class TestSatelliteSocket:
- """Tests für SatelliteSocket."""
- def test_socket_initialization(self):
- """Testet die Socket-Initialisierung."""
- sockets = SatelliteSocket()
- assert sockets.command is None
- assert sockets.audio_in is None
- assert sockets.audio_out is None
- assert sockets.music_out is None
- class TestSatelliteManager:
- """Tests für SatelliteManager."""
- @pytest.fixture
- def mock_application(self):
- """Erstellt eine Mock-Anwendung."""
- return MagicMock()
- @pytest.fixture
- def manager(self, mock_application):
- """Erstellt einen SatelliteManager."""
- return SatelliteManager(mock_application)
- @pytest.fixture
- def satellite(self):
- """Erstellt einen Test-Satellite."""
- return Satellite(
- satellite_id="sat-1",
- room_id="wohnzimmer",
- mac_address="AA:BB:CC:DD:EE:FF",
- alias="Echo 1"
- )
- def test_manager_initialization(self, manager):
- """Testet die Manager-Initialisierung."""
- assert manager.count == 0
- assert manager.connected_count == 0
- def test_add_satellite(self, manager, satellite):
- """Testet das Hinzufügen eines Satellites."""
- manager.add(satellite)
- assert manager.count == 1
- assert satellite.id in manager._satellites
- def test_remove_satellite(self, manager, satellite):
- """Testet das Entfernen eines Satellites."""
- manager.add(satellite)
- removed = manager.remove(satellite.id)
- assert removed == satellite
- assert manager.count == 0
- def test_remove_nonexistent(self, manager):
- """Testet das Entfernen eines nicht existierenden Satellites."""
- assert manager.remove("nonexistent") is None
- def test_get_satellite(self, manager, satellite):
- """Testet get."""
- manager.add(satellite)
- result = manager.get(satellite.id)
- assert result == satellite
- def test_get_by_mac(self, manager, satellite):
- """Testet get_by_mac."""
- manager.add(satellite)
- result = manager.get_by_mac("AA:BB:CC:DD:EE:FF")
- assert result == satellite
- def test_get_by_room(self, manager, satellite):
- """Testet get_by_room."""
- manager.add(satellite)
- result = manager.get_by_room("wohnzimmer")
- assert len(result) == 1
- assert result[0] == satellite
- def test_get_connected(self, manager, satellite):
- """Testet get_connected."""
- satellite.set_connected()
- manager.add(satellite)
- connected = manager.get_connected()
- assert len(connected) == 1
- assert manager.connected_count == 1
- def test_get_disconnected(self, manager, satellite):
- """Testet get_disconnected."""
- manager.add(satellite)
- disconnected = manager.get_disconnected()
- assert len(disconnected) == 1
- def test_getitem_by_index(self, manager, satellite):
- """Testet __getitem__ mit Index."""
- manager.add(satellite)
- result = manager[0]
- assert result == satellite
- def test_getitem_by_id(self, manager, satellite):
- """Testet __getitem__ mit ID."""
- manager.add(satellite)
- result = manager[satellite.id]
- assert result == satellite
- def test_getitem_by_room_selector(self, manager, satellite):
- """Testet __getitem__ mit Room-Selektor."""
- manager.add(satellite)
- result = manager["room:wohnzimmer"]
- assert len(result) == 1
- assert result[0] == satellite
- def test_getitem_by_mac_selector(self, manager, satellite):
- """Testet __getitem__ mit MAC-Selektor."""
- manager.add(satellite)
- result = manager["mac:AA:BB:CC:DD:EE:FF"]
- assert result == satellite
- def test_getitem_raises_keyerror(self, manager):
- """Testet, dass __getitem__ KeyError wirft."""
- with pytest.raises(KeyError):
- _ = manager["nonexistent"]
- def test_getitem_raises_indexerror(self, manager):
- """Testet, dass __getitem__ IndexError wirft."""
- with pytest.raises(IndexError):
- _ = manager[0]
- def test_contains(self, manager, satellite):
- """Testet __contains__."""
- manager.add(satellite)
- assert satellite.id in manager
- assert "AA:BB:CC:DD:EE:FF" in manager
- assert "nonexistent" not in manager
- def test_iter(self, manager, satellite):
- """Testet __iter__."""
- manager.add(satellite)
- satellites = list(manager)
- assert len(satellites) == 1
- assert satellites[0] == satellite
- def test_len(self, manager, satellite):
- """Testet __len__."""
- assert len(manager) == 0
- manager.add(satellite)
- assert len(manager) == 1
- @pytest.mark.asyncio
- async def test_disconnect_satellite(self, manager, satellite):
- """Testet disconnect."""
- satellite.set_connected()
- manager.add(satellite)
- result = await manager.disconnect(satellite.id, "Test")
- assert result is True
- assert satellite.state == ConnectionState.DISCONNECTED
- @pytest.mark.asyncio
- async def test_disconnect_all(self, manager, satellite):
- """Testet disconnect_all."""
- satellite.set_connected()
- manager.add(satellite)
- count = await manager.disconnect_all()
- assert count == 1
- def test_find(self, manager):
- """Testet find."""
- sat1 = Satellite(room_id="wohnzimmer", alias="Echo 1")
- sat2 = Satellite(room_id="küche", alias="Echo 2")
- sat1.set_connected()
- manager.add(sat1)
- manager.add(sat2)
- # Nach Raum suchen
- result = manager.find(room="wohnzimmer")
- assert len(result) == 1
- # Nach Alias suchen
- result = manager.find(alias="Echo")
- assert len(result) == 2
- # Nach Verbindungsstatus suchen
- result = manager.find(connected=True)
- assert len(result) == 1
- class TestPendingRegistration:
- """Tests für PendingRegistration."""
- def test_pending_creation(self):
- """Testet die Erstellung einer ausstehenden Registrierung."""
- pending = PendingRegistration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="wohnzimmer",
- alias="Echo 1"
- )
- assert pending.mac_address == "AA:BB:CC:DD:EE:FF"
- assert pending.is_expired() is False
- class TestRegistrationManager:
- """Tests für RegistrationManager."""
- @pytest.fixture
- def mock_application(self):
- """Erstellt eine Mock-Anwendung."""
- return MagicMock()
- @pytest.fixture
- def manager(self, mock_application, temp_dir):
- """Erstellt einen RegistrationManager."""
- return RegistrationManager(mock_application, directory=temp_dir)
- def test_manager_initialization(self, manager):
- """Testet die Manager-Initialisierung."""
- assert manager.registration_mode is False
- assert manager.pending_count == 0
- def test_enable_registration_mode(self, manager):
- """Testet das Aktivieren des Registrierungsmodus."""
- manager.enable_registration_mode(timeout_seconds=60)
- assert manager.registration_mode is True
- def test_disable_registration_mode(self, manager):
- """Testet das Deaktivieren des Registrierungsmodus."""
- manager.enable_registration_mode()
- manager.disable_registration_mode()
- assert manager.registration_mode is False
- def test_begin_registration_requires_mode(self, manager):
- """Testet, dass Registrierung Modus erfordert."""
- result = manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="test",
- alias="Test"
- )
- assert result is False
- def test_begin_registration(self, manager):
- """Testet das Starten einer Registrierung."""
- manager.enable_registration_mode()
- result = manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="wohnzimmer",
- alias="Echo 1"
- )
- assert result is True
- assert manager.pending_count == 1
- def test_complete_registration(self, manager):
- """Testet das Abschließen einer Registrierung."""
- manager.enable_registration_mode()
- manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="wohnzimmer",
- alias="Echo 1"
- )
- satellite = manager.complete_registration("AA:BB:CC:DD:EE:FF")
- assert satellite is not None
- assert satellite.mac_address == "AA:BB:CC:DD:EE:FF"
- assert satellite.room_id == "wohnzimmer"
- assert manager.pending_count == 0
- def test_complete_nonexistent_registration(self, manager):
- """Testet Abschluss einer nicht existierenden Registrierung."""
- satellite = manager.complete_registration("XX:XX:XX:XX:XX:XX")
- assert satellite is None
- def test_cancel_registration(self, manager):
- """Testet das Abbrechen einer Registrierung."""
- manager.enable_registration_mode()
- manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="test",
- alias="Test"
- )
- result = manager.cancel_registration("AA:BB:CC:DD:EE:FF")
- assert result is True
- assert manager.pending_count == 0
- def test_is_registered(self, manager):
- """Testet is_registered."""
- manager.enable_registration_mode()
- manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="test",
- alias="Test"
- )
- manager.complete_registration("AA:BB:CC:DD:EE:FF")
- assert manager.is_registered("AA:BB:CC:DD:EE:FF") is True
- assert manager.is_registered("XX:XX:XX:XX:XX:XX") is False
- def test_load_registered(self, manager):
- """Testet load_registered."""
- # Registriere und speichere
- manager.enable_registration_mode()
- manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="wohnzimmer",
- alias="Echo 1"
- )
- original = manager.complete_registration("AA:BB:CC:DD:EE:FF")
- # Lade erneut
- loaded = manager.load_registered("AA:BB:CC:DD:EE:FF")
- assert loaded is not None
- assert loaded.mac_address == original.mac_address
- assert loaded.room_id == original.room_id
- def test_load_all(self, manager):
- """Testet load_all."""
- # Registriere zwei Satellites
- manager.enable_registration_mode()
- manager.begin_registration("AA:AA:AA:AA:AA:AA", "raum1", "Echo 1")
- manager.complete_registration("AA:AA:AA:AA:AA:AA")
- manager.begin_registration("BB:BB:BB:BB:BB:BB", "raum2", "Echo 2")
- manager.complete_registration("BB:BB:BB:BB:BB:BB")
- satellites = manager.load_all()
- assert len(satellites) == 2
- def test_delete_registration(self, manager):
- """Testet delete_registration."""
- manager.enable_registration_mode()
- manager.begin_registration(
- mac_address="AA:BB:CC:DD:EE:FF",
- room="test",
- alias="Test"
- )
- manager.complete_registration("AA:BB:CC:DD:EE:FF")
- result = manager.delete_registration("AA:BB:CC:DD:EE:FF")
- assert result is True
- assert manager.is_registered("AA:BB:CC:DD:EE:FF") is False
|