test_config.py 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. # -*- coding: utf-8 -*-
  2. """
  3. Unit-Tests für trixy_core.config.
  4. """
  5. import json
  6. import pytest
  7. from dataclasses import dataclass
  8. from pathlib import Path
  9. from trixy_core.config.config_manager import ConfigManager
  10. from trixy_core.config.datasets.server import (
  11. ServerConfig, NetworkConfig, SecurityConfig,
  12. AudioConfig, WakewordConfig, PluginConfig
  13. )
  14. from trixy_core.config.datasets.client import (
  15. ClientConfig, ServerConnectionConfig,
  16. ClientAudioConfig, SatelliteIdentityConfig
  17. )
  18. from trixy_core.config.datasets.standalone import StandaloneConfig
  19. from trixy_core.config.datasets.trainer import (
  20. TrainerConfig, WakewordTrainerConfig,
  21. VoiceRecognitionTrainerConfig, DataConfig
  22. )
  23. class TestServerConfig:
  24. """Tests für Server-Konfiguration."""
  25. def test_default_network_config(self):
  26. """Testet die Standard-Netzwerk-Konfiguration."""
  27. config = NetworkConfig()
  28. assert config.command_port == 2101
  29. assert config.audio_input_port == 2102
  30. assert config.audio_output_port == 2103
  31. assert config.music_port == 2104
  32. assert config.bind_address == "0.0.0.0"
  33. assert config.max_connections == 100
  34. def test_default_security_config(self):
  35. """Testet die Standard-Sicherheits-Konfiguration."""
  36. config = SecurityConfig()
  37. assert config.encryption_enabled is True
  38. assert config.ssl_enabled is False
  39. assert config.allowed_mac_addresses == []
  40. def test_default_audio_config(self):
  41. """Testet die Standard-Audio-Konfiguration."""
  42. config = AudioConfig()
  43. assert config.sample_rate == 16000
  44. assert config.channels == 1
  45. assert config.bit_depth == 16
  46. assert config.music_sample_rate == 44100 # Standard für die meisten Geräte
  47. assert config.music_channels == 2
  48. def test_default_wakeword_config(self):
  49. """Testet die Standard-Wakeword-Konfiguration."""
  50. config = WakewordConfig()
  51. assert config.models == ["custom", "system_command"]
  52. assert config.threshold == 0.5
  53. assert config.debounce_seconds == 1.0
  54. def test_default_server_config(self):
  55. """Testet die Standard-Server-Konfiguration."""
  56. config = ServerConfig()
  57. assert isinstance(config.network, NetworkConfig)
  58. assert isinstance(config.security, SecurityConfig)
  59. assert config.profile == "default"
  60. class TestClientConfig:
  61. """Tests für Client-Konfiguration."""
  62. def test_default_server_connection(self):
  63. """Testet die Standard-Server-Verbindung."""
  64. config = ServerConnectionConfig()
  65. assert config.host == "localhost"
  66. assert config.port == 2101
  67. assert config.reconnect_interval_seconds == 5.0
  68. def test_default_client_audio(self):
  69. """Testet die Standard-Client-Audio-Konfiguration."""
  70. config = ClientAudioConfig()
  71. assert config.sample_rate == 16000
  72. assert config.input_device is None
  73. assert config.output_device is None
  74. def test_default_identity(self):
  75. """Testet die Standard-Identität."""
  76. config = SatelliteIdentityConfig()
  77. assert config.room == ""
  78. assert config.alias == ""
  79. assert config.mac_address == ""
  80. def test_default_client_config(self):
  81. """Testet die Standard-Client-Konfiguration."""
  82. config = ClientConfig()
  83. assert isinstance(config.server, ServerConnectionConfig)
  84. assert isinstance(config.identity, SatelliteIdentityConfig)
  85. class TestStandaloneConfig:
  86. """Tests für Standalone-Konfiguration."""
  87. def test_default_standalone_config(self):
  88. """Testet die Standard-Standalone-Konfiguration."""
  89. config = StandaloneConfig()
  90. assert config.room == "standalone"
  91. assert config.alias == "Trixy"
  92. assert config.profile == "default"
  93. class TestTrainerConfig:
  94. """Tests für Trainer-Konfiguration."""
  95. def test_default_wakeword_trainer(self):
  96. """Testet die Standard-Wakeword-Trainer-Konfiguration."""
  97. config = WakewordTrainerConfig()
  98. assert config.model_name == "custom"
  99. assert config.epochs == 100
  100. assert config.batch_size == 32
  101. assert config.learning_rate == 0.001
  102. def test_default_voice_recognition_trainer(self):
  103. """Testet die Standard-Sprechererkennung-Trainer-Konfiguration."""
  104. config = VoiceRecognitionTrainerConfig()
  105. assert config.embedding_size == 256
  106. assert config.epochs == 100
  107. def test_default_data_config(self):
  108. """Testet die Standard-Daten-Konfiguration."""
  109. config = DataConfig()
  110. assert config.min_samples_per_class == 10
  111. def test_default_trainer_config(self):
  112. """Testet die Standard-Trainer-Konfiguration."""
  113. config = TrainerConfig()
  114. assert config.device == "auto"
  115. assert config.seed == 42
  116. assert config.verbose is True
  117. class TestConfigManager:
  118. """Tests für ConfigManager."""
  119. @pytest.fixture
  120. def manager(self):
  121. """Erstellt einen ConfigManager."""
  122. return ConfigManager()
  123. @pytest.fixture
  124. def config_file(self, temp_dir):
  125. """Erstellt eine Test-Konfigurationsdatei."""
  126. config = {
  127. "network": {
  128. "command_port": 3000,
  129. "audio_input_port": 3001
  130. },
  131. "profile": "test"
  132. }
  133. path = temp_dir / "test_config.json"
  134. path.write_text(json.dumps(config))
  135. return path
  136. def test_load_config(self, manager, config_file):
  137. """Testet das Laden einer Konfiguration."""
  138. config = manager.load(config_file, ServerConfig, name="test")
  139. assert config.network.command_port == 3000
  140. assert config.network.audio_input_port == 3001
  141. assert config.profile == "test"
  142. def test_load_nonexistent_uses_defaults(self, manager, temp_dir):
  143. """Testet, dass fehlende Dateien Standardwerte verwenden."""
  144. path = temp_dir / "nonexistent.json"
  145. config = manager.load(path, ServerConfig, name="default")
  146. assert config.network.command_port == 2101 # Standard
  147. def test_get_config(self, manager, config_file):
  148. """Testet das Abrufen einer Konfiguration."""
  149. manager.load(config_file, ServerConfig, name="test")
  150. config = manager.get("test")
  151. assert config is not None
  152. assert isinstance(config, ServerConfig)
  153. def test_get_nonexistent_config(self, manager):
  154. """Testet get für nicht existierende Konfiguration."""
  155. assert manager.get("nonexistent") is None
  156. def test_get_typed(self, manager, config_file):
  157. """Testet get_typed."""
  158. manager.load(config_file, ServerConfig, name="test")
  159. config = manager.get_typed("test", ServerConfig)
  160. assert isinstance(config, ServerConfig)
  161. def test_save_config(self, manager, temp_dir):
  162. """Testet das Speichern einer Konfiguration."""
  163. path = temp_dir / "save_test.json"
  164. config = ServerConfig()
  165. config.profile = "saved"
  166. manager.load(path, ServerConfig, name="save")
  167. manager.save("save", config)
  168. # Datei lesen und prüfen
  169. data = json.loads(path.read_text())
  170. assert data["profile"] == "saved"
  171. def test_reload_config(self, manager, config_file):
  172. """Testet das Neuladen einer Konfiguration."""
  173. manager.load(config_file, ServerConfig, name="test")
  174. # Datei ändern
  175. config_file.write_text(json.dumps({
  176. "profile": "reloaded"
  177. }))
  178. config = manager.reload("test")
  179. assert config.profile == "reloaded"
  180. def test_on_reload_callback(self, manager, config_file):
  181. """Testet Reload-Callbacks."""
  182. called = []
  183. def callback(config):
  184. called.append(config)
  185. manager.load(config_file, ServerConfig, name="test")
  186. manager.on_reload("test", callback)
  187. # Datei ändern
  188. config_file.write_text(json.dumps({"profile": "callback_test"}))
  189. manager.reload("test")
  190. assert len(called) == 1
  191. assert called[0].profile == "callback_test"
  192. def test_create_default(self, manager, temp_dir):
  193. """Testet das Erstellen einer Standard-Konfiguration."""
  194. path = temp_dir / "default_config.json"
  195. config = manager.create_default(ServerConfig, path)
  196. assert path.exists()
  197. assert isinstance(config, ServerConfig)
  198. # Datei lesen und prüfen
  199. data = json.loads(path.read_text())
  200. assert "network" in data
  201. def test_nested_dataclass_loading(self, manager, temp_dir):
  202. """Testet das Laden verschachtelter Dataclasses."""
  203. config = {
  204. "network": {
  205. "command_port": 5000,
  206. "bind_address": "127.0.0.1"
  207. },
  208. "security": {
  209. "encryption_enabled": False
  210. }
  211. }
  212. path = temp_dir / "nested.json"
  213. path.write_text(json.dumps(config))
  214. loaded = manager.load(path, ServerConfig, name="nested")
  215. assert loaded.network.command_port == 5000
  216. assert loaded.network.bind_address == "127.0.0.1"
  217. assert loaded.security.encryption_enabled is False
  218. def test_stop_watching(self, manager):
  219. """Testet das Stoppen der Dateiüberwachung."""
  220. # Sollte ohne Fehler durchlaufen
  221. manager.stop_watching()