7a0da7932b
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled
323 lines
11 KiB
Python
323 lines
11 KiB
Python
"""
|
|
Behavioral tests for url_utils module.
|
|
|
|
Tests the normalize_url function for URL normalization.
|
|
"""
|
|
|
|
import pytest
|
|
|
|
|
|
class TestNormalizeUrlWithScheme:
|
|
"""Tests for URLs that already have a scheme."""
|
|
|
|
def test_https_url_unchanged(self):
|
|
"""HTTPS URL is returned unchanged."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("https://example.com") == "https://example.com"
|
|
|
|
def test_http_url_unchanged(self):
|
|
"""HTTP URL is returned unchanged."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("http://example.com") == "http://example.com"
|
|
|
|
def test_https_with_port_unchanged(self):
|
|
"""HTTPS URL with port is unchanged."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert (
|
|
normalize_url("https://example.com:8080")
|
|
== "https://example.com:8080"
|
|
)
|
|
|
|
def test_http_with_port_unchanged(self):
|
|
"""HTTP URL with port is unchanged."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert (
|
|
normalize_url("http://example.com:8080")
|
|
== "http://example.com:8080"
|
|
)
|
|
|
|
def test_https_with_path_unchanged(self):
|
|
"""HTTPS URL with path is unchanged."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert (
|
|
normalize_url("https://example.com/path")
|
|
== "https://example.com/path"
|
|
)
|
|
|
|
|
|
class TestNormalizeUrlMalformed:
|
|
"""Tests for malformed URLs with missing slashes."""
|
|
|
|
def test_http_colon_missing_slashes(self):
|
|
"""http:example.com gets slashes added."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("http:example.com") == "http://example.com"
|
|
|
|
def test_https_colon_missing_slashes(self):
|
|
"""https:example.com gets slashes added."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("https:example.com") == "https://example.com"
|
|
|
|
|
|
class TestNormalizeUrlDoubleSlashPrefix:
|
|
"""Tests for URLs starting with //."""
|
|
|
|
def test_double_slash_prefix_removed(self):
|
|
"""// prefix is handled and scheme added."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
# //example.com should get scheme based on whether it's private
|
|
result = normalize_url("//example.com")
|
|
assert result.startswith("http://") or result.startswith("https://")
|
|
assert "example.com" in result
|
|
|
|
|
|
class TestNormalizeUrlLocalhost:
|
|
"""Tests for localhost URLs."""
|
|
|
|
def test_localhost_gets_http(self):
|
|
"""localhost gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("localhost") == "http://localhost"
|
|
|
|
def test_localhost_with_port_gets_http(self):
|
|
"""localhost:port gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("localhost:11434") == "http://localhost:11434"
|
|
|
|
def test_127_0_0_1_gets_http(self):
|
|
"""127.0.0.1 gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("127.0.0.1") == "http://127.0.0.1"
|
|
|
|
def test_127_0_0_1_with_port_gets_http(self):
|
|
"""127.0.0.1:port gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("127.0.0.1:8080") == "http://127.0.0.1:8080"
|
|
|
|
|
|
class TestNormalizeUrlPrivateIPs:
|
|
"""Tests for private IP addresses."""
|
|
|
|
def test_10_x_gets_http(self):
|
|
"""10.x.x.x gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("10.0.0.1") == "http://10.0.0.1"
|
|
|
|
def test_172_16_x_gets_http(self):
|
|
"""172.16.x.x gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("172.16.0.1") == "http://172.16.0.1"
|
|
|
|
def test_192_168_x_gets_http(self):
|
|
"""192.168.x.x gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("192.168.1.1") == "http://192.168.1.1"
|
|
|
|
def test_private_ip_with_port_gets_http(self):
|
|
"""Private IP with port gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("192.168.1.1:3000") == "http://192.168.1.1:3000"
|
|
|
|
|
|
class TestNormalizeUrlPublicHosts:
|
|
"""Tests for public hostnames."""
|
|
|
|
def test_public_hostname_gets_https(self):
|
|
"""Public hostname gets https:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("example.com") == "https://example.com"
|
|
|
|
def test_public_hostname_with_port_gets_https(self):
|
|
"""Public hostname with port gets https:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("example.com:443") == "https://example.com:443"
|
|
|
|
def test_api_subdomain_gets_https(self):
|
|
"""API subdomain gets https:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("api.openai.com") == "https://api.openai.com"
|
|
|
|
def test_public_ip_gets_https(self):
|
|
"""Public IP address gets https:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("8.8.8.8") == "https://8.8.8.8"
|
|
|
|
|
|
class TestNormalizeUrlLocalDomain:
|
|
"""Tests for .local mDNS domains."""
|
|
|
|
def test_local_domain_gets_http(self):
|
|
"""host.local gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("myserver.local") == "http://myserver.local"
|
|
|
|
def test_local_domain_with_port_gets_http(self):
|
|
"""host.local:port gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert (
|
|
normalize_url("myserver.local:8080") == "http://myserver.local:8080"
|
|
)
|
|
|
|
|
|
class TestNormalizeUrlIPv6:
|
|
"""Tests for IPv6 addresses."""
|
|
|
|
def test_bracketed_ipv6_loopback(self):
|
|
"""Bracketed IPv6 loopback gets http://."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
result = normalize_url("[::1]")
|
|
assert result == "http://[::1]"
|
|
|
|
def test_bracketed_ipv6_public(self):
|
|
"""Bracketed public IPv6 gets https://."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
result = normalize_url("[2001:4860:4860::8888]")
|
|
assert result == "https://[2001:4860:4860::8888]"
|
|
|
|
|
|
class TestNormalizeUrlWhitespace:
|
|
"""Tests for whitespace handling."""
|
|
|
|
def test_strips_leading_whitespace(self):
|
|
"""Leading whitespace is stripped."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url(" https://example.com") == "https://example.com"
|
|
|
|
def test_strips_trailing_whitespace(self):
|
|
"""Trailing whitespace is stripped."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("https://example.com ") == "https://example.com"
|
|
|
|
def test_strips_both_whitespace(self):
|
|
"""Both leading and trailing whitespace is stripped."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url(" https://example.com ") == "https://example.com"
|
|
|
|
|
|
class TestNormalizeUrlEmpty:
|
|
"""Tests for empty URL handling."""
|
|
|
|
def test_empty_string_raises(self):
|
|
"""Empty string raises ValueError."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
|
normalize_url("")
|
|
assert "empty" in str(excinfo.value).lower()
|
|
|
|
def test_whitespace_only_returns_bare_scheme(self):
|
|
"""Whitespace-only string returns bare https:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
# Edge case: whitespace passes initial check (truthy)
|
|
# but after stripping becomes empty hostname
|
|
# Implementation adds https:// to empty string
|
|
result = normalize_url(" ")
|
|
# This is current behavior - returns 'https://'
|
|
assert result == "https://"
|
|
|
|
|
|
class TestNormalizeUrlWithPath:
|
|
"""Tests for URLs with paths."""
|
|
|
|
def test_hostname_with_path_gets_scheme(self):
|
|
"""Hostname with path gets appropriate scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
result = normalize_url("example.com/api/v1")
|
|
assert result == "https://example.com/api/v1"
|
|
|
|
def test_localhost_with_path_gets_http(self):
|
|
"""localhost with path gets http://."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
result = normalize_url("localhost:8080/api")
|
|
assert result == "http://localhost:8080/api"
|
|
|
|
|
|
class TestNormalizeUrlEdgeCases:
|
|
"""Tests for edge cases."""
|
|
|
|
def test_0_0_0_0_is_private(self):
|
|
"""0.0.0.0 gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("0.0.0.0") == "http://0.0.0.0"
|
|
|
|
def test_link_local_is_private(self):
|
|
"""169.254.x.x (link-local) gets http:// scheme."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("169.254.0.1") == "http://169.254.0.1"
|
|
|
|
|
|
class TestIsPrivateIPExport:
|
|
"""Tests for is_private_ip re-export."""
|
|
|
|
def test_is_private_ip_exported(self):
|
|
"""is_private_ip is exported from url_utils."""
|
|
from local_deep_research.utilities.url_utils import is_private_ip
|
|
|
|
# Should be callable
|
|
assert callable(is_private_ip)
|
|
# Should work
|
|
assert is_private_ip("127.0.0.1") is True
|
|
assert is_private_ip("8.8.8.8") is False
|
|
|
|
|
|
class TestNormalizeUrlRealWorldExamples:
|
|
"""Tests with real-world URL examples."""
|
|
|
|
def test_ollama_default_url(self):
|
|
"""Ollama default URL (localhost:11434)."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("localhost:11434") == "http://localhost:11434"
|
|
|
|
def test_openai_api_url(self):
|
|
"""OpenAI API URL."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("api.openai.com") == "https://api.openai.com"
|
|
|
|
def test_searxng_local_url(self):
|
|
"""SearXNG local instance URL."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert (
|
|
normalize_url("192.168.1.100:8888") == "http://192.168.1.100:8888"
|
|
)
|
|
|
|
def test_docker_internal_url(self):
|
|
"""Docker internal network URL (172.17.x.x)."""
|
|
from local_deep_research.utilities.url_utils import normalize_url
|
|
|
|
assert normalize_url("172.17.0.2:5000") == "http://172.17.0.2:5000"
|