"""Unit tests for validation module.""" import pytest from haproxy_mcp.validation import ( validate_domain, validate_ip, validate_port, validate_backend_name, domain_to_backend, ) class TestValidateDomain: """Tests for validate_domain function.""" def test_valid_simple_domain(self): """Valid simple domain.""" assert validate_domain("example.com") is True def test_valid_subdomain(self): """Valid subdomain.""" assert validate_domain("api.example.com") is True def test_valid_deep_subdomain(self): """Valid deep subdomain.""" assert validate_domain("a.b.c.example.com") is True def test_valid_domain_with_numbers(self): """Valid domain with numbers.""" assert validate_domain("api123.example.com") is True def test_valid_domain_with_hyphen(self): """Valid domain with hyphens.""" assert validate_domain("my-api.example-site.com") is True def test_valid_single_char_labels(self): """Valid domain with single character labels.""" assert validate_domain("a.b.c") is True def test_valid_max_label_length(self): """Valid domain with max label length (63 chars).""" label = "a" * 63 assert validate_domain(f"{label}.com") is True def test_invalid_empty_domain(self): """Empty domain is invalid.""" assert validate_domain("") is False def test_invalid_none_domain(self): """None domain is invalid.""" assert validate_domain(None) is False def test_invalid_starts_with_hyphen(self): """Domain starting with hyphen is invalid.""" assert validate_domain("-example.com") is False def test_invalid_ends_with_hyphen(self): """Domain label ending with hyphen is invalid.""" assert validate_domain("example-.com") is False def test_invalid_double_dot(self): """Domain with double dot is invalid.""" assert validate_domain("example..com") is False def test_invalid_starts_with_dot(self): """Domain starting with dot is invalid.""" assert validate_domain(".example.com") is False def test_invalid_special_characters(self): """Domain with special characters is invalid.""" assert validate_domain("example@.com") is False assert validate_domain("example!.com") is False assert validate_domain("example$.com") is False def test_invalid_underscore(self): """Domain with underscore is invalid.""" assert validate_domain("my_api.example.com") is False def test_invalid_too_long(self): """Domain exceeding 253 chars is invalid.""" long_domain = "a" * 254 assert validate_domain(long_domain) is False def test_invalid_label_too_long(self): """Domain label exceeding 63 chars is invalid.""" label = "a" * 64 assert validate_domain(f"{label}.com") is False def test_valid_numeric_domain(self): """Domain with all numeric label is valid.""" assert validate_domain("123.example.com") is True def test_invalid_only_dots(self): """Domain with only dots is invalid.""" assert validate_domain("...") is False class TestValidateIP: """Tests for validate_ip function.""" def test_valid_ipv4(self): """Valid IPv4 address.""" assert validate_ip("192.168.1.1") is True assert validate_ip("10.0.0.1") is True assert validate_ip("255.255.255.255") is True assert validate_ip("0.0.0.0") is True def test_valid_ipv6(self): """Valid IPv6 address.""" assert validate_ip("::1") is True assert validate_ip("2001:db8::1") is True assert validate_ip("fe80::1") is True assert validate_ip("2001:0db8:0000:0000:0000:0000:0000:0001") is True def test_invalid_empty_string(self): """Empty string is invalid by default.""" assert validate_ip("") is False def test_valid_empty_string_when_allowed(self): """Empty string is valid when allow_empty=True.""" assert validate_ip("", allow_empty=True) is True def test_invalid_none(self): """None is invalid.""" assert validate_ip(None) is False def test_invalid_hostname(self): """Hostname is not a valid IP.""" assert validate_ip("example.com") is False def test_invalid_ipv4_out_of_range(self): """IPv4 with octets out of range is invalid.""" assert validate_ip("256.1.1.1") is False assert validate_ip("1.1.1.300") is False def test_invalid_ipv4_format(self): """Invalid IPv4 format.""" assert validate_ip("192.168.1") is False assert validate_ip("192.168.1.1.1") is False def test_invalid_ipv6_format(self): """Invalid IPv6 format.""" assert validate_ip("2001:db8:::1") is False assert validate_ip("gggg::1") is False def test_invalid_mixed_format(self): """Mixed invalid format.""" assert validate_ip("192.168.1.1:8080") is False class TestValidatePort: """Tests for validate_port function.""" def test_valid_port_min(self): """Valid minimum port.""" assert validate_port("1") is True def test_valid_port_max(self): """Valid maximum port.""" assert validate_port("65535") is True def test_valid_port_common(self): """Valid common ports.""" assert validate_port("80") is True assert validate_port("443") is True assert validate_port("8080") is True def test_invalid_port_zero(self): """Port 0 is invalid.""" assert validate_port("0") is False def test_invalid_port_negative(self): """Negative port is invalid.""" assert validate_port("-1") is False def test_invalid_port_too_high(self): """Port above 65535 is invalid.""" assert validate_port("65536") is False def test_invalid_port_empty(self): """Empty port is invalid.""" assert validate_port("") is False def test_invalid_port_none(self): """None port is invalid.""" assert validate_port(None) is False def test_invalid_port_not_numeric(self): """Non-numeric port is invalid.""" assert validate_port("abc") is False assert validate_port("80a") is False def test_invalid_port_float(self): """Float port is invalid.""" assert validate_port("80.5") is False class TestValidateBackendName: """Tests for validate_backend_name function.""" def test_valid_pool_name(self): """Valid pool backend names.""" assert validate_backend_name("pool_1") is True assert validate_backend_name("pool_100") is True def test_valid_alphanumeric(self): """Valid alphanumeric names.""" assert validate_backend_name("backend1") is True assert validate_backend_name("my_backend") is True assert validate_backend_name("my-backend") is True def test_valid_mixed(self): """Valid mixed character names.""" assert validate_backend_name("api_example_com_backend") is True assert validate_backend_name("my-api-backend-1") is True def test_invalid_empty(self): """Empty name is invalid.""" assert validate_backend_name("") is False def test_invalid_none(self): """None name is invalid.""" assert validate_backend_name(None) is False def test_invalid_special_chars(self): """Names with special characters are invalid.""" assert validate_backend_name("backend@1") is False assert validate_backend_name("my.backend") is False assert validate_backend_name("my/backend") is False assert validate_backend_name("my backend") is False def test_invalid_too_long(self): """Name exceeding 255 chars is invalid.""" long_name = "a" * 256 assert validate_backend_name(long_name) is False def test_valid_max_length(self): """Name at exactly 255 chars is valid.""" max_name = "a" * 255 assert validate_backend_name(max_name) is True class TestDomainToBackend: """Tests for domain_to_backend function.""" def test_simple_domain(self): """Simple domain conversion.""" assert domain_to_backend("example.com") == "example_com" def test_subdomain(self): """Subdomain conversion.""" assert domain_to_backend("api.example.com") == "api_example_com" def test_domain_with_hyphens(self): """Domain with hyphens.""" result = domain_to_backend("my-api.example.com") assert result == "my_api_example_com" def test_complex_domain(self): """Complex domain conversion.""" result = domain_to_backend("a.b.c.example-site.com") assert result == "a_b_c_example_site_com" def test_already_simple(self): """Domain that's already mostly valid.""" result = domain_to_backend("example123") assert result == "example123" def test_invalid_result_raises(self): """Invalid conversion result raises ValueError.""" # This should never happen with real domains, but test the safeguard with pytest.raises(ValueError): # Mock a case where conversion would fail domain_to_backend("")