122 lines
3.6 KiB
Go
122 lines
3.6 KiB
Go
package service
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"path/filepath"
|
|
"slices"
|
|
"testing"
|
|
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
|
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
|
)
|
|
|
|
func assertStringSet(t *testing.T, label string, got, want []string) {
|
|
t.Helper()
|
|
g := append([]string(nil), got...)
|
|
w := append([]string(nil), want...)
|
|
slices.Sort(g)
|
|
slices.Sort(w)
|
|
if !slices.Equal(g, w) {
|
|
t.Fatalf("%s = %v, want %v", label, got, want)
|
|
}
|
|
}
|
|
|
|
func marshalIps(t *testing.T, entries ...clientIpEntry) string {
|
|
t.Helper()
|
|
b, err := json.Marshal(entries)
|
|
if err != nil {
|
|
t.Fatalf("marshal ips: %v", err)
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// readClientIps returns the stored IP entries for an email as a map[ip]timestamp,
|
|
// plus whether the row exists at all.
|
|
func readClientIps(t *testing.T, email string) (map[string]int64, bool) {
|
|
t.Helper()
|
|
var row model.InboundClientIps
|
|
err := database.GetDB().Where("client_email = ?", email).First(&row).Error
|
|
if database.IsNotFound(err) {
|
|
return nil, false
|
|
}
|
|
if err != nil {
|
|
t.Fatalf("read ips %q: %v", email, err)
|
|
}
|
|
var entries []clientIpEntry
|
|
if err := json.Unmarshal([]byte(row.Ips), &entries); err != nil {
|
|
t.Fatalf("unmarshal ips %q: %v", email, err)
|
|
}
|
|
out := make(map[string]int64, len(entries))
|
|
for _, e := range entries {
|
|
out[e.IP] = e.Timestamp
|
|
}
|
|
return out, true
|
|
}
|
|
|
|
// Shared fixtures for the traffic/node test files. These helpers lived
|
|
// in node_client_traffic_sum_test.go until that file's snapshot-merge
|
|
// tests were retired with the traditional node sync (B6); the helpers
|
|
// themselves serve surviving tests, so they moved here.
|
|
|
|
func setupClientIpTestDB(t *testing.T) {
|
|
t.Helper()
|
|
dbDir := t.TempDir()
|
|
t.Setenv("XUI_DB_FOLDER", dbDir)
|
|
if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
|
t.Fatalf("InitDB: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = database.CloseDB() })
|
|
}
|
|
|
|
func initTrafficTestDB(t *testing.T) *gorm.DB {
|
|
t.Helper()
|
|
dbDir := t.TempDir()
|
|
t.Setenv("XUI_DB_FOLDER", dbDir)
|
|
if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
|
t.Fatalf("InitDB: %v", err)
|
|
}
|
|
t.Cleanup(func() { _ = database.CloseDB() })
|
|
return database.GetDB()
|
|
}
|
|
|
|
func createNodeInbound(t *testing.T, db *gorm.DB, nodeID int, tag string, port int) {
|
|
t.Helper()
|
|
nid := nodeID
|
|
ib := &model.Inbound{UserId: 1, Tag: tag, Enable: true, Port: port, Protocol: model.VLESS, NodeID: &nid}
|
|
if err := db.Create(ib).Error; err != nil {
|
|
t.Fatalf("create node inbound %q: %v", tag, err)
|
|
}
|
|
}
|
|
|
|
// createNodeInboundWithClient mirrors createNodeInbound but stores the client
|
|
// in the settings JSON.
|
|
func createNodeInboundWithClient(t *testing.T, db *gorm.DB, nodeID int, tag string, port int, email string) {
|
|
t.Helper()
|
|
nid := nodeID
|
|
settings := fmt.Sprintf(`{"clients": [{"email": %q, "enable": true}]}`, email)
|
|
ib := &model.Inbound{UserId: 1, Tag: tag, Enable: true, Port: port, Protocol: model.VLESS, NodeID: &nid, Settings: settings}
|
|
if err := db.Create(ib).Error; err != nil {
|
|
t.Fatalf("create node inbound %q: %v", tag, err)
|
|
}
|
|
}
|
|
|
|
func readTraffic(t *testing.T, db *gorm.DB, email string) xray.ClientTraffic {
|
|
t.Helper()
|
|
var ct xray.ClientTraffic
|
|
if err := db.Model(xray.ClientTraffic{}).Where("email = ?", email).First(&ct).Error; err != nil {
|
|
t.Fatalf("read client_traffics %q: %v", email, err)
|
|
}
|
|
return ct
|
|
}
|
|
|
|
func assertUpDown(t *testing.T, ct xray.ClientTraffic, wantUp, wantDown int64, when string) {
|
|
t.Helper()
|
|
if ct.Up != wantUp || ct.Down != wantDown {
|
|
t.Errorf("%s: up=%d down=%d, want %d/%d", when, ct.Up, ct.Down, wantUp, wantDown)
|
|
}
|
|
}
|