Files
actions/validate-inputs/tests/test_network_validator.py
Ismo Vuorinen 7061aafd35 chore: add tests, update docs and actions (#299)
* docs: update documentation

* feat: validate-inputs has it's own pyproject

* security: mask DOCKERHUB_PASSWORD

* chore: add tokens, checkout, recrete docs, integration tests

* fix: add `statuses: write` permission to pr-lint
2025-10-18 13:09:19 +03:00

237 lines
8.4 KiB
Python

"""Tests for the NetworkValidator module."""
import sys
from pathlib import Path
import pytest # pylint: disable=import-error
# Add the parent directory to the path
sys.path.insert(0, str(Path(__file__).parent.parent))
from tests.fixtures.version_test_data import (
EMAIL_INVALID,
EMAIL_VALID,
USERNAME_INVALID,
USERNAME_VALID,
)
from validators.network import NetworkValidator
class TestNetworkValidator:
"""Test cases for NetworkValidator."""
def setup_method(self):
"""Set up test environment."""
self.validator = NetworkValidator()
def test_initialization(self):
"""Test validator initialization."""
assert self.validator.errors == []
rules = self.validator.get_validation_rules()
assert rules is not None
@pytest.mark.parametrize("email,description", EMAIL_VALID)
def test_validate_email_valid(self, email, description):
"""Test email validation with valid emails."""
self.validator.errors = []
result = self.validator.validate_email(email)
assert result is True, f"Failed for {description}: {email}"
assert len(self.validator.errors) == 0
@pytest.mark.parametrize("email,description", EMAIL_INVALID)
def test_validate_email_invalid(self, email, description):
"""Test email validation with invalid emails."""
self.validator.errors = []
result = self.validator.validate_email(email)
if email == "": # Empty email might be allowed
assert isinstance(result, bool)
else:
assert result is False, f"Should fail for {description}: {email}"
assert len(self.validator.errors) > 0
@pytest.mark.parametrize("username,description", USERNAME_VALID)
def test_validate_username_valid(self, username, description):
"""Test username validation with valid usernames."""
self.validator.errors = []
result = self.validator.validate_username(username)
assert result is True, f"Failed for {description}: {username}"
assert len(self.validator.errors) == 0
@pytest.mark.parametrize("username,description", USERNAME_INVALID)
def test_validate_username_invalid(self, username, description):
"""Test username validation with invalid usernames."""
self.validator.errors = []
result = self.validator.validate_username(username)
if username == "": # Empty username is allowed
assert result is True
else:
assert result is False, f"Should fail for {description}: {username}"
def test_validate_url_valid(self):
"""Test URL validation with valid URLs."""
valid_urls = [
"https://github.com",
"http://example.com",
"https://api.github.com/repos/owner/repo",
"https://example.com:8080",
"https://sub.domain.example.com",
"http://localhost",
"http://localhost:3000",
"https://192.168.1.1",
"https://example.com/path/to/resource",
"https://example.com/path?query=value",
"https://example.com#fragment",
]
for url in valid_urls:
self.validator.errors = []
result = self.validator.validate_url(url)
assert result is True, f"Should accept URL: {url}"
def test_validate_url_invalid(self):
"""Test URL validation with invalid URLs."""
invalid_urls = [
"not-a-url",
"ftp://example.com", # FTP not supported
"javascript:alert(1)", # JavaScript protocol
"file:///etc/passwd", # File protocol
"//example.com", # Protocol-relative URL
"example.com", # Missing protocol
"http://", # Incomplete URL
"http:/example.com", # Single slash
"http:///example.com", # Triple slash
"", # Empty
]
for url in invalid_urls:
self.validator.errors = []
result = self.validator.validate_url(url)
if url == "":
# Empty might be allowed for optional
assert isinstance(result, bool)
else:
assert result is False, f"Should reject URL: {url}"
def test_validate_hostname_valid(self):
"""Test hostname validation with valid hostnames."""
valid_hostnames = [
"example.com",
"sub.example.com",
"sub.sub.example.com",
"example-site.com",
"123.example.com",
"localhost",
"my-server",
"server123",
"192.168.1.1",
"::1", # IPv6 localhost
]
for hostname in valid_hostnames:
self.validator.errors = []
result = self.validator.validate_hostname(hostname)
assert result is True, f"Should accept hostname: {hostname}"
def test_validate_hostname_invalid(self):
"""Test hostname validation with invalid hostnames."""
invalid_hostnames = [
"example..com", # Double dot
"-example.com", # Leading dash
"example-.com", # Trailing dash
"exam ple.com", # Space
"example.com/path", # Path included
"http://example.com", # Protocol included
"example.com:8080", # Port included
"", # Empty
]
for hostname in invalid_hostnames:
self.validator.errors = []
result = self.validator.validate_hostname(hostname)
if hostname == "":
assert isinstance(result, bool)
else:
assert result is False, f"Should reject hostname: {hostname}"
def test_validate_ip_address(self):
"""Test IP address validation."""
valid_ips = [
"192.168.1.1",
"10.0.0.1",
"172.16.0.1",
"8.8.8.8",
"0.0.0.0", # noqa: S104
"255.255.255.255",
]
for ip in valid_ips:
self.validator.errors = []
result = self.validator.validate_ip_address(ip)
assert result is True, f"Should accept IP: {ip}"
invalid_ips = [
"256.256.256.256", # Out of range
"192.168.1", # Incomplete
"192.168.1.1.1", # Too many octets
"192.168.-1.1", # Negative
"192.168.a.1", # Non-numeric
"example.com", # Domain name
]
for ip in invalid_ips:
self.validator.errors = []
result = self.validator.validate_ip_address(ip)
assert result is False, f"Should reject IP: {ip}"
def test_validate_port_number(self):
"""Test port number validation."""
valid_ports = [
"80",
"443",
"8080",
"3000",
"65535", # Maximum port
"1", # Minimum port
]
for port in valid_ports:
self.validator.errors = []
result = self.validator.validate_port(port)
assert result is True, f"Should accept port: {port}"
invalid_ports = [
"0", # Too low
"65536", # Too high
"-1", # Negative
"abc", # Non-numeric
"80.0", # Decimal
]
for port in invalid_ports:
self.validator.errors = []
result = self.validator.validate_port(port)
assert result is False, f"Should reject port: {port}"
def test_empty_values_handling(self):
"""Test that empty values are handled appropriately."""
assert self.validator.validate_email("") is True # Empty allowed for optional
assert self.validator.validate_username("") is True
assert isinstance(self.validator.validate_url(""), bool)
assert isinstance(self.validator.validate_hostname(""), bool)
def test_validate_inputs_with_network_keywords(self):
"""Test validation of inputs with network-related keywords."""
inputs = {
"email": "test@example.com",
"username": "testuser",
"url": "https://example.com",
"webhook-url": "https://hooks.example.com/webhook",
"api-endpoint": "https://api.example.com/v1",
"hostname": "server.example.com",
"server-address": "192.168.1.100",
"port": "8080",
}
result = self.validator.validate_inputs(inputs)
assert isinstance(result, bool)