119 lines
3.3 KiB
Go
119 lines
3.3 KiB
Go
package app
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTransportNormalizeBootstrapTarget(t *testing.T) {
|
|
cases := map[string]string{
|
|
"vless://user@example.com:443?type=tcp": "example.com",
|
|
"example.com:8443": "example.com",
|
|
"203.0.113.10:443": "203.0.113.10",
|
|
"[2001:db8::1]:443": "2001:db8::1",
|
|
"https://api.example.net/path?q=1": "api.example.net",
|
|
}
|
|
for in, want := range cases {
|
|
got := transportNormalizeBootstrapTarget(in)
|
|
if got != want {
|
|
t.Fatalf("normalize mismatch for %q: got=%q want=%q", in, got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTransportCollectSingBoxConfigCandidates(t *testing.T) {
|
|
tmp := t.TempDir()
|
|
cfg := filepath.Join(tmp, "singbox.json")
|
|
body := `{
|
|
"log": {"level":"info"},
|
|
"outbounds": [
|
|
{"type":"vless","server":"n3.elmprod.tech","server_port":40903},
|
|
{"type":"shadowsocks","server":"198.51.100.5","server_port":443}
|
|
]
|
|
}`
|
|
if err := os.WriteFile(cfg, []byte(body), 0o644); err != nil {
|
|
t.Fatalf("write config: %v", err)
|
|
}
|
|
client := TransportClient{
|
|
ID: "sg-test",
|
|
Kind: TransportClientSingBox,
|
|
Config: map[string]any{
|
|
"config_path": cfg,
|
|
},
|
|
}
|
|
got := transportCollectSingBoxConfigCandidates(client)
|
|
joined := strings.Join(got, ",")
|
|
if !strings.Contains(joined, "n3.elmprod.tech") {
|
|
t.Fatalf("missing server host in candidates: %#v", got)
|
|
}
|
|
if !strings.Contains(joined, "198.51.100.5") {
|
|
t.Fatalf("missing server ip in candidates: %#v", got)
|
|
}
|
|
}
|
|
|
|
func TestTransportSystemdActionAppliesSingBoxBootstrapBypass(t *testing.T) {
|
|
origRunner := transportRunCommand
|
|
origPath := transportBootstrapStatePath
|
|
defer func() {
|
|
transportRunCommand = origRunner
|
|
transportBootstrapStatePath = origPath
|
|
}()
|
|
|
|
tmp := t.TempDir()
|
|
transportBootstrapStatePath = filepath.Join(tmp, "bootstrap-routes.json")
|
|
|
|
calls := make([]string, 0, 8)
|
|
transportRunCommand = func(_ time.Duration, name string, args ...string) (string, string, int, error) {
|
|
cmd := name + " " + strings.Join(args, " ")
|
|
calls = append(calls, cmd)
|
|
switch cmd {
|
|
case "ip -4 route show table main default":
|
|
return "default via 192.0.2.1 dev eth0\n", "", 0, nil
|
|
case "ip -4 route replace 203.0.113.10/32 table agvpn via 192.0.2.1 dev eth0":
|
|
return "", "", 0, nil
|
|
case "systemctl start singbox@sg-test.service":
|
|
return "", "", 0, nil
|
|
default:
|
|
return "", "", 0, nil
|
|
}
|
|
}
|
|
|
|
client := TransportClient{
|
|
ID: "sg-test",
|
|
Kind: TransportClientSingBox,
|
|
Config: map[string]any{
|
|
"runner": "systemd",
|
|
"unit": "singbox@.service",
|
|
"bootstrap_host": "203.0.113.10",
|
|
},
|
|
}
|
|
|
|
res := transportSystemdBackend{}.Action(client, "start")
|
|
if !res.OK {
|
|
t.Fatalf("expected action success, got %#v", res)
|
|
}
|
|
|
|
gotCalls := strings.Join(calls, " | ")
|
|
want := []string{
|
|
"ip -4 route show table main default",
|
|
"ip -4 route replace 203.0.113.10/32 table agvpn via 192.0.2.1 dev eth0",
|
|
"systemctl start singbox@sg-test.service",
|
|
}
|
|
for _, part := range want {
|
|
if !strings.Contains(gotCalls, part) {
|
|
t.Fatalf("expected call %q, got %s", part, gotCalls)
|
|
}
|
|
}
|
|
data, err := os.ReadFile(transportBootstrapStatePath)
|
|
if err != nil {
|
|
t.Fatalf("read bootstrap state: %v", err)
|
|
}
|
|
text := string(data)
|
|
if !strings.Contains(text, "203.0.113.10") || !strings.Contains(text, "sg-test") {
|
|
t.Fatalf("unexpected bootstrap state: %s", text)
|
|
}
|
|
}
|