API / kiro-gateway /tests /unit /test_vpn_proxy.py
sshinmen's picture
Clean deploy to HF Space
bf9e111
Raw
History Blame Contribute Delete
11.1 kB
# -*- coding: utf-8 -*-
"""
Unit tests for VPN/Proxy configuration logic.
Tests verify that proxy environment variables are set correctly
for different input formats and scenarios.
"""
import os
import pytest
@pytest.mark.parametrize(
"test_id, initial_no_proxy, vpn_url, expected_http_proxy, expected_https_proxy, expected_no_proxy",
[
(
"proxy_with_http_scheme",
None,
"http://192.168.1.103:2080",
"http://192.168.1.103:2080",
"http://192.168.1.103:2080",
"127.0.0.1,localhost"
),
(
"proxy_with_socks5_scheme",
None,
"socks5://192.168.1.103:1080",
"socks5://192.168.1.103:1080",
"socks5://192.168.1.103:1080",
"127.0.0.1,localhost"
),
(
"proxy_without_scheme",
None,
"192.168.1.103:2080",
"http://192.168.1.103:2080",
"http://192.168.1.103:2080",
"127.0.0.1,localhost"
),
(
"proxy_with_auth",
None,
"http://user:pass@192.168.1.103:2080",
"http://user:pass@192.168.1.103:2080",
"http://user:pass@192.168.1.103:2080",
"127.0.0.1,localhost"
),
(
"proxy_preserves_existing_no_proxy",
"internal.corp,*.example.com",
"http://192.168.1.103:2080",
"http://192.168.1.103:2080",
"http://192.168.1.103:2080",
"internal.corp,*.example.com,127.0.0.1,localhost"
),
(
"proxy_empty_url",
None,
"",
None,
None,
None
),
]
)
def test_vpn_proxy_environment_setup(
test_id,
initial_no_proxy,
vpn_url,
expected_http_proxy,
expected_https_proxy,
expected_no_proxy,
monkeypatch
):
"""
Parametrized test for VPN/Proxy setup via environment variables.
Verifies that:
- HTTP_PROXY, HTTPS_PROXY, ALL_PROXY are set correctly
- URL normalization works (adds http:// if no scheme)
- NO_PROXY includes localhost and preserves existing values
- Empty URL doesn't set any proxy variables
"""
print(f"\n--- Running VPN/Proxy test: ID = {test_id} ---")
# Clear proxy environment variables before test
for key in ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "NO_PROXY"]:
monkeypatch.delenv(key, raising=False)
# Set initial NO_PROXY if specified
if initial_no_proxy:
monkeypatch.setenv("NO_PROXY", initial_no_proxy)
print(f"Initial NO_PROXY: '{initial_no_proxy}'")
# Simulate VPN_PROXY_URL configuration
print(f"VPN_PROXY_URL set to: '{vpn_url}'")
# Replicate logic from main.py (lines 175-197)
if vpn_url:
proxy_url_with_scheme = vpn_url if "://" in vpn_url else f"http://{vpn_url}"
os.environ['HTTP_PROXY'] = proxy_url_with_scheme
os.environ['HTTPS_PROXY'] = proxy_url_with_scheme
os.environ['ALL_PROXY'] = proxy_url_with_scheme
no_proxy_hosts = os.environ.get("NO_PROXY", "")
local_hosts = "127.0.0.1,localhost"
if no_proxy_hosts:
os.environ["NO_PROXY"] = f"{no_proxy_hosts},{local_hosts}"
else:
os.environ["NO_PROXY"] = local_hosts
# --- Assertions ---
print("\n[Verification]")
if expected_http_proxy:
actual_http_proxy = os.environ.get("HTTP_PROXY")
print(f"HTTP_PROXY: Expected '{expected_http_proxy}', Got '{actual_http_proxy}'")
assert actual_http_proxy == expected_http_proxy, "HTTP_PROXY mismatch!"
actual_https_proxy = os.environ.get("HTTPS_PROXY")
print(f"HTTPS_PROXY: Expected '{expected_https_proxy}', Got '{actual_https_proxy}'")
assert actual_https_proxy == expected_https_proxy, "HTTPS_PROXY mismatch!"
actual_all_proxy = os.environ.get("ALL_PROXY")
print(f"ALL_PROXY: Expected '{expected_http_proxy}', Got '{actual_all_proxy}'")
assert actual_all_proxy == expected_http_proxy, "ALL_PROXY mismatch!"
else:
# If proxy should not be set
assert os.environ.get("HTTP_PROXY") is None, "HTTP_PROXY should be None!"
assert os.environ.get("HTTPS_PROXY") is None, "HTTPS_PROXY should be None!"
print("Proxy not set (as expected)")
if expected_no_proxy:
actual_no_proxy = os.environ.get("NO_PROXY")
print(f"NO_PROXY: Expected '{expected_no_proxy}', Got '{actual_no_proxy}'")
assert actual_no_proxy == expected_no_proxy, "NO_PROXY mismatch!"
print(f"--- Test '{test_id}' passed successfully ---")
def test_proxy_scheme_normalization():
"""
Verifies that URLs without scheme are correctly normalized to http://.
Tests various input formats:
- Plain host:port β†’ http://host:port
- http:// β†’ unchanged
- https:// β†’ unchanged
- socks5:// β†’ unchanged
"""
print("\n--- Test: Proxy scheme normalization ---")
test_cases = [
("192.168.1.100:8080", "http://192.168.1.100:8080"),
("http://192.168.1.100:8080", "http://192.168.1.100:8080"),
("https://192.168.1.100:8080", "https://192.168.1.100:8080"),
("socks5://192.168.1.100:8080", "socks5://192.168.1.100:8080"),
("127.0.0.1:7890", "http://127.0.0.1:7890"),
]
for input_url, expected_url in test_cases:
print(f"\nInput: '{input_url}'")
# Logic from main.py
proxy_url_with_scheme = input_url if "://" in input_url else f"http://{input_url}"
print(f"Result: '{proxy_url_with_scheme}'")
print(f"Expected: '{expected_url}'")
assert proxy_url_with_scheme == expected_url, f"Normalization failed for '{input_url}'"
print("\n--- Test passed: all schemes normalized correctly ---")
def test_no_proxy_list_merging(monkeypatch):
"""
Verifies correct merging of existing and new NO_PROXY values.
Tests:
- Empty existing β†’ only localhost
- Existing values β†’ preserved and localhost added
- Duplicate localhost β†’ acceptable (not a problem)
"""
print("\n--- Test: NO_PROXY list merging ---")
test_cases = [
# (existing, expected_result)
("", "127.0.0.1,localhost"),
("internal.local", "internal.local,127.0.0.1,localhost"),
("192.168.0.0/16,10.0.0.0/8", "192.168.0.0/16,10.0.0.0/8,127.0.0.1,localhost"),
("*.corp.com,localhost", "*.corp.com,localhost,127.0.0.1,localhost"), # Duplicate localhost - OK
]
for existing_value, expected_result in test_cases:
print(f"\nExisting NO_PROXY: '{existing_value}'")
# Simulate logic
if existing_value:
monkeypatch.setenv("NO_PROXY", existing_value)
else:
monkeypatch.delenv("NO_PROXY", raising=False)
no_proxy_hosts = os.environ.get("NO_PROXY", "")
local_hosts = "127.0.0.1,localhost"
if no_proxy_hosts:
result = f"{no_proxy_hosts},{local_hosts}"
else:
result = local_hosts
print(f"Result: '{result}'")
print(f"Expected: '{expected_result}'")
assert result == expected_result, f"Merging failed for '{existing_value}'"
print("\n--- Test passed: lists merged correctly ---")
def test_proxy_does_not_affect_local_connections(monkeypatch):
"""
Verifies that local addresses (127.0.0.1, localhost) are always in NO_PROXY.
This ensures that local tests don't go through VPN/proxy,
which would be slow and incorrect.
"""
print("\n--- Test: Local addresses excluded from proxy ---")
# Simulate proxy setup
vpn_url = "http://vpn.example.com:8080"
os.environ['HTTP_PROXY'] = vpn_url
os.environ['HTTPS_PROXY'] = vpn_url
no_proxy_hosts = os.environ.get("NO_PROXY", "")
local_hosts = "127.0.0.1,localhost"
if no_proxy_hosts:
os.environ["NO_PROXY"] = f"{no_proxy_hosts},{local_hosts}"
else:
os.environ["NO_PROXY"] = local_hosts
no_proxy_value = os.environ.get("NO_PROXY")
print(f"NO_PROXY set to: '{no_proxy_value}'")
# Assertions
assert "127.0.0.1" in no_proxy_value, "127.0.0.1 must be in NO_PROXY!"
assert "localhost" in no_proxy_value, "localhost must be in NO_PROXY!"
print("βœ… Local addresses correctly excluded from proxy")
print("--- Test passed ---")
def test_proxy_with_special_characters():
"""
Verifies that proxy URLs with special characters in credentials work correctly.
Tests authentication with:
- Special characters in password
- URL encoding (if needed)
"""
print("\n--- Test: Proxy with special characters in credentials ---")
test_cases = [
# (input_url, expected_normalized)
("http://user:p@ss@proxy.com:8080", "http://user:p@ss@proxy.com:8080"),
("http://admin:P@ssw0rd!@192.168.1.1:3128", "http://admin:P@ssw0rd!@192.168.1.1:3128"),
("socks5://user123:pass456@localhost:1080", "socks5://user123:pass456@localhost:1080"),
]
for input_url, expected_url in test_cases:
print(f"\nInput: '{input_url}'")
# Normalization logic (should preserve special chars)
proxy_url_with_scheme = input_url if "://" in input_url else f"http://{input_url}"
print(f"Result: '{proxy_url_with_scheme}'")
print(f"Expected: '{expected_url}'")
assert proxy_url_with_scheme == expected_url, f"Special chars handling failed for '{input_url}'"
print("\n--- Test passed: special characters preserved correctly ---")
def test_empty_vpn_proxy_url_does_not_set_variables(monkeypatch):
"""
Verifies that empty VPN_PROXY_URL doesn't set any proxy variables.
This is the default behavior - direct connection without proxy.
"""
print("\n--- Test: Empty VPN_PROXY_URL (direct connection) ---")
# Clear all proxy variables
for key in ["HTTP_PROXY", "HTTPS_PROXY", "ALL_PROXY", "NO_PROXY"]:
monkeypatch.delenv(key, raising=False)
# Simulate empty VPN_PROXY_URL
vpn_url = ""
# Logic from main.py - should NOT execute if vpn_url is empty
if vpn_url:
proxy_url_with_scheme = vpn_url if "://" in vpn_url else f"http://{vpn_url}"
os.environ['HTTP_PROXY'] = proxy_url_with_scheme
os.environ['HTTPS_PROXY'] = proxy_url_with_scheme
os.environ['ALL_PROXY'] = proxy_url_with_scheme
# Verify no proxy variables are set
assert os.environ.get("HTTP_PROXY") is None, "HTTP_PROXY should not be set!"
assert os.environ.get("HTTPS_PROXY") is None, "HTTPS_PROXY should not be set!"
assert os.environ.get("ALL_PROXY") is None, "ALL_PROXY should not be set!"
print("βœ… No proxy variables set (direct connection)")
print("--- Test passed ---")
print("VPN/Proxy tests loaded. Will verify proxy setup logic!")