Skip to main content
Glama
test_url_validator.pyโ€ข6.25 kB
""" Unit tests for URL validation functionality. """ import unittest from url_validator import URLValidator, ValidationResult class TestURLValidator(unittest.TestCase): """Test cases for URL validation.""" def setUp(self): """Set up test fixtures.""" self.validator = URLValidator() def test_valid_http_url(self): """Test validation of valid HTTP URLs.""" result = self.validator.validate("http://example.com") self.assertTrue(result.is_valid) self.assertIsNone(result.error_message) self.assertEqual(result.normalized_url, "http://example.com") def test_valid_https_url(self): """Test validation of valid HTTPS URLs.""" result = self.validator.validate("https://example.com") self.assertTrue(result.is_valid) self.assertIsNone(result.error_message) self.assertEqual(result.normalized_url, "https://example.com") def test_url_normalization_adds_https(self): """Test that URLs without protocol get https:// added.""" result = self.validator.validate("example.com") self.assertTrue(result.is_valid) self.assertEqual(result.normalized_url, "https://example.com") def test_invalid_url_format(self): """Test validation rejects invalid URL formats.""" invalid_urls = [ "invalid-url", "not a url", "http://", "://example.com", "" ] for url in invalid_urls: with self.subTest(url=url): result = self.validator.validate(url) self.assertFalse(result.is_valid) self.assertIsNotNone(result.error_message) def test_empty_url(self): """Test validation rejects empty URLs.""" result = self.validator.validate("") self.assertFalse(result.is_valid) self.assertEqual(result.error_message, "URL cannot be empty") def test_non_string_url(self): """Test validation rejects non-string URLs.""" result = self.validator.validate(123) self.assertFalse(result.is_valid) self.assertEqual(result.error_message, "URL must be a string") def test_blocked_schemes(self): """Test validation blocks dangerous URL schemes.""" blocked_schemes = [ ("file://etc/passwd", ["invalid url format", "scheme"]), ("ftp://example.com", ["scheme", "invalid url format"]), ("javascript:alert('xss')", ["invalid url format", "scheme"]), ("data:text/html,<script>alert('xss')</script>", ["invalid url format", "scheme"]) ] for url, expected_errors in blocked_schemes: with self.subTest(url=url): result = self.validator.validate(url) self.assertFalse(result.is_valid) # Either the validators library rejects it as invalid format # or our validation catches the dangerous scheme error_lower = result.error_message.lower() if result.error_message else "" self.assertTrue(any(expected in error_lower for expected in expected_errors), f"Expected one of {expected_errors} in '{result.error_message}'") def test_unsupported_schemes(self): """Test validation rejects unsupported schemes.""" # Test with ftp:// scheme which should be properly detected as unsupported test_urls = [ "ftp://files.example.com/file.txt", "ldap://directory.example.com" ] for url in test_urls: with self.subTest(url=url): result = self.validator.validate(url) self.assertFalse(result.is_valid) # Should either be caught as unsupported scheme or invalid format error_lower = result.error_message.lower() if result.error_message else "" acceptable_errors = ["unsupported scheme", "invalid url format", "scheme"] self.assertTrue(any(err in error_lower for err in acceptable_errors), f"Expected validation error for {url}, got: {result.error_message}") def test_blocked_localhost_domains(self): """Test validation blocks localhost domains.""" localhost_urls = [ "http://localhost", "https://127.0.0.1", "http://0.0.0.0", "https://::1" ] # Note: validators library may reject some of these as invalid format # rather than reaching our domain check, which is also acceptable for url in localhost_urls: with self.subTest(url=url): result = self.validator.validate(url) self.assertFalse(result.is_valid) def test_blocked_private_ip_ranges(self): """Test validation blocks private IP ranges.""" private_ips = [ "http://10.0.0.1", "https://172.16.0.1", "http://192.168.1.1", "https://169.254.1.1" ] for url in private_ips: with self.subTest(url=url): result = self.validator.validate(url) self.assertFalse(result.is_valid) self.assertIn("private IP", result.error_message) def test_url_length_limit(self): """Test validation rejects URLs that are too long.""" long_url = "https://example.com/" + "a" * 2050 # Over 2048 char limit result = self.validator.validate(long_url) self.assertFalse(result.is_valid) self.assertIn("too long", result.error_message) def test_valid_public_domains(self): """Test validation allows valid public domains.""" valid_urls = [ "https://www.google.com", "http://httpbin.org", "https://api.github.com", "https://example.org/path?query=value" ] for url in valid_urls: with self.subTest(url=url): result = self.validator.validate(url) self.assertTrue(result.is_valid, f"URL {url} should be valid but got: {result.error_message}") if __name__ == "__main__": unittest.main()

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/crybo-rybo/websurfer-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server