5000079cbe
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
176 lines
4.8 KiB
Python
176 lines
4.8 KiB
Python
import yaml
|
|
from expander import filter_proxy, expand_config, build_mihomo_config
|
|
|
|
PROXY_FULL = {
|
|
"name": "node1",
|
|
"type": "ss",
|
|
"server": "1.2.3.4",
|
|
"port": 443,
|
|
"password": "secret",
|
|
"cipher": "aes-256-gcm",
|
|
"alive": True, # runtime field — should be stripped
|
|
"history": [], # runtime field — should be stripped
|
|
"extra": {"foo": "bar"}, # runtime field — should be stripped
|
|
}
|
|
|
|
BASE_YAML = """
|
|
proxies: []
|
|
proxy-providers:
|
|
provider1:
|
|
type: http
|
|
url: https://example.com/sub
|
|
interval: 3600
|
|
proxy-groups:
|
|
- name: Proxy
|
|
type: select
|
|
use:
|
|
- provider1
|
|
rules:
|
|
- MATCH,DIRECT
|
|
"""
|
|
|
|
|
|
def test_filter_proxy_removes_runtime_fields():
|
|
filtered = filter_proxy(PROXY_FULL)
|
|
assert "alive" not in filtered
|
|
assert "history" not in filtered
|
|
assert "extra" not in filtered
|
|
assert filtered["name"] == "node1"
|
|
assert filtered["server"] == "1.2.3.4"
|
|
|
|
|
|
def test_expand_config_replaces_providers_with_proxies():
|
|
proxies = [
|
|
{"name": "node1", "type": "ss", "server": "1.2.3.4", "port": 443,
|
|
"password": "pwd", "cipher": "aes-256-gcm"},
|
|
]
|
|
result = expand_config(BASE_YAML, {"provider1": proxies})
|
|
cfg = yaml.safe_load(result)
|
|
|
|
assert "proxy-providers" not in cfg
|
|
assert any(p["name"] == "node1" for p in cfg["proxies"])
|
|
|
|
|
|
def test_expand_config_fills_use_in_proxy_groups():
|
|
proxies = [
|
|
{"name": "node1", "type": "ss", "server": "1.2.3.4", "port": 443,
|
|
"password": "pwd", "cipher": "aes-256-gcm"},
|
|
{"name": "node2", "type": "ss", "server": "5.6.7.8", "port": 443,
|
|
"password": "pwd", "cipher": "aes-256-gcm"},
|
|
]
|
|
result = expand_config(BASE_YAML, {"provider1": proxies})
|
|
cfg = yaml.safe_load(result)
|
|
|
|
proxy_group = next(g for g in cfg["proxy-groups"] if g["name"] == "Proxy")
|
|
assert "use" not in proxy_group
|
|
assert "node1" in proxy_group["proxies"]
|
|
assert "node2" in proxy_group["proxies"]
|
|
|
|
|
|
def test_expand_config_preserves_existing_proxies():
|
|
base = """
|
|
proxies:
|
|
- name: static-node
|
|
type: direct
|
|
proxy-providers:
|
|
p1:
|
|
type: http
|
|
url: https://example.com/sub
|
|
interval: 3600
|
|
proxy-groups: []
|
|
rules: []
|
|
"""
|
|
result = expand_config(base, {"p1": [{"name": "dynamic-node", "type": "ss",
|
|
"server": "1.2.3.4", "port": 443}]})
|
|
cfg = yaml.safe_load(result)
|
|
names = [p["name"] for p in cfg["proxies"]]
|
|
assert "static-node" in names
|
|
assert "dynamic-node" in names
|
|
|
|
|
|
def test_expand_config_empty_providers():
|
|
result = expand_config(BASE_YAML, {})
|
|
cfg = yaml.safe_load(result)
|
|
assert "proxy-providers" not in cfg
|
|
|
|
|
|
def test_build_mihomo_config_merges_providers():
|
|
yaml1 = """
|
|
proxy-providers:
|
|
p1:
|
|
type: http
|
|
url: https://a.example.com/sub
|
|
interval: 3600
|
|
health-check:
|
|
enable: true
|
|
url: http://www.gstatic.com/generate_204
|
|
interval: 300
|
|
"""
|
|
yaml2 = """
|
|
proxy-providers:
|
|
p2:
|
|
type: http
|
|
url: https://b.example.com/sub
|
|
interval: 3600
|
|
"""
|
|
result = build_mihomo_config([yaml1, yaml2], "mysecret")
|
|
cfg = yaml.safe_load(result)
|
|
|
|
assert cfg["external-controller"] == "0.0.0.0:9090"
|
|
assert cfg["secret"] == "mysecret"
|
|
assert cfg["mixed-port"] == 7890
|
|
assert cfg["allow-lan"] is False
|
|
assert "p1" in cfg["proxy-providers"]
|
|
assert "p2" in cfg["proxy-providers"]
|
|
assert cfg["proxy-providers"]["p1"]["health-check"]["enable"] is True
|
|
|
|
|
|
def test_build_mihomo_config_deduplicates_by_name():
|
|
yaml1 = """
|
|
proxy-providers:
|
|
p1:
|
|
type: http
|
|
url: https://original.example.com/sub
|
|
interval: 3600
|
|
"""
|
|
yaml2 = """
|
|
proxy-providers:
|
|
p1:
|
|
type: http
|
|
url: https://duplicate.example.com/sub
|
|
interval: 3600
|
|
"""
|
|
result = build_mihomo_config([yaml1, yaml2], "s")
|
|
cfg = yaml.safe_load(result)
|
|
assert cfg["proxy-providers"]["p1"]["url"] == "https://original.example.com/sub"
|
|
|
|
|
|
def test_build_mihomo_config_no_providers():
|
|
result = build_mihomo_config(["proxies: []"], "s")
|
|
cfg = yaml.safe_load(result)
|
|
assert "proxy-providers" not in cfg
|
|
|
|
|
|
def test_expand_config_skips_proxies_without_name():
|
|
result = expand_config(BASE_YAML, {"provider1": [
|
|
{"type": "ss", "server": "1.2.3.4", "port": 443}, # no "name"
|
|
{"name": "valid-node", "type": "ss", "server": "5.6.7.8", "port": 443},
|
|
]})
|
|
cfg = yaml.safe_load(result)
|
|
names = [p["name"] for p in cfg["proxies"]]
|
|
assert "valid-node" in names
|
|
assert len(names) == 1
|
|
|
|
|
|
def test_build_mihomo_config_skips_malformed_yaml():
|
|
valid_yaml = """
|
|
proxy-providers:
|
|
p1:
|
|
type: http
|
|
url: https://example.com/sub
|
|
interval: 3600
|
|
"""
|
|
result = build_mihomo_config([valid_yaml, ":: invalid yaml ::: {{{"], "s")
|
|
cfg = yaml.safe_load(result)
|
|
assert "p1" in cfg["proxy-providers"]
|