|
20 | 20 | create_transport_with_sigv4, |
21 | 21 | determine_aws_region, |
22 | 22 | determine_service_name, |
| 23 | + validate_endpoint_url, |
23 | 24 | ) |
24 | 25 | from unittest.mock import MagicMock, patch |
25 | 26 |
|
26 | 27 |
|
| 28 | +class TestValidateEndpointUrl: |
| 29 | + """Test cases for validate_endpoint_url function.""" |
| 30 | + |
| 31 | + def test_https_url_passes(self): |
| 32 | + """HTTPS URLs should pass validation.""" |
| 33 | + validate_endpoint_url('https://example.com/mcp') |
| 34 | + # No exception = pass |
| 35 | + |
| 36 | + def test_https_with_port_passes(self): |
| 37 | + """HTTPS URLs with explicit port should pass.""" |
| 38 | + validate_endpoint_url('https://example.com:443/mcp') |
| 39 | + |
| 40 | + def test_https_aws_endpoints_pass(self): |
| 41 | + """HTTPS URLs for AWS endpoints should pass.""" |
| 42 | + aws_endpoints = [ |
| 43 | + 'https://test-service.us-west-2.api.aws/mcp', |
| 44 | + 'https://bedrock-agentcore.us-east-1.amazonaws.com', |
| 45 | + 'https://gateway.bedrock-agentcore.us-west-2.amazonaws.com/mcp', |
| 46 | + ] |
| 47 | + for endpoint in aws_endpoints: |
| 48 | + validate_endpoint_url(endpoint) # No exception = pass |
| 49 | + |
| 50 | + def test_http_remote_raises_error(self): |
| 51 | + """HTTP URLs for remote hosts should raise ValueError.""" |
| 52 | + with pytest.raises(ValueError) as exc_info: |
| 53 | + validate_endpoint_url('http://example.com/mcp') |
| 54 | + assert 'HTTP is not allowed' in str(exc_info.value) |
| 55 | + assert 'HTTPS' in str(exc_info.value) |
| 56 | + |
| 57 | + def test_http_remote_error_includes_url(self): |
| 58 | + """Error message should include the invalid URL.""" |
| 59 | + with pytest.raises(ValueError) as exc_info: |
| 60 | + validate_endpoint_url('http://remote-server.example.com/mcp') |
| 61 | + assert 'remote-server.example.com' in str(exc_info.value) |
| 62 | + |
| 63 | + def test_http_localhost_allowed(self): |
| 64 | + """HTTP URLs for localhost should pass by default.""" |
| 65 | + validate_endpoint_url('http://localhost:8080/mcp') |
| 66 | + validate_endpoint_url('http://127.0.0.1:8080/mcp') |
| 67 | + validate_endpoint_url('http://[::1]:8080/mcp') |
| 68 | + |
| 69 | + def test_http_localhost_without_port_allowed(self): |
| 70 | + """HTTP URLs for localhost without port should pass.""" |
| 71 | + validate_endpoint_url('http://localhost/mcp') |
| 72 | + validate_endpoint_url('http://127.0.0.1/mcp') |
| 73 | + |
| 74 | + def test_http_localhost_disallowed_when_strict(self): |
| 75 | + """HTTP localhost should fail when allow_localhost_http=False.""" |
| 76 | + with pytest.raises(ValueError) as exc_info: |
| 77 | + validate_endpoint_url('http://localhost:8080/mcp', allow_localhost_http=False) |
| 78 | + assert 'HTTP is not allowed' in str(exc_info.value) |
| 79 | + |
| 80 | + def test_missing_scheme_raises_error(self): |
| 81 | + """URLs without scheme should raise ValueError.""" |
| 82 | + with pytest.raises(ValueError) as exc_info: |
| 83 | + validate_endpoint_url('example.com/mcp') |
| 84 | + assert 'missing URL scheme' in str(exc_info.value) |
| 85 | + |
| 86 | + def test_unsupported_scheme_ftp_raises_error(self): |
| 87 | + """FTP scheme should raise ValueError.""" |
| 88 | + with pytest.raises(ValueError) as exc_info: |
| 89 | + validate_endpoint_url('ftp://example.com/mcp') |
| 90 | + assert 'unsupported scheme' in str(exc_info.value) |
| 91 | + assert 'ftp' in str(exc_info.value) |
| 92 | + |
| 93 | + def test_unsupported_scheme_file_raises_error(self): |
| 94 | + """File scheme should raise ValueError.""" |
| 95 | + with pytest.raises(ValueError) as exc_info: |
| 96 | + validate_endpoint_url('file:///path/to/file') |
| 97 | + assert 'unsupported scheme' in str(exc_info.value) |
| 98 | + assert 'file' in str(exc_info.value) |
| 99 | + |
| 100 | + def test_unsupported_scheme_ws_raises_error(self): |
| 101 | + """WebSocket scheme should raise ValueError.""" |
| 102 | + with pytest.raises(ValueError) as exc_info: |
| 103 | + validate_endpoint_url('ws://example.com/mcp') |
| 104 | + assert 'unsupported scheme' in str(exc_info.value) |
| 105 | + assert 'ws' in str(exc_info.value) |
| 106 | + |
| 107 | + def test_unsupported_scheme_wss_raises_error(self): |
| 108 | + """Secure WebSocket scheme should raise ValueError.""" |
| 109 | + with pytest.raises(ValueError) as exc_info: |
| 110 | + validate_endpoint_url('wss://example.com/mcp') |
| 111 | + assert 'unsupported scheme' in str(exc_info.value) |
| 112 | + assert 'wss' in str(exc_info.value) |
| 113 | + |
| 114 | + |
27 | 115 | class TestCreateTransportWithSigv4: |
28 | 116 | """Test cases for create_transport_with_sigv4 function (line 129).""" |
29 | 117 |
|
@@ -183,15 +271,15 @@ def test_validate_service_name_without_service_failure(self): |
183 | 271 | assert '--service argument' in str(exc_info.value) |
184 | 272 |
|
185 | 273 | def test_validate_service_name_invalid_url_failure(self): |
186 | | - """Test validation with invalid URL.""" |
| 274 | + """Test validation with invalid URL raises scheme validation error.""" |
187 | 275 | endpoint = 'not-a-url' |
188 | 276 |
|
189 | 277 | with pytest.raises(ValueError) as exc_info: |
190 | 278 | determine_service_name(endpoint) |
191 | 279 |
|
192 | | - assert 'Could not determine AWS service name' in str(exc_info.value) |
| 280 | + # URL validation now catches this first with a scheme error |
| 281 | + assert 'missing URL scheme' in str(exc_info.value) |
193 | 282 | assert endpoint in str(exc_info.value) |
194 | | - assert '--service argument' in str(exc_info.value) |
195 | 283 |
|
196 | 284 |
|
197 | 285 | class TestDetermineRegion: |
|
0 commit comments