mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-09-28 10:12:07 +03:00
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.
This commit is contained in:
@@ -100,8 +100,8 @@ question it already answers.
|
||||
subtests and `t.Helper()` on helpers. An assertion must pin the exact value,
|
||||
typed error or emitted string — `err != nil` and `len(x) > 0` are findings,
|
||||
not nits. Prefer real dependencies: a throwaway DB via
|
||||
`database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` with `t.Cleanup`, and
|
||||
`httptest` for HTTP. `internal/sub`'s `initSubDB(t)` is the template.
|
||||
`dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))`
|
||||
(`internal/database/dbtest`), and `httptest` for HTTP. `internal/sub`'s `initSubDB(t)` is the template.
|
||||
A test must FAIL without its fix; one that passes either way certifies
|
||||
nothing and then gets cited as proof the fix works.
|
||||
|
||||
|
||||
@@ -154,9 +154,11 @@ file locations when it can answer in one hop.
|
||||
- Stdlib `testing` only (no testify). Table-driven, `t.Run` subtests,
|
||||
`t.Helper()` on helpers. Assert the exact value / typed error / emitted
|
||||
string, never just `err != nil`. Prefer real deps over mocks: throwaway DB via
|
||||
`database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` +
|
||||
`t.Cleanup(func() { _ = database.CloseDB() })`; `httptest` for HTTP.
|
||||
`internal/sub`'s `initSubDB(t)` is the template.
|
||||
`dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))`
|
||||
(`internal/database/dbtest`: copies a once-migrated template and registers
|
||||
`CloseDB` cleanup; a fresh `database.InitDB` costs ~7x more, ~850ms under
|
||||
`-race`); `httptest` for HTTP. Keep `database.InitDB` for reopening a file or
|
||||
migrating a hand-built legacy DB. `internal/sub`'s `initSubDB(t)` is the template.
|
||||
- Code must pass `golangci-lint run` (gofumpt + goimports formatting): `make lint`.
|
||||
- Postgres, xray-gRPC-e2e and scale tests `t.Skip` unless `XUI_TEST_PG_DSN`,
|
||||
`XUI_DB_TYPE`+`XUI_DB_DSN`, `XRAY_E2E_BINARY` or `XUI_SCALE_TEST` is set — a
|
||||
|
||||
+1
-1
@@ -253,7 +253,7 @@ Tests live next to the code (`foo.go` ↔ `foo_test.go`); frontend specs and gol
|
||||
|
||||
- **Stdlib `testing` only** — no testify. Table-driven with `t.Run` subtests and `t.Helper()` on helpers.
|
||||
- **Assert the contract, not internals.** Pin the exact value / typed error / emitted string — not `err != nil` or `len > 0`. A test that still passes when the behavior is broken is worse than no test.
|
||||
- **Real dependencies over mocks.** Get a throwaway DB with `database.InitDB(filepath.Join(t.TempDir(), "x-ui.db"))` + `t.Cleanup(func() { _ = database.CloseDB() })` (Windows-safe), and use `httptest` servers for HTTP. The `internal/sub` suite's `initSubDB(t)` is the template.
|
||||
- **Real dependencies over mocks.** Get a throwaway DB with `dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))` from `internal/database/dbtest`: it copies a once-migrated template (migrating from scratch per test is ~7x slower, worst under `-race`) and closes the DB before `t.TempDir` cleanup (Windows-safe). Keep `database.InitDB` for reopening an existing file or migrating a hand-built legacy DB. Use `httptest` servers for HTTP. The `internal/sub` suite's `initSubDB(t)` is the template.
|
||||
|
||||
### Running
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"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/service/panel"
|
||||
)
|
||||
@@ -16,10 +17,7 @@ import (
|
||||
func newTokenCLIEnv(t *testing.T) {
|
||||
t.Helper()
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(config.GetDBPath()); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, config.GetDBPath())
|
||||
}
|
||||
|
||||
func tokenNames(t *testing.T) []string {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Package dbtest opens throwaway panel databases for tests. Migrating a new
|
||||
// SQLite file costs ~850ms under -race; copying a migrated template ~130ms.
|
||||
package dbtest
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
)
|
||||
|
||||
var migrated struct {
|
||||
once sync.Once
|
||||
data []byte
|
||||
err error
|
||||
}
|
||||
|
||||
// InitDB opens a new, fully migrated panel database at path and closes it when
|
||||
// t ends. Reopen an existing file with database.InitDB instead.
|
||||
func InitDB(t testing.TB, path string) {
|
||||
t.Helper()
|
||||
if config.GetDBKind() != "postgres" {
|
||||
if _, err := os.Stat(path); err == nil {
|
||||
t.Fatalf("dbtest.InitDB would overwrite existing %s; reopen it with database.InitDB", path)
|
||||
}
|
||||
data, err := migratedTemplate()
|
||||
if err != nil {
|
||||
t.Fatalf("build template database: %v", err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o700); err != nil {
|
||||
t.Fatalf("create database dir: %v", err)
|
||||
}
|
||||
if err := os.WriteFile(path, data, 0o600); err != nil {
|
||||
t.Fatalf("copy template database: %v", err)
|
||||
}
|
||||
}
|
||||
if err := database.InitDB(path); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
}
|
||||
|
||||
func migratedTemplate() ([]byte, error) {
|
||||
migrated.once.Do(func() {
|
||||
dir, err := os.MkdirTemp("", "xui-dbtest-")
|
||||
if err != nil {
|
||||
migrated.err = err
|
||||
return
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
path := filepath.Join(dir, "template.db")
|
||||
if err := database.InitDB(path); err != nil {
|
||||
migrated.err = err
|
||||
return
|
||||
}
|
||||
// Closing the last connection checkpoints the WAL into the main file.
|
||||
if err := database.CloseDB(); err != nil {
|
||||
migrated.err = err
|
||||
return
|
||||
}
|
||||
migrated.data, migrated.err = os.ReadFile(path)
|
||||
})
|
||||
return migrated.data, migrated.err
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package dbtest
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/model"
|
||||
)
|
||||
|
||||
func TestInitDBGivesEachTestItsOwnDatabase(t *testing.T) {
|
||||
t.Run("first test writes", func(t *testing.T) {
|
||||
InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
if err := database.GetDB().Create(&model.Setting{Key: "dbtestProbe", Value: "first"}).Error; err != nil {
|
||||
t.Fatalf("write probe: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("next test starts clean", func(t *testing.T) {
|
||||
InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
var leaked int64
|
||||
if err := database.GetDB().Model(&model.Setting{}).Where("key = ?", "dbtestProbe").Count(&leaked).Error; err != nil {
|
||||
t.Fatalf("count probe: %v", err)
|
||||
}
|
||||
if leaked != 0 {
|
||||
t.Fatalf("database holds %d probe rows written by the previous test; copies must not share state", leaked)
|
||||
}
|
||||
var admins int64
|
||||
if err := database.GetDB().Model(&model.User{}).Count(&admins).Error; err != nil {
|
||||
t.Fatalf("count users: %v", err)
|
||||
}
|
||||
if admins != 1 {
|
||||
t.Fatalf("users = %d, want the 1 seeded admin a fresh install has", admins)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -6,17 +6,13 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func initSubDB(t *testing.T) {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
// Close the handle before t.TempDir cleanup so Windows doesn't refuse to
|
||||
// remove the still-open sqlite file.
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
}
|
||||
|
||||
// The subscription page's Copy URL must be built from the same host the
|
||||
|
||||
@@ -6,17 +6,14 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
||||
)
|
||||
|
||||
// #6559: the Master panel must send a stable X-HWID when fetching external
|
||||
// subscriptions, otherwise an HWID-limited donor answers 404.
|
||||
func TestFetchSendsStableHwid(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
var gotHwid string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -302,10 +303,7 @@ func TestExpandEntryCacheHitWritesNothing(t *testing.T) {
|
||||
|
||||
func TestFetchUsesConfiguredExternalSubUserAgent(t *testing.T) {
|
||||
resetSubscriptionCache(t)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "ua.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "ua.db"))
|
||||
|
||||
const customUA = "Happ/4.2.1"
|
||||
if err := database.GetDB().Create(&model.Setting{
|
||||
@@ -333,10 +331,7 @@ func TestFetchUsesConfiguredExternalSubUserAgent(t *testing.T) {
|
||||
|
||||
func TestFetchFallsBackToDefaultExternalSubUserAgent(t *testing.T) {
|
||||
resetSubscriptionCache(t)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "ua-default.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "ua-default.db"))
|
||||
|
||||
var gotUA string
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -15,10 +16,7 @@ func seedSubDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
// seedSubInbound creates a VLESS inbound with one client wired into the
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -27,10 +28,7 @@ func initHwidSubRouter(t *testing.T, limit int) (*gin.Engine, string) {
|
||||
}
|
||||
|
||||
t.Setenv("XUI_DB_FOLDER", tmp)
|
||||
if err := database.InitDB(filepath.Join(tmp, "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(tmp, "x-ui.db"))
|
||||
|
||||
const subID = "sub-hwid-route"
|
||||
const email = "route@example.com"
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -19,10 +20,7 @@ func initMutDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
// --- json_service.go:40 — rules are merged into routing only when non-empty ---
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
yaml "github.com/goccy/go-yaml"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
func mergeRemoteClashRulesYAML(base map[string]any, raw string) error {
|
||||
@@ -607,10 +608,7 @@ func TestRemoteRoutingHTTPClientRejectsLoopback(t *testing.T) {
|
||||
|
||||
func TestRemoteRoutingPersistedLoadRetriesAfterDatabaseBecomesReady(t *testing.T) {
|
||||
dbPath := filepath.Join(t.TempDir(), "x-ui.db")
|
||||
if err := database.InitDB(dbPath); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, dbPath)
|
||||
|
||||
deeplink, err := normalizeHappRouting([]byte(`{"Name":"persisted-after-ready"}`))
|
||||
if err != nil {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -18,10 +19,7 @@ import (
|
||||
func TestGetSubs_DuplicateSettingsClients_Deduped(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
const subId = "sub-dup"
|
||||
const email = "dup@example.com"
|
||||
@@ -76,10 +74,7 @@ func TestGetSubs_DuplicateSettingsClients_Deduped(t *testing.T) {
|
||||
func TestMatchingClients_DedupsCaseInsensitiveEmail(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
const subId = "s1"
|
||||
const uuid = "11111111-2222-4333-8444-555555555555"
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/service"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -15,12 +16,7 @@ import (
|
||||
|
||||
func setupInfoNodeTestDB(t *testing.T) {
|
||||
t.Helper()
|
||||
if err := database.InitDB(t.TempDir() + "/test_infonode.db"); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = database.CloseDB()
|
||||
})
|
||||
dbtest.InitDB(t, t.TempDir()+"/test_infonode.db")
|
||||
db := database.GetDB()
|
||||
if err := db.AutoMigrate(
|
||||
&model.Inbound{},
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -17,10 +18,7 @@ import (
|
||||
func TestStatsForClient_OrphanedInboundIdFallback(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
const email = "old-client@example.com"
|
||||
const total = int64(100) * gb
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -16,10 +17,7 @@ import (
|
||||
func TestGetSubs_OrdersBySubSortIndexThenId(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
const subId = "sub-sort"
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -12,10 +13,7 @@ import (
|
||||
func TestAggregateTrafficByEmails_FallsBackToClientLimits(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
const email = "node-client@example.com"
|
||||
const totalBytes = int64(300) * 1024 * 1024 * 1024
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -38,10 +39,7 @@ func setupScaleSubDB(t *testing.T) {
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(os.Getenv("XUI_SCALE_TEST"))) {
|
||||
case "1", "true", "yes":
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "scale.db")); err != nil {
|
||||
t.Fatalf("InitDB(sqlite): %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "scale.db"))
|
||||
return
|
||||
}
|
||||
t.Skip("set XUI_SCALE_TEST=1 (sqlite) or XUI_DB_TYPE=postgres + XUI_DB_DSN (postgres) to run the scale benchmark")
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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/util/crypto"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/session"
|
||||
@@ -31,10 +32,7 @@ func newAPIAuthTestEngine(t *testing.T) (*gin.Engine, *APIController) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
engine := gin.New()
|
||||
store := cookie.NewStore([]byte("api-auth-test-secret"))
|
||||
engine.Use(sessions.Sessions("3x-ui", store))
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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/entity"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
||||
@@ -22,10 +23,7 @@ func seedPartlyApplyingClient(t *testing.T, email string, basePort int) (healthy
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
ids := make([]int, 0, 2)
|
||||
@@ -129,10 +127,7 @@ func TestDeleteHandlerFlagsRestartOnPartialApply(t *testing.T) {
|
||||
func TestImportHandlerFlagsRestartWhenTrafficRestoreFails(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
db := database.GetDB()
|
||||
ib := &model.Inbound{
|
||||
UserId: 1, Enable: true, Port: 43340, Tag: "in-import-partial",
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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/service"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -45,10 +46,7 @@ func TestClientRenewalPreviewHTTP(t *testing.T) {
|
||||
{name: "negative count", zone: "UTC", count: -1, invalid: true, wantError: "renewal preview reset and resetCount must not be negative\n"},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
db := database.GetDB()
|
||||
if err := db.Create(&model.Setting{Key: "timeLocation", Value: tt.zone}).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/entity"
|
||||
@@ -25,10 +26,7 @@ func newHostTestDB(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
type hostEnvelope struct {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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/util/crypto"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
|
||||
@@ -23,10 +24,7 @@ func TestNodeSyncPushSkipsOperatorTLSGuard(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
prev := runtime.GetManager()
|
||||
runtime.SetManager(runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }, SetNeedRestart: func() {}}))
|
||||
t.Cleanup(func() { runtime.SetManager(prev) })
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
@@ -25,10 +26,7 @@ func newNodeCredentialTestEngine(t *testing.T) *gin.Engine {
|
||||
gin.SetMode(gin.TestMode)
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
engine := gin.New()
|
||||
engine.Use(func(c *gin.Context) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"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/util/crypto"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/locale"
|
||||
@@ -57,10 +58,7 @@ func TestValidateRegex(t *testing.T) {
|
||||
|
||||
func TestAPITokenMutationRoutesEnforceExpectedScope(t *testing.T) {
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
row := &model.ApiToken{Name: "route-scope", Token: crypto.HashTokenSHA256("token"), Enabled: true, Scope: model.ApiScopeNodeSync}
|
||||
if err := database.GetDB().Create(row).Error; err != nil {
|
||||
t.Fatalf("seed token: %v", err)
|
||||
@@ -95,10 +93,7 @@ func TestAPITokenMutationRoutesEnforceExpectedScope(t *testing.T) {
|
||||
// rebind the authenticator without presenting a current code.
|
||||
func TestUpdateSettingRequiresCodeToReplaceTwoFactorToken(t *testing.T) {
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
settingService := service.SettingService{}
|
||||
if err := settingService.SetTwoFactorToken("ORIGINALSECRET234567"); err != nil {
|
||||
@@ -195,13 +190,8 @@ func TestTestDiscordEndpoint(t *testing.T) {
|
||||
|
||||
// Setup DB
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_ = database.CloseDB()
|
||||
SetDiscordService(nil)
|
||||
})
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
t.Cleanup(func() { SetDiscordService(nil) })
|
||||
|
||||
settingService := service.SettingService{}
|
||||
svc := discord.NewDiscordService(settingService)
|
||||
|
||||
@@ -11,16 +11,13 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
func setupSubBalancerRouter(t *testing.T) *gin.Engine {
|
||||
t.Helper()
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
gin.SetMode(gin.TestMode)
|
||||
router := gin.New()
|
||||
NewSubBalancerController(router.Group("/panel/api"))
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"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"
|
||||
)
|
||||
@@ -21,10 +22,7 @@ func TestWarpIntervalReportsClockPersistenceFailure(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
db := database.GetDB()
|
||||
for _, setting := range []*model.Setting{
|
||||
{Key: "warpUpdateInterval", Value: "0"},
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
)
|
||||
@@ -47,15 +48,7 @@ func setupIntegrationDB(t *testing.T) {
|
||||
log.SetFlags(origLogFlags)
|
||||
})
|
||||
|
||||
if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
||||
t.Fatalf("database.InitDB failed: %v", err)
|
||||
}
|
||||
// LIFO cleanup order: this runs before t.TempDir's own cleanup.
|
||||
t.Cleanup(func() {
|
||||
if err := database.CloseDB(); err != nil {
|
||||
t.Logf("database.CloseDB warning: %v", err)
|
||||
}
|
||||
})
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
// enforceIpLimitForTest runs the same two steps processObserved does: select
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -197,10 +198,7 @@ func TestPartitionLiveIps_ConcurrentLiveIpsSortedAscending(t *testing.T) {
|
||||
func TestGetInboundByEmailFallbackIgnoresProtocolScalarFields(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
inbound := &model.Inbound{
|
||||
UserId: 1,
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
)
|
||||
@@ -35,10 +36,7 @@ func setupScaleJobDB(t *testing.T) {
|
||||
}
|
||||
switch strings.ToLower(strings.TrimSpace(os.Getenv("XUI_SCALE_TEST"))) {
|
||||
case "1", "true", "yes":
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "scale.db")); err != nil {
|
||||
t.Fatalf("InitDB(sqlite): %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "scale.db"))
|
||||
return
|
||||
}
|
||||
t.Skip("set XUI_SCALE_TEST=1 (sqlite) or XUI_DB_TYPE=postgres + XUI_DB_DSN (postgres) to run the scale benchmark")
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/service"
|
||||
)
|
||||
@@ -13,10 +14,7 @@ func initLdapJobDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func TestBuildClient_ConvertsDefaultTotalGBToBytes(t *testing.T) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
|
||||
@@ -53,10 +54,7 @@ func TestHeartbeatDropsSubNodesOfNodesItNoLongerProbes(t *testing.T) {
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
xuilogger.InitLogger(logging.ERROR)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
runtime.SetManager(runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }, SetNeedRestart: func() {}}))
|
||||
t.Cleanup(func() { runtime.SetManager(nil) })
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
|
||||
@@ -26,10 +27,7 @@ import (
|
||||
// whole table made every node store and echo back the entire fleet's IPs.
|
||||
func TestNodeTrafficSyncPushesOnlyHostedClientIps(t *testing.T) {
|
||||
xuilogger.InitLogger(logging.ERROR)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
service.StartTrafficWriter()
|
||||
t.Cleanup(service.StopTrafficWriter)
|
||||
runtime.SetManager(runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }, SetNeedRestart: func() {}}))
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/runtime"
|
||||
@@ -18,10 +19,7 @@ import (
|
||||
// must drop their online sets itself: a disabled node here, a deleted one below.
|
||||
func TestNodeTrafficSyncDropsOnlineClientsOfUnsyncedNodes(t *testing.T) {
|
||||
xuilogger.InitLogger(logging.ERROR)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
runtime.SetManager(runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }, SetNeedRestart: func() {}}))
|
||||
t.Cleanup(func() { runtime.SetManager(nil) })
|
||||
process := xray.NewTestProcess(nil, "")
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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/eventbus"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
@@ -24,10 +25,7 @@ import (
|
||||
func goingDownNodes(t *testing.T, n int) {
|
||||
t.Helper()
|
||||
xuilogger.InitLogger(logging.ERROR)
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
runtime.SetManager(runtime.NewManager(runtime.LocalDeps{APIPort: func() int { return 0 }, SetNeedRestart: func() {}}))
|
||||
t.Cleanup(func() { runtime.SetManager(nil) })
|
||||
srv := httptest.NewServer(nil)
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -15,10 +16,7 @@ func initResetJobDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
type seededClient struct {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/global"
|
||||
)
|
||||
|
||||
@@ -44,10 +44,7 @@ func inContractScope(method, path string) bool {
|
||||
|
||||
func registeredContractRoutes(t *testing.T) map[string]bool {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
previous := global.GetWebServer()
|
||||
s := NewServer()
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -14,10 +15,7 @@ func setupBulkDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func clientsSettings(t *testing.T, clients []model.Client) string {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -16,10 +17,7 @@ import (
|
||||
func TestResetClientExpiryTimeByEmail_MultiInbound(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -91,10 +89,7 @@ func TestResetClientExpiryTimeByEmail_MultiInbound(t *testing.T) {
|
||||
func TestSetClientEnableByEmail_MultiInbound(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -14,10 +15,7 @@ import (
|
||||
func TestEffectiveFlowsByEmails(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
db := database.GetDB()
|
||||
|
||||
const vision = "xtls-rprx-vision"
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -46,10 +47,7 @@ func TestClientWithInboundFlow_GatesByInboundCapability(t *testing.T) {
|
||||
func TestFlowIsolation_VisionDoesNotLeakToWsInbound(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -95,10 +93,7 @@ func TestFlowIsolation_VisionDoesNotLeakToWsInbound(t *testing.T) {
|
||||
func TestEffectiveFlow_NonFlowInboundSyncedLastDoesNotHideVision(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
reality := &model.Inbound{Tag: "vless-reality", Enable: true, Port: 40001, Protocol: model.VLESS, StreamSettings: `{"network":"tcp","security":"reality"}`}
|
||||
@@ -145,10 +140,7 @@ func TestEffectiveFlow_NonFlowInboundSyncedLastDoesNotHideVision(t *testing.T) {
|
||||
func TestEffectiveFlow_ClearedFlowStaysCleared(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
reality := &model.Inbound{Tag: "vless-reality", Enable: true, Port: 41001, Protocol: model.VLESS, StreamSettings: `{"network":"tcp","security":"reality"}`}
|
||||
@@ -191,10 +183,7 @@ func TestEffectiveFlow_ClearedFlowStaysCleared(t *testing.T) {
|
||||
func TestAttach_PreservesVisionFlowWhenCanonicalColumnZeroed(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -267,10 +256,7 @@ func TestAttach_PreservesVisionFlowWhenCanonicalColumnZeroed(t *testing.T) {
|
||||
func TestBulkAttach_PreservesVisionFlowWhenCanonicalColumnZeroed(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/runtime"
|
||||
)
|
||||
@@ -13,10 +14,7 @@ import (
|
||||
func TestSetRemoteTraffic_PreservesPanelLocalGroupAndComment(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -82,10 +80,7 @@ func TestSetRemoteTraffic_PreservesPanelLocalGroupAndComment(t *testing.T) {
|
||||
func TestSyncInbound_KeepsGroupWhenIncomingEmpty(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -125,10 +120,7 @@ func TestSyncInbound_KeepsGroupWhenIncomingEmpty(t *testing.T) {
|
||||
func TestClientUpdate_ClearsGroup(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -12,10 +13,7 @@ func initClientHwidTestDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func seedHwidClient(t *testing.T, limit int) *model.ClientRecord {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -188,10 +189,7 @@ func TestSetClientLimitHwidIsSerializedWithSyncInbound(t *testing.T) {
|
||||
func BenchmarkSetClientLimitHwidSerialized(b *testing.B) {
|
||||
dbDir := b.TempDir()
|
||||
b.Setenv("XUI_DB_FOLDER", dbDir)
|
||||
if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
||||
b.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
b.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(b, filepath.Join(dbDir, "x-ui.db"))
|
||||
StartTrafficWriter()
|
||||
b.Cleanup(StopTrafficWriter)
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -5,16 +5,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestSyncInbound_UpdatesMtprotoSecretAndAdTag(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -5,16 +5,14 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestSyncInbound_PreservesCredentialsAcrossProtocols(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -74,10 +72,7 @@ func TestSyncInbound_PreservesCredentialsAcrossProtocols(t *testing.T) {
|
||||
func TestSyncInbound_AllowsClearingFlow(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -11,17 +11,14 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
||||
)
|
||||
|
||||
func setupTestDB(t *testing.T) service.SettingService {
|
||||
t.Helper()
|
||||
dbPath := filepath.Join(t.TempDir(), "x-ui.db")
|
||||
if err := database.InitDB(dbPath); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, dbPath)
|
||||
return service.SettingService{}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/service"
|
||||
)
|
||||
|
||||
@@ -132,10 +132,7 @@ func startFakeSMTPServer(t *testing.T) (string, func() []string) {
|
||||
}
|
||||
|
||||
func TestSendUsesBareAddressFromNameAddrSmtpFrom(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
addr, recordedLines := startFakeSMTPServer(t)
|
||||
host, portStr, err := net.SplitHostPort(addr)
|
||||
@@ -182,10 +179,7 @@ func TestSendUsesBareAddressFromNameAddrSmtpFrom(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestConnectionReportsMissingFrom(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
settingService := service.SettingService{}
|
||||
mustSet := func(name string, err error) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"golang.org/x/crypto/chacha20poly1305"
|
||||
|
||||
"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/logger"
|
||||
)
|
||||
@@ -30,10 +31,7 @@ func initHappTestDB(t *testing.T) {
|
||||
if err := os.WriteFile(filepath.Join(dbDir, "config.json"), []byte(`{"log":{}}`), 0o600); err != nil {
|
||||
t.Fatalf("write Xray config: %v", err)
|
||||
}
|
||||
if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func seedHappClient(t *testing.T, subID string) *model.ClientRecord {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -18,10 +19,7 @@ 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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func marshalIps(t *testing.T, entries ...clientIpEntry) string {
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -26,10 +27,7 @@ import (
|
||||
func TestAddClientTraffic_MatchesByEmail(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -97,10 +95,7 @@ func TestAddClientTraffic_MatchesByEmail(t *testing.T) {
|
||||
func TestAdjustTraffics_DelayedStartConvertsDespiteStaleInboundId(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -166,10 +161,7 @@ func TestAdjustTraffics_DelayedStartConvertsDespiteStaleInboundId(t *testing.T)
|
||||
func TestAddClientTraffic_ExpiryWriteOnlyForConvertedClients(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
|
||||
"gorm.io/gorm"
|
||||
@@ -95,10 +96,7 @@ func initFlowTestDB(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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
return database.GetDB()
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -16,10 +17,7 @@ import (
|
||||
func TestRestoreVisionFlowForEligibleInbound(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
db := database.GetDB()
|
||||
|
||||
const vision = "xtls-rprx-vision"
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"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/xray"
|
||||
)
|
||||
@@ -22,10 +23,7 @@ import (
|
||||
func TestMigrationRequirements_BackfillsClientTrafficsWithMultiDomainInbound(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
@@ -96,10 +94,7 @@ func TestMigrationRequirements_BackfillsClientTrafficsWithMultiDomainInbound(t *
|
||||
func TestMigrationRequirementsReturnsAddClientStatFailure(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
db := database.GetDB()
|
||||
first := &model.Inbound{UserId: 1, Tag: "first", Port: 31001, Protocol: model.VLESS, Settings: `{"clients":[{"email":"first@example.test","id":"id-1"}]}`, StreamSettings: `{}`}
|
||||
if err := db.Create(first).Error; err != nil {
|
||||
@@ -136,10 +131,7 @@ func TestMigrationRequirementsReturnsAddClientStatFailure(t *testing.T) {
|
||||
func TestMigrationRequirements_CleansLegacyZeroAddrTag(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
legacy := &model.Inbound{
|
||||
|
||||
@@ -5,14 +5,12 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
func TestSetInboundSubSortIndexLeavesSettingsUntouched(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
const settings = `{"clients":[{"email":"a@example.test","id":"11111111-1111-1111-1111-111111111111"}]}`
|
||||
ib := &model.Inbound{UserId: 1, Remark: "r", Port: 21001, Protocol: model.VLESS, Settings: settings, SubSortIndex: 1, Enable: true}
|
||||
@@ -57,10 +55,7 @@ func TestSetInboundSubSortIndexUsesNarrowNodeUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestSetInboundSubSortIndexPreservesNegative(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
ib := &model.Inbound{UserId: 1, Remark: "r", Port: 21003, Protocol: model.VLESS, Settings: `{"clients":[]}`, SubSortIndex: 1, Enable: true}
|
||||
if err := database.GetDB().Create(ib).Error; err != nil {
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/xray"
|
||||
)
|
||||
@@ -17,10 +18,7 @@ import (
|
||||
func TestGetClientTrafficTgBot_SettingsSerializationStyles(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
db := database.GetDB()
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/crypto/nodetoken"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
piaprotocol "github.com/mhsanaei/3x-ui/v3/internal/pia"
|
||||
)
|
||||
|
||||
@@ -48,10 +48,7 @@ func (f *fakePiaRegistrar) RegisterKey(_ context.Context, server piaprotocol.Wir
|
||||
|
||||
func setupPiaService(t *testing.T) *PiaService {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
payload := []byte(`{"version":6,"groups":{"wg":[{"name":"wireguard","ports":[1337]}]},"regions":[{"id":"us-east","name":"US East","country":"US","geo":false,"offline":false,"port_forward":true,"servers":{"wg":[{"ip":"198.51.100.10","cn":"useast1"},{"ip":"198.51.100.20","cn":"useast2"}]}},{"id":"de-berlin","name":"Berlin","country":"DE","geo":false,"offline":false,"port_forward":false,"servers":{"wg":[{"ip":"203.0.113.10","cn":"berlin1"}]}}]}`)
|
||||
svc := NewPiaService()
|
||||
svc.Auth = fakePiaAuth{token: "tokentokentokentoken12"}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -69,10 +70,7 @@ func withWarpAPIBase(t *testing.T, base string) {
|
||||
}
|
||||
|
||||
func TestChangeWarpIPPreservesLicenseKey(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
const license = "WARPPLLUS-KEY-0123456789abcdefgh" // 32 chars, >= 26 gate
|
||||
seedWarp(t, license)
|
||||
@@ -124,10 +122,7 @@ func TestChangeWarpIPPreservesLicenseKey(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestChangeWarpIPKeepsLicenseWhenReapplyFails(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
const license = "WARPPLLUS-KEY-0123456789abcdefgh"
|
||||
seedWarp(t, license)
|
||||
|
||||
@@ -7,14 +7,11 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
func TestDoWarpRequestCapsResponseBody(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
oversize := maxResponseSize + 4096
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"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/runtime"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -18,10 +19,7 @@ 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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
return database.GetDB()
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/util/crypto"
|
||||
)
|
||||
@@ -14,14 +15,7 @@ func setupAPITokenTestDB(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() {
|
||||
if err := database.CloseDB(); err != nil {
|
||||
t.Fatalf("CloseDB: %v", err)
|
||||
}
|
||||
})
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func TestAPITokenScopeExpiryAndExpectedRevoke(t *testing.T) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -36,10 +37,7 @@ func TestApiTokenCreatedAtSeconds(t *testing.T) {
|
||||
|
||||
func TestRecreateByNamePreservesTokenWhenReplacementFails(t *testing.T) {
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(config.GetDBPath()); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, config.GetDBPath())
|
||||
|
||||
svc := ApiTokenService{}
|
||||
first, err := svc.RecreateByName("cli-fallback")
|
||||
@@ -73,10 +71,7 @@ func TestRecreateByNamePreservesTokenWhenReplacementFails(t *testing.T) {
|
||||
// and now takes operator input from -tokenName, so it must cap it too.
|
||||
func TestRecreateByNameRejectsOverlongName(t *testing.T) {
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(config.GetDBPath()); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, config.GetDBPath())
|
||||
|
||||
const wantErr = "token name must be 64 characters or fewer"
|
||||
|
||||
@@ -95,10 +90,7 @@ func TestRecreateByNameRejectsOverlongName(t *testing.T) {
|
||||
|
||||
func TestRecreateByNameKeepsOneToken(t *testing.T) {
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(config.GetDBPath()); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, config.GetDBPath())
|
||||
|
||||
svc := ApiTokenService{}
|
||||
first, err := svc.RecreateByName("cli-fallback")
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
var sponsorTestNow = time.Date(2026, 10, 15, 0, 0, 0, 0, time.UTC)
|
||||
@@ -131,10 +131,7 @@ func TestActiveSponsorsResolvesLogoAndSlots(t *testing.T) {
|
||||
func setupSponsorServer(t *testing.T, body string) *atomic.Int32 {
|
||||
t.Helper()
|
||||
t.Setenv("XUI_DB_FOLDER", t.TempDir())
|
||||
if err := database.InitDB(config.GetDBPath()); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, config.GetDBPath())
|
||||
|
||||
var hits atomic.Int32
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/amneziawgnet"
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
)
|
||||
@@ -27,14 +28,7 @@ func setupConflictDB(t *testing.T) {
|
||||
|
||||
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() {
|
||||
if err := database.CloseDB(); err != nil {
|
||||
t.Logf("CloseDB warning: %v", err)
|
||||
}
|
||||
})
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func seedInboundConflict(t *testing.T, tag, listen string, port int, protocol model.Protocol, streamSettings, settings string) {
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/config"
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -41,10 +42,7 @@ func setupScaleDB(t *testing.T) {
|
||||
if dbPath == "" {
|
||||
dbPath = filepath.Join(t.TempDir(), "scale.db")
|
||||
}
|
||||
if err := database.InitDB(dbPath); err != nil {
|
||||
t.Fatalf("InitDB(sqlite): %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, dbPath)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
// A panel restarts with an empty snapshot until the @2s ticker fires, and a
|
||||
@@ -12,10 +12,7 @@ import (
|
||||
func TestCurrentStatusSamplesBeforeFirstTick(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
svc := &ServerService{}
|
||||
if svc.LastStatus() != nil {
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
// Loyalsoldier and runetfreedom write "<hash> geoip.dat"; chocolate4u writes
|
||||
@@ -141,10 +141,7 @@ func geofileTestEnv(t *testing.T, entries map[string]geofileEntry) string {
|
||||
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
binFolder := t.TempDir()
|
||||
t.Setenv("XUI_BIN_FOLDER", binFolder)
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
func TestSniffImportKind(t *testing.T) {
|
||||
@@ -30,10 +31,7 @@ func TestSniffImportKind(t *testing.T) {
|
||||
|
||||
t.Run("panel migration dump", func(t *testing.T) {
|
||||
dbPath := filepath.Join(t.TempDir(), "x-ui.db")
|
||||
if err := database.InitDB(dbPath); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, dbPath)
|
||||
dump, err := database.DumpSQLiteToBytes(dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("DumpSQLiteToBytes: %v", err)
|
||||
|
||||
@@ -6,15 +6,13 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
func TestStageSQLiteUploadRebuildsFromDump(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
dbPath := filepath.Join(dir, "x-ui.db")
|
||||
if err := database.InitDB(dbPath); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, dbPath)
|
||||
dump, err := database.DumpSQLiteToBytes(dbPath)
|
||||
if err != nil {
|
||||
t.Fatalf("DumpSQLiteToBytes: %v", err)
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
)
|
||||
|
||||
// A box with no IPv6 route spends 3s per lookup service, and a status sample
|
||||
@@ -15,10 +15,7 @@ import (
|
||||
func TestStatusSampleDoesNotWaitOnPublicIPLookup(t *testing.T) {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
release := make(chan struct{})
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/util/crypto"
|
||||
)
|
||||
|
||||
@@ -16,10 +17,7 @@ func setupSettingMtlsDB(t *testing.T) *SettingService {
|
||||
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() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
return &SettingService{}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/xlzd/gotp"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
@@ -52,14 +53,7 @@ func TestResetSettingsRegeneratesSubscriptionPaths(t *testing.T) {
|
||||
|
||||
func setupSettingTestDB(t *testing.T) {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
if err := database.CloseDB(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
}
|
||||
|
||||
func TestGetAllSettingViewRedactsSecrets(t *testing.T) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
|
||||
"github.com/op/go-logging"
|
||||
|
||||
"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"
|
||||
xuilogger "github.com/mhsanaei/3x-ui/v3/internal/logger"
|
||||
)
|
||||
@@ -20,14 +20,7 @@ func setupSubBalancerDB(t *testing.T) {
|
||||
subBalancerLoggerOnce.Do(func() { xuilogger.InitLogger(logging.ERROR) })
|
||||
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() {
|
||||
if err := database.CloseDB(); err != nil {
|
||||
t.Logf("CloseDB warning: %v", err)
|
||||
}
|
||||
})
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
}
|
||||
|
||||
func TestSubBalancerServiceCRUD(t *testing.T) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/mymmrac/telego"
|
||||
@@ -15,10 +16,7 @@ import (
|
||||
|
||||
func seedPickerInbounds(t *testing.T, protocols ...model.Protocol) {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
for i, protocol := range protocols {
|
||||
port := 20000 + i
|
||||
ib := &model.Inbound{Remark: string(protocol), Enable: true, Port: port, Protocol: protocol, Tag: fmt.Sprintf("inbound-%d", port), Settings: `{}`}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
|
||||
"github.com/mymmrac/telego"
|
||||
)
|
||||
@@ -12,10 +12,7 @@ import (
|
||||
// Regression test: keying the add-client wizard by chat alone left the two
|
||||
// admins of a group chat filling in one client between them.
|
||||
func TestAddClientDraftIsPerAdminInGroupChat(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
const (
|
||||
groupChat = int64(-1001234567890)
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
|
||||
"github.com/mymmrac/telego"
|
||||
)
|
||||
@@ -84,10 +84,7 @@ func lastDraftCard(t *testing.T, texts []string) string {
|
||||
// Regression test: one package-level draft per bot meant an admin's new client
|
||||
// was filled in by another chat's steps.
|
||||
func TestAddClientDraftIsPerChat(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
const (
|
||||
chatA = int64(7101)
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/web/locale"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
|
||||
@@ -35,10 +35,7 @@ func clientInfoLocalizer(t *testing.T) {
|
||||
// Regression test: a start-after-first-use client is stored as a negative duration,
|
||||
// and a disabled one rendered it as a 1969 date.
|
||||
func TestClientInfoShowsStartAfterFirstUseWhenDisabled(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
clientInfoLocalizer(t)
|
||||
|
||||
traffic := &xray.ClientTraffic{
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"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/global"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/xray"
|
||||
@@ -33,10 +34,7 @@ func newLinksCallbackTgbot(t *testing.T, email string) (*Tgbot, func(string) int
|
||||
swapTestBot(t, mock.URL)
|
||||
t.Cleanup(mock.Close)
|
||||
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
inbound := &model.Inbound{
|
||||
UserId: 1,
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"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/xray"
|
||||
|
||||
@@ -59,10 +60,7 @@ func seedReportClients(t *testing.T, remark string, emails []string) {
|
||||
|
||||
func initReportDB(t *testing.T) *Tgbot {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
origRunning := isRunning
|
||||
t.Cleanup(func() { isRunning = origRunning })
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"sync"
|
||||
"testing"
|
||||
|
||||
"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/mymmrac/telego"
|
||||
@@ -58,10 +58,7 @@ func swapTestBot(t *testing.T, url string) {
|
||||
|
||||
func newStaleButtonTgbot(t *testing.T) *Tgbot {
|
||||
t.Helper()
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
return &Tgbot{}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/database/dbtest"
|
||||
"github.com/mhsanaei/3x-ui/v3/internal/eventbus"
|
||||
)
|
||||
|
||||
@@ -61,10 +61,7 @@ func runObservatory(t *testing.T, threshold int, seq []probe) []eventbus.EventTy
|
||||
}
|
||||
|
||||
func TestApplyObservatoryDebounce(t *testing.T) {
|
||||
if err := database.InitDB(filepath.Join(t.TempDir(), "x-ui.db")); err != nil {
|
||||
t.Fatalf("init db: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(t.TempDir(), "x-ui.db"))
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -150,10 +147,7 @@ func TestValidObsTag(t *testing.T) {
|
||||
|
||||
func TestApplyObservatoryKeepsUnicodeTags(t *testing.T) {
|
||||
dbDir := t.TempDir()
|
||||
if err := database.InitDB(filepath.Join(dbDir, "x-ui.db")); err != nil {
|
||||
t.Fatalf("InitDB: %v", err)
|
||||
}
|
||||
t.Cleanup(func() { _ = database.CloseDB() })
|
||||
dbtest.InitDB(t, filepath.Join(dbDir, "x-ui.db"))
|
||||
|
||||
s := &XrayMetricsService{settingService: SettingService{}}
|
||||
s.applyObservatory(time.Unix(1000, 0), map[string]rawObsEntry{
|
||||
|
||||
Reference in New Issue
Block a user