Files
2026-09-16 18:16:30 +08:00

250 lines
7.7 KiB
Go

package cfprobe
import (
"os"
"path/filepath"
"strings"
"testing"
)
func TestMergeExplicitInstallConfig(t *testing.T) {
existing := Config{
ServerID: "sid",
Secret: "secret",
WorkerURL: "https://worker.example.com/report",
ReportInterval: 120,
ResetDay: 5,
ConnectionMode: connectionModeAuto,
PingMode: pingModeTCP,
AutoUpdate: false,
}
flagConfig := Config{
ReportInterval: defaultReportIntervalSec,
ResetDay: 1,
ConnectionMode: connectionModeHTTP,
PingMode: pingModeICMP,
AutoUpdate: true,
UpdateProxy: "https://gh-proxy.example.com",
}
merged := existing
mergeExplicitInstallConfig(&merged, flagConfig, map[string]bool{"auto_update": true})
if !merged.AutoUpdate {
t.Fatal("AutoUpdate = false, want true when -auto_update=1 is explicit")
}
if merged.ReportInterval != existing.ReportInterval || merged.ResetDay != existing.ResetDay {
t.Fatalf("non-explicit fields changed: %+v", merged)
}
if merged.UpdateProxy != "" {
t.Fatalf("UpdateProxy = %q, want preserved empty", merged.UpdateProxy)
}
if merged.ConnectionMode != connectionModeAuto {
t.Fatalf("ConnectionMode = %q, want preserved %q", merged.ConnectionMode, connectionModeAuto)
}
if merged.PingMode != pingModeTCP {
t.Fatalf("PingMode = %q, want preserved %q", merged.PingMode, pingModeTCP)
}
merged = existing
mergeExplicitInstallConfig(&merged, flagConfig, map[string]bool{"connection_mode": true})
if merged.ConnectionMode != connectionModeHTTP {
t.Fatalf("ConnectionMode = %q, want %q", merged.ConnectionMode, connectionModeHTTP)
}
merged = existing
mergeExplicitInstallConfig(&merged, flagConfig, map[string]bool{"ping_mode": true})
if merged.PingMode != pingModeICMP {
t.Fatalf("PingMode = %q, want %q", merged.PingMode, pingModeICMP)
}
merged = existing
mergeExplicitInstallConfig(&merged, flagConfig, map[string]bool{"install_ghproxy": true})
if merged.UpdateProxy != flagConfig.UpdateProxy {
t.Fatalf("UpdateProxy = %q, want %q", merged.UpdateProxy, flagConfig.UpdateProxy)
}
existingAuto := existing
existingAuto.AutoUpdate = true
merged = existingAuto
off := flagConfig
off.AutoUpdate = false
mergeExplicitInstallConfig(&merged, off, map[string]bool{"auto_update": true})
if merged.AutoUpdate {
t.Fatal("AutoUpdate = true, want false when -auto_update=0 is explicit")
}
}
func TestWriteSystemdUserServiceUsesUserSafeSettings(t *testing.T) {
tmp := t.TempDir()
paths := Paths{
ServiceName: "cf-probe",
BinaryFile: filepath.Join(tmp, "bin", "cf-probe"),
ConfigDir: filepath.Join(tmp, ".cf-probe"),
ConfigFile: filepath.Join(tmp, ".cf-probe", "config.conf"),
ServiceFile: filepath.Join(tmp, "cf-probe.service"),
}
if err := writeSystemdUserService(paths, false); err != nil {
t.Fatalf("writeSystemdUserService returned error: %v", err)
}
data, err := os.ReadFile(paths.ServiceFile)
if err != nil {
t.Fatalf("read service file: %v", err)
}
content := string(data)
wantExec := "ExecStart=" + quoteSystemdExecArg(paths.BinaryFile) + " run -config=" + quoteSystemdExecArg(paths.ConfigFile) + " -debug=0"
if !strings.Contains(content, wantExec) {
t.Fatalf("service content missing ExecStart %q:\n%s", wantExec, content)
}
for _, disallowed := range []string{
"WorkingDirectory=",
"CPUSchedulingPolicy=",
"IOSchedulingClass=",
"IOSchedulingPriority=",
} {
if strings.Contains(content, disallowed) {
t.Fatalf("user service should not contain %s:\n%s", disallowed, content)
}
}
}
func TestWriteLaunchdUserServiceUsesUserPaths(t *testing.T) {
tmp := t.TempDir()
paths := Paths{
ServiceName: "cf-probe",
BinaryFile: filepath.Join(tmp, ".cf-probe", "bin", "cf-probe"),
ConfigFile: filepath.Join(tmp, ".cf-probe", "config.conf"),
LogFile: filepath.Join(tmp, ".cf-probe", "cf-probe.log"),
LaunchdLabel: "com.cfsm.cf-probe",
LaunchdUserFile: filepath.Join(tmp, "Library", "LaunchAgents", "com.cfsm.cf-probe.plist"),
LaunchdRootFile: filepath.Join(tmp, "Library", "LaunchDaemons", "com.cfsm.cf-probe.plist"),
UserMode: true,
RunUID: 501,
}
if err := writeLaunchdService(paths, false); err != nil {
t.Fatalf("writeLaunchdService returned error: %v", err)
}
if _, err := os.Stat(paths.LaunchdUserFile); err != nil {
t.Fatalf("user launchd plist missing: %v", err)
}
if _, err := os.Stat(paths.LaunchdRootFile); !os.IsNotExist(err) {
t.Fatalf("root launchd plist should not be written: %v", err)
}
data, err := os.ReadFile(paths.LaunchdUserFile)
if err != nil {
t.Fatalf("read launchd plist: %v", err)
}
content := string(data)
for _, want := range []string{
"<string>" + paths.BinaryFile + "</string>",
"<string>run</string>",
"<string>-config=" + paths.ConfigFile + "</string>",
"<string>-debug=0</string>",
"<string>" + paths.LogFile + "</string>",
} {
if !strings.Contains(content, want) {
t.Fatalf("launchd plist missing %q:\n%s", want, content)
}
}
if strings.Contains(content, "UserName") || strings.Contains(content, "root") {
t.Fatalf("user launchd plist should not contain root user block:\n%s", content)
}
}
func TestManagementLogFileByServiceSystem(t *testing.T) {
paths := Paths{
ServiceName: "cf-probe",
LogFile: "/var/log/cf-probe.log",
}
tests := []struct {
system string
want string
}{
{"systemd", ""},
{"systemd-user", ""},
{"procd", ""},
{"openrc", "/var/log/cf-probe.log"},
{"launchd", "/var/log/cf-probe.log"},
{"synology-rc", "/var/log/cf-probe.log"},
{"background", "/var/log/cf-probe.log"},
{"windows", "/var/log/cf-probe.log"},
{"upstart", filepath.Join("/var/log/upstart", "cf-probe.log")},
}
for _, tt := range tests {
t.Run(tt.system, func(t *testing.T) {
if got := managementLogFile(paths, tt.system); got != tt.want {
t.Fatalf("managementLogFile() = %q, want %q", got, tt.want)
}
})
}
}
func TestMigrateTrafficMovesLegacyTraffic(t *testing.T) {
tmp := t.TempDir()
oldDir := filepath.Join(tmp, "old")
newDir := filepath.Join(tmp, "new")
oldTraffic := filepath.Join(oldDir, "traffic.dat")
newTraffic := filepath.Join(newDir, "traffic.dat")
if err := os.MkdirAll(oldDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(oldTraffic, []byte("RX_PREV=1\n"), 0o600); err != nil {
t.Fatal(err)
}
err := migrateTraffic(Paths{
ConfigDir: newDir,
TrafficFile: newTraffic,
OldTrafficFile: oldTraffic,
})
if err != nil {
t.Fatalf("migrateTraffic returned error: %v", err)
}
got, err := os.ReadFile(newTraffic)
if err != nil {
t.Fatalf("new traffic missing: %v", err)
}
if string(got) != "RX_PREV=1\n" {
t.Fatalf("traffic = %q", got)
}
if _, err := os.Stat(oldTraffic); !os.IsNotExist(err) {
t.Fatalf("old traffic still exists or stat failed: %v", err)
}
}
func TestMigrateTrafficKeepsExistingTraffic(t *testing.T) {
tmp := t.TempDir()
oldDir := filepath.Join(tmp, "old")
newDir := filepath.Join(tmp, "new")
oldTraffic := filepath.Join(oldDir, "traffic.dat")
newTraffic := filepath.Join(newDir, "traffic.dat")
if err := os.MkdirAll(oldDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(newDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(oldTraffic, []byte("old\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(newTraffic, []byte("new\n"), 0o600); err != nil {
t.Fatal(err)
}
if err := migrateTraffic(Paths{ConfigDir: newDir, TrafficFile: newTraffic, OldTrafficFile: oldTraffic}); err != nil {
t.Fatalf("migrateTraffic returned error: %v", err)
}
got, err := os.ReadFile(newTraffic)
if err != nil {
t.Fatal(err)
}
if string(got) != "new\n" {
t.Fatalf("traffic = %q", got)
}
if _, err := os.Stat(oldTraffic); err != nil {
t.Fatalf("old traffic should be preserved when current exists: %v", err)
}
}