#!/usr/bin/env python3 """ Tests for Neptune database provider configuration and validation. These tests validate Neptune-specific configuration requirements including: - Endpoint format validation (neptune-db:// and neptune-graph://) - AOSS host requirement validation - AWS credential validation (mocked) - Environment variable overrides - Factory creation with Neptune provider """ import os import sys from pathlib import Path from unittest.mock import MagicMock, patch from config.schema import DatabaseProvidersConfig, GraphitiConfig, NeptuneProviderConfig from services.factories import DatabaseDriverFactory def test_neptune_provider_config_validation(): """Test NeptuneProviderConfig validation rules.""" print('\nTesting Neptune provider configuration validation...') # Test valid Database endpoint try: config = NeptuneProviderConfig( host='neptune-db://my-cluster.us-east-1.neptune.amazonaws.com', aoss_host='my-aoss.us-east-1.aoss.amazonaws.com', port=8182, aoss_port=443, ) print('✓ Valid Database endpoint accepted') assert config.host.startswith('neptune-db://') except Exception as e: print(f'✗ Failed to accept valid Database endpoint: {e}') raise # Test valid Analytics endpoint try: config = NeptuneProviderConfig( host='neptune-graph://g-abc123xyz', aoss_host='my-aoss.us-east-1.aoss.amazonaws.com', ) print('✓ Valid Analytics endpoint accepted') assert config.host.startswith('neptune-graph://') except Exception as e: print(f'✗ Failed to accept valid Analytics endpoint: {e}') raise # Test invalid endpoint format try: config = NeptuneProviderConfig( host='https://my-neptune.com', aoss_host='my-aoss.us-east-1.aoss.amazonaws.com', ) print('✗ Invalid endpoint format should have been rejected') raise AssertionError('Expected ValueError for invalid endpoint format') except ValueError as e: print(f'✓ Invalid endpoint format rejected: {str(e)[:60]}...') assert 'must start with neptune-db:// or neptune-graph://' in str(e) # Test missing AOSS host try: config = NeptuneProviderConfig( host='neptune-db://my-cluster.us-east-1.neptune.amazonaws.com', aoss_host=None, ) print('✗ Missing AOSS host should have been rejected') raise AssertionError('Expected ValueError for missing AOSS host') except ValueError as e: print(f'✓ Missing AOSS host rejected: {str(e)[:60]}...') assert 'requires aoss_host' in str(e) # Test port range validation try: config = NeptuneProviderConfig( host='neptune-db://my-cluster.us-east-1.neptune.amazonaws.com', aoss_host='my-aoss.us-east-1.aoss.amazonaws.com', port=70000, # Invalid port ) print('✗ Invalid port should have been rejected') raise AssertionError('Expected ValidationError for invalid port') except Exception as e: print(f'✓ Invalid port rejected: {str(e)[:60]}...') print('✓ Neptune provider configuration validation complete') def test_neptune_environment_overrides(): """Test Neptune configuration with environment variable overrides.""" print('\nTesting Neptune environment variable overrides...') # Set Neptune environment variables test_env = { 'NEPTUNE_HOST': 'neptune-db://test-cluster.us-west-2.neptune.amazonaws.com', 'AOSS_HOST': 'test-aoss.us-west-2.aoss.amazonaws.com', 'NEPTUNE_PORT': '9999', 'AOSS_PORT': '9443', 'AWS_REGION': 'us-west-2', } with patch.dict(os.environ, test_env, clear=False): try: # Load config with environment overrides config_path = Path(__file__).parent.parent / 'config' / 'config.yaml' config = GraphitiConfig(_env_file=None, config_path=str(config_path)) print(f'✓ Loaded configuration with environment overrides') # Verify environment variables were applied if config.database.providers and config.database.providers.neptune: neptune_config = config.database.providers.neptune print( f' Neptune host: {neptune_config.host}' ) print( f' AOSS host: {neptune_config.aoss_host}' ) print(f' Neptune port: {neptune_config.port}') print(f' AOSS port: {neptune_config.aoss_port}') print(f' Region: {neptune_config.region}') # Verify the overrides were applied correctly assert neptune_config.host == test_env['NEPTUNE_HOST'] assert neptune_config.aoss_host == test_env['AOSS_HOST'] assert neptune_config.port == 9999 assert neptune_config.aoss_port == 9443 assert neptune_config.region == test_env['AWS_REGION'] print('✓ All environment overrides applied correctly') else: print('⚠ Neptune provider not configured, skipping validation') except Exception as e: print(f'✗ Failed to load configuration with environment overrides: {e}') raise print('✓ Neptune environment override tests complete') def test_neptune_factory_creation_with_mock_credentials(): """Test Neptune factory creation with mocked AWS credentials.""" print('\nTesting Neptune factory creation with mocked credentials...') # Mock AWS credentials mock_credentials = MagicMock() mock_credentials.access_key = 'mock_access_key' mock_credentials.secret_key = 'mock_secret_key' mock_credentials.token = None mock_session = MagicMock() mock_session.get_credentials.return_value = mock_credentials mock_session.region_name = 'us-east-1' # Create test configuration test_config = { 'database': { 'provider': 'neptune', 'providers': { 'neptune': { 'host': 'neptune-db://test-cluster.us-east-1.neptune.amazonaws.com', 'aoss_host': 'test-aoss.us-east-1.aoss.amazonaws.com', 'port': 8182, 'aoss_port': 443, 'region': 'us-east-1', } }, } } with patch('boto3.Session', return_value=mock_session): try: # Create database config using factory config = DatabaseProvidersConfig(**test_config['database']['providers']) print('✓ Created DatabaseProvidersConfig with Neptune') # Verify Neptune config was created assert config.neptune is not None print('✓ Neptune provider config exists') # Create driver config from factory db_config = DatabaseDriverFactory.create_config(test_config) print('✓ Created driver config from factory') # Verify config contains expected Neptune parameters assert db_config['driver'] == 'neptune' assert db_config['host'] == 'neptune-db://test-cluster.us-east-1.neptune.amazonaws.com' assert db_config['aoss_host'] == 'test-aoss.us-east-1.aoss.amazonaws.com' assert db_config['port'] == 8182 assert db_config['aoss_port'] == 443 assert db_config['region'] == 'us-east-1' print('✓ All Neptune parameters validated correctly') except Exception as e: print(f'✗ Factory creation failed: {e}') raise print('✓ Neptune factory creation tests complete') def test_neptune_factory_missing_credentials(): """Test Neptune factory creation fails gracefully without AWS credentials.""" print('\nTesting Neptune factory behavior with missing AWS credentials...') # Mock AWS session with no credentials mock_session = MagicMock() mock_session.get_credentials.return_value = None mock_session.region_name = 'us-east-1' test_config = { 'database': { 'provider': 'neptune', 'providers': { 'neptune': { 'host': 'neptune-db://test-cluster.us-east-1.neptune.amazonaws.com', 'aoss_host': 'test-aoss.us-east-1.aoss.amazonaws.com', 'port': 8182, 'aoss_port': 443, } }, } } with patch('boto3.Session', return_value=mock_session): try: db_config = DatabaseDriverFactory.create_config(test_config) print('✗ Factory should have failed with missing credentials') raise AssertionError('Expected ValueError for missing AWS credentials') except ValueError as e: print(f'✓ Missing credentials rejected: {str(e)[:60]}...') assert 'AWS credentials not configured' in str(e) assert 'aws configure' in str(e).lower() print('✓ Missing credentials handling validated') def test_neptune_factory_import_check(): """Test Neptune factory import checking and error messages.""" print('\nTesting Neptune driver import availability...') try: from graphiti_core.driver.neptune_driver import NeptuneDriver print('✓ NeptuneDriver successfully imported') print(f' NeptuneDriver class: {NeptuneDriver.__name__}') except ImportError as e: print(f'⚠ NeptuneDriver not available: {e}') print(' This is expected if graphiti-core[neptune] is not installed') print(' Install with: uv add graphiti-core[neptune]') print('✓ Import check complete') def test_database_providers_config_with_neptune(): """Test DatabaseProvidersConfig accepts Neptune configuration.""" print('\nTesting DatabaseProvidersConfig with Neptune...') try: config = DatabaseProvidersConfig( neptune=NeptuneProviderConfig( host='neptune-db://my-cluster.us-east-1.neptune.amazonaws.com', aoss_host='my-aoss.us-east-1.aoss.amazonaws.com', port=8182, aoss_port=443, region='us-east-1', ) ) print('✓ DatabaseProvidersConfig created with Neptune') assert config.neptune is not None assert config.neptune.host == 'neptune-db://my-cluster.us-east-1.neptune.amazonaws.com' assert config.neptune.aoss_host == 'my-aoss.us-east-1.aoss.amazonaws.com' assert config.neptune.port == 8182 assert config.neptune.aoss_port == 443 assert config.neptune.region == 'us-east-1' print('✓ All Neptune fields validated correctly') except Exception as e: print(f'✗ Failed to create DatabaseProvidersConfig with Neptune: {e}') raise print('✓ DatabaseProvidersConfig Neptune integration complete') if __name__ == '__main__': print('=' * 70) print('Neptune Configuration Tests') print('=' * 70) try: test_neptune_provider_config_validation() test_neptune_environment_overrides() test_database_providers_config_with_neptune() test_neptune_factory_import_check() test_neptune_factory_creation_with_mock_credentials() test_neptune_factory_missing_credentials() print('\n' + '=' * 70) print('All Neptune tests passed!') print('=' * 70) except Exception as e: print('\n' + '=' * 70) print(f'Tests failed: {e}') print('=' * 70) raise