feat: machine mode, PEM-only certs, ECH support, multi-instance config, batch ops, xbctl
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidateCustomOutbounds(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
outbounds []OutboundConfig
|
||||
kernel string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "valid chain",
|
||||
outbounds: []OutboundConfig{
|
||||
{Tag: "warp", Protocol: "wireguard", Settings: map[string]any{"server": "1.1.1.1", "server_port": 2408, "private_key": "pk"}},
|
||||
{Tag: "proxy", Protocol: "socks", ProxyTag: "warp", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}},
|
||||
},
|
||||
kernel: "singbox",
|
||||
},
|
||||
{
|
||||
name: "valid native vmess settings preserved",
|
||||
outbounds: []OutboundConfig{{Tag: "vmess-native", Protocol: "vmess", Settings: map[string]any{"vnext": []any{map[string]any{"address": "1.1.1.1", "port": 443}}}}},
|
||||
kernel: "xray",
|
||||
},
|
||||
{
|
||||
name: "missing tag",
|
||||
outbounds: []OutboundConfig{{Protocol: "socks", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}}},
|
||||
wantErr: "custom_outbounds[0].tag is required",
|
||||
},
|
||||
{
|
||||
name: "missing protocol",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}}},
|
||||
wantErr: "custom_outbounds[0].protocol is required",
|
||||
},
|
||||
{
|
||||
name: "duplicate tag",
|
||||
outbounds: []OutboundConfig{
|
||||
{Tag: "proxy", Protocol: "socks", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}},
|
||||
{Tag: "proxy", Protocol: "http", Settings: map[string]any{"server": "3.3.3.3", "server_port": 8080}},
|
||||
},
|
||||
wantErr: `custom_outbounds[1].tag duplicates "proxy"`,
|
||||
},
|
||||
{
|
||||
name: "self proxy tag",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", ProxyTag: "proxy", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}}},
|
||||
wantErr: "custom_outbounds[0].proxy_tag must not reference itself",
|
||||
},
|
||||
{
|
||||
name: "unknown proxy tag",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", ProxyTag: "missing", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}}},
|
||||
wantErr: `custom_outbounds[0].proxy_tag references unknown outbound "missing"`,
|
||||
},
|
||||
{
|
||||
name: "built-in proxy tag allowed",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", ProxyTag: "direct", Settings: map[string]any{"server": "2.2.2.2", "server_port": 1080}}},
|
||||
},
|
||||
{
|
||||
name: "unsupported protocol for kernel",
|
||||
outbounds: []OutboundConfig{{Tag: "hy2", Protocol: "hysteria2", Settings: map[string]any{"server": "2.2.2.2", "server_port": 8443}}},
|
||||
kernel: "xray",
|
||||
wantErr: `custom_outbounds[0].protocol "hysteria2" is not supported by kernel "xray"`,
|
||||
},
|
||||
{
|
||||
name: "missing settings",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks"}},
|
||||
wantErr: "custom_outbounds[0].settings is required",
|
||||
},
|
||||
{
|
||||
name: "reserved snake case key in settings",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", Settings: map[string]any{"proxy_tag": "bad", "server": "2.2.2.2", "server_port": 1080}}},
|
||||
wantErr: "custom_outbounds[0].settings.proxy_tag is reserved",
|
||||
},
|
||||
{
|
||||
name: "reserved camel case key in settings",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", Settings: map[string]any{"proxyTag": "bad", "server": "2.2.2.2", "server_port": 1080}}},
|
||||
wantErr: "custom_outbounds[0].settings.proxyTag is reserved",
|
||||
},
|
||||
{
|
||||
name: "invalid server_port",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", Settings: map[string]any{"server": "2.2.2.2", "server_port": 70000}}},
|
||||
wantErr: "custom_outbounds[0].settings.server_port must be between 1 and 65535",
|
||||
},
|
||||
{
|
||||
name: "invalid camel case serverPort",
|
||||
outbounds: []OutboundConfig{{Tag: "proxy", Protocol: "socks", Settings: map[string]any{"server": "2.2.2.2", "serverPort": 70000}}},
|
||||
wantErr: "custom_outbounds[0].settings.serverPort must be between 1 and 65535",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
err := ValidateCustomOutboundsForKernel(tc.outbounds, tc.kernel, nil)
|
||||
if tc.wantErr == "" && err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if tc.wantErr != "" {
|
||||
if err == nil {
|
||||
t.Fatal("expected error, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.wantErr) {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user