mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-13 09:36:05 +00:00
162 lines
3.5 KiB
Go
162 lines
3.5 KiB
Go
//go:build !windows
|
|
|
|
package xray
|
|
|
|
import (
|
|
"os"
|
|
"os/exec"
|
|
"os/signal"
|
|
"path/filepath"
|
|
"syscall"
|
|
"testing"
|
|
"time"
|
|
|
|
xuilogger "github.com/mhsanaei/3x-ui/v3/logger"
|
|
"github.com/op/go-logging"
|
|
)
|
|
|
|
func TestStopWaitsForGracefulExit(t *testing.T) {
|
|
initProcessTestLogger(t)
|
|
|
|
p := startProcessHelper(t, "delayed-term")
|
|
|
|
start := time.Now()
|
|
if err := p.Stop(); err != nil {
|
|
t.Fatalf("Stop: %v", err)
|
|
}
|
|
if elapsed := time.Since(start); elapsed < 150*time.Millisecond {
|
|
t.Fatalf("Stop returned before child exited; elapsed=%s", elapsed)
|
|
}
|
|
if p.IsRunning() {
|
|
t.Fatal("process still reports running after Stop")
|
|
}
|
|
}
|
|
|
|
func TestIntentionalStopDoesNotRecordExitError(t *testing.T) {
|
|
initProcessTestLogger(t)
|
|
|
|
p := startProcessHelper(t, "default-term")
|
|
|
|
if err := p.Stop(); err != nil {
|
|
t.Fatalf("Stop: %v", err)
|
|
}
|
|
if err := p.GetErr(); err != nil {
|
|
t.Fatalf("GetErr after intentional stop = %v, want nil", err)
|
|
}
|
|
if result := p.GetResult(); result != "" {
|
|
t.Fatalf("GetResult after intentional stop = %q, want empty", result)
|
|
}
|
|
}
|
|
|
|
func TestStopKillsProcessThatIgnoresSIGTERM(t *testing.T) {
|
|
initProcessTestLogger(t)
|
|
|
|
oldGraceful := xrayGracefulStopTimeout
|
|
oldForce := xrayForceStopTimeout
|
|
xrayGracefulStopTimeout = 100 * time.Millisecond
|
|
xrayForceStopTimeout = 2 * time.Second
|
|
t.Cleanup(func() {
|
|
xrayGracefulStopTimeout = oldGraceful
|
|
xrayForceStopTimeout = oldForce
|
|
})
|
|
|
|
p := startProcessHelper(t, "ignore-term")
|
|
|
|
if err := p.Stop(); err != nil {
|
|
t.Fatalf("Stop: %v", err)
|
|
}
|
|
if p.IsRunning() {
|
|
t.Fatal("process still reports running after forced stop")
|
|
}
|
|
}
|
|
|
|
func initProcessTestLogger(t *testing.T) {
|
|
t.Helper()
|
|
t.Setenv("XUI_LOG_FOLDER", t.TempDir())
|
|
xuilogger.InitLogger(logging.ERROR)
|
|
}
|
|
|
|
func startProcessHelper(t *testing.T, mode string) *process {
|
|
t.Helper()
|
|
|
|
readyPath := filepath.Join(t.TempDir(), "ready")
|
|
cmd := exec.Command(os.Args[0], "-test.run=TestXrayProcessHelper", "--", mode)
|
|
cmd.Env = append(os.Environ(),
|
|
"XRAY_PROCESS_HELPER=1",
|
|
"XRAY_PROCESS_READY="+readyPath,
|
|
)
|
|
|
|
p := newProcess(nil)
|
|
if err := p.startCommand(cmd); err != nil {
|
|
t.Fatalf("start helper process: %v", err)
|
|
}
|
|
waitForProcessHelperReady(t, readyPath)
|
|
|
|
t.Cleanup(func() {
|
|
if p.IsRunning() {
|
|
p.intentionalStop.Store(true)
|
|
_ = p.cmd.Process.Kill()
|
|
_ = p.waitForExit(2 * time.Second)
|
|
}
|
|
})
|
|
|
|
return p
|
|
}
|
|
|
|
func waitForProcessHelperReady(t *testing.T, readyPath string) {
|
|
t.Helper()
|
|
|
|
deadline := time.Now().Add(2 * time.Second)
|
|
for time.Now().Before(deadline) {
|
|
if _, err := os.Stat(readyPath); err == nil {
|
|
return
|
|
}
|
|
time.Sleep(10 * time.Millisecond)
|
|
}
|
|
t.Fatalf("helper process did not become ready")
|
|
}
|
|
|
|
func TestXrayProcessHelper(t *testing.T) {
|
|
if os.Getenv("XRAY_PROCESS_HELPER") != "1" {
|
|
return
|
|
}
|
|
|
|
mode := ""
|
|
for i, arg := range os.Args {
|
|
if arg == "--" && i+1 < len(os.Args) {
|
|
mode = os.Args[i+1]
|
|
break
|
|
}
|
|
}
|
|
|
|
switch mode {
|
|
case "delayed-term":
|
|
sigCh := make(chan os.Signal, 1)
|
|
signal.Notify(sigCh, syscall.SIGTERM)
|
|
markProcessHelperReady(t)
|
|
<-sigCh
|
|
time.Sleep(200 * time.Millisecond)
|
|
os.Exit(0)
|
|
case "default-term":
|
|
markProcessHelperReady(t)
|
|
select {}
|
|
case "ignore-term":
|
|
signal.Ignore(syscall.SIGTERM)
|
|
markProcessHelperReady(t)
|
|
select {}
|
|
default:
|
|
t.Fatalf("unknown helper mode %q", mode)
|
|
}
|
|
}
|
|
|
|
func markProcessHelperReady(t *testing.T) {
|
|
t.Helper()
|
|
|
|
readyPath := os.Getenv("XRAY_PROCESS_READY")
|
|
if readyPath == "" {
|
|
t.Fatal("XRAY_PROCESS_READY is not set")
|
|
}
|
|
if err := os.WriteFile(readyPath, []byte("ready"), 0644); err != nil {
|
|
t.Fatalf("write helper ready file: %v", err)
|
|
}
|
|
}
|