"""Tests for Crawler Proxy Configuration""" import os import pytest from unittest.mock import patch from kb_workflow.crawler.config import ( CrawlerConfig, ProxyConfig, get_crawler_config, reset_crawler_config, ) class TestProxyConfig: """Tests for ProxyConfig model.""" def test_parse_proxy_from_https_env(self): """Parse proxy from HTTPS_PROXY environment variable.""" reset_crawler_config() with patch.dict(os.environ, {"HTTPS_PROXY": "http://127.0.0.1:7890"}, clear=False): os.environ.pop("HTTP_PROXY", None) config = CrawlerConfig.from_env() assert config.proxy is not None assert config.proxy.server == "http://127.0.0.1:7890" def test_parse_proxy_from_http_env(self): """Parse proxy from HTTP_PROXY (HTTPS_PROXY takes priority).""" reset_crawler_config() with patch.dict(os.environ, { "HTTP_PROXY": "http://127.0.0.1:8080", "HTTPS_PROXY": "http://127.0.0.1:7890" }, clear=False): config = CrawlerConfig.from_env() assert config.proxy.server == "http://127.0.0.1:7890" def test_parse_proxy_with_auth(self): """Parse proxy with authentication credentials.""" reset_crawler_config() with patch.dict(os.environ, { "HTTPS_PROXY": "http://user:pass@proxy.example.com:8080" }, clear=False): os.environ.pop("HTTP_PROXY", None) config = CrawlerConfig.from_env() assert config.proxy.username == "user" assert config.proxy.password == "pass" assert config.proxy.server == "http://proxy.example.com:8080" def test_no_proxy_configured(self): """Handle case when no proxy is configured.""" reset_crawler_config() # Save current values old_http = os.environ.get("HTTP_PROXY") old_https = os.environ.get("HTTPS_PROXY") try: os.environ.pop("HTTP_PROXY", None) os.environ.pop("HTTPS_PROXY", None) config = CrawlerConfig.from_env() assert config.proxy is None finally: # Restore if old_http: os.environ["HTTP_PROXY"] = old_http if old_https: os.environ["HTTPS_PROXY"] = old_https def test_proxy_required_validation_fails(self): """Raise ValueError when proxy required but not configured.""" config = CrawlerConfig(proxy=None, proxy_required=True) with pytest.raises(ValueError, match="Proxy configuration missing"): config.validate_proxy() def test_proxy_required_validation_passes(self): """Pass validation when proxy is configured and required.""" config = CrawlerConfig( proxy=ProxyConfig(server="http://127.0.0.1:7890"), proxy_required=True ) # Should not raise exception config.validate_proxy() def test_proxy_not_required(self): """Pass validation when proxy is not required.""" config = CrawlerConfig(proxy=None, proxy_required=False) # Should not raise exception config.validate_proxy() def test_to_playwright_format(self): """Convert to Playwright proxy format.""" proxy = ProxyConfig( server="http://127.0.0.1:7890", username="user", password="pass" ) result = proxy.to_playwright_format() assert result == { "server": "http://127.0.0.1:7890", "username": "user", "password": "pass" } def test_to_playwright_format_no_auth(self): """Convert to Playwright format without authentication.""" proxy = ProxyConfig(server="http://127.0.0.1:7890") result = proxy.to_playwright_format() assert result == {"server": "http://127.0.0.1:7890"} def test_get_crawler_config_singleton(self): """Test that get_crawler_config returns cached instance.""" reset_crawler_config() with patch.dict(os.environ, {"HTTPS_PROXY": "http://127.0.0.1:7890"}, clear=False): os.environ.pop("HTTP_PROXY", None) config1 = get_crawler_config() config2 = get_crawler_config() assert config1 is config2 def test_default_values(self): """Test default configuration values.""" config = CrawlerConfig(proxy=None, proxy_required=False) assert config.min_delay == 1.0 assert config.max_delay == 3.0 assert config.max_retries == 3 assert config.retry_min_wait == 2.0 assert config.retry_max_wait == 10.0