Files
3x-ui/internal/web/controller/xray_setting_warp_test.go
MHSanaei 12d51d7195 perf(tests): copy a migrated template DB instead of migrating per test
Most tests opened a throwaway panel DB with database.InitDB, which runs the
full AutoMigrate + seed on an empty file every time: ~230ms, and ~850ms under
-race because GORM's reflection-heavy migration is what the detector slows
most. internal/web/service does this in ~550 of its 830 tests, so the CI race
job spent ~10 of its ~14.6 minutes re-migrating empty databases.

internal/database/dbtest.InitDB migrates once per test process, then hands
each test its own copy of that file (~130ms under -race) and registers the
CloseDB cleanup. The copy then goes through InitDB like a panel restart, so
every test still starts from the state a fresh install has. Tests that reopen
an existing file, migrate a hand-built legacy DB or target Postgres keep
calling database.InitDB.

Locally under -race: internal/web/service 626s (last CI run) -> 114s,
internal/sub 246s -> 35s.
2026-09-27 03:04:50 +02:00

70 lines
2.1 KiB
Go

package controller
import (
"errors"
"net/http"
"net/http/httptest"
"net/url"
"path/filepath"
"strings"
"testing"
"github.com/gin-gonic/gin"
"gorm.io/gorm"
"github.com/mhsanaei/3x-ui/v3/internal/database"
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
"github.com/mhsanaei/3x-ui/v3/internal/web/locale"
)
func TestWarpIntervalReportsClockPersistenceFailure(t *testing.T) {
gin.SetMode(gin.TestMode)
dbDir := t.TempDir()
t.Setenv("XUI_DB_FOLDER", dbDir)
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
db := database.GetDB()
for _, setting := range []*model.Setting{
{Key: "warpUpdateInterval", Value: "0"},
{Key: "warpLastUpdate", Value: "0"},
} {
if err := db.Create(setting).Error; err != nil {
t.Fatalf("seed %s: %v", setting.Key, err)
}
}
const callback = "test:fail_warp_clock_update"
errInjected := errors.New("injected WARP clock persistence failure")
if err := db.Callback().Update().Before("gorm:update").Register(callback, func(tx *gorm.DB) {
setting, ok := tx.Statement.Model.(*model.Setting)
if ok && setting.Key == "warpLastUpdate" {
tx.AddError(errInjected)
}
}); err != nil {
t.Fatalf("register update callback: %v", err)
}
t.Cleanup(func() {
if err := db.Callback().Update().Remove(callback); err != nil {
t.Errorf("remove update callback: %v", err)
}
})
engine := gin.New()
engine.Use(func(c *gin.Context) {
c.Set("I18n", func(_ locale.I18nType, key string, _ ...string) string { return key })
c.Next()
})
NewXraySettingController(engine.Group("/panel/api"))
form := url.Values{"interval": {"7"}}
req := httptest.NewRequest(http.MethodPost, "/panel/api/xray/warp/interval", strings.NewReader(form.Encode()))
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
w := httptest.NewRecorder()
engine.ServeHTTP(w, req)
if !strings.Contains(w.Body.String(), `"success":false`) {
t.Fatalf("interval update reported success after clock persistence failure: %s", w.Body.String())
}
if !strings.Contains(w.Body.String(), errInjected.Error()) {
t.Fatalf("response omitted clock persistence error: %s", w.Body.String())
}
}