Files
Gitea/models/unittest/unit_tests.go
T
bircni ed4a23e893 enhance: inherit team access for all units (#38938)
Admin and write team authorize now grant that mode on every unit,
including units added later, instead of only rows present in
`team_unit`. Granular teams keep `authorize=none` and explicit unit
rows.

Closes the `TEAM-UNIT-PERMISSION` design gap from
https://github.com/go-gitea/gitea/pull/34128.

Maybe also fix #15962 (actually maybe it had been fixed before, the root
cause is out-of-sync "access" table)


## Screenshots

only writing selected:
<img width="1399" height="1007" alt="image"
src="https://github.com/user-attachments/assets/1d1b4c49-a59a-47b6-998f-0464a067395b"
/>


_Created with the help of AI_

---------

Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
2026-08-17 20:30:24 +00:00

198 lines
5.5 KiB
Go

// Copyright 2016 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package unittest
import (
"context"
"fmt"
"math"
"os"
"strings"
"gitea.dev/models/db"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"xorm.io/builder"
)
// Code in this file is mainly used by unittest.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)
type TestingT interface {
require.TestingT
assert.TestingT
Context() context.Context
Helper()
}
type testCond struct {
query any
args []any
}
type testOrderBy string
// Cond create a condition with arguments for a test
func Cond(query any, args ...any) any {
return &testCond{query: query, args: args}
}
// 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. FIXME: some tables do not have "id" column
for _, condition := range conditions {
switch cond := condition.(type) {
case *testCond:
e = e.Where(cond.query, cond.args...)
case testOrderBy:
orderBy = string(cond)
default:
e = e.Where(cond)
}
}
return e.OrderBy(orderBy)
}
func getBeanIfExists(t TestingT, bean any, conditions ...any) (bool, error) {
e := db.GetEngine(t.Context())
return whereOrderConditions(e, conditions).Get(bean)
}
func GetBean[T any](t TestingT, bean T, conditions ...any) (ret T) {
exists, err := getBeanIfExists(t, 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 TestingT, bean T, conditions ...any) T {
t.Helper()
exists, err := getBeanIfExists(t, bean, conditions...)
require.NoError(t, err)
require.True(t, exists,
"Expected to find %+v (of type %T, with conditions %+v), but did not",
bean, bean, conditions)
return bean
}
// AssertExistsAndLoadMap assert that a row exists and load it from the test database
func AssertExistsAndLoadMap(t TestingT, table string, conditions ...any) map[string]string {
t.Helper()
e := db.GetEngine(t.Context()).Table(table)
res, err := whereOrderConditions(e, conditions).Query()
assert.NoError(t, err)
assert.Len(t, res, 1,
"Expected to find one row in %s (with conditions %+v), but found %d",
table, conditions, len(res),
)
if len(res) == 1 {
rec := map[string]string{}
for k, v := range res[0] {
rec[k] = string(v)
}
return rec
}
return nil
}
// GetCount get the count of a bean
func GetCount(t TestingT, bean any, conditions ...any) int {
e := db.GetEngine(t.Context())
for _, condition := range conditions {
switch cond := condition.(type) {
case *testCond:
e = e.Where(cond.query, cond.args...)
default:
e = e.Where(cond)
}
}
count, err := e.Count(bean)
assert.NoError(t, err)
return int(count)
}
// AssertNotExistsBean assert that a bean does not exist in the test database
func AssertNotExistsBean(t TestingT, bean any, conditions ...any) {
t.Helper()
exists, err := getBeanIfExists(t, bean, conditions...)
assert.NoError(t, err)
assert.False(t, exists)
}
// AssertCount assert the count of a bean
func AssertCount(t TestingT, bean, expected any) bool {
t.Helper()
return assert.EqualValues(t, expected, GetCount(t, bean))
}
// AssertInt64InRange assert value is in range [low, high]
func AssertInt64InRange(t TestingT, low, high, value int64) {
t.Helper()
assert.True(t, value >= low && value <= high,
"Expected value in range [%d, %d], found %d", low, high, value)
}
// GetCountByCond get the count of database entries matching bean
func GetCountByCond(t TestingT, tableName string, cond builder.Cond) int64 {
t.Helper()
e := db.GetEngine(t.Context())
count, err := e.Table(tableName).Where(cond).Count()
assert.NoError(t, err)
return count
}
// AssertCountByCond test the count of database entries matching bean
func AssertCountByCond(t TestingT, tableName string, cond builder.Cond, expected int) bool {
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 := GetXORMEngine()
goDB := x.DB().DB
sql, ok := sqlOrBean.(string)
if !ok {
sql = "SELECT * FROM " + x.TableName(sqlOrBean)
} else if !strings.Contains(sql, " ") {
sql = "SELECT * FROM " + 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, ", "))
}
}