| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116 |
- 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)
- }
- }
|