Test query must have "order by" explicitly to avoid unstable results (#24963)

The query must have the "ORDER BY", otherwise the result is not
deterministic.

Replace "interface{}" with "any" by the way.
This commit is contained in:
wxiaoguang 2023-05-29 11:20:57 +08:00 committed by GitHub
parent 84c8ab9fd1
commit ad13df36b7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -19,42 +19,52 @@ import (
const NonexistentID = int64(math.MaxInt64) const NonexistentID = int64(math.MaxInt64)
type testCond struct { type testCond struct {
query interface{} query any
args []interface{} args []any
} }
type testOrderBy string
// Cond create a condition with arguments for a test // Cond create a condition with arguments for a test
func Cond(query interface{}, args ...interface{}) interface{} { func Cond(query any, args ...any) any {
return &testCond{query: query, args: args} return &testCond{query: query, args: args}
} }
func whereConditions(e db.Engine, conditions []interface{}) db.Engine { // OrderBy creates "ORDER BY" a test query
func OrderBy(orderBy string) any {
return testOrderBy(orderBy)
}
func whereOrderConditions(e db.Engine, conditions []any) db.Engine {
orderBy := "id" // query must have the "ORDER BY", otherwise the result is not deterministic
for _, condition := range conditions { for _, condition := range conditions {
switch cond := condition.(type) { switch cond := condition.(type) {
case *testCond: case *testCond:
e = e.Where(cond.query, cond.args...) e = e.Where(cond.query, cond.args...)
case testOrderBy:
orderBy = string(cond)
default: default:
e = e.Where(cond) e = e.Where(cond)
} }
} }
return e return e.OrderBy(orderBy)
} }
// LoadBeanIfExists loads beans from fixture database if exist // LoadBeanIfExists loads beans from fixture database if exist
func LoadBeanIfExists(bean interface{}, conditions ...interface{}) (bool, error) { func LoadBeanIfExists(bean any, conditions ...any) (bool, error) {
e := db.GetEngine(db.DefaultContext) e := db.GetEngine(db.DefaultContext)
return whereConditions(e, conditions).Get(bean) return whereOrderConditions(e, conditions).Get(bean)
} }
// BeanExists for testing, check if a bean exists // BeanExists for testing, check if a bean exists
func BeanExists(t assert.TestingT, bean interface{}, conditions ...interface{}) bool { func BeanExists(t assert.TestingT, bean any, conditions ...any) bool {
exists, err := LoadBeanIfExists(bean, conditions...) exists, err := LoadBeanIfExists(bean, conditions...)
assert.NoError(t, err) assert.NoError(t, err)
return exists return exists
} }
// AssertExistsAndLoadBean assert that a bean exists and load it from the test database // AssertExistsAndLoadBean assert that a bean exists and load it from the test database
func AssertExistsAndLoadBean[T any](t assert.TestingT, bean T, conditions ...interface{}) T { func AssertExistsAndLoadBean[T any](t assert.TestingT, bean T, conditions ...any) T {
exists, err := LoadBeanIfExists(bean, conditions...) exists, err := LoadBeanIfExists(bean, conditions...)
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, exists, assert.True(t, exists,
@ -64,9 +74,9 @@ func AssertExistsAndLoadBean[T any](t assert.TestingT, bean T, conditions ...int
} }
// AssertExistsAndLoadMap assert that a row exists and load it from the test database // AssertExistsAndLoadMap assert that a row exists and load it from the test database
func AssertExistsAndLoadMap(t assert.TestingT, table string, conditions ...interface{}) map[string]string { func AssertExistsAndLoadMap(t assert.TestingT, table string, conditions ...any) map[string]string {
e := db.GetEngine(db.DefaultContext).Table(table) e := db.GetEngine(db.DefaultContext).Table(table)
res, err := whereConditions(e, conditions).Query() res, err := whereOrderConditions(e, conditions).Query()
assert.NoError(t, err) assert.NoError(t, err)
assert.True(t, len(res) == 1, assert.True(t, len(res) == 1,
"Expected to find one row in %s (with conditions %+v), but found %d", "Expected to find one row in %s (with conditions %+v), but found %d",
@ -84,15 +94,15 @@ func AssertExistsAndLoadMap(t assert.TestingT, table string, conditions ...inter
} }
// GetCount get the count of a bean // GetCount get the count of a bean
func GetCount(t assert.TestingT, bean interface{}, conditions ...interface{}) int { func GetCount(t assert.TestingT, bean any, conditions ...any) int {
e := db.GetEngine(db.DefaultContext) e := db.GetEngine(db.DefaultContext)
count, err := whereConditions(e, conditions).Count(bean) count, err := whereOrderConditions(e, conditions).Count(bean)
assert.NoError(t, err) assert.NoError(t, err)
return int(count) return int(count)
} }
// AssertNotExistsBean assert that a bean does not exist in the test database // AssertNotExistsBean assert that a bean does not exist in the test database
func AssertNotExistsBean(t assert.TestingT, bean interface{}, conditions ...interface{}) { func AssertNotExistsBean(t assert.TestingT, bean any, conditions ...any) {
exists, err := LoadBeanIfExists(bean, conditions...) exists, err := LoadBeanIfExists(bean, conditions...)
assert.NoError(t, err) assert.NoError(t, err)
assert.False(t, exists) assert.False(t, exists)
@ -100,20 +110,20 @@ func AssertNotExistsBean(t assert.TestingT, bean interface{}, conditions ...inte
// AssertExistsIf asserts that a bean exists or does not exist, depending on // AssertExistsIf asserts that a bean exists or does not exist, depending on
// what is expected. // what is expected.
func AssertExistsIf(t assert.TestingT, expected bool, bean interface{}, conditions ...interface{}) { func AssertExistsIf(t assert.TestingT, expected bool, bean any, conditions ...any) {
exists, err := LoadBeanIfExists(bean, conditions...) exists, err := LoadBeanIfExists(bean, conditions...)
assert.NoError(t, err) assert.NoError(t, err)
assert.Equal(t, expected, exists) assert.Equal(t, expected, exists)
} }
// AssertSuccessfulInsert assert that beans is successfully inserted // AssertSuccessfulInsert assert that beans is successfully inserted
func AssertSuccessfulInsert(t assert.TestingT, beans ...interface{}) { func AssertSuccessfulInsert(t assert.TestingT, beans ...any) {
err := db.Insert(db.DefaultContext, beans...) err := db.Insert(db.DefaultContext, beans...)
assert.NoError(t, err) assert.NoError(t, err)
} }
// AssertCount assert the count of a bean // AssertCount assert the count of a bean
func AssertCount(t assert.TestingT, bean, expected interface{}) { func AssertCount(t assert.TestingT, bean, expected any) {
assert.EqualValues(t, expected, GetCount(t, bean)) assert.EqualValues(t, expected, GetCount(t, bean))
} }