Michael Hu commited on
Commit
fafafc3
Β·
1 Parent(s): 6aea21a

Create configuration and dependency injection setup

Browse files
config.example.json ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "tts": {
3
+ "preferred_providers": ["kokoro", "dia", "cosyvoice2", "dummy"],
4
+ "default_voice": "default",
5
+ "default_speed": 1.0,
6
+ "default_language": "en",
7
+ "enable_streaming": true,
8
+ "max_text_length": 10000
9
+ },
10
+ "stt": {
11
+ "preferred_providers": ["whisper", "parakeet"],
12
+ "default_model": "whisper",
13
+ "chunk_length_s": 30,
14
+ "batch_size": 16,
15
+ "enable_vad": true
16
+ },
17
+ "translation": {
18
+ "default_provider": "nllb",
19
+ "model_name": "facebook/nllb-200-3.3B",
20
+ "max_chunk_length": 1000,
21
+ "batch_size": 8,
22
+ "cache_translations": true
23
+ },
24
+ "processing": {
25
+ "temp_dir": "/tmp/audio_processing",
26
+ "cleanup_temp_files": true,
27
+ "max_file_size_mb": 100,
28
+ "supported_audio_formats": ["wav", "mp3", "flac", "ogg"],
29
+ "processing_timeout_seconds": 300
30
+ },
31
+ "logging": {
32
+ "level": "INFO",
33
+ "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
34
+ "enable_file_logging": false,
35
+ "log_file_path": "app.log",
36
+ "max_log_file_size_mb": 10,
37
+ "backup_count": 5
38
+ }
39
+ }
src/infrastructure/config/container_setup.py ADDED
@@ -0,0 +1,426 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Container setup module for registering all services and dependencies."""
2
+
3
+ import logging
4
+ from typing import Optional
5
+
6
+ from .app_config import AppConfig
7
+ from .dependency_container import DependencyContainer, ServiceLifetime
8
+ from ..tts.provider_factory import TTSProviderFactory
9
+ from ..stt.provider_factory import STTProviderFactory
10
+ from ..translation.provider_factory import TranslationProviderFactory
11
+ from ...domain.interfaces.audio_processing import IAudioProcessingService
12
+ from ...domain.interfaces.speech_recognition import ISpeechRecognitionService
13
+ from ...domain.interfaces.translation import ITranslationService
14
+ from ...domain.interfaces.speech_synthesis import ISpeechSynthesisService
15
+ from ...domain.services.audio_processing_service import AudioProcessingService
16
+ from ...application.services.audio_processing_service import AudioProcessingApplicationService
17
+ from ...application.services.configuration_service import ConfigurationApplicationService
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+
22
+ def setup_container(config_file: Optional[str] = None) -> DependencyContainer:
23
+ """
24
+ Set up and configure the dependency injection container with all services.
25
+
26
+ Args:
27
+ config_file: Optional path to configuration file
28
+
29
+ Returns:
30
+ DependencyContainer: Configured container instance
31
+ """
32
+ logger.info("Setting up dependency injection container")
33
+
34
+ # Create configuration
35
+ config = AppConfig(config_file=config_file)
36
+
37
+ # Create container with configuration
38
+ container = DependencyContainer(config)
39
+
40
+ # Register core services
41
+ _register_core_services(container, config)
42
+
43
+ # Register domain services
44
+ _register_domain_services(container)
45
+
46
+ # Register application services
47
+ _register_application_services(container)
48
+
49
+ # Register provider services
50
+ _register_provider_services(container)
51
+
52
+ logger.info("Dependency injection container setup completed")
53
+ return container
54
+
55
+
56
+ def _register_core_services(container: DependencyContainer, config: AppConfig) -> None:
57
+ """
58
+ Register core infrastructure services.
59
+
60
+ Args:
61
+ container: Dependency container
62
+ config: Application configuration
63
+ """
64
+ logger.debug("Registering core services")
65
+
66
+ # Configuration is already registered as singleton in container constructor
67
+ # But we ensure it's the same instance
68
+ container.register_singleton(AppConfig, config)
69
+
70
+ # Register provider factories as singletons
71
+ container.register_singleton(
72
+ TTSProviderFactory,
73
+ lambda: TTSProviderFactory()
74
+ )
75
+
76
+ container.register_singleton(
77
+ STTProviderFactory,
78
+ lambda: STTProviderFactory()
79
+ )
80
+
81
+ container.register_singleton(
82
+ TranslationProviderFactory,
83
+ lambda: TranslationProviderFactory()
84
+ )
85
+
86
+ logger.debug("Core services registered")
87
+
88
+
89
+ def _register_domain_services(container: DependencyContainer) -> None:
90
+ """
91
+ Register domain services.
92
+
93
+ Args:
94
+ container: Dependency container
95
+ """
96
+ logger.debug("Registering domain services")
97
+
98
+ # Register domain audio processing service as transient
99
+ # It requires other services to be injected
100
+ def create_audio_processing_service() -> IAudioProcessingService:
101
+ """Factory function for creating audio processing service."""
102
+ # Get provider services from container
103
+ stt_provider = container.get_stt_provider()
104
+ translation_provider = container.get_translation_provider()
105
+ tts_provider = container.get_tts_provider()
106
+
107
+ return AudioProcessingService(
108
+ speech_recognition_service=stt_provider,
109
+ translation_service=translation_provider,
110
+ speech_synthesis_service=tts_provider
111
+ )
112
+
113
+ container.register_transient(
114
+ IAudioProcessingService,
115
+ create_audio_processing_service
116
+ )
117
+
118
+ logger.debug("Domain services registered")
119
+
120
+
121
+ def _register_application_services(container: DependencyContainer) -> None:
122
+ """
123
+ Register application services.
124
+
125
+ Args:
126
+ container: Dependency container
127
+ """
128
+ logger.debug("Registering application services")
129
+
130
+ # Register audio processing application service as scoped
131
+ # It manages resources and should be scoped to request/session
132
+ def create_audio_processing_app_service() -> AudioProcessingApplicationService:
133
+ """Factory function for creating audio processing application service."""
134
+ return AudioProcessingApplicationService(container)
135
+
136
+ container.register_scoped(
137
+ AudioProcessingApplicationService,
138
+ create_audio_processing_app_service
139
+ )
140
+
141
+ # Register configuration application service as singleton
142
+ # Configuration service can be shared across requests
143
+ def create_configuration_app_service() -> ConfigurationApplicationService:
144
+ """Factory function for creating configuration application service."""
145
+ return ConfigurationApplicationService(container)
146
+
147
+ container.register_singleton(
148
+ ConfigurationApplicationService,
149
+ create_configuration_app_service
150
+ )
151
+
152
+ logger.debug("Application services registered")
153
+
154
+
155
+ def _register_provider_services(container: DependencyContainer) -> None:
156
+ """
157
+ Register provider services with fallback logic.
158
+
159
+ Args:
160
+ container: Dependency container
161
+ """
162
+ logger.debug("Registering provider services")
163
+
164
+ # Register TTS provider service as transient with fallback
165
+ def create_tts_provider() -> ISpeechSynthesisService:
166
+ """Factory function for creating TTS provider with fallback."""
167
+ return container.get_tts_provider()
168
+
169
+ container.register_transient(
170
+ ISpeechSynthesisService,
171
+ create_tts_provider
172
+ )
173
+
174
+ # Register STT provider service as transient with fallback
175
+ def create_stt_provider() -> ISpeechRecognitionService:
176
+ """Factory function for creating STT provider with fallback."""
177
+ return container.get_stt_provider()
178
+
179
+ container.register_transient(
180
+ ISpeechRecognitionService,
181
+ create_stt_provider
182
+ )
183
+
184
+ # Register translation provider service as transient with fallback
185
+ def create_translation_provider() -> ITranslationService:
186
+ """Factory function for creating translation provider with fallback."""
187
+ return container.get_translation_provider()
188
+
189
+ container.register_transient(
190
+ ITranslationService,
191
+ create_translation_provider
192
+ )
193
+
194
+ logger.debug("Provider services registered")
195
+
196
+
197
+ def configure_logging(config: AppConfig) -> None:
198
+ """
199
+ Configure application logging based on configuration.
200
+
201
+ Args:
202
+ config: Application configuration
203
+ """
204
+ try:
205
+ logging_config = config.get_logging_config()
206
+
207
+ # Configure root logger
208
+ root_logger = logging.getLogger()
209
+ root_logger.setLevel(getattr(logging, logging_config['level'].upper(), logging.INFO))
210
+
211
+ # Clear existing handlers
212
+ for handler in root_logger.handlers[:]:
213
+ root_logger.removeHandler(handler)
214
+
215
+ # Create console handler
216
+ console_handler = logging.StreamHandler()
217
+ console_handler.setLevel(root_logger.level)
218
+
219
+ # Create formatter
220
+ formatter = logging.Formatter(logging_config['format'])
221
+ console_handler.setFormatter(formatter)
222
+
223
+ # Add console handler
224
+ root_logger.addHandler(console_handler)
225
+
226
+ # Add file handler if enabled
227
+ if logging_config.get('enable_file_logging', False):
228
+ from logging.handlers import RotatingFileHandler
229
+
230
+ file_handler = RotatingFileHandler(
231
+ logging_config['log_file_path'],
232
+ maxBytes=logging_config['max_log_file_size_mb'] * 1024 * 1024,
233
+ backupCount=logging_config['backup_count']
234
+ )
235
+ file_handler.setLevel(root_logger.level)
236
+ file_handler.setFormatter(formatter)
237
+
238
+ root_logger.addHandler(file_handler)
239
+
240
+ logger.info(f"Logging configured: level={logging_config['level']}")
241
+
242
+ except Exception as e:
243
+ # Fallback to basic logging configuration
244
+ logging.basicConfig(
245
+ level=logging.INFO,
246
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
247
+ )
248
+ logger.warning(f"Failed to configure logging from config, using defaults: {e}")
249
+
250
+
251
+ def create_configured_container(config_file: Optional[str] = None) -> DependencyContainer:
252
+ """
253
+ Create and configure a complete dependency injection container.
254
+
255
+ This is the main entry point for setting up the application's dependency injection.
256
+
257
+ Args:
258
+ config_file: Optional path to configuration file
259
+
260
+ Returns:
261
+ DependencyContainer: Fully configured container
262
+ """
263
+ try:
264
+ # Setup container
265
+ container = setup_container(config_file)
266
+
267
+ # Configure logging
268
+ config = container.resolve(AppConfig)
269
+ configure_logging(config)
270
+
271
+ # Validate container setup
272
+ _validate_container_setup(container)
273
+
274
+ logger.info("Application container created and configured successfully")
275
+ return container
276
+
277
+ except Exception as e:
278
+ logger.error(f"Failed to create configured container: {e}")
279
+ raise
280
+
281
+
282
+ def _validate_container_setup(container: DependencyContainer) -> None:
283
+ """
284
+ Validate that the container is properly set up.
285
+
286
+ Args:
287
+ container: Container to validate
288
+
289
+ Raises:
290
+ RuntimeError: If validation fails
291
+ """
292
+ logger.debug("Validating container setup")
293
+
294
+ required_services = [
295
+ AppConfig,
296
+ TTSProviderFactory,
297
+ STTProviderFactory,
298
+ TranslationProviderFactory,
299
+ IAudioProcessingService,
300
+ AudioProcessingApplicationService,
301
+ ConfigurationApplicationService,
302
+ ISpeechSynthesisService,
303
+ ISpeechRecognitionService,
304
+ ITranslationService
305
+ ]
306
+
307
+ missing_services = []
308
+
309
+ for service_type in required_services:
310
+ if not container.is_registered(service_type):
311
+ missing_services.append(service_type.__name__)
312
+
313
+ if missing_services:
314
+ raise RuntimeError(f"Container validation failed. Missing services: {missing_services}")
315
+
316
+ # Test service resolution
317
+ try:
318
+ config = container.resolve(AppConfig)
319
+ app_service = container.resolve(AudioProcessingApplicationService)
320
+ config_service = container.resolve(ConfigurationApplicationService)
321
+
322
+ logger.debug("Container validation successful")
323
+
324
+ except Exception as e:
325
+ raise RuntimeError(f"Container validation failed during service resolution: {e}")
326
+
327
+
328
+ def get_service_registry_info(container: DependencyContainer) -> dict:
329
+ """
330
+ Get information about registered services in the container.
331
+
332
+ Args:
333
+ container: Container to inspect
334
+
335
+ Returns:
336
+ dict: Service registry information
337
+ """
338
+ try:
339
+ registered_services = container.get_registered_services()
340
+
341
+ # Get provider availability
342
+ config = container.resolve(AppConfig)
343
+ tts_factory = container.resolve(TTSProviderFactory)
344
+ stt_factory = container.resolve(STTProviderFactory)
345
+ translation_factory = container.resolve(TranslationProviderFactory)
346
+
347
+ provider_info = {
348
+ 'tts_providers': tts_factory.get_available_providers(),
349
+ 'stt_providers': stt_factory.get_available_providers(),
350
+ 'translation_providers': [p.value for p in translation_factory.get_available_providers()]
351
+ }
352
+
353
+ return {
354
+ 'registered_services': registered_services,
355
+ 'provider_availability': provider_info,
356
+ 'configuration_summary': {
357
+ 'config_file': config.config_file,
358
+ 'temp_dir': config.processing.temp_dir,
359
+ 'log_level': config.logging.level,
360
+ 'tts_preferred_providers': config.tts.preferred_providers,
361
+ 'stt_default_model': config.stt.default_model,
362
+ 'translation_default_provider': config.translation.default_provider
363
+ }
364
+ }
365
+
366
+ except Exception as e:
367
+ logger.error(f"Failed to get service registry info: {e}")
368
+ return {
369
+ 'error': str(e),
370
+ 'registered_services': container.get_registered_services() if container else {}
371
+ }
372
+
373
+
374
+ # Global container instance management
375
+ _global_container: Optional[DependencyContainer] = None
376
+
377
+
378
+ def initialize_global_container(config_file: Optional[str] = None) -> DependencyContainer:
379
+ """
380
+ Initialize the global container instance.
381
+
382
+ Args:
383
+ config_file: Optional configuration file path
384
+
385
+ Returns:
386
+ DependencyContainer: Global container instance
387
+ """
388
+ global _global_container
389
+
390
+ if _global_container is not None:
391
+ logger.warning("Global container already initialized, cleaning up previous instance")
392
+ _global_container.cleanup()
393
+
394
+ _global_container = create_configured_container(config_file)
395
+ logger.info("Global container initialized")
396
+
397
+ return _global_container
398
+
399
+
400
+ def get_global_container() -> DependencyContainer:
401
+ """
402
+ Get the global container instance.
403
+
404
+ Returns:
405
+ DependencyContainer: Global container instance
406
+
407
+ Raises:
408
+ RuntimeError: If container is not initialized
409
+ """
410
+ global _global_container
411
+
412
+ if _global_container is None:
413
+ logger.info("Global container not initialized, creating with defaults")
414
+ _global_container = create_configured_container()
415
+
416
+ return _global_container
417
+
418
+
419
+ def cleanup_global_container() -> None:
420
+ """Cleanup the global container instance."""
421
+ global _global_container
422
+
423
+ if _global_container is not None:
424
+ _global_container.cleanup()
425
+ _global_container = None
426
+ logger.info("Global container cleaned up")
test_dependency_injection.py CHANGED
@@ -1,58 +1,314 @@
1
  #!/usr/bin/env python3
2
- """Test script for dependency injection implementation."""
3
 
4
  import sys
5
  import os
 
 
6
 
7
- # Add src to path
8
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))
9
-
10
- try:
11
- from infrastructure.config.dependency_container import DependencyContainer, get_container
12
- from infrastructure.config.app_config import AppConfig
13
- from infrastructure.tts.provider_factory import TTSProviderFactory
14
- from infrastructure.stt.provider_factory import STTProviderFactory
15
- from infrastructure.translation.provider_factory import TranslationProviderFactory
16
-
17
- print("πŸ§ͺ Testing Dependency Injection Implementation...")
18
- print()
19
-
20
- # Test basic container functionality
21
- container = DependencyContainer()
22
- print('βœ… DependencyContainer created successfully')
23
-
24
- # Test configuration resolution
25
- config = container.resolve(AppConfig)
26
- print(f'βœ… AppConfig resolved: {type(config).__name__}')
27
-
28
- # Test factory resolution
29
- tts_factory = container.resolve(TTSProviderFactory)
30
- stt_factory = container.resolve(STTProviderFactory)
31
- translation_factory = container.resolve(TranslationProviderFactory)
32
-
33
- print(f'βœ… TTSProviderFactory resolved: {type(tts_factory).__name__}')
34
- print(f'βœ… STTProviderFactory resolved: {type(stt_factory).__name__}')
35
- print(f'βœ… TranslationProviderFactory resolved: {type(translation_factory).__name__}')
36
-
37
- # Test global container
38
- global_container = get_container()
39
- print(f'βœ… Global container retrieved: {type(global_container).__name__}')
40
-
41
- # Test service registration info
42
- services = container.get_registered_services()
43
- print(f'βœ… Registered services: {len(services)} services')
44
- for service_name, lifetime in services.items():
45
- print(f' - {service_name}: {lifetime}')
46
-
47
- # Test cleanup
48
- container.cleanup()
49
- print('βœ… Container cleanup completed')
50
-
51
- print()
52
- print('πŸŽ‰ All dependency injection tests passed!')
53
-
54
- except Exception as e:
55
- print(f'❌ Test failed: {e}')
56
- import traceback
57
- traceback.print_exc()
58
- sys.exit(1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #!/usr/bin/env python3
2
+ """Test script for dependency injection and configuration setup."""
3
 
4
  import sys
5
  import os
6
+ import logging
7
+ from pathlib import Path
8
 
9
+ # Add src to path for imports
10
+ sys.path.insert(0, str(Path(__file__).parent / "src"))
11
+
12
+ from infrastructure.config.container_setup import (
13
+ create_configured_container,
14
+ get_service_registry_info,
15
+ initialize_global_container,
16
+ get_global_container,
17
+ cleanup_global_container
18
+ )
19
+ from infrastructure.config.app_config import AppConfig
20
+ from infrastructure.config.dependency_container import DependencyContainer
21
+ from application.services.audio_processing_service import AudioProcessingApplicationService
22
+ from application.services.configuration_service import ConfigurationApplicationService
23
+
24
+
25
+ def test_configuration_loading():
26
+ """Test configuration loading from file and environment."""
27
+ print("=" * 60)
28
+ print("Testing Configuration Loading")
29
+ print("=" * 60)
30
+
31
+ try:
32
+ # Test default configuration
33
+ print("\n1. Testing default configuration...")
34
+ config = AppConfig()
35
+ print(f"βœ“ Default config loaded successfully")
36
+ print(f" - TTS preferred providers: {config.tts.preferred_providers}")
37
+ print(f" - STT default model: {config.stt.default_model}")
38
+ print(f" - Translation provider: {config.translation.default_provider}")
39
+ print(f" - Temp directory: {config.processing.temp_dir}")
40
+ print(f" - Log level: {config.logging.level}")
41
+
42
+ # Test configuration from file
43
+ print("\n2. Testing configuration from file...")
44
+ config_file = "config.example.json"
45
+ if os.path.exists(config_file):
46
+ config_from_file = AppConfig(config_file=config_file)
47
+ print(f"βœ“ Config loaded from {config_file}")
48
+ print(f" - TTS preferred providers: {config_from_file.tts.preferred_providers}")
49
+ print(f" - Processing timeout: {config_from_file.processing.processing_timeout_seconds}s")
50
+ else:
51
+ print(f"⚠ Config file {config_file} not found, skipping file test")
52
+
53
+ # Test environment variable override
54
+ print("\n3. Testing environment variable override...")
55
+ os.environ['TTS_DEFAULT_SPEED'] = '1.5'
56
+ os.environ['LOG_LEVEL'] = 'DEBUG'
57
+
58
+ config_with_env = AppConfig()
59
+ print(f"βœ“ Config with environment overrides loaded")
60
+ print(f" - TTS default speed: {config_with_env.tts.default_speed}")
61
+ print(f" - Log level: {config_with_env.logging.level}")
62
+
63
+ # Clean up environment
64
+ del os.environ['TTS_DEFAULT_SPEED']
65
+ del os.environ['LOG_LEVEL']
66
+
67
+ return True
68
+
69
+ except Exception as e:
70
+ print(f"βœ— Configuration loading failed: {e}")
71
+ return False
72
+
73
+
74
+ def test_dependency_container():
75
+ """Test dependency container setup and service resolution."""
76
+ print("\n" + "=" * 60)
77
+ print("Testing Dependency Container")
78
+ print("=" * 60)
79
+
80
+ try:
81
+ # Test container creation
82
+ print("\n1. Testing container creation...")
83
+ container = create_configured_container()
84
+ print("βœ“ Container created successfully")
85
+
86
+ # Test service registration info
87
+ print("\n2. Testing service registry...")
88
+ registry_info = get_service_registry_info(container)
89
+ print("βœ“ Service registry information retrieved")
90
+ print(f" - Registered services: {len(registry_info['registered_services'])}")
91
+
92
+ for service_name, lifetime in registry_info['registered_services'].items():
93
+ print(f" β€’ {service_name}: {lifetime}")
94
+
95
+ # Test provider availability
96
+ print("\n3. Testing provider availability...")
97
+ provider_info = registry_info['provider_availability']
98
+ print(f" - Available TTS providers: {provider_info['tts_providers']}")
99
+ print(f" - Available STT providers: {provider_info['stt_providers']}")
100
+ print(f" - Available translation providers: {provider_info['translation_providers']}")
101
+
102
+ # Test service resolution
103
+ print("\n4. Testing service resolution...")
104
+
105
+ # Resolve configuration
106
+ config = container.resolve(AppConfig)
107
+ print("βœ“ AppConfig resolved successfully")
108
+
109
+ # Resolve application services
110
+ audio_service = container.resolve(AudioProcessingApplicationService)
111
+ print("βœ“ AudioProcessingApplicationService resolved successfully")
112
+
113
+ config_service = container.resolve(ConfigurationApplicationService)
114
+ print("βœ“ ConfigurationApplicationService resolved successfully")
115
+
116
+ # Test provider services
117
+ tts_provider = container.get_tts_provider()
118
+ print(f"βœ“ TTS provider resolved: {tts_provider.__class__.__name__}")
119
+
120
+ stt_provider = container.get_stt_provider()
121
+ print(f"βœ“ STT provider resolved: {stt_provider.__class__.__name__}")
122
+
123
+ translation_provider = container.get_translation_provider()
124
+ print(f"βœ“ Translation provider resolved: {translation_provider.__class__.__name__}")
125
+
126
+ # Test scoped services
127
+ print("\n5. Testing scoped services...")
128
+ with container.create_scope() as scope:
129
+ scoped_audio_service = scope.resolve(AudioProcessingApplicationService)
130
+ print("βœ“ Scoped AudioProcessingApplicationService resolved")
131
+
132
+ # Cleanup
133
+ container.cleanup()
134
+ print("βœ“ Container cleanup completed")
135
+
136
+ return True
137
+
138
+ except Exception as e:
139
+ print(f"βœ— Dependency container test failed: {e}")
140
+ import traceback
141
+ traceback.print_exc()
142
+ return False
143
+
144
+
145
+ def test_global_container():
146
+ """Test global container management."""
147
+ print("\n" + "=" * 60)
148
+ print("Testing Global Container Management")
149
+ print("=" * 60)
150
+
151
+ try:
152
+ # Test global container initialization
153
+ print("\n1. Testing global container initialization...")
154
+ global_container = initialize_global_container()
155
+ print("βœ“ Global container initialized")
156
+
157
+ # Test global container access
158
+ print("\n2. Testing global container access...")
159
+ retrieved_container = get_global_container()
160
+ print("βœ“ Global container retrieved")
161
+
162
+ assert global_container is retrieved_container, "Global container instances should be the same"
163
+ print("βœ“ Global container instance consistency verified")
164
+
165
+ # Test service resolution through global container
166
+ print("\n3. Testing service resolution through global container...")
167
+ config = retrieved_container.resolve(AppConfig)
168
+ print("βœ“ Configuration resolved through global container")
169
+
170
+ # Test global container cleanup
171
+ print("\n4. Testing global container cleanup...")
172
+ cleanup_global_container()
173
+ print("βœ“ Global container cleaned up")
174
+
175
+ return True
176
+
177
+ except Exception as e:
178
+ print(f"βœ— Global container test failed: {e}")
179
+ return False
180
+
181
+
182
+ def test_configuration_service():
183
+ """Test configuration application service."""
184
+ print("\n" + "=" * 60)
185
+ print("Testing Configuration Application Service")
186
+ print("=" * 60)
187
+
188
+ try:
189
+ # Create container
190
+ container = create_configured_container()
191
+
192
+ # Get configuration service
193
+ print("\n1. Testing configuration service resolution...")
194
+ config_service = container.resolve(ConfigurationApplicationService)
195
+ print("βœ“ Configuration service resolved")
196
+
197
+ # Test getting current configuration
198
+ print("\n2. Testing configuration retrieval...")
199
+ current_config = config_service.get_current_configuration()
200
+ print("βœ“ Current configuration retrieved")
201
+ print(f" - Configuration sections: {list(current_config.keys())}")
202
+
203
+ # Test TTS configuration
204
+ print("\n3. Testing TTS configuration...")
205
+ tts_config = config_service.get_tts_configuration()
206
+ print(f"βœ“ TTS configuration: {len(tts_config)} settings")
207
+
208
+ # Test configuration updates
209
+ print("\n4. Testing configuration updates...")
210
+ updated_tts = config_service.update_tts_configuration({
211
+ 'default_speed': 1.2,
212
+ 'enable_streaming': False
213
+ })
214
+ print("βœ“ TTS configuration updated")
215
+ print(f" - New default speed: {updated_tts['default_speed']}")
216
+ print(f" - Streaming enabled: {updated_tts['enable_streaming']}")
217
+
218
+ # Test provider availability
219
+ print("\n5. Testing provider availability check...")
220
+ availability = config_service.get_provider_availability()
221
+ print("βœ“ Provider availability checked")
222
+ for category, providers in availability.items():
223
+ print(f" - {category.upper()}: {providers}")
224
+
225
+ # Test system info
226
+ print("\n6. Testing system information...")
227
+ system_info = config_service.get_system_info()
228
+ print("βœ“ System information retrieved")
229
+ print(f" - Supported languages: {len(system_info['supported_languages'])}")
230
+ print(f" - Supported audio formats: {system_info['supported_audio_formats']}")
231
+
232
+ # Test configuration validation
233
+ print("\n7. Testing configuration validation...")
234
+ validation_issues = config_service.validate_configuration()
235
+ print("βœ“ Configuration validation completed")
236
+
237
+ total_issues = sum(len(issues) for issues in validation_issues.values())
238
+ if total_issues == 0:
239
+ print(" - No validation issues found")
240
+ else:
241
+ print(f" - Found {total_issues} validation issues")
242
+ for category, issues in validation_issues.items():
243
+ if issues:
244
+ print(f" β€’ {category}: {issues}")
245
+
246
+ # Cleanup
247
+ container.cleanup()
248
+
249
+ return True
250
+
251
+ except Exception as e:
252
+ print(f"βœ— Configuration service test failed: {e}")
253
+ import traceback
254
+ traceback.print_exc()
255
+ return False
256
+
257
+
258
+ def main():
259
+ """Run all tests."""
260
+ print("Dependency Injection and Configuration Test Suite")
261
+ print("=" * 60)
262
+
263
+ # Configure basic logging
264
+ logging.basicConfig(
265
+ level=logging.WARNING, # Reduce noise during testing
266
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
267
+ )
268
+
269
+ tests = [
270
+ ("Configuration Loading", test_configuration_loading),
271
+ ("Dependency Container", test_dependency_container),
272
+ ("Global Container Management", test_global_container),
273
+ ("Configuration Service", test_configuration_service)
274
+ ]
275
+
276
+ results = []
277
+
278
+ for test_name, test_func in tests:
279
+ try:
280
+ result = test_func()
281
+ results.append((test_name, result))
282
+ except Exception as e:
283
+ print(f"\nβœ— {test_name} failed with exception: {e}")
284
+ results.append((test_name, False))
285
+
286
+ # Print summary
287
+ print("\n" + "=" * 60)
288
+ print("Test Results Summary")
289
+ print("=" * 60)
290
+
291
+ passed = 0
292
+ failed = 0
293
+
294
+ for test_name, result in results:
295
+ status = "βœ“ PASSED" if result else "βœ— FAILED"
296
+ print(f"{test_name:<30} {status}")
297
+
298
+ if result:
299
+ passed += 1
300
+ else:
301
+ failed += 1
302
+
303
+ print(f"\nTotal: {len(results)} tests, {passed} passed, {failed} failed")
304
+
305
+ if failed == 0:
306
+ print("\nπŸŽ‰ All tests passed!")
307
+ return 0
308
+ else:
309
+ print(f"\n❌ {failed} test(s) failed!")
310
+ return 1
311
+
312
+
313
+ if __name__ == "__main__":
314
+ sys.exit(main())