""" Integration tests for Claude API configuration system Tests Skills with different Claude API configurations, environment variables, and backward compatibility """ import os import pytest import tempfile import yaml from pathlib import Path from unittest.mock import Mock, patch, AsyncMock from typing import Dict, Any # Import the modules we're testing import sys sys.path.insert(0, str(Path(__file__).parent.parent)) from config_validation import ClaudeAPIConfig from configuration_loader import ConfigurationLoader from configuration_migrator import ConfigurationMigrator class TestEnvironmentVariableIntegration: """Test environment variable scenarios in configuration""" def setup_method(self): """Set up test fixtures""" self.temp_dir = Path(tempfile.mkdtemp()) self.loader = ConfigurationLoader() self.migrator = ConfigurationMigrator() def teardown_method(self): """Clean up test fixtures""" import shutil shutil.rmtree(self.temp_dir) # Clean up any test environment variables test_vars = ['TEST_CLAUDE_API_KEY', 'TEST_CLAUDE_API_URL', 'TEST_CLAUDE_MODEL'] for var in test_vars: if var in os.environ: del os.environ[var] def create_test_config_file(self, config_data: Dict[str, Any]) -> Path: """Create a test configuration file""" config_file = self.temp_dir / 'test_config.yaml' with config_file.open('w') as f: yaml.dump(config_data, f) return config_file def test_environment_variable_expansion(self): """Test environment variable expansion""" # Set up environment variables os.environ['TEST_CLAUDE_API_KEY'] = 'sk-ant-test-key-12345678901234567890123456789012345678901234567890' os.environ['TEST_CLAUDE_API_URL'] = 'https://custom-api.example.com' config_data = { 'claude': { 'api_key': '${TEST_CLAUDE_API_KEY}', 'api_url': '${TEST_CLAUDE_API_URL}', 'model': 'claude-3-5-sonnet-20241022' } } expanded = self.loader.expand_environment_variables(config_data) assert expanded['claude']['api_key'] == 'sk-ant-test-key-12345678901234567890123456789012345678901234567890' assert expanded['claude']['api_url'] == 'https://custom-api.example.com' assert expanded['claude']['model'] == 'claude-3-5-sonnet-20241022' def test_environment_variable_defaults(self): """Test environment variable expansion with defaults""" config_data = { 'claude': { 'api_key': 'sk-ant-test-key-12345678901234567890123456789012345678901234567890', 'api_url': '${CLAUDE_API_URL:-https://api.anthropic.com}', 'model': '${CLAUDE_MODEL:-claude-3-5-sonnet-20241022}' } } expanded = self.loader.expand_environment_variables(config_data) # Should use defaults since env vars are not set assert expanded['claude']['api_url'] == 'https://api.anthropic.com' assert expanded['claude']['model'] == 'claude-3-5-sonnet-20241022' class TestBackwardCompatibilityIntegration: """Test backward compatibility with existing setups""" def setup_method(self): """Set up test fixtures""" self.migrator = ConfigurationMigrator() def test_legacy_model_migration(self): """Test migration of legacy model names""" legacy_config = { 'claude': { 'api_key': 'sk-ant-test-key-12345678901234567890123456789012345678901234567890', 'model': 'claude-3-sonnet' # Legacy model name } } migrated = self.migrator.migrate_claude_config(legacy_config) # Should migrate to new model name assert migrated['claude']['model'] == 'claude-3-sonnet-20240229' # Should add default API URL assert migrated['claude']['api_url'] == 'https://api.anthropic.com' def test_migration_needed_detection(self): """Test detection of configurations that need migration""" # Config that needs migration legacy_config = { 'claude': { 'api_key': 'sk-ant-test-key-12345678901234567890123456789012345678901234567890', 'model': 'claude-3-opus' # Legacy model name } } assert self.migrator.check_migration_needed(legacy_config) is True # Config that doesn't need migration modern_config = { 'claude': { 'api_key': 'sk-ant-test-key-12345678901234567890123456789012345678901234567890', 'api_url': 'https://api.anthropic.com', 'model': 'claude-3-5-sonnet-20241022', 'max_tokens': 4096, 'temperature': 0.7 }, 'journal': { 'daily_notes_folder': 'Daily', 'date_format': 'YYYY-MM-DD', 'file_extension': '.md' }, 'output': { 'experiences_folder': 'Knowledge/Experiences', 'lessons_folder': 'Knowledge/Lessons', 'tasks_folder': 'Tasks/Daily', 'problems_folder': 'Knowledge/Problems', 'achievements_folder': 'Knowledge/Achievements', 'improvements_folder': 'Knowledge/Improvements' }, 'analysis': { 'categories': [], 'extraction_rules': {} }, 'logging': { 'level': 'INFO', 'file': 'logs/journal_organizer.log' } } assert self.migrator.check_migration_needed(modern_config) is False class TestConfigurationValidation: """Test configuration validation scenarios""" def test_claude_api_config_validation(self): """Test ClaudeAPIConfig validation""" # Valid configuration config = ClaudeAPIConfig( api_key='sk-ant-test-key-12345678901234567890123456789012345678901234567890', api_url='https://custom-api.example.com', model='claude-3-5-sonnet-20241022' ) assert config.api_key.startswith('sk-ant-') assert config.api_url == 'https://custom-api.example.com' assert config.model == 'claude-3-5-sonnet-20241022' def test_invalid_configuration_handling(self): """Test handling of invalid configurations""" # Invalid API key format with pytest.raises(ValueError, match="Claude API key should start with"): ClaudeAPIConfig(api_key='invalid-key') # Invalid URL format with pytest.raises(ValueError, match="Invalid URL format"): ClaudeAPIConfig( api_key='sk-ant-test-key-12345678901234567890123456789012345678901234567890', api_url='not-a-url' ) # Invalid model name with pytest.raises(ValueError, match="Invalid model name"): ClaudeAPIConfig( api_key='sk-ant-test-key-12345678901234567890123456789012345678901234567890', model='invalid-model' )