feat: update gitea vendor
runner nix smoke / nix label and flake smoke (push) Failing after 1m28s

This commit is contained in:
2026-09-26 21:18:24 +00:00
parent c439c1b948
commit d9b2a4e787
3538 changed files with 116131 additions and 44340 deletions
@@ -9,7 +9,7 @@ import (
"strconv"
"strings"
"code.gitea.io/gitea/models/db"
"gitea.dev/models/db"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -4,19 +4,24 @@
package unittest
import (
"context"
"fmt"
"strings"
"unicode"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"gitea.dev/models/db"
"gitea.dev/modules/auth/password/hash"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
"xorm.io/xorm"
"xorm.io/xorm/contexts"
"xorm.io/xorm/schemas"
)
type FixturesLoader interface {
Load() error
MarkTableChanged(tableName string)
}
var fixturesLoader FixturesLoader
@@ -57,15 +62,101 @@ func loadFixtureResetSeqPgsql(e *xorm.Engine) error {
return nil
}
type fixturesHookStruct struct{}
func cutSpaceForSQL(s string) (string, string, bool) {
s = strings.TrimSpace(s)
pos := strings.IndexFunc(s, unicode.IsSpace)
if pos == -1 {
return s, "", false
}
return s[:pos], strings.TrimSpace(s[pos+1:]), true
}
func trimTableNameQuotes(s string) string {
pos := strings.IndexByte(s, '.')
if pos != -1 {
s = s[pos+1:]
}
return strings.Trim(s, "\"`[]")
}
func (f fixturesHookStruct) BeforeProcess(c *contexts.ContextHook) (context.Context, error) {
if c.Ctx.Value(db.ContextKeyTestFixtures) != nil {
return c.Ctx, nil
}
ctx, sql := c.Ctx, c.SQL
cmdPart, cmdRemaining, ok := cutSpaceForSQL(sql)
if !ok {
return ctx, nil
}
// ignore the SQLs which don't change data
if util.AsciiEqualFold(cmdPart, "SELECT") ||
util.AsciiEqualFold(cmdPart, "SHOW") ||
util.AsciiEqualFold(cmdPart, "PRAGMA") ||
util.AsciiEqualFold(cmdPart, "ALTER") ||
util.AsciiEqualFold(cmdPart, "CREATE") ||
util.AsciiEqualFold(cmdPart, "DROP") ||
util.AsciiEqualFold(cmdPart, "IF") ||
util.AsciiEqualFold(cmdPart, "SET") ||
util.AsciiEqualFold(cmdPart, "sp_rename") ||
util.AsciiEqualFold(cmdPart, "BEGIN") ||
util.AsciiEqualFold(cmdPart, "ROLLBACK") ||
util.AsciiEqualFold(cmdPart, "COMMIT") {
return ctx, nil
}
switch {
case util.AsciiEqualFold(cmdPart, "INSERT"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "INTO") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "MERGE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "INTO") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "UPDATE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "DELETE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "FROM") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
case util.AsciiEqualFold(cmdPart, "TRUNCATE"):
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
if util.AsciiEqualFold(cmdPart, "TABLE") {
cmdPart, cmdRemaining, _ = cutSpaceForSQL(cmdRemaining)
}
fixturesLoader.MarkTableChanged(trimTableNameQuotes(cmdPart))
default:
// should either parse the table name if it changes data, or ignore it
panic("unrecognized sql: " + sql)
}
_ = cmdRemaining
return ctx, nil
}
func (f fixturesHookStruct) AfterProcess(c *contexts.ContextHook) error {
return nil
}
// InitFixtures initialize test fixtures for a test database
func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
xormEngine := util.IfZero(util.OptionalArg(engine), GetXORMEngine())
func InitFixtures(opts FixturesOptions) (err error) {
xormEngine := GetXORMEngine()
fixturesLoader, err = NewFixturesLoader(xormEngine, opts)
// fixturesLoader = NewFixturesLoaderVendor(xormEngine, opts)
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
xormEngine.AddHook(&fixturesHookStruct{})
return err
}
@@ -4,6 +4,7 @@
package unittest
import (
"context"
"database/sql"
"encoding/hex"
"fmt"
@@ -11,10 +12,11 @@ import (
"path/filepath"
"slices"
"strings"
"sync"
"code.gitea.io/gitea/models/db"
"gitea.dev/models/db"
"gopkg.in/yaml.v3"
"go.yaml.in/yaml/v4"
"xorm.io/xorm"
"xorm.io/xorm/schemas"
)
@@ -32,7 +34,7 @@ type FixtureItem struct {
type fixturesLoaderInternal struct {
xormEngine *xorm.Engine
xormTableNames map[string]bool
tableSyncMap sync.Map
db *sql.DB
dbType schemas.DBType
fixtures map[string]*FixtureItem
@@ -148,25 +150,36 @@ func (f *fixturesLoaderInternal) Load() error {
}
defer func() { _ = tx.Rollback() }()
ctx := context.WithValue(context.Background(), db.ContextKeyTestFixtures, true)
for _, fixture := range f.fixtures {
if !f.xormTableNames[fixture.tableName] {
synced, existing := f.tableSyncMap.Load(fixture.tableName)
if synced == true || !existing {
continue
}
if err := f.loadFixtures(tx, fixture); err != nil {
return fmt.Errorf("failed to load fixtures from %s: %w", fixture.fileFullPath, err)
}
f.tableSyncMap.Store(fixture.tableName, true)
}
if err = tx.Commit(); err != nil {
return err
}
for xormTableName := range f.xormTableNames {
if f.fixtures[xormTableName] == nil {
_, _ = f.xormEngine.Exec("DELETE FROM `" + xormTableName + "`")
f.tableSyncMap.Range(func(k, v any) bool {
tableName, synced := k.(string), v.(bool)
if !synced && f.fixtures[tableName] == nil {
_, _ = f.xormEngine.Context(ctx).Exec("DELETE FROM `" + tableName + "`")
}
}
f.tableSyncMap.Store(tableName, true)
return true
})
return nil
}
func (f *fixturesLoaderInternal) MarkTableChanged(tableName string) {
f.tableSyncMap.Store(tableName, false)
}
func FixturesFileFullPaths(dir string, files []string) (map[string]*FixtureItem, error) {
if files != nil && len(files) == 0 {
return nil, nil //nolint:nilnil // load nothing
@@ -215,11 +228,12 @@ func NewFixturesLoader(x *xorm.Engine, opts FixturesOptions) (FixturesLoader, er
f.paramPlaceholder = func(idx int) string { return "?" }
}
// If a model is not imported in a package (no bean is registered), the table won't exist in database.
// So only use tables of registered models (beans).
xormBeans, _ := db.NamesToBean()
f.xormTableNames = map[string]bool{}
for _, bean := range xormBeans {
f.xormTableNames[x.TableName(bean)] = true
beanTableName := x.TableName(bean)
f.tableSyncMap.Store(trimTableNameQuotes(beanTableName), false)
}
return f, nil
}
@@ -8,9 +8,9 @@ import (
"path/filepath"
"testing"
"code.gitea.io/gitea/models/unittest"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/setting"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"gitea.dev/modules/setting"
"github.com/stretchr/testify/require"
"xorm.io/xorm"
@@ -70,7 +70,7 @@ func prepareTestFixturesLoaders(t testing.TB) unittest.FixturesOptions {
opts := unittest.FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: []string{
"user.yml",
}}
require.NoError(t, unittest.CreateTestEngine(opts))
require.NoError(t, unittest.CreateTestEngine(filepath.Join(t.TempDir(), "sqlite-test.db"), opts))
return opts
}
@@ -95,7 +95,7 @@ func TestFixturesLoader(t *testing.T) {
func BenchmarkFixturesLoader(b *testing.B) {
opts := prepareTestFixturesLoaders(b)
require.NoError(b, unittest.CreateTestEngine(opts))
require.NoError(b, unittest.CreateTestEngine(filepath.Join(b.TempDir(), "sqlite-test.db"), opts))
loaderInternal, err := unittest.NewFixturesLoader(unittest.GetXORMEngine(), opts)
require.NoError(b, err)
loaderVendor, err := NewFixturesLoaderVendor(unittest.GetXORMEngine(), opts)
@@ -9,8 +9,8 @@ import (
"path/filepath"
"strings"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/util"
"gitea.dev/modules/setting"
"gitea.dev/modules/util"
)
// SyncFile synchronizes the two files. This is skipped if both files
@@ -0,0 +1,142 @@
// Copyright 2026 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package unittest
import (
"fmt"
"io"
"maps"
"net/http"
"net/http/httptest"
"net/url"
"os"
"slices"
"strings"
"testing"
"gitea.dev/modules/log"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// MockServerOptions tweaks NewMockWebServer behavior.
type MockServerOptions struct {
// Routes installs extra handlers on the mux before the fixture fallback;
// more specific patterns win.
Routes func(mux *http.ServeMux)
// StripPrefix is trimmed from the request path before forwarding upstream,
// useful when the client prepends a prefix the real upstream does not use
// (e.g. go-github prepends "/api/v3").
StripPrefix string
}
// NewMockWebServer returns a test HTTP server that records upstream responses on demand
// and replays them from disk on subsequent runs.
//
// - liveMode=true: requests are forwarded to liveServerBaseURL and responses written as
// fixture files under testDataDir.
// - liveMode=false: responses come from existing fixture files.
//
// Fixture format: header lines ("Name: value"), a blank line, then the body. Before
// replay, occurrences of liveServerBaseURL in the body are swapped for the mock URL.
//
// The typical switch is an env var holding an API token; fixtures ship committed so the
// default run (no token) works offline.
//
// token := os.Getenv("GITEA_TOKEN")
// mock := NewMockWebServer(t, "https://gitea.com", fixtureDir, token != "")
func NewMockWebServer(t *testing.T, liveServerBaseURL, testDataDir string, liveMode bool, opts ...MockServerOptions) *httptest.Server {
t.Helper()
var opt MockServerOptions
if len(opts) > 0 {
opt = opts[0]
}
ignoredHeaders := []string{"cf-ray", "server", "date", "report-to", "nel", "x-request-id", "set-cookie"}
var mockURL string
fallback := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
reqPath := r.URL.EscapedPath()
if r.URL.RawQuery != "" {
reqPath += "?" + r.URL.RawQuery
}
log.Info("mock server: %s %s", r.Method, reqPath)
fixturePath := fmt.Sprintf("%s/%s_%s", testDataDir, r.Method, url.QueryEscape(reqPath))
if strings.Contains(r.URL.Path, ".git/") {
fixturePath = fmt.Sprintf("%s/%s_%s", testDataDir, r.Method, url.QueryEscape(r.URL.Path))
}
if liveMode {
require.NoError(t, os.MkdirAll(testDataDir, 0o755))
liveURL := liveServerBaseURL + strings.TrimPrefix(reqPath, opt.StripPrefix)
req, err := http.NewRequest(r.Method, liveURL, r.Body)
require.NoError(t, err, "building upstream request to %s", liveURL)
for name, values := range r.Header {
if strings.EqualFold(name, "accept-encoding") {
continue
}
for _, value := range values {
req.Header.Add(name, value)
}
}
resp, err := http.DefaultClient.Do(req)
require.NoError(t, err, "upstream request to %s failed", liveURL)
defer resp.Body.Close()
assert.Less(t, resp.StatusCode, 400, "upstream %s returned status %d", liveURL, resp.StatusCode)
out, err := os.Create(fixturePath)
require.NoError(t, err, "creating fixture %s", fixturePath)
defer out.Close()
for _, name := range slices.Sorted(maps.Keys(resp.Header)) {
if slices.Contains(ignoredHeaders, strings.ToLower(name)) {
continue
}
for _, value := range resp.Header[name] {
_, err := fmt.Fprintf(out, "%s: %s\n", name, value)
require.NoError(t, err)
}
}
_, err = out.WriteString("\n")
require.NoError(t, err)
_, err = io.Copy(out, resp.Body)
require.NoError(t, err, "writing fixture body for %s", liveURL)
require.NoError(t, out.Sync())
}
raw, err := os.ReadFile(fixturePath)
require.NoError(t, err, "missing fixture: %s", fixturePath)
replayed := strings.ReplaceAll(string(raw), liveServerBaseURL, mockURL)
headers, body, _ := strings.Cut(replayed, "\n\n")
for line := range strings.SplitSeq(headers, "\n") {
name, value, ok := strings.Cut(line, ": ")
if !ok || strings.EqualFold(name, "Content-Length") {
continue
}
w.Header().Set(name, value)
}
w.WriteHeader(http.StatusOK)
_, err = w.Write([]byte(body))
require.NoError(t, err)
})
mux := http.NewServeMux()
if opt.Routes != nil {
opt.Routes(mux)
}
mux.Handle("/", fallback)
server := httptest.NewServer(mux)
mockURL = server.URL
t.Cleanup(server.Close)
return server
}
@@ -9,7 +9,7 @@ import (
)
func fieldByName(v reflect.Value, field string) reflect.Value {
if v.Kind() == reflect.Ptr {
if v.Kind() == reflect.Pointer {
v = v.Elem()
}
f := v.FieldByName(field)
+132 -89
View File
@@ -5,61 +5,30 @@ package unittest
import (
"context"
"database/sql"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/system"
"code.gitea.io/gitea/modules/auth/password/hash"
"code.gitea.io/gitea/modules/cache"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"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"
"gitea.dev/models/db"
"gitea.dev/models/system"
"gitea.dev/modules/cache"
"gitea.dev/modules/git"
"gitea.dev/modules/setting"
"gitea.dev/modules/setting/config"
"gitea.dev/modules/storage"
"gitea.dev/modules/tempdir"
"gitea.dev/modules/testlogger"
"gitea.dev/modules/util"
"github.com/stretchr/testify/assert"
"xorm.io/xorm"
"xorm.io/xorm/names"
)
// InitSettingsForTesting initializes config provider and load common settings for tests
func InitSettingsForTesting() {
setting.SetupGiteaTestEnv()
log.OsExiter = func(code int) {
if code != 0 {
// non-zero exit code (log.Fatal) shouldn't occur during testing, if it happens, show a full stacktrace for more details
panic(fmt.Errorf("non-zero exit code during testing: %d", code))
}
os.Exit(0)
}
if setting.CustomConf == "" {
setting.CustomConf = filepath.Join(setting.CustomPath, "conf/app-unittest-tmp.ini")
_ = os.Remove(setting.CustomConf)
}
// init paths and config system for testing
getTestEnv := func(key string) string {
return ""
}
setting.InitWorkPathAndCommonConfig(getTestEnv, setting.ArgWorkPathAndCustomConf{CustomConf: setting.CustomConf})
if err := setting.PrepareAppDataPath(); err != nil {
log.Fatal("Can not prepare APP_DATA_PATH: %v", err)
}
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
}
// TestOptions represents test options
type TestOptions struct {
FixtureFiles []string
@@ -75,11 +44,20 @@ func MainTest(m *testing.M, testOptsArg ...*TestOptions) {
func mainTest(m *testing.M, testOptsArg ...*TestOptions) int {
testOpts := util.OptionalArg(testOptsArg, &TestOptions{})
InitSettingsForTesting()
tempWorkPath, tempCleanup, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("unit-test-dir-")
if err != nil {
return testlogger.MainErrorf("Failed to create temp dir for unit test: %v", err)
}
defer tempCleanup()
defer setting.MockBuiltinPaths(tempWorkPath, "", "")()
setting.SetupGiteaTestEnv()
giteaRoot := setting.GetGiteaTestSourceRoot()
fixturesOpts := FixturesOptions{Dir: filepath.Join(giteaRoot, "models", "fixtures"), Files: testOpts.FixtureFiles}
if err := CreateTestEngine(fixturesOpts); err != nil {
testlogger.Panicf("Error creating test engine: %v\n", err)
if err := CreateTestEngine(filepath.Join(tempWorkPath, "sqlite-test.db"), fixturesOpts); err != nil {
return testlogger.MainErrorf("Error creating test database engine: %v", err)
}
setting.AppURL = "https://try.gitea.io/"
@@ -91,59 +69,28 @@ func mainTest(m *testing.M, testOptsArg ...*TestOptions) int {
setting.SSH.Domain = "try.gitea.io"
setting.Database.Type = "sqlite3"
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
repoRootPath, cleanup1, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("repos")
if err != nil {
testlogger.Panicf("TempDir: %v\n", err)
}
defer cleanup1()
setting.RepoRootPath = repoRootPath
appDataPath, cleanup2, err := tempdir.OsTempDir("gitea-test").MkdirTempRandom("appdata")
if err != nil {
testlogger.Panicf("TempDir: %v\n", err)
}
defer cleanup2()
setting.AppDataPath = appDataPath
setting.GravatarSource = "https://secure.gravatar.com/avatar/"
setting.Attachment.Storage.Path = filepath.Join(setting.AppDataPath, "attachments")
setting.LFS.Storage.Path = filepath.Join(setting.AppDataPath, "lfs")
setting.Avatar.Storage.Path = filepath.Join(setting.AppDataPath, "avatars")
setting.RepoAvatar.Storage.Path = filepath.Join(setting.AppDataPath, "repo-avatars")
setting.RepoArchive.Storage.Path = filepath.Join(setting.AppDataPath, "repo-archive")
setting.Packages.Storage.Path = filepath.Join(setting.AppDataPath, "packages")
setting.Actions.LogStorage.Path = filepath.Join(setting.AppDataPath, "actions_log")
setting.Git.HomePath = filepath.Join(setting.AppDataPath, "home")
setting.IncomingEmail.ReplyToAddress = "incoming+%{token}@localhost"
config.SetDynGetter(system.NewDatabaseDynKeyGetter())
if err = cache.Init(); err != nil {
testlogger.Panicf("cache.Init: %v\n", err)
return testlogger.MainErrorf("cache.Init: %v", err)
}
if err = storage.Init(); err != nil {
testlogger.Panicf("storage.Init: %v\n", err)
return testlogger.MainErrorf("storage.Init: %v", err)
}
if err = SyncDirs(filepath.Join(giteaRoot, "tests", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
testlogger.Panicf("util.SyncDirs: %v\n", err)
return testlogger.MainErrorf("util.SyncDirs: %v", err)
}
if err = git.InitFull(); err != nil {
testlogger.Panicf("git.Init: %v\n", err)
return testlogger.MainErrorf("git.Init: %v", err)
}
if testOpts.SetUp != nil {
if err := testOpts.SetUp(); err != nil {
testlogger.Panicf("set up failed: %v\n", err)
return testlogger.MainErrorf("set up failed: %v", err)
}
}
@@ -151,25 +98,121 @@ func mainTest(m *testing.M, testOptsArg ...*TestOptions) int {
if testOpts.TearDown != nil {
if err := testOpts.TearDown(); err != nil {
testlogger.Panicf("tear down failed: %v\n", err)
return testlogger.MainErrorf("tear down failed: %v", err)
}
}
return exitStatus
}
func ResetTestDatabase() (cleanup func(), err error) {
defer func() {
if cleanup == nil {
cleanup = func() {}
}
}()
connOpts := db.GlobalConnOptions()
driverDefault, connStrDefault, err := db.ConnStrDefaultDatabase(connOpts)
if err != nil {
return nil, err
}
driverDatabase, connStrDatabase, err := db.ConnStr(connOpts)
if err != nil {
return nil, err
}
if connOpts.Type.IsSQLite3() {
if !strings.HasSuffix(connOpts.SQLitePath, "-test.db") {
return nil, errors.New(`testing database file for sqlite3 must end in "-test.db"`)
}
_ = os.Remove(connOpts.SQLitePath)
err = os.MkdirAll(filepath.Dir(connOpts.SQLitePath), os.ModePerm)
if err != nil {
return nil, err
}
cleanup = func() {
_ = os.Remove(connOpts.SQLitePath)
_ = os.Remove(filepath.Dir(connOpts.SQLitePath))
}
return cleanup, nil
}
if !strings.Contains(connOpts.Database, "test") {
return nil, fmt.Errorf(`testing database name for %s must contain "test"`, connOpts.Database)
}
quotedDbName := connOpts.Database
if connOpts.Type.IsMSSQL() {
quotedDbName = `[` + connOpts.Database + `]`
}
sqlExec := func(sqlDB *sql.DB, sql string) error {
_, err := sqlDB.Exec(sql)
if err != nil {
return fmt.Errorf("failed to execute SQL %q: %w", sql, err)
}
return nil
}
createDatabase := func() error {
sqlDB, err := sql.Open(driverDefault, connStrDefault)
if err != nil {
return err
}
defer sqlDB.Close()
if err = sqlExec(sqlDB, "DROP DATABASE IF EXISTS "+quotedDbName); err != nil {
return err
}
return sqlExec(sqlDB, "CREATE DATABASE "+quotedDbName)
}
if err = createDatabase(); err != nil {
return nil, err
}
cleanup = func() {
sqlDB, err := sql.Open(driverDefault, connStrDefault)
if err != nil {
return
}
defer sqlDB.Close()
_, _ = sqlDB.Exec("DROP DATABASE IF EXISTS " + quotedDbName)
}
createDatabaseSchema := func() error {
if !connOpts.Type.IsPostgreSQL() {
return nil
}
if connOpts.Schema == "" {
return nil
}
sqlDB, err := sql.Open(driverDatabase, connStrDatabase)
if err != nil {
return err
}
defer sqlDB.Close()
if err = sqlExec(sqlDB, "DROP SCHEMA IF EXISTS "+connOpts.Schema); err != nil {
return err
}
return sqlExec(sqlDB, "CREATE SCHEMA "+connOpts.Schema)
}
return cleanup, createDatabaseSchema()
}
// FixturesOptions fixtures needs to be loaded options
type FixturesOptions struct {
Dir string
Files []string
}
// CreateTestEngine creates a memory database and loads the fixture data from fixturesDir
func CreateTestEngine(opts FixturesOptions) error {
x, err := xorm.NewEngine("sqlite3", "file::memory:?cache=shared&_txlock=immediate")
// CreateTestEngine creates a test database and loads the fixture data from fixturesDir
func CreateTestEngine(testSQLiteFile string, opts FixturesOptions) error {
driver, connStr, err := db.ConnStr(db.ConnOptions{Type: setting.DatabaseTypeSQLite3, SQLitePath: testSQLiteFile, SQLiteBusyTimeout: setting.DefaultSQLiteBusyTimeout})
if err != nil {
return err
}
x, err := xorm.NewEngine(driver, connStr)
if err != nil {
if strings.Contains(err.Error(), "unknown driver") {
return fmt.Errorf("sqlite3 requires: -tags sqlite,sqlite_unlock_notify\n%w", err)
}
return err
}
x.SetMapper(names.GonicMapper{})
@@ -10,7 +10,7 @@ import (
"os"
"strings"
"code.gitea.io/gitea/models/db"
"gitea.dev/models/db"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@@ -47,7 +47,7 @@ func OrderBy(orderBy string) any {
}
func whereOrderConditions(e db.Engine, conditions []any) db.Engine {
orderBy := "id" // query must have the "ORDER BY", otherwise the result is not deterministic
orderBy := "id" // query must have the "ORDER BY", otherwise the result is not deterministic. FIXME: some tables do not have "id" column
for _, condition := range conditions {
switch cond := condition.(type) {
case *testCond: