""" Comprehensive Integration Tests for Configuration System Tests the entire configuration system end-to-end, ensuring all components work together seamlessly including validation, error handling, and strategy creation. """ import pytest import json from typing import Dict, List, Any from components.charts.config import ( # Core configuration classes StrategyChartConfig, SubplotConfig, SubplotType, ChartStyle, ChartLayout, TradingStrategy, IndicatorCategory, # Configuration functions create_custom_strategy_config, validate_configuration, validate_configuration_strict, check_configuration_health, # Example strategies create_ema_crossover_strategy, create_momentum_breakout_strategy, create_mean_reversion_strategy, create_scalping_strategy, create_swing_trading_strategy, get_all_example_strategies, # Indicator management get_all_default_indicators, get_indicators_by_category, create_indicator_config, # Error handling ErrorSeverity, ConfigurationError, validate_strategy_name, get_indicator_suggestions, # Validation ValidationLevel, ConfigurationValidator ) class TestConfigurationSystemIntegration: """Test the entire configuration system working together.""" def test_complete_strategy_creation_workflow(self): """Test complete workflow from strategy creation to validation.""" # 1. Create a custom strategy configuration config, errors = create_custom_strategy_config( strategy_name="Integration Test Strategy", strategy_type=TradingStrategy.DAY_TRADING, description="A comprehensive test strategy", timeframes=["15m", "1h", "4h"], overlay_indicators=["ema_12", "ema_26", "sma_50"], subplot_configs=[ { "subplot_type": "rsi", "height_ratio": 0.25, "indicators": ["rsi_14"], "title": "RSI Momentum" }, { "subplot_type": "macd", "height_ratio": 0.25, "indicators": ["macd_12_26_9"], "title": "MACD Convergence" } ] ) # 2. Validate configuration was created successfully # Note: Config might be None if indicators don't exist in test environment if config is not None: assert config.strategy_name == "Integration Test Strategy" assert len(config.overlay_indicators) == 3 assert len(config.subplot_configs) == 2 # 3. Validate the configuration using basic validation is_valid, validation_errors = config.validate() # 4. Perform strict validation error_report = validate_configuration_strict(config) # 5. Check configuration health health_check = check_configuration_health(config) assert "is_healthy" in health_check assert "total_indicators" in health_check else: # Configuration failed to create - check that we got errors assert len(errors) > 0 def test_example_strategies_integration(self): """Test all example strategies work with the validation system.""" strategies = get_all_example_strategies() assert len(strategies) >= 5 # We created 5 example strategies for strategy_name, strategy_example in strategies.items(): config = strategy_example.config # Test configuration is valid assert isinstance(config, StrategyChartConfig) assert config.strategy_name is not None assert config.strategy_type is not None assert len(config.overlay_indicators) > 0 or len(config.subplot_configs) > 0 # Test validation passes (using the main validation function) validation_report = validate_configuration(config) # Note: May have warnings in test environment due to missing indicators assert isinstance(validation_report.is_valid, bool) # Test health check health = check_configuration_health(config) assert "is_healthy" in health assert "total_indicators" in health def test_indicator_system_integration(self): """Test indicator system integration with configurations.""" # Get all available indicators indicators = get_all_default_indicators() assert len(indicators) > 20 # Should have many indicators # Test indicators by category for category in IndicatorCategory: category_indicators = get_indicators_by_category(category) assert isinstance(category_indicators, dict) # Test creating configurations for each indicator for indicator_name, indicator_preset in list(category_indicators.items())[:3]: # Test first 3 # Test that indicator preset has required properties assert hasattr(indicator_preset, 'config') assert hasattr(indicator_preset, 'name') assert hasattr(indicator_preset, 'category') def test_error_handling_integration(self): """Test error handling integration across the system.""" # Test with invalid strategy name error = validate_strategy_name("nonexistent_strategy") assert error is not None assert error.severity == ErrorSeverity.CRITICAL assert len(error.suggestions) > 0 # Test with invalid configuration invalid_config = StrategyChartConfig( strategy_name="Invalid Strategy", strategy_type=TradingStrategy.DAY_TRADING, description="Strategy with missing indicators", timeframes=["1h"], overlay_indicators=["nonexistent_indicator_999"] ) # Validate with strict validation error_report = validate_configuration_strict(invalid_config) assert not error_report.is_usable assert len(error_report.missing_indicators) > 0 # Check that error handling provides suggestions suggestions = get_indicator_suggestions("nonexistent") assert isinstance(suggestions, list) def test_validation_system_integration(self): """Test validation system with different validation approaches.""" # Create a configuration with potential issues config = StrategyChartConfig( strategy_name="Test Validation", strategy_type=TradingStrategy.SCALPING, description="Test strategy", timeframes=["1d"], # Wrong timeframe for scalping overlay_indicators=["ema_12", "sma_20"] ) # Test main validation function validation_report = validate_configuration(config) assert isinstance(validation_report.is_valid, bool) # Test strict validation strict_report = validate_configuration_strict(config) assert hasattr(strict_report, 'is_usable') # Test basic validation is_valid, errors = config.validate() assert isinstance(is_valid, bool) assert isinstance(errors, list) def test_json_serialization_integration(self): """Test JSON serialization/deserialization of configurations.""" # Create a strategy strategy = create_ema_crossover_strategy() config = strategy.config # Convert to dict (simulating JSON serialization) config_dict = { "strategy_name": config.strategy_name, "strategy_type": config.strategy_type.value, "description": config.description, "timeframes": config.timeframes, "overlay_indicators": config.overlay_indicators, "subplot_configs": [ { "subplot_type": subplot.subplot_type.value, "height_ratio": subplot.height_ratio, "indicators": subplot.indicators, "title": subplot.title } for subplot in config.subplot_configs ] } # Verify serialization works json_str = json.dumps(config_dict) assert len(json_str) > 0 # Verify deserialization works restored_dict = json.loads(json_str) assert restored_dict["strategy_name"] == config.strategy_name assert restored_dict["strategy_type"] == config.strategy_type.value def test_configuration_modification_workflow(self): """Test modifying and re-validating configurations.""" # Start with a valid configuration config = create_swing_trading_strategy().config # Verify it's initially valid (may have issues due to missing indicators in test env) initial_health = check_configuration_health(config) assert "is_healthy" in initial_health # Modify the configuration (add an invalid indicator) config.overlay_indicators.append("invalid_indicator_999") # Verify it's now invalid modified_health = check_configuration_health(config) assert not modified_health["is_healthy"] assert modified_health["missing_indicators"] > 0 # Remove the invalid indicator config.overlay_indicators.remove("invalid_indicator_999") # Verify it's valid again (or at least better) final_health = check_configuration_health(config) # Note: May still have issues due to test environment assert final_health["missing_indicators"] < modified_health["missing_indicators"] def test_multi_timeframe_strategy_integration(self): """Test strategies with multiple timeframes.""" config, errors = create_custom_strategy_config( strategy_name="Multi-Timeframe Strategy", strategy_type=TradingStrategy.SWING_TRADING, description="Strategy using multiple timeframes", timeframes=["1h", "4h", "1d"], overlay_indicators=["ema_21", "sma_50", "sma_200"], subplot_configs=[ { "subplot_type": "rsi", "height_ratio": 0.2, "indicators": ["rsi_14"], "title": "RSI (14)" } ] ) if config is not None: assert len(config.timeframes) == 3 # Validate the multi-timeframe strategy validation_report = validate_configuration(config) health_check = check_configuration_health(config) # Should be valid and healthy (or at least structured correctly) assert isinstance(validation_report.is_valid, bool) assert "total_indicators" in health_check else: # Configuration failed - check we got errors assert len(errors) > 0 def test_strategy_type_consistency_integration(self): """Test strategy type consistency validation across the system.""" test_cases = [ { "strategy_type": TradingStrategy.SCALPING, "timeframes": ["1m", "5m"], "expected_consistent": True }, { "strategy_type": TradingStrategy.SCALPING, "timeframes": ["1d", "1w"], "expected_consistent": False }, { "strategy_type": TradingStrategy.SWING_TRADING, "timeframes": ["4h", "1d"], "expected_consistent": True }, { "strategy_type": TradingStrategy.SWING_TRADING, "timeframes": ["1m", "5m"], "expected_consistent": False } ] for case in test_cases: config = StrategyChartConfig( strategy_name=f"Test {case['strategy_type'].value}", strategy_type=case["strategy_type"], description="Test strategy for consistency", timeframes=case["timeframes"], overlay_indicators=["ema_12", "sma_20"] ) # Check validation report validation_report = validate_configuration(config) error_report = validate_configuration_strict(config) # Just verify the system processes the configurations assert isinstance(validation_report.is_valid, bool) assert hasattr(error_report, 'is_usable') class TestConfigurationSystemPerformance: """Test performance and scalability of the configuration system.""" def test_large_configuration_performance(self): """Test system performance with large configurations.""" # Create a configuration with many indicators large_config, errors = create_custom_strategy_config( strategy_name="Large Configuration Test", strategy_type=TradingStrategy.DAY_TRADING, description="Strategy with many indicators", timeframes=["5m", "15m", "1h", "4h"], overlay_indicators=[ "ema_12", "ema_26", "ema_50", "sma_20", "sma_50", "sma_200" ], subplot_configs=[ { "subplot_type": "rsi", "height_ratio": 0.15, "indicators": ["rsi_7", "rsi_14", "rsi_21"], "title": "RSI Multi-Period" }, { "subplot_type": "macd", "height_ratio": 0.15, "indicators": ["macd_12_26_9"], "title": "MACD" } ] ) if large_config is not None: assert len(large_config.overlay_indicators) == 6 assert len(large_config.subplot_configs) == 2 # Validate performance is acceptable import time start_time = time.time() # Perform multiple operations for _ in range(10): validate_configuration_strict(large_config) check_configuration_health(large_config) end_time = time.time() execution_time = end_time - start_time # Should complete in reasonable time (less than 5 seconds for 10 iterations) assert execution_time < 5.0 else: # Large configuration failed - verify we got errors assert len(errors) > 0 def test_multiple_strategies_performance(self): """Test performance when working with multiple strategies.""" # Get all example strategies strategies = get_all_example_strategies() # Time the validation of all strategies import time start_time = time.time() for strategy_name, strategy_example in strategies.items(): config = strategy_example.config validate_configuration_strict(config) check_configuration_health(config) end_time = time.time() execution_time = end_time - start_time # Should complete in reasonable time assert execution_time < 3.0 class TestConfigurationSystemRobustness: """Test system robustness and edge cases.""" def test_empty_configuration_handling(self): """Test handling of empty configurations.""" empty_config = StrategyChartConfig( strategy_name="Empty Strategy", strategy_type=TradingStrategy.DAY_TRADING, description="Empty strategy", timeframes=["1h"], overlay_indicators=[], subplot_configs=[] ) # System should handle empty config gracefully error_report = validate_configuration_strict(empty_config) assert not error_report.is_usable # Should be unusable assert len(error_report.errors) > 0 # Should have errors health_check = check_configuration_health(empty_config) assert not health_check["is_healthy"] assert health_check["total_indicators"] == 0 def test_invalid_data_handling(self): """Test handling of invalid data types and values.""" # Test with None values - basic validation try: config = StrategyChartConfig( strategy_name="Test Strategy", strategy_type=TradingStrategy.DAY_TRADING, description="Test with edge cases", timeframes=["1h"], overlay_indicators=["ema_12"] ) # Should handle gracefully error_report = validate_configuration_strict(config) assert isinstance(error_report.is_usable, bool) except (TypeError, ValueError): # Also acceptable to raise an error pass def test_configuration_boundary_cases(self): """Test boundary cases in configuration.""" # Test with single indicator minimal_config = StrategyChartConfig( strategy_name="Minimal Strategy", strategy_type=TradingStrategy.DAY_TRADING, description="Minimal viable strategy", timeframes=["1h"], overlay_indicators=["ema_12"] ) error_report = validate_configuration_strict(minimal_config) health_check = check_configuration_health(minimal_config) # Should be processed without crashing assert isinstance(error_report.is_usable, bool) assert health_check["total_indicators"] >= 0 assert len(health_check["recommendations"]) >= 0 def test_configuration_versioning_compatibility(self): """Test that configurations are forward/backward compatible.""" # Create a basic configuration config = create_ema_crossover_strategy().config # Verify all required fields are present required_fields = [ 'strategy_name', 'strategy_type', 'description', 'timeframes', 'overlay_indicators', 'subplot_configs' ] for field in required_fields: assert hasattr(config, field) assert getattr(config, field) is not None class TestConfigurationSystemDocumentation: """Test that configuration system is well-documented and discoverable.""" def test_available_indicators_discovery(self): """Test that available indicators can be discovered.""" indicators = get_all_default_indicators() assert len(indicators) > 0 # Test that indicators are categorized for category in IndicatorCategory: category_indicators = get_indicators_by_category(category) assert isinstance(category_indicators, dict) def test_available_strategies_discovery(self): """Test that available strategies can be discovered.""" strategies = get_all_example_strategies() assert len(strategies) >= 5 # Each strategy should have required metadata for strategy_name, strategy_example in strategies.items(): # Check for core attributes (these are the actual attributes) assert hasattr(strategy_example, 'config') assert hasattr(strategy_example, 'description') assert hasattr(strategy_example, 'difficulty') assert hasattr(strategy_example, 'risk_level') assert hasattr(strategy_example, 'author') def test_error_message_quality(self): """Test that error messages are helpful and informative.""" # Test missing strategy error error = validate_strategy_name("nonexistent_strategy") assert error is not None assert len(error.message) > 10 # Should be descriptive assert len(error.suggestions) > 0 # Should have suggestions assert len(error.recovery_steps) > 0 # Should have recovery steps # Test missing indicator suggestions suggestions = get_indicator_suggestions("nonexistent_indicator") assert isinstance(suggestions, list) if __name__ == "__main__": pytest.main([__file__, "-v"])