Files
3x-ui-agent/internal/web/service/mtproto_fake_test.go
Sanaei f727d04f65
Release 3X-UI for Docker / build (push) Canceled after 0s
Release 3X-UI / build (386) (push) Canceled after 0s
Release 3X-UI / build (amd64) (push) Canceled after 0s
Release 3X-UI / build (arm64) (push) Canceled after 0s
Release 3X-UI / build (armv5) (push) Canceled after 0s
Release 3X-UI / build (armv6) (push) Canceled after 0s
Release 3X-UI / build (armv7) (push) Canceled after 0s
Release 3X-UI / build (s390x) (push) Canceled after 0s
Release 3X-UI / Build for Windows (amd64) (push) Canceled after 0s
Release 3X-UI / Publish rolling dev release (push) Canceled after 0s
v3.7.0
2026-08-24 15:07:15 +02:00

117 lines
3.5 KiB
Go

package service
import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/mhsanaei/3x-ui/v3/internal/database"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
"github.com/mhsanaei/3x-ui/v3/internal/mtproto"
"github.com/mhsanaei/3x-ui/v3/internal/xray"
)
const (
mtprotoTestSecretA = "ee00112233445566778899aabbccddeeff6578616d706c652e636f6d"
mtprotoTestSecretB = "ee101112131415161718191a1b1c1d1e1f6578616d706c652e636f6d"
mtprotoTestSecretC = "ee202122232425262728292a2b2c2d2e2f6578616d706c652e636f6d"
mtprotoTestSecretD = "ee303132333435363738393a3b3c3d3e3f6578616d706c652e636f6d"
)
func seedClientTraffic(t *testing.T, inboundId int, email string, enable bool) {
t.Helper()
row := xray.ClientTraffic{InboundId: inboundId, Email: email, Enable: enable}
if err := database.GetDB().Create(&row).Error; err != nil {
t.Fatalf("seed traffic %s: %v", email, err)
}
}
func loadInboundByTag(t *testing.T, tag string) *model.Inbound {
t.Helper()
var ib model.Inbound
if err := database.GetDB().Where("tag = ?", tag).First(&ib).Error; err != nil {
t.Fatalf("load inbound %s: %v", tag, err)
}
return &ib
}
// fakeMtgChildMain is what the re-executed test binary runs when posing as an
// mtg child process: it appends its pid to the file named by MTG_FAKE_PIDFILE
// so tests can count spawns, then blocks until the manager kills it.
func fakeMtgChildMain() {
if f, err := os.OpenFile(os.Getenv("MTG_FAKE_PIDFILE"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0o644); err == nil {
fmt.Fprintf(f, "%d\n", os.Getpid())
f.Close()
}
select {}
}
// installFakeMtg points the mtproto manager at a copy of the running test
// binary posing as mtg (via the MTG_FAKE_CHILD gate in TestMain) and returns
// the pid file whose line count equals the number of processes spawned so far.
func installFakeMtg(t *testing.T) string {
t.Helper()
binDir := t.TempDir()
self, err := os.Executable()
if err != nil {
t.Fatalf("locate test binary: %v", err)
}
payload, err := os.ReadFile(self)
if err != nil {
t.Fatalf("read test binary: %v", err)
}
if err := os.WriteFile(filepath.Join(binDir, mtproto.GetBinaryName()), payload, 0o755); err != nil {
t.Fatalf("install fake mtg: %v", err)
}
pidFile := filepath.Join(binDir, "mtg-pids.txt")
t.Setenv("XUI_BIN_FOLDER", binDir)
t.Setenv("MTG_FAKE_CHILD", "1")
t.Setenv("MTG_FAKE_PIDFILE", pidFile)
return pidFile
}
func countSpawns(t *testing.T, pidFile string) int {
t.Helper()
data, err := os.ReadFile(pidFile)
if os.IsNotExist(err) {
return 0
}
if err != nil {
t.Fatalf("read pid file: %v", err)
}
return len(strings.Fields(string(data)))
}
// waitForSpawns polls until exactly want processes have registered, failing
// fast when the count overshoots and on timeout.
func waitForSpawns(t *testing.T, pidFile string, want int) {
t.Helper()
deadline := time.Now().Add(5 * time.Second)
for {
got := countSpawns(t, pidFile)
if got == want {
return
}
if got > want {
t.Fatalf("expected %d mtg spawn(s), got %d", want, got)
}
if time.Now().After(deadline) {
t.Fatalf("expected %d mtg spawn(s), still %d after timeout", want, got)
}
time.Sleep(20 * time.Millisecond)
}
}
// assertNoNewSpawns gives a wrongly spawned child time to register, then
// asserts the spawn count is still exactly want.
func assertNoNewSpawns(t *testing.T, pidFile string, want int) {
t.Helper()
time.Sleep(500 * time.Millisecond)
if got := countSpawns(t, pidFile); got != want {
t.Fatalf("expected the mtg process to be kept (%d spawn(s)), got %d", want, got)
}
}