This commit is contained in:
wxiaoguang
2026-04-25 20:24:43 +08:00
parent 0b7aee8147
commit e86d62e497
8 changed files with 113 additions and 108 deletions

View File

@@ -91,7 +91,7 @@ func deleteDB() error {
defer schrows.Close()
if !schrows.Next() {
// Create and setup a DB schema
// Create and set up a DB schema
_, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema)
if err != nil {
return err
@@ -134,7 +134,8 @@ func PrepareTestEnv(t *testing.T, skip int, syncModels ...any) (*xorm.Engine, fu
ourSkip := 2
ourSkip += skip
deferFn := testlogger.PrintCurrentTest(t, ourSkip)
require.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
giteaRoot := setting.GetGiteaTestSourceRoot()
require.NoError(t, unittest.SyncDirs(filepath.Join(giteaRoot, "tests/gitea-repositories-meta"), setting.RepoRootPath))
if err := deleteDB(); err != nil {
t.Fatalf("unable to reset database: %v", err)
@@ -202,17 +203,18 @@ func LoadTableSchemasMap(t *testing.T, x *xorm.Engine) map[string]*schemas.Table
func mainTest(m *testing.M) int {
testlogger.Init()
setting.SetupGiteaTestEnv()
tmpDataPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("migration-test-data-")
tempWorkPath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("migration-test-data-")
if err != nil {
testlogger.Panicf("Unable to create temporary data path %v\n", err)
return testlogger.MainErrorf("Unable to create temporary dir for migration test: %v", err)
}
defer cleanup()
setting.AppDataPath = tmpDataPath
setting.MockBuiltinPaths(tempWorkPath, "", "")
setting.SetupGiteaTestEnv()
if err = git.InitFull(); err != nil {
testlogger.Panicf("Unable to InitFull: %v\n", err)
return testlogger.MainErrorf("Unable to InitFull: %v", err)
}
setting.LoadDBSetting()
setting.InitLoggersForTest()

View File

@@ -19,6 +19,7 @@ import (
"code.gitea.io/gitea/modules/setting/config"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/tempdir"
"code.gitea.io/gitea/modules/testlogger"
"code.gitea.io/gitea/modules/util"
"github.com/stretchr/testify/assert"
@@ -40,29 +41,21 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
}
func mainTest(m *testing.M, testOptsArg ...*TestOptions) int {
reportError := func(msg string, a ...any) int {
_, _ = fmt.Fprintf(os.Stderr, msg+"\n", a...)
return 1
}
testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
tempWorkPath, tempCleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("unit-test-dir-")
if err != nil {
return reportError("Failed to create temp dir for unit test: %v", err)
return testlogger.MainErrorf("Failed to create temp dir for unit test: %v", err)
}
defer tempCleanup()
defer setting.MockBuiltinPaths(tempWorkPath, "", "")()
setting.SetupGiteaTestEnv()
if setting.RepoRootPath == "" || setting.AppDataPath == "" {
return reportError("SetupGiteaTestEnv failed, paths are not initialized")
}
giteaRoot := setting.GetGiteaTestSourceRoot()
fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
if err := CreateTestEngine(fixturesOpts); err != nil {
return reportError("Error creating test database engine: %v", err)
return testlogger.MainErrorf("Error creating test database engine: %v", err)
}
setting.AppURL = "https://try.gitea.io/"
@@ -80,22 +73,22 @@ func mainTest(m *testing.M, testOptsArg ...*TestOptions) int {
config.SetDynGetter(system.NewDatabaseDynKeyGetter())
if err = cache.Init(); err != nil {
return reportError("cache.Init: %v", err)
return testlogger.MainErrorf("cache.Init: %v", err)
}
if err = storage.Init(); err != nil {
return reportError("storage.Init: %v", err)
return testlogger.MainErrorf("storage.Init: %v", err)
}
if err = SyncDirs(filepath.Join(giteaRoot, "tests", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
return reportError("util.SyncDirs: %v", err)
return testlogger.MainErrorf("util.SyncDirs: %v", err)
}
if err = git.InitFull(); err != nil {
return reportError("git.Init: %v", err)
return testlogger.MainErrorf("git.Init: %v", err)
}
if testOpts.SetUp != nil {
if err := testOpts.SetUp(); err != nil {
return reportError("set up failed: %v", err)
return testlogger.MainErrorf("set up failed: %v", err)
}
}
@@ -103,7 +96,7 @@ func mainTest(m *testing.M, testOptsArg ...*TestOptions) int {
if testOpts.TearDown != nil {
if err := testOpts.TearDown(); err != nil {
return reportError("tear down failed: %v", err)
return testlogger.MainErrorf("tear down failed: %v", err)
}
}
return exitStatus

View File

@@ -192,13 +192,13 @@ func RunGitTests(m interface{ Run() int }) {
func runGitTests(m interface{ Run() int }) int {
gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home")
if err != nil {
testlogger.Panicf("unable to create temp dir: %s", err.Error())
return testlogger.MainErrorf("unable to create temp dir: %v", err)
}
defer cleanup()
setting.Git.HomePath = gitHomePath
if err = InitFull(); err != nil {
testlogger.Panicf("failed to call Init: %s", err.Error())
return testlogger.MainErrorf("failed to call Init: %s", err)
}
return m.Run()
}

View File

@@ -24,7 +24,7 @@ func testMain(m *testing.M) int {
// "setting.Git.HomePath" is initialized in "git" package but really used in "gitcmd" package
gitHomePath, cleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("git-home")
if err != nil {
testlogger.Panicf("failed to create temp dir: %v", err)
return testlogger.MainErrorf("failed to create temp dir: %v", err)
}
defer cleanup()

View File

@@ -101,6 +101,10 @@ func SetupGiteaTestEnv() {
cleanUpEnv()
initWorkPathAndConfig()
if RepoRootPath == "" || AppDataPath == "" {
panic("SetupGiteaTestEnv failed, paths are not initialized")
}
// TODO: some git repo hooks (test fixtures) still use these env variables, need to be refactored in the future
_ = os.Setenv("GITEA_ROOT", giteaRoot)
_ = os.Setenv("GITEA_CONF", giteaConf) // test fixture git hooks use "$GITEA_ROOT/$GITEA_CONF" in their scripts

View File

@@ -173,7 +173,8 @@ func Init() {
log.RegisterEventWriter("test", newTestLoggerWriter)
}
func Panicf(format string, args ...any) {
// don't call os.Exit, otherwise the "defer" functions won't be executed
panic(fmt.Sprintf(format, args...))
// MainErrorf is used to report an error from TestMain and return a non-zero value to indicate the failure
func MainErrorf(msg string, a ...any) int {
_, _ = fmt.Fprintf(os.Stderr, msg+"\n", a...)
return 1
}

View File

@@ -87,16 +87,19 @@ func testMain(m *testing.M) int {
graceful.InitManager(managerCtx)
defer cancel()
tests.InitTest()
err := tests.InitTest()
if err != nil {
return testlogger.MainErrorf("InitTest error: %v", err)
}
testWebRoutes = routers.NormalRoutes()
err := unittest.InitFixtures(
err = unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),
},
)
if err != nil {
testlogger.Panicf("InitFixtures: %v", err)
return testlogger.MainErrorf("InitFixtures: %v", err)
}
// FIXME: the console logger is deleted by mistake, so if there is any `log.Fatal`, developers won't see any error message.

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"code.gitea.io/gitea/models/db"
@@ -15,7 +16,6 @@ import (
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/testlogger"
@@ -25,8 +25,9 @@ import (
"github.com/stretchr/testify/assert"
)
func InitTest() {
func InitTest() error {
testlogger.Init()
if os.Getenv("GITEA_TEST_CONF") == "" {
// By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
// It's easier for developers to debug bugs step by step with a debugger.
@@ -39,101 +40,102 @@ func InitTest() {
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
if err := git.InitFull(); err != nil {
log.Fatal("git.InitOnceWithSync: %v", err)
return err
}
setting.LoadDBSetting()
if err := storage.Init(); err != nil {
testlogger.Panicf("Init storage failed: %v\n", err)
return err
}
switch {
case setting.Database.Type.IsMySQL():
connType := "tcp"
if len(setting.Database.Host) > 0 && setting.Database.Host[0] == '/' { // looks like a unix socket
connType = "unix"
}
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
}
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
log.Fatal("db.Exec: %v", err)
}
case setting.Database.Type.IsPostgreSQL():
var db *sql.DB
var err error
if setting.Database.Host[0] == '/' {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
} else {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
}
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
}
dbrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
if err != nil {
log.Fatal("db.Query: %v", err)
}
defer dbrows.Close()
if !dbrows.Next() {
if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
log.Fatal("db.Exec: CREATE DATABASE: %v", err)
{
connType := util.Iif(strings.HasPrefix(setting.Database.Host, "/"), "unix", "tcp")
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
return err
}
}
// Check if we need to setup a specific schema
if len(setting.Database.Schema) == 0 {
break
}
db.Close()
if setting.Database.Host[0] == '/' {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
} else {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
case setting.Database.Type.IsPostgreSQL():
openPostgreSQL := func() (*sql.DB, error) {
if strings.HasPrefix(setting.Database.Host, "/") {
return sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
}
return sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
}
// This is a different db object; requires a different Close()
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
}
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
if err != nil {
log.Fatal("db.Query: %v", err)
}
defer schrows.Close()
if !schrows.Next() {
// Create and setup a DB schema
if _, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema); err != nil {
log.Fatal("db.Exec: CREATE SCHEMA: %v", err)
// create database
{
db, err := openPostgreSQL()
if err != nil {
return err
}
defer db.Close()
dbRows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
if err != nil {
return err
}
defer dbRows.Close()
if !dbRows.Next() {
if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
return err
}
}
// Check if we need to set up a specific schema
if setting.Database.Schema == "" {
break
}
db.Close()
}
// create schema
{
db, err := openPostgreSQL()
if err != nil {
return err
}
defer db.Close()
schemaRows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
if err != nil {
return err
}
defer schemaRows.Close()
if !schemaRows.Next() {
// Create and set up a DB schema
if _, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema); err != nil {
return err
}
}
}
case setting.Database.Type.IsMSSQL():
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
log.Fatal("sql.Open: %v", err)
{
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
return err
}
}
if _, err := db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
log.Fatal("db.Exec: %v", err)
}
defer db.Close()
}
routers.InitWebInstalled(graceful.GetManager().HammerContext())
return nil
}
func PrepareAttachmentsStorage(t testing.TB) {