summaryrefslogtreecommitdiffstats
path: root/models/db
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2021-11-12 22:36:47 +0800
committerGitHub <noreply@github.com>2021-11-12 22:36:47 +0800
commitdf64fa486555de6f403a795fd16c2e9e1d59e535 (patch)
treeb899e9b9e5d57409b1bf0e3afbd606b6a3900235 /models/db
parent7f802631c54d2e91301158380b273b872d62bd80 (diff)
downloadgitea-df64fa486555de6f403a795fd16c2e9e1d59e535.tar.gz
gitea-df64fa486555de6f403a795fd16c2e9e1d59e535.zip
Decouple unit test code from business code (#17623)
Diffstat (limited to 'models/db')
-rwxr-xr-xmodels/db/engine.go5
-rw-r--r--models/db/paginator/main_test.go (renamed from models/db/main_test.go)6
-rw-r--r--models/db/paginator/paginator.go8
-rw-r--r--models/db/paginator/paginator_test.go (renamed from models/db/list_options_test.go)13
-rw-r--r--models/db/test_fixtures.go117
-rw-r--r--models/db/unit_tests.go206
6 files changed, 61 insertions, 294 deletions
diff --git a/models/db/engine.go b/models/db/engine.go
index d5f2470a7a..d1b279e016 100755
--- a/models/db/engine.go
+++ b/models/db/engine.go
@@ -124,7 +124,8 @@ func NewEngine() (*xorm.Engine, error) {
return engine, nil
}
-func syncTables() error {
+//SyncAllTables sync the schemas of all tables, is required by unit test code
+func SyncAllTables() error {
return x.StoreEngine("InnoDB").Sync2(tables...)
}
@@ -176,7 +177,7 @@ func InitEngineWithMigration(ctx context.Context, migrateFunc func(*xorm.Engine)
return fmt.Errorf("migrate: %v", err)
}
- if err = syncTables(); err != nil {
+ if err = SyncAllTables(); err != nil {
return fmt.Errorf("sync database struct error: %v", err)
}
diff --git a/models/db/main_test.go b/models/db/paginator/main_test.go
index f34ff65813..601ed89710 100644
--- a/models/db/main_test.go
+++ b/models/db/paginator/main_test.go
@@ -2,13 +2,15 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package db
+package paginator
import (
"path/filepath"
"testing"
+
+ "code.gitea.io/gitea/models/unittest"
)
func TestMain(m *testing.M) {
- MainTest(m, filepath.Join("..", ".."))
+ unittest.MainTest(m, filepath.Join("..", "..", ".."))
}
diff --git a/models/db/paginator/paginator.go b/models/db/paginator/paginator.go
new file mode 100644
index 0000000000..747539f30e
--- /dev/null
+++ b/models/db/paginator/paginator.go
@@ -0,0 +1,8 @@
+// Copyright 2021 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package paginator
+
+// dummy only. in the future, the models/db/list_options.go should be moved here to decouple from db package
+// otherwise the unit test will cause cycle import
diff --git a/models/db/list_options_test.go b/models/db/paginator/paginator_test.go
index 2c860afdfb..fdb8eee441 100644
--- a/models/db/list_options_test.go
+++ b/models/db/paginator/paginator_test.go
@@ -2,11 +2,12 @@
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
-package db
+package paginator
import (
"testing"
+ "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/setting"
"github.com/stretchr/testify/assert"
@@ -14,35 +15,35 @@ import (
func TestPaginator(t *testing.T) {
cases := []struct {
- Paginator
+ db.Paginator
Skip int
Take int
Start int
End int
}{
{
- Paginator: &ListOptions{Page: -1, PageSize: -1},
+ Paginator: &db.ListOptions{Page: -1, PageSize: -1},
Skip: 0,
Take: setting.API.DefaultPagingNum,
Start: 0,
End: setting.API.DefaultPagingNum,
},
{
- Paginator: &ListOptions{Page: 2, PageSize: 10},
+ Paginator: &db.ListOptions{Page: 2, PageSize: 10},
Skip: 10,
Take: 10,
Start: 10,
End: 20,
},
{
- Paginator: NewAbsoluteListOptions(-1, -1),
+ Paginator: db.NewAbsoluteListOptions(-1, -1),
Skip: 0,
Take: setting.API.DefaultPagingNum,
Start: 0,
End: setting.API.DefaultPagingNum,
},
{
- Paginator: NewAbsoluteListOptions(2, 10),
+ Paginator: db.NewAbsoluteListOptions(2, 10),
Skip: 2,
Take: 10,
Start: 2,
diff --git a/models/db/test_fixtures.go b/models/db/test_fixtures.go
deleted file mode 100644
index 2715b688ea..0000000000
--- a/models/db/test_fixtures.go
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2017 The Gitea Authors. All rights reserved.
-// Use of this source code is governed by a MIT-style
-// license that can be found in the LICENSE file.
-
-package db
-
-import (
- "fmt"
- "os"
- "time"
-
- "github.com/go-testfixtures/testfixtures/v3"
- "xorm.io/xorm"
- "xorm.io/xorm/schemas"
-)
-
-var fixtures *testfixtures.Loader
-
-// InitFixtures initialize test fixtures for a test database
-func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
- e := x
- if len(engine) == 1 {
- e = engine[0]
- }
-
- var testfiles func(*testfixtures.Loader) error
- if opts.Dir != "" {
- testfiles = testfixtures.Directory(opts.Dir)
- } else {
- testfiles = testfixtures.Files(opts.Files...)
- }
- 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(),
- testfiles,
- }
-
- if e.Dialect().URI().DBType == schemas.POSTGRES {
- loaderOptions = append(loaderOptions, testfixtures.SkipResetSequences())
- }
-
- fixtures, err = testfixtures.New(loaderOptions...)
- if err != nil {
- return err
- }
-
- return err
-}
-
-// LoadFixtures load fixtures for a test database
-func LoadFixtures(engine ...*xorm.Engine) error {
- e := x
- if len(engine) == 1 {
- e = engine[0]
- }
- var err error
- // Database transaction conflicts could occur and result in ROLLBACK
- // As a simple workaround, we just retry 20 times.
- for i := 0; i < 20; i++ {
- err = fixtures.Load()
- if 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
- }
- }
- }
- }
- return err
-}
diff --git a/models/db/unit_tests.go b/models/db/unit_tests.go
index 6f079c8676..2b1691726f 100644
--- a/models/db/unit_tests.go
+++ b/models/db/unit_tests.go
@@ -6,157 +6,26 @@ package db
import (
"context"
- "fmt"
"math"
- "net/url"
- "os"
- "path/filepath"
- "testing"
- "code.gitea.io/gitea/modules/base"
- "code.gitea.io/gitea/modules/setting"
- "code.gitea.io/gitea/modules/storage"
- "code.gitea.io/gitea/modules/util"
+ "code.gitea.io/gitea/modules/unittestbridge"
- "github.com/stretchr/testify/assert"
"xorm.io/xorm"
- "xorm.io/xorm/names"
)
+// Code in this file is mainly used by models.CheckConsistencyFor, which is not in the unit test for various reasons.
+// In the future if we can decouple CheckConsistencyFor into separate unit test code, then this file can be moved into unittest package too.
+
// NonexistentID an ID that will never exist
const NonexistentID = int64(math.MaxInt64)
-// giteaRoot a path to the gitea root
-var (
- giteaRoot string
- fixturesDir string
-)
-
-// FixturesDir returns the fixture directory
-func FixturesDir() string {
- return fixturesDir
-}
-
-func fatalTestError(fmtStr string, args ...interface{}) {
- fmt.Fprintf(os.Stderr, fmtStr, args...)
- os.Exit(1)
-}
-
-// MainTest a reusable TestMain(..) function for unit tests that need to use a
-// test database. Creates the test database, and sets necessary settings.
-func MainTest(m *testing.M, pathToGiteaRoot string, fixtureFiles ...string) {
- var err error
- giteaRoot = pathToGiteaRoot
- fixturesDir = filepath.Join(pathToGiteaRoot, "models", "fixtures")
-
- var opts FixturesOptions
- if len(fixtureFiles) == 0 {
- opts.Dir = fixturesDir
- } else {
- for _, f := range fixtureFiles {
- if len(f) != 0 {
- opts.Files = append(opts.Files, filepath.Join(fixturesDir, f))
- }
- }
- }
-
- if err = CreateTestEngine(opts); err != nil {
- fatalTestError("Error creating test engine: %v\n", err)
- }
-
- setting.AppURL = "https://try.gitea.io/"
- setting.RunUser = "runuser"
- setting.SSH.Port = 3000
- setting.SSH.Domain = "try.gitea.io"
- setting.Database.UseSQLite3 = true
- setting.RepoRootPath, err = os.MkdirTemp(os.TempDir(), "repos")
- if err != nil {
- fatalTestError("TempDir: %v\n", err)
- }
- setting.AppDataPath, err = os.MkdirTemp(os.TempDir(), "appdata")
- if err != nil {
- fatalTestError("TempDir: %v\n", err)
- }
- setting.AppWorkPath = pathToGiteaRoot
- setting.StaticRootPath = pathToGiteaRoot
- setting.GravatarSourceURL, err = url.Parse("https://secure.gravatar.com/avatar/")
- if err != nil {
- fatalTestError("url.Parse: %v\n", err)
- }
- 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")
-
- if err = storage.Init(); err != nil {
- fatalTestError("storage.Init: %v\n", err)
- }
-
- if err = util.RemoveAll(setting.RepoRootPath); err != nil {
- fatalTestError("util.RemoveAll: %v\n", err)
- }
- if err = util.CopyDir(filepath.Join(pathToGiteaRoot, "integrations", "gitea-repositories-meta"), setting.RepoRootPath); err != nil {
- fatalTestError("util.CopyDir: %v\n", err)
- }
-
- exitStatus := m.Run()
- if err = util.RemoveAll(setting.RepoRootPath); err != nil {
- fatalTestError("util.RemoveAll: %v\n", err)
- }
- if err = util.RemoveAll(setting.AppDataPath); err != nil {
- fatalTestError("util.RemoveAll: %v\n", err)
- }
- os.Exit(exitStatus)
-}
-
-// 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 {
- var err error
- x, err = xorm.NewEngine("sqlite3", "file::memory:?cache=shared&_txlock=immediate")
- if err != nil {
- return err
- }
- x.SetMapper(names.GonicMapper{})
- if err = syncTables(); err != nil {
- return err
- }
- switch os.Getenv("GITEA_UNIT_TESTS_VERBOSE") {
- case "true", "1":
- x.ShowSQL(true)
- }
-
+//SetUnitTestEngine is used by unit test code
+func SetUnitTestEngine(eng *xorm.Engine) {
+ x = eng
DefaultContext = &Context{
Context: context.Background(),
e: x,
}
-
- return InitFixtures(opts)
-}
-
-// PrepareTestDatabase load test fixtures into test database
-func PrepareTestDatabase() error {
- return LoadFixtures()
-}
-
-// PrepareTestEnv prepares the environment for unit tests. Can only be called
-// by tests that use the above MainTest(..) function.
-func PrepareTestEnv(t testing.TB) {
- assert.NoError(t, PrepareTestDatabase())
- assert.NoError(t, util.RemoveAll(setting.RepoRootPath))
- metaPath := filepath.Join(giteaRoot, "integrations", "gitea-repositories-meta")
- assert.NoError(t, util.CopyDir(metaPath, setting.RepoRootPath))
- base.SetupGiteaRoot() // Makes sure GITEA_ROOT is set
}
type testCond struct {
@@ -182,10 +51,6 @@ func whereConditions(sess *xorm.Session, conditions []interface{}) {
// LoadBeanIfExists loads beans from fixture database if exist
func LoadBeanIfExists(bean interface{}, conditions ...interface{}) (bool, error) {
- return loadBeanIfExists(bean, conditions...)
-}
-
-func loadBeanIfExists(bean interface{}, conditions ...interface{}) (bool, error) {
sess := x.NewSession()
defer sess.Close()
whereConditions(sess, conditions)
@@ -193,61 +58,68 @@ func loadBeanIfExists(bean interface{}, conditions ...interface{}) (bool, error)
}
// BeanExists for testing, check if a bean exists
-func BeanExists(t testing.TB, bean interface{}, conditions ...interface{}) bool {
- exists, err := loadBeanIfExists(bean, conditions...)
- assert.NoError(t, err)
+func BeanExists(t unittestbridge.Tester, bean interface{}, conditions ...interface{}) bool {
+ ta := unittestbridge.NewAsserter(t)
+ exists, err := LoadBeanIfExists(bean, conditions...)
+ ta.NoError(err)
return exists
}
-// AssertExistsAndLoadBean assert that a bean exists and load it from the test
-// database
-func AssertExistsAndLoadBean(t testing.TB, bean interface{}, conditions ...interface{}) interface{} {
- exists, err := loadBeanIfExists(bean, conditions...)
- assert.NoError(t, err)
- assert.True(t, exists,
+// AssertExistsAndLoadBean assert that a bean exists and load it from the test database
+func AssertExistsAndLoadBean(t unittestbridge.Tester, bean interface{}, conditions ...interface{}) interface{} {
+ ta := unittestbridge.NewAsserter(t)
+ exists, err := LoadBeanIfExists(bean, conditions...)
+ ta.NoError(err)
+ ta.True(exists,
"Expected to find %+v (of type %T, with conditions %+v), but did not",
bean, bean, conditions)
return bean
}
// GetCount get the count of a bean
-func GetCount(t testing.TB, bean interface{}, conditions ...interface{}) int {
+func GetCount(t unittestbridge.Tester, bean interface{}, conditions ...interface{}) int {
+ ta := unittestbridge.NewAsserter(t)
sess := x.NewSession()
defer sess.Close()
whereConditions(sess, conditions)
count, err := sess.Count(bean)
- assert.NoError(t, err)
+ ta.NoError(err)
return int(count)
}
// AssertNotExistsBean assert that a bean does not exist in the test database
-func AssertNotExistsBean(t testing.TB, bean interface{}, conditions ...interface{}) {
- exists, err := loadBeanIfExists(bean, conditions...)
- assert.NoError(t, err)
- assert.False(t, exists)
+func AssertNotExistsBean(t unittestbridge.Tester, bean interface{}, conditions ...interface{}) {
+ ta := unittestbridge.NewAsserter(t)
+ exists, err := LoadBeanIfExists(bean, conditions...)
+ ta.NoError(err)
+ ta.False(exists)
}
// AssertExistsIf asserts that a bean exists or does not exist, depending on
// what is expected.
-func AssertExistsIf(t *testing.T, expected bool, bean interface{}, conditions ...interface{}) {
- exists, err := loadBeanIfExists(bean, conditions...)
- assert.NoError(t, err)
- assert.Equal(t, expected, exists)
+func AssertExistsIf(t unittestbridge.Tester, expected bool, bean interface{}, conditions ...interface{}) {
+ ta := unittestbridge.NewAsserter(t)
+ exists, err := LoadBeanIfExists(bean, conditions...)
+ ta.NoError(err)
+ ta.Equal(expected, exists)
}
// AssertSuccessfulInsert assert that beans is successfully inserted
-func AssertSuccessfulInsert(t testing.TB, beans ...interface{}) {
+func AssertSuccessfulInsert(t unittestbridge.Tester, beans ...interface{}) {
+ ta := unittestbridge.NewAsserter(t)
_, err := x.Insert(beans...)
- assert.NoError(t, err)
+ ta.NoError(err)
}
// AssertCount assert the count of a bean
-func AssertCount(t testing.TB, bean, expected interface{}) {
- assert.EqualValues(t, expected, GetCount(t, bean))
+func AssertCount(t unittestbridge.Tester, bean, expected interface{}) {
+ ta := unittestbridge.NewAsserter(t)
+ ta.EqualValues(expected, GetCount(ta, bean))
}
// AssertInt64InRange assert value is in range [low, high]
-func AssertInt64InRange(t testing.TB, low, high, value int64) {
- assert.True(t, value >= low && value <= high,
+func AssertInt64InRange(t unittestbridge.Tester, low, high, value int64) {
+ ta := unittestbridge.NewAsserter(t)
+ ta.True(value >= low && value <= high,
"Expected value in range [%d, %d], found %d", low, high, value)
}