Refactor tests (#33021)

1. fix incorrect tests, for example: BeanExists doesn't do assert and
shouldn't be used
2. remove unnecessary test functions
3. introduce DumpQueryResult to help to see the database rows during
test (at least I need it)

```
====== DumpQueryResult: SELECT * FROM action_runner_token ======
- # row[0]
  id: 1
  token: xeiWBL5kuTYxGPynHCqQdoeYmJAeG3IzGXCYTrDX
  owner_id: 0
...
```
This commit is contained in:
wxiaoguang 2024-12-29 09:05:56 +08:00 committed by GitHub
parent e95b946f6d
commit 0ed160ffea
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 83 additions and 68 deletions

View file

@ -1,12 +1,10 @@
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
//nolint:forbidigo
package unittest
import (
"fmt"
"os"
"time"
"code.gitea.io/gitea/models/db"
@ -37,7 +35,7 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
} else {
fixtureOptionFiles = testfixtures.Files(opts.Files...)
}
dialect := "unknown"
var dialect string
switch e.Dialect().URI().DBType {
case schemas.POSTGRES:
dialect = "postgres"
@ -48,8 +46,7 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
case schemas.SQLITE:
dialect = "sqlite3"
default:
fmt.Println("Unsupported RDBMS for integration tests")
os.Exit(1)
return fmt.Errorf("unsupported RDBMS for integration tests: %q", e.Dialect().URI().DBType)
}
loaderOptions := []func(loader *testfixtures.Loader) error{
testfixtures.Database(e.DB().DB),
@ -69,9 +66,7 @@ func InitFixtures(opts FixturesOptions, engine ...*xorm.Engine) (err error) {
// register the dummy hash algorithm function used in the test fixtures
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
return err
}
@ -87,7 +82,7 @@ func LoadFixtures(engine ...*xorm.Engine) error {
time.Sleep(200 * time.Millisecond)
}
if err != nil {
fmt.Printf("LoadFixtures failed after retries: %v\n", err)
return fmt.Errorf("LoadFixtures failed after retries: %w", err)
}
// Now if we're running postgres we need to tell it to update the sequences
if e.Dialect().URI().DBType == schemas.POSTGRES {
@ -108,21 +103,18 @@ func LoadFixtures(engine ...*xorm.Engine) error {
AND T.relname = PGT.tablename
ORDER BY S.relname;`)
if err != nil {
fmt.Printf("Failed to generate sequence update: %v\n", err)
return err
return fmt.Errorf("failed to generate sequence update: %w", 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 fmt.Errorf("failed to update sequence: %s, error: %w", value, err)
}
}
}
}
_ = hash.Register("dummy", hash.NewDummyHasher)
setting.PasswordHashAlgo, _ = hash.SetDefaultPasswordHashAlgorithm("dummy")
return err
return nil
}

View file

@ -4,7 +4,7 @@
package unittest
import (
"log"
"fmt"
"reflect"
)
@ -14,7 +14,7 @@ func fieldByName(v reflect.Value, field string) reflect.Value {
}
f := v.FieldByName(field)
if !f.IsValid() {
log.Panicf("can not read %s for %v", field, v)
panic(fmt.Errorf("can not read %s for %v", field, v))
}
return f
}

View file

@ -34,11 +34,6 @@ var (
fixturesDir string
)
// FixturesDir returns the fixture directory
func FixturesDir() string {
return fixturesDir
}
func fatalTestError(fmtStr string, args ...any) {
_, _ = fmt.Fprintf(os.Stderr, fmtStr, args...)
os.Exit(1)

View file

@ -4,13 +4,17 @@
package unittest
import (
"fmt"
"math"
"os"
"strings"
"code.gitea.io/gitea/models/db"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"xorm.io/builder"
"xorm.io/xorm"
)
// Code in this file is mainly used by unittest.CheckConsistencyFor, which is not in the unit test for various reasons.
@ -51,22 +55,23 @@ func whereOrderConditions(e db.Engine, conditions []any) db.Engine {
return e.OrderBy(orderBy)
}
// LoadBeanIfExists loads beans from fixture database if exist
func LoadBeanIfExists(bean any, conditions ...any) (bool, error) {
func getBeanIfExists(bean any, conditions ...any) (bool, error) {
e := db.GetEngine(db.DefaultContext)
return whereOrderConditions(e, conditions).Get(bean)
}
// BeanExists for testing, check if a bean exists
func BeanExists(t assert.TestingT, bean any, conditions ...any) bool {
exists, err := LoadBeanIfExists(bean, conditions...)
assert.NoError(t, err)
return exists
func GetBean[T any](t require.TestingT, bean T, conditions ...any) (ret T) {
exists, err := getBeanIfExists(bean, conditions...)
require.NoError(t, err)
if exists {
return bean
}
return ret
}
// AssertExistsAndLoadBean assert that a bean exists and load it from the test database
func AssertExistsAndLoadBean[T any](t require.TestingT, bean T, conditions ...any) T {
exists, err := LoadBeanIfExists(bean, conditions...)
exists, err := getBeanIfExists(bean, conditions...)
require.NoError(t, err)
require.True(t, exists,
"Expected to find %+v (of type %T, with conditions %+v), but did not",
@ -112,25 +117,11 @@ func GetCount(t assert.TestingT, bean any, conditions ...any) int {
// AssertNotExistsBean assert that a bean does not exist in the test database
func AssertNotExistsBean(t assert.TestingT, bean any, conditions ...any) {
exists, err := LoadBeanIfExists(bean, conditions...)
exists, err := getBeanIfExists(bean, conditions...)
assert.NoError(t, err)
assert.False(t, exists)
}
// AssertExistsIf asserts that a bean exists or does not exist, depending on
// what is expected.
func AssertExistsIf(t assert.TestingT, expected bool, bean any, conditions ...any) {
exists, err := LoadBeanIfExists(bean, conditions...)
assert.NoError(t, err)
assert.Equal(t, expected, exists)
}
// AssertSuccessfulInsert assert that beans is successfully inserted
func AssertSuccessfulInsert(t assert.TestingT, beans ...any) {
err := db.Insert(db.DefaultContext, beans...)
assert.NoError(t, err)
}
// AssertCount assert the count of a bean
func AssertCount(t assert.TestingT, bean, expected any) bool {
return assert.EqualValues(t, expected, GetCount(t, bean))
@ -155,3 +146,39 @@ func AssertCountByCond(t assert.TestingT, tableName string, cond builder.Cond, e
return assert.EqualValues(t, expected, GetCountByCond(t, tableName, cond),
"Failed consistency test, the counted bean (of table %s) was %+v", tableName, cond)
}
// DumpQueryResult dumps the result of a query for debugging purpose
func DumpQueryResult(t require.TestingT, sqlOrBean any, sqlArgs ...any) {
x := db.GetEngine(db.DefaultContext).(*xorm.Engine)
goDB := x.DB().DB
sql, ok := sqlOrBean.(string)
if !ok {
sql = fmt.Sprintf("SELECT * FROM %s", db.TableName(sqlOrBean))
} else if !strings.Contains(sql, " ") {
sql = fmt.Sprintf("SELECT * FROM %s", sql)
}
rows, err := goDB.Query(sql, sqlArgs...)
require.NoError(t, err)
defer rows.Close()
columns, err := rows.Columns()
require.NoError(t, err)
_, _ = fmt.Fprintf(os.Stdout, "====== DumpQueryResult: %s ======\n", sql)
idx := 0
for rows.Next() {
row := make([]any, len(columns))
rowPointers := make([]any, len(columns))
for i := range row {
rowPointers[i] = &row[i]
}
require.NoError(t, rows.Scan(rowPointers...))
_, _ = fmt.Fprintf(os.Stdout, "- # row[%d]\n", idx)
for i, col := range columns {
_, _ = fmt.Fprintf(os.Stdout, " %s: %v\n", col, row[i])
}
idx++
}
if idx == 0 {
_, _ = fmt.Fprintf(os.Stdout, "(no result, columns: %s)\n", strings.Join(columns, ", "))
}
}