mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-06-07 13:44:24 +00:00
182 lines
4.9 KiB
Go
182 lines
4.9 KiB
Go
|
|
package database
|
||
|
|
|
||
|
|
import (
|
||
|
|
"path/filepath"
|
||
|
|
"testing"
|
||
|
|
|
||
|
|
"github.com/mhsanaei/3x-ui/v2/database/model"
|
||
|
|
"github.com/mhsanaei/3x-ui/v2/xray"
|
||
|
|
"gorm.io/driver/sqlite"
|
||
|
|
"gorm.io/gorm"
|
||
|
|
"gorm.io/gorm/logger"
|
||
|
|
)
|
||
|
|
|
||
|
|
// openTestSQLiteDB opens an in-memory or file-based SQLite database for testing.
|
||
|
|
func openTestSQLiteDB(t *testing.T, dbPath string) *gorm.DB {
|
||
|
|
t.Helper()
|
||
|
|
gdb, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{Logger: logger.Discard})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("failed to open test SQLite DB: %v", err)
|
||
|
|
}
|
||
|
|
t.Cleanup(func() {
|
||
|
|
sqlDB, _ := gdb.DB()
|
||
|
|
if sqlDB != nil {
|
||
|
|
sqlDB.Close()
|
||
|
|
}
|
||
|
|
})
|
||
|
|
return gdb
|
||
|
|
}
|
||
|
|
|
||
|
|
// createTestTables runs AutoMigrate on the given DB for all models.
|
||
|
|
func createTestTables(t *testing.T, gdb *gorm.DB) {
|
||
|
|
t.Helper()
|
||
|
|
models := []any{
|
||
|
|
&model.User{},
|
||
|
|
&model.Inbound{},
|
||
|
|
&model.OutboundTraffics{},
|
||
|
|
&model.Setting{},
|
||
|
|
&model.InboundClientIps{},
|
||
|
|
&xray.ClientTraffic{},
|
||
|
|
&model.HistoryOfSeeders{},
|
||
|
|
}
|
||
|
|
for _, m := range models {
|
||
|
|
if err := gdb.AutoMigrate(m); err != nil {
|
||
|
|
t.Fatalf("AutoMigrate failed: %v", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMigrateAllTables_EmoprySource(t *testing.T) {
|
||
|
|
srcDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "src.db"))
|
||
|
|
dstDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "dst.db"))
|
||
|
|
|
||
|
|
createTestTables(t, srcDB)
|
||
|
|
createTestTables(t, dstDB)
|
||
|
|
|
||
|
|
err := migrateAllTables(srcDB, dstDB)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("migrateAllTables on empty source should succeed: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Verify destination is still empty
|
||
|
|
for _, name := range tableNames() {
|
||
|
|
var count int64
|
||
|
|
dstDB.Table(name).Count(&count)
|
||
|
|
if count != 0 {
|
||
|
|
t.Errorf("table %s should be empty, got %d rows", name, count)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMigrateAllTables_WithData(t *testing.T) {
|
||
|
|
srcDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "src.db"))
|
||
|
|
dstDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "dst.db"))
|
||
|
|
|
||
|
|
createTestTables(t, srcDB)
|
||
|
|
createTestTables(t, dstDB)
|
||
|
|
|
||
|
|
// Insert test data into source
|
||
|
|
srcDB.Create(&model.User{Username: "testuser", Password: "testpass", Role: "admin"})
|
||
|
|
srcDB.Create(&model.Setting{Key: "testkey", Value: "testvalue"})
|
||
|
|
|
||
|
|
err := migrateAllTables(srcDB, dstDB)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("migrateAllTables failed: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Verify data was copied
|
||
|
|
var userCount int64
|
||
|
|
dstDB.Table("users").Count(&userCount)
|
||
|
|
if userCount != 1 {
|
||
|
|
t.Errorf("expected 1 user in dst, got %d", userCount)
|
||
|
|
}
|
||
|
|
|
||
|
|
var settingCount int64
|
||
|
|
dstDB.Table("settings").Count(&settingCount)
|
||
|
|
if settingCount != 1 {
|
||
|
|
t.Errorf("expected 1 setting in dst, got %d", settingCount)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMigrateAllTables_OverwritesExisting(t *testing.T) {
|
||
|
|
srcDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "src.db"))
|
||
|
|
dstDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "dst.db"))
|
||
|
|
|
||
|
|
createTestTables(t, srcDB)
|
||
|
|
createTestTables(t, dstDB)
|
||
|
|
|
||
|
|
// Insert existing data in destination that should be cleared
|
||
|
|
dstDB.Create(&model.User{Username: "olduser", Password: "oldpass", Role: "admin"})
|
||
|
|
dstDB.Create(&model.Setting{Key: "oldkey", Value: "oldvalue"})
|
||
|
|
|
||
|
|
// Insert new data in source
|
||
|
|
srcDB.Create(&model.User{Username: "newuser", Password: "newpass", Role: "admin"})
|
||
|
|
|
||
|
|
err := migrateAllTables(srcDB, dstDB)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("migrateAllTables failed: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Verify old data was replaced
|
||
|
|
var userCount int64
|
||
|
|
dstDB.Table("users").Count(&userCount)
|
||
|
|
if userCount != 1 {
|
||
|
|
t.Errorf("expected 1 user in dst after overwrite, got %d", userCount)
|
||
|
|
}
|
||
|
|
|
||
|
|
var user model.User
|
||
|
|
dstDB.Table("users").First(&user)
|
||
|
|
if user.Username != "newuser" {
|
||
|
|
t.Errorf("expected username 'newuser', got '%s'", user.Username)
|
||
|
|
}
|
||
|
|
|
||
|
|
// Settings should be empty since source has no settings
|
||
|
|
var settingCount int64
|
||
|
|
dstDB.Table("settings").Count(&settingCount)
|
||
|
|
if settingCount != 0 {
|
||
|
|
t.Errorf("expected 0 settings in dst after overwrite, got %d", settingCount)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMigrateTable_Generic(t *testing.T) {
|
||
|
|
srcDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "src.db"))
|
||
|
|
dstDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "dst.db"))
|
||
|
|
|
||
|
|
createTestTables(t, srcDB)
|
||
|
|
createTestTables(t, dstDB)
|
||
|
|
|
||
|
|
// Insert test users
|
||
|
|
srcDB.Create(&model.User{Username: "user1", Password: "pass1", Role: "admin"})
|
||
|
|
srcDB.Create(&model.User{Username: "user2", Password: "pass2", Role: "admin"})
|
||
|
|
|
||
|
|
count, err := migrateTable[model.User](srcDB, dstDB, "users")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("migrateTable failed: %v", err)
|
||
|
|
}
|
||
|
|
if count != 2 {
|
||
|
|
t.Errorf("expected 2 rows migrated, got %d", count)
|
||
|
|
}
|
||
|
|
|
||
|
|
var dstCount int64
|
||
|
|
dstDB.Table("users").Count(&dstCount)
|
||
|
|
if dstCount != 2 {
|
||
|
|
t.Errorf("expected 2 users in dst, got %d", dstCount)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMigrateTable_EmptyTable(t *testing.T) {
|
||
|
|
srcDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "src.db"))
|
||
|
|
dstDB := openTestSQLiteDB(t, filepath.Join(t.TempDir(), "dst.db"))
|
||
|
|
|
||
|
|
createTestTables(t, srcDB)
|
||
|
|
createTestTables(t, dstDB)
|
||
|
|
|
||
|
|
count, err := migrateTable[model.User](srcDB, dstDB, "users")
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("migrateTable on empty table should succeed: %v", err)
|
||
|
|
}
|
||
|
|
if count != 0 {
|
||
|
|
t.Errorf("expected 0 rows migrated, got %d", count)
|
||
|
|
}
|
||
|
|
}
|