Improve testing init, clean up webhook tests (#37412)

Avoid webhook test fixtures affect other tests (be triggered)

Also fixed more testing problems including path init, global config
pollution & conflict

---------

Signed-off-by: silverwind <me@silverwind.io>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: wxiaoguang <2114189+wxiaoguang@users.noreply.github.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: silverwind <me@silverwind.io>
This commit is contained in:
Copilot
2026-04-25 18:55:18 +00:00
committed by GitHub
parent 24b60f8ff9
commit 9b9fb95559
25 changed files with 692 additions and 710 deletions

View File

@@ -87,16 +87,19 @@ func testMain(m *testing.M) int {
graceful.InitManager(managerCtx)
defer cancel()
tests.InitTest()
err := tests.InitTest()
if err != nil {
return testlogger.MainErrorf("InitTest error: %v", err)
}
testWebRoutes = routers.NormalRoutes()
err := unittest.InitFixtures(
err = unittest.InitFixtures(
unittest.FixturesOptions{
Dir: filepath.Join(filepath.Dir(setting.AppPath), "models/fixtures/"),
Dir: filepath.Join(setting.GetGiteaTestSourceRoot(), "models/fixtures/"),
},
)
if err != nil {
testlogger.Panicf("InitFixtures: %v", err)
return testlogger.MainErrorf("InitFixtures: %v", err)
}
// FIXME: the console logger is deleted by mistake, so if there is any `log.Fatal`, developers won't see any error message.

View File

@@ -40,7 +40,7 @@ func initMigrationTest(t *testing.T) func() {
setting.SetupGiteaTestEnv()
assert.NotEmpty(t, setting.RepoRootPath)
assert.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, unittest.SyncDirs(filepath.Join(setting.GetGiteaTestSourceRoot(), "tests/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, git.InitFull())
setting.LoadDBSetting()
setting.InitLoggersForTest()

View File

@@ -17,6 +17,7 @@ import (
"time"
auth_model "code.gitea.io/gitea/models/auth"
"code.gitea.io/gitea/models/db"
git_model "code.gitea.io/gitea/models/git"
issues_model "code.gitea.io/gitea/models/issues"
pull_model "code.gitea.io/gitea/models/pull"
@@ -92,12 +93,25 @@ func testPullCleanUp(t *testing.T, session *TestSession, user, repo, pullnum str
return resp
}
func preparePullMergeWebhook(t *testing.T, repoID int64) {
require.NoError(t, db.TruncateBeans(t.Context(), &webhook.Webhook{}, &webhook.HookTask{}))
require.NoError(t, db.Insert(t.Context(), &webhook.Webhook{
RepoID: repoID,
URL: "http://localhost/gitea-test-webhook-pull-merge",
ContentType: webhook.ContentTypeJSON,
Events: `{"push_only":true,"send_everything":false,"choose_events":false,"events":{"create":false,"push":true,"pull_request":false}}`,
IsActive: true,
}))
}
func assertPullMergeWebhookTask(t *testing.T, repoID int64) {
hook := unittest.AssertExistsAndLoadBean(t, &webhook.Webhook{RepoID: repoID})
unittest.AssertExistsAndLoadBean(t, &webhook.HookTask{HookID: hook.ID})
}
func TestPullMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
preparePullMergeWebhook(t, 1)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -123,18 +137,13 @@ func TestPullMerge(t *testing.T) {
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 3, repo.NumOpenPulls)
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
assertPullMergeWebhookTask(t, 1)
})
}
func TestPullRebase(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
preparePullMergeWebhook(t, 1)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -160,18 +169,13 @@ func TestPullRebase(t *testing.T) {
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 3, repo.NumOpenPulls)
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
assertPullMergeWebhookTask(t, 1)
})
}
func TestPullRebaseMerge(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
preparePullMergeWebhook(t, 1)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -197,18 +201,13 @@ func TestPullRebaseMerge(t *testing.T) {
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 3, repo.NumOpenPulls)
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
assertPullMergeWebhookTask(t, 1)
})
}
func TestPullSquash(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
preparePullMergeWebhook(t, 1)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -223,18 +222,13 @@ func TestPullSquash(t *testing.T) {
DeleteBranch: false,
})
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
assertPullMergeWebhookTask(t, 1)
})
}
func TestPullSquashWithHeadCommitID(t *testing.T) {
onGiteaRun(t, func(t *testing.T, giteaURL *url.URL) {
hookTasks, err := webhook.HookTasks(t.Context(), 1, 1) // Retrieve previous hook number
assert.NoError(t, err)
hookTasksLenBefore := len(hookTasks)
preparePullMergeWebhook(t, 1)
session := loginUser(t, "user1") // FIXME: don't use admin user for testing
testRepoFork(t, session, "user2", "repo1", "user1", "repo1", "")
testEditFile(t, session, "user1", "repo1", "master", "README.md", "Hello, World (Edited)\n")
@@ -267,9 +261,7 @@ func TestPullSquashWithHeadCommitID(t *testing.T) {
assert.Equal(t, 4, repo.NumPulls)
assert.Equal(t, 3, repo.NumOpenPulls)
hookTasks, err = webhook.HookTasks(t.Context(), 1, 1)
assert.NoError(t, err)
assert.Len(t, hookTasks, hookTasksLenBefore+1)
assertPullMergeWebhookTask(t, 1)
})
}
@@ -303,18 +295,14 @@ func TestPullCleanUpAfterMerge(t *testing.T) {
// Check PR branch deletion
resp = testPullCleanUp(t, session, elem[1], elem[2], elem[4])
respJSON := struct {
Redirect string
}{}
DecodeJSON(t, resp, &respJSON)
respJSON := test.ParseJSONRedirect(resp.Body.Bytes())
require.NotEmpty(t, respJSON.Redirect, "Redirected URL is not found")
assert.NotEmpty(t, respJSON.Redirect, "Redirected URL is not found")
elem = strings.Split(respJSON.Redirect, "/")
elem = strings.Split(*respJSON.Redirect, "/")
assert.Equal(t, "pulls", elem[3])
// Check branch deletion result
req := NewRequest(t, "GET", respJSON.Redirect)
req := NewRequest(t, "GET", *respJSON.Redirect)
resp = session.MakeRequest(t, req, http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
@@ -767,8 +755,7 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
// search issues
searchIssuesResp := session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
var apiIssuesBefore []*api.Issue
DecodeJSON(t, searchIssuesResp, &apiIssuesBefore)
apiIssuesBefore := DecodeJSON(t, searchIssuesResp, []*api.Issue{})
assert.Empty(t, apiIssuesBefore)
// merge the pull request
@@ -790,11 +777,9 @@ func TestPullMergeIndexerNotifier(t *testing.T) {
// search issues again
searchIssuesResp = session.MakeRequest(t, NewRequest(t, "GET", link.String()), http.StatusOK)
var apiIssuesAfter []*api.Issue
DecodeJSON(t, searchIssuesResp, &apiIssuesAfter)
if assert.Len(t, apiIssuesAfter, 1) {
assert.Equal(t, issue.ID, apiIssuesAfter[0].ID)
}
apiIssuesAfter := DecodeJSON(t, searchIssuesResp, []*api.Issue{})
require.Len(t, apiIssuesAfter, 1)
assert.Equal(t, issue.ID, apiIssuesAfter[0].ID)
})
}

View File

@@ -10,12 +10,14 @@ import (
"net/http/httptest"
"net/url"
"path"
"strconv"
"strings"
"testing"
"time"
actions_model "code.gitea.io/gitea/models/actions"
auth_model "code.gitea.io/gitea/models/auth"
db_model "code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/models/perm"
"code.gitea.io/gitea/models/repo"
"code.gitea.io/gitea/models/unittest"
@@ -40,26 +42,28 @@ import (
func TestNewWebHookLink(t *testing.T) {
defer tests.PrepareTestEnv(t)()
require.NoError(t, db_model.Insert(t.Context(), &webhook.Webhook{
RepoID: 1,
URL: "http://localhost/gitea-test-webhook-link",
ContentType: webhook.ContentTypeJSON,
Events: `{}`,
IsActive: true,
}))
hook := unittest.AssertExistsAndLoadBean(t, &webhook.Webhook{RepoID: 1})
session := loginUser(t, "user2")
baseurl := "/user2/repo1/settings/hooks"
tests := []string{
// webhook list page
baseurl,
// new webhook page
baseurl + "/gitea/new",
// edit webhook page
baseurl + "/1",
webhooksBaseHref := "/user2/repo1/settings/hooks"
cases := []string{
webhooksBaseHref,
webhooksBaseHref + "/gitea/new",
webhooksBaseHref + "/" + strconv.FormatInt(hook.ID, 10), // edit webhook
}
for _, url := range tests {
resp := session.MakeRequest(t, NewRequest(t, "GET", url), http.StatusOK)
for _, reqHref := range cases {
resp := session.MakeRequest(t, NewRequest(t, "GET", reqHref), http.StatusOK)
htmlDoc := NewHTMLParser(t, resp.Body)
menus := htmlDoc.doc.Find(".ui.top.attached.header .ui.dropdown .menu a")
menus.Each(func(i int, menu *goquery.Selection) {
url, exist := menu.Attr("href")
assert.True(t, exist)
assert.True(t, strings.HasPrefix(url, baseurl))
foundHref := menu.AttrOr("href", "")
assert.True(t, strings.HasPrefix(foundHref, webhooksBaseHref))
})
}
}

View File

@@ -8,6 +8,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"testing"
"code.gitea.io/gitea/models/db"
@@ -15,7 +16,6 @@ import (
"code.gitea.io/gitea/models/unittest"
"code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/graceful"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/storage"
"code.gitea.io/gitea/modules/testlogger"
@@ -25,8 +25,9 @@ import (
"github.com/stretchr/testify/assert"
)
func InitTest() {
func InitTest() error {
testlogger.Init()
if os.Getenv("GITEA_TEST_CONF") == "" {
// By default, use sqlite.ini for testing, then IDE like GoLand can start the test process with debugger.
// It's easier for developers to debug bugs step by step with a debugger.
@@ -39,101 +40,102 @@ func InitTest() {
setting.Repository.DefaultBranch = "master" // many test code still assume that default branch is called "master"
if err := git.InitFull(); err != nil {
log.Fatal("git.InitOnceWithSync: %v", err)
return err
}
setting.LoadDBSetting()
if err := storage.Init(); err != nil {
testlogger.Panicf("Init storage failed: %v\n", err)
return err
}
switch {
case setting.Database.Type.IsMySQL():
connType := "tcp"
if len(setting.Database.Host) > 0 && setting.Database.Host[0] == '/' { // looks like a unix socket
connType = "unix"
}
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
}
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
log.Fatal("db.Exec: %v", err)
}
case setting.Database.Type.IsPostgreSQL():
var db *sql.DB
var err error
if setting.Database.Host[0] == '/' {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
} else {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
}
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
}
dbrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
if err != nil {
log.Fatal("db.Query: %v", err)
}
defer dbrows.Close()
if !dbrows.Next() {
if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
log.Fatal("db.Exec: CREATE DATABASE: %v", err)
{
connType := util.Iif(strings.HasPrefix(setting.Database.Host, "/"), "unix", "tcp")
db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/",
setting.Database.User, setting.Database.Passwd, connType, setting.Database.Host))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS " + setting.Database.Name); err != nil {
return err
}
}
// Check if we need to setup a specific schema
if len(setting.Database.Schema) == 0 {
break
}
db.Close()
if setting.Database.Host[0] == '/' {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
} else {
db, err = sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
case setting.Database.Type.IsPostgreSQL():
openPostgreSQL := func() (*sql.DB, error) {
if strings.HasPrefix(setting.Database.Host, "/") {
return sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@/%s?sslmode=%s&host=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Name, setting.Database.SSLMode, setting.Database.Host))
}
return sql.Open("postgres", fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=%s",
setting.Database.User, setting.Database.Passwd, setting.Database.Host, setting.Database.Name, setting.Database.SSLMode))
}
// This is a different db object; requires a different Close()
defer db.Close()
if err != nil {
log.Fatal("sql.Open: %v", err)
}
schrows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
if err != nil {
log.Fatal("db.Query: %v", err)
}
defer schrows.Close()
if !schrows.Next() {
// Create and setup a DB schema
if _, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema); err != nil {
log.Fatal("db.Exec: CREATE SCHEMA: %v", err)
// create database
{
db, err := openPostgreSQL()
if err != nil {
return err
}
defer db.Close()
dbRows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = '%s'", setting.Database.Name))
if err != nil {
return err
}
defer dbRows.Close()
if !dbRows.Next() {
if _, err = db.Exec("CREATE DATABASE " + setting.Database.Name); err != nil {
return err
}
}
// Check if we need to set up a specific schema
if setting.Database.Schema == "" {
break
}
db.Close()
}
// create schema
{
db, err := openPostgreSQL()
if err != nil {
return err
}
defer db.Close()
schemaRows, err := db.Query(fmt.Sprintf("SELECT 1 FROM information_schema.schemata WHERE schema_name = '%s'", setting.Database.Schema))
if err != nil {
return err
}
defer schemaRows.Close()
if !schemaRows.Next() {
// Create and set up a DB schema
if _, err = db.Exec("CREATE SCHEMA " + setting.Database.Schema); err != nil {
return err
}
}
}
case setting.Database.Type.IsMSSQL():
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
log.Fatal("sql.Open: %v", err)
{
host, port := setting.ParseMSSQLHostPort(setting.Database.Host)
db, err := sql.Open("mssql", fmt.Sprintf("server=%s; port=%s; database=%s; user id=%s; password=%s;",
host, port, "master", setting.Database.User, setting.Database.Passwd))
if err != nil {
return err
}
defer db.Close()
if _, err = db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
return err
}
}
if _, err := db.Exec(fmt.Sprintf("If(db_id(N'%s') IS NULL) BEGIN CREATE DATABASE %s; END;", setting.Database.Name, setting.Database.Name)); err != nil {
log.Fatal("db.Exec: %v", err)
}
defer db.Close()
}
routers.InitWebInstalled(graceful.GetManager().HammerContext())
return nil
}
func PrepareAttachmentsStorage(t testing.TB) {
@@ -154,7 +156,7 @@ func PrepareGitRepoDirectory(t testing.TB) {
if !assert.NotEmpty(t, setting.RepoRootPath) {
return
}
assert.NoError(t, unittest.SyncDirs(filepath.Join(filepath.Dir(setting.AppPath), "tests/gitea-repositories-meta"), setting.RepoRootPath))
assert.NoError(t, unittest.SyncDirs(filepath.Join(setting.GetGiteaTestSourceRoot(), "tests/gitea-repositories-meta"), setting.RepoRootPath))
}
func PrepareArtifactsStorage(t testing.TB) {