forgejo/models/unittest/fixtures.go
Earl Warren 27ee15e86e
[TESTS] tests.AddFixtures helper loads additional per-test fixtures
(cherry picked from commit 93a844dd13)
(cherry picked from commit 6d6d1a121c)
(cherry picked from commit 8b101f2860)
(cherry picked from commit 3e56212d6d)
(cherry picked from commit 4f619bc585)
(cherry picked from commit 06a47ea56e)
(cherry picked from commit 5a4d56e77b)
(cherry picked from commit 84b9d3a0c3)
(cherry picked from commit 1eb2eca71c)
(cherry picked from commit 11d0fe5400)
(cherry picked from commit c93b8b9d3c)
(cherry picked from commit 679a7e2efa)
(cherry picked from commit e31a3abb7d)
(cherry picked from commit 72bedf68a7)
(cherry picked from commit ef139ac06f)
(cherry picked from commit 134bf83982)
(cherry picked from commit caf5780c57)
2024-02-05 14:44:33 +01:00

147 lines
4 KiB
Go

// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
package unittest
import (
"fmt"
"os"
"path/filepath"
"time"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/setting"
"github.com/go-testfixtures/testfixtures/v3"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
var fixturesLoader *testfixtures.Loader
// GetXORMEngine gets the XORM engine
func GetXORMEngine(engine ...*xorm.Engine) (x *xorm.Engine) {
if len(engine) == 1 {
return engine[0]
}
return db.DefaultContext.(*db.Context).Engine().(*xorm.Engine)
}
func OverrideFixtures(opts FixturesOptions, engine ...*xorm.Engine) func() {
old := fixturesLoader
if err := InitFixtures(opts, engine...); err != nil {
panic(err)
}
return func() {
fixturesLoader = old
}
}
// InitFixtures initialize test fixtures for a test database
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
e := GetXORMEngine(engine...)
var fixtureOptionFiles func(*testfixtures.Loader) error
if opts.Dir != "" {
fixtureOptionFiles = testfixtures.Directory(opts.Dir)
} else {
fixtureOptionFiles = testfixtures.Files(opts.Files...)
}
var fixtureOptionDirs []func(*testfixtures.Loader) error
if opts.Dirs != nil {
for _, dir := range opts.Dirs {
fixtureOptionDirs = append(fixtureOptionDirs, testfixtures.Directory(filepath.Join(opts.Base, dir)))
}
}
dialect := "unknown"
switch e.Dialect().URI().DBType {
case schemas.POSTGRES:
dialect = "postgres"
case schemas.MYSQL:
dialect = "mysql"
case schemas.MSSQL:
dialect = "mssql"
case schemas.SQLITE:
dialect = "sqlite3"
default:
fmt.Println("Unsupported RDBMS for integration tests")
os.Exit(1)
}
loaderOptions := []func(loader *testfixtures.Loader) error{
testfixtures.Database(e.DB().DB),
testfixtures.Dialect(dialect),
testfixtures.DangerousSkipTestDatabaseCheck(),
fixtureOptionFiles,
}
loaderOptions = append(loaderOptions, fixtureOptionDirs...)
if e.Dialect().URI().DBType == schemas.POSTGRES {
loaderOptions = append(loaderOptions, testfixtures.SkipResetSequences())
}
fixturesLoader, err = testfixtures.New(loaderOptions...)
if err != nil {
return err
}
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
return err
}
// LoadFixtures load fixtures for a test database
func LoadFixtures(engine ...*xorm.Engine) error {
e := GetXORMEngine(engine...)
var err error
// (doubt) database transaction conflicts could occur and result in ROLLBACK? just try for a few times.
for i := 0; i < 5; i++ {
if err = fixturesLoader.Load(); err == nil {
break
}
time.Sleep(200 * time.Millisecond)
}
if err != nil {
fmt.Printf("LoadFixtures failed after retries: %v\n", err)
}
// Now if we're running postgres we need to tell it to update the sequences
if e.Dialect().URI().DBType == schemas.POSTGRES {
results, err := e.QueryString(`SELECT 'SELECT SETVAL(' ||
quote_literal(quote_ident(PGT.schemaname) || '.' || quote_ident(S.relname)) ||
', COALESCE(MAX(' ||quote_ident(C.attname)|| '), 1) ) FROM ' ||
quote_ident(PGT.schemaname)|| '.'||quote_ident(T.relname)|| ';'
FROM pg_class AS S,
pg_depend AS D,
pg_class AS T,
pg_attribute AS C,
pg_tables AS PGT
WHERE S.relkind = 'S'
AND S.oid = D.objid
AND D.refobjid = T.oid
AND D.refobjid = C.attrelid
AND D.refobjsubid = C.attnum
AND T.relname = PGT.tablename
ORDER BY S.relname;`)
if err != nil {
fmt.Printf("Failed to generate sequence update: %v\n", err)
return err
}
for _, r := range results {
for _, value := range r {
_, err = e.Exec(value)
if err != nil {
fmt.Printf("Failed to update sequence: %s Error: %v\n", value, err)
return err
}
}
}
}
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
return err
}