diff --git a/tests/e2e/debugserver_test.go b/tests/e2e/debugserver_test.go index 8742790b14..e60fd44955 100644 --- a/tests/e2e/debugserver_test.go +++ b/tests/e2e/debugserver_test.go @@ -25,7 +25,7 @@ func TestDebugserver(t *testing.T) { signal.Notify(done, syscall.SIGINT, syscall.SIGTERM) onForgejoRun(t, func(*testing.T, *url.URL) { - defer DeclareGitRepos(t)() + DeclareGitRepos(t) fmt.Println(setting.AppURL) <-done }) diff --git a/tests/e2e/declare_repos_test.go b/tests/e2e/declare_repos_test.go index e72f260299..ce1e04bb4e 100644 --- a/tests/e2e/declare_repos_test.go +++ b/tests/e2e/declare_repos_test.go @@ -19,12 +19,11 @@ import ( user_model "forgejo.org/models/user" "forgejo.org/modules/git" "forgejo.org/modules/indexer/stats" - "forgejo.org/modules/optional" "forgejo.org/modules/timeutil" issue_service "forgejo.org/services/issue" files_service "forgejo.org/services/repository/files" "forgejo.org/services/wiki" - "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -44,7 +43,7 @@ type SetupRepo func(*user_model.User, *repo_model.Repository) // put your Git repo declarations in here // feel free to amend the helper function below or use the raw variant directly -func DeclareGitRepos(t *testing.T) func() { +func DeclareGitRepos(t *testing.T) { now := timeutil.TimeStampNow() postIssue := func(repo *repo_model.Repository, user *user_model.User, age int64, title, content string) { issue := &issues_model.Issue{ @@ -57,45 +56,45 @@ func DeclareGitRepos(t *testing.T) func() { require.NoError(t, issue_service.NewIssue(db.DefaultContext, repo, issue, nil, nil, nil)) } - cleanupFunctions := []func(){ - newRepo(t, 2, "diff-test", nil, []FileChanges{{ - Filename: "testfile", - Versions: []string{"hello", "hallo", "hola", "native", "ubuntu-latest", "- runs-on: ubuntu-latest", "- runs-on: debian-latest"}, - }}, nil), - newRepo(t, 2, "language-stats-test", nil, []FileChanges{{ - Filename: "main.rs", - Versions: []string{"fn main() {", "println!(\"Hello World!\");", "}"}, - }}, nil), - newRepo(t, 2, "mentions-highlighted", nil, []FileChanges{ - { - Filename: "history1.md", - Versions: []string{""}, - CommitMsg: "A commit message which mentions @user2 in the title\nand has some additional text which mentions @user1", - }, - { - Filename: "history2.md", - Versions: []string{""}, - CommitMsg: "Another commit which mentions @user1 in the title\nand @user2 in the text", - }, - }, nil), - newRepo(t, 2, "file-uploads", nil, []FileChanges{{ - Filename: "UPLOAD_TEST.md", - Versions: []string{"# File upload test\nUse this repo to test various file upload features in new branches."}, - }}, nil), - newRepo(t, 2, "unicode-escaping", &tests.DeclarativeRepoOptions{ - EnabledUnits: optional.Some([]unit_model.Type{unit_model.TypeCode, unit_model.TypeWiki}), - }, []FileChanges{{ - Filename: "a-file", - Versions: []string{"{a}{а}"}, - }}, func(user *user_model.User, repo *repo_model.Repository) { - wiki.InitWiki(db.DefaultContext, repo) - wiki.AddWikiPage(db.DefaultContext, user, repo, "Home", "{a}{а}", "{a}{а}") - wiki.AddWikiPage(db.DefaultContext, user, repo, "_Sidebar", "{a}{а}", "{a}{а}") - wiki.AddWikiPage(db.DefaultContext, user, repo, "_Footer", "{a}{а}", "{a}{а}") - }), - newRepo(t, 2, "multiple-combo-boxes", nil, []FileChanges{{ - Filename: ".forgejo/issue_template/multi-combo-boxes.yaml", - Versions: []string{` + newRepo(t, 2, "diff-test", nil, []FileChanges{{ + Filename: "testfile", + Versions: []string{"hello", "hallo", "hola", "native", "ubuntu-latest", "- runs-on: ubuntu-latest", "- runs-on: debian-latest"}, + }}, nil) + newRepo(t, 2, "language-stats-test", nil, []FileChanges{{ + Filename: "main.rs", + Versions: []string{"fn main() {", "println!(\"Hello World!\");", "}"}, + }}, nil) + newRepo(t, 2, "mentions-highlighted", nil, []FileChanges{ + { + Filename: "history1.md", + Versions: []string{""}, + CommitMsg: "A commit message which mentions @user2 in the title\nand has some additional text which mentions @user1", + }, + { + Filename: "history2.md", + Versions: []string{""}, + CommitMsg: "Another commit which mentions @user1 in the title\nand @user2 in the text", + }, + }, nil) + newRepo(t, 2, "file-uploads", nil, []FileChanges{{ + Filename: "UPLOAD_TEST.md", + Versions: []string{"# File upload test\nUse this repo to test various file upload features in new branches."}, + }}, nil) + newRepo(t, 2, "unicode-escaping", map[unit_model.Type]convert.Conversion{ + unit_model.TypeCode: nil, + unit_model.TypeWiki: nil, + }, []FileChanges{{ + Filename: "a-file", + Versions: []string{"{a}{а}"}, + }}, func(user *user_model.User, repo *repo_model.Repository) { + wiki.InitWiki(db.DefaultContext, repo) + wiki.AddWikiPage(db.DefaultContext, user, repo, "Home", "{a}{а}", "{a}{а}") + wiki.AddWikiPage(db.DefaultContext, user, repo, "_Sidebar", "{a}{а}", "{a}{а}") + wiki.AddWikiPage(db.DefaultContext, user, repo, "_Footer", "{a}{а}", "{a}{а}") + }) + newRepo(t, 2, "multiple-combo-boxes", nil, []FileChanges{{ + Filename: ".forgejo/issue_template/multi-combo-boxes.yaml", + Versions: []string{` name: "Multiple combo-boxes" description: "To show something" body: @@ -108,79 +107,70 @@ body: attributes: label: two `}, - }}, nil), - newRepo(t, 11, "dependency-test", &tests.DeclarativeRepoOptions{ - UnitConfig: optional.Some(map[unit_model.Type]convert.Conversion{ - unit_model.TypeIssues: &repo_model.IssuesConfig{ - EnableDependencies: true, - }, - }), - }, []FileChanges{}, func(user *user_model.User, repo *repo_model.Repository) { - postIssue(repo, user, 500, "first issue here", "an issue created earlier") - postIssue(repo, user, 400, "second issue here", "not the right issue, but in the right repo") - postIssue(repo, user, 300, "third issue here", "depends on things") - postIssue(repo, user, 200, "unrelated issue", "shrug emoji") - postIssue(repo, user, 100, "newest issue", "very new") - }), - newRepo(t, 11, "dependency-test-2", &tests.DeclarativeRepoOptions{ - UnitConfig: optional.Some(map[unit_model.Type]convert.Conversion{ - unit_model.TypeIssues: &repo_model.IssuesConfig{ - EnableDependencies: true, - }, - }), - }, []FileChanges{}, func(user *user_model.User, repo *repo_model.Repository) { - postIssue(repo, user, 450, "right issue", "an issue containing word right") - postIssue(repo, user, 150, "left issue", "an issue containing word left") - }), - newRepo(t, 2, "long-diff-test", nil, []FileChanges{{ - Filename: "test-README.md", - Versions: []string{ - readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/0-README.md"), - }, - }}, func(user *user_model.User, repo *repo_model.Repository) { - commit1Sha := addCommitToBranch(t, user, repo, "main", "test-branch", "test-README.md", "", - readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/1-README.md")) - commit2Sha := addCommitToBranch(t, user, repo, "test-branch", "test-branch", "test-README.md", commit1Sha, - readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/2-README.md")) - addCommitToBranch(t, user, repo, "test-branch", "test-branch", "test-README.md", commit2Sha, - readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/3-README.md")) - }), - newRepo(t, 2, "huge-diff-test", nil, []FileChanges{{ - Filename: "glossary.po", - Versions: []string{ - func() string { - var sb strings.Builder - sb.Write([]byte("0")) - for i := 1; i < 2000; i++ { - sb.WriteString(strconv.Itoa(i)) - sb.WriteByte('\n') + }}, nil) + newRepo(t, 11, "dependency-test", map[unit_model.Type]convert.Conversion{ + unit_model.TypeIssues: &repo_model.IssuesConfig{ + EnableDependencies: true, + }, + unit_model.TypeCode: nil, + }, []FileChanges{}, func(user *user_model.User, repo *repo_model.Repository) { + postIssue(repo, user, 500, "first issue here", "an issue created earlier") + postIssue(repo, user, 400, "second issue here", "not the right issue, but in the right repo") + postIssue(repo, user, 300, "third issue here", "depends on things") + postIssue(repo, user, 200, "unrelated issue", "shrug emoji") + postIssue(repo, user, 100, "newest issue", "very new") + }) + newRepo(t, 11, "dependency-test-2", map[unit_model.Type]convert.Conversion{ + unit_model.TypeIssues: &repo_model.IssuesConfig{ + EnableDependencies: true, + }, + unit_model.TypeCode: nil, + }, []FileChanges{}, func(user *user_model.User, repo *repo_model.Repository) { + postIssue(repo, user, 450, "right issue", "an issue containing word right") + postIssue(repo, user, 150, "left issue", "an issue containing word left") + }) + newRepo(t, 2, "long-diff-test", nil, []FileChanges{{ + Filename: "test-README.md", + Versions: []string{ + readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/0-README.md"), + }, + }}, func(user *user_model.User, repo *repo_model.Repository) { + commit1Sha := addCommitToBranch(t, user, repo, "main", "test-branch", "test-README.md", "", + readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/1-README.md")) + commit2Sha := addCommitToBranch(t, user, repo, "test-branch", "test-branch", "test-README.md", commit1Sha, + readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/2-README.md")) + addCommitToBranch(t, user, repo, "test-branch", "test-branch", "test-README.md", commit2Sha, + readStringFile(t, "tests/e2e/declarative-repo/long-diff-test/3-README.md")) + }) + newRepo(t, 2, "huge-diff-test", nil, []FileChanges{{ + Filename: "glossary.po", + Versions: []string{ + func() string { + var sb strings.Builder + sb.Write([]byte("0")) + for i := 1; i < 2000; i++ { + sb.WriteString(strconv.Itoa(i)) + sb.WriteByte('\n') + } + return sb.String() + }(), + }, + }}, func(user *user_model.User, repo *repo_model.Repository) { + addCommitToBranch(t, user, repo, "main", "main-2", "glossary.po", "", + func() string { + var sb strings.Builder + sb.Write([]byte("0")) + for i := 1; i < 2000; i++ { + sb.WriteString(strconv.Itoa(i)) + if i%12 == 0 { + sb.WriteString("Blub") } - return sb.String() - }(), - }, - }}, func(user *user_model.User, repo *repo_model.Repository) { - addCommitToBranch(t, user, repo, "main", "main-2", "glossary.po", "", - func() string { - var sb strings.Builder - sb.Write([]byte("0")) - for i := 1; i < 2000; i++ { - sb.WriteString(strconv.Itoa(i)) - if i%12 == 0 { - sb.WriteString("Blub") - } - sb.WriteByte('\n') - } - return sb.String() - }()) - }), - // add your repo declarations here - } - - return func() { - for _, cleanup := range cleanupFunctions { - cleanup() - } - } + sb.WriteByte('\n') + } + return sb.String() + }()) + }) + // add your repo declarations here } func readStringFile(t *testing.T, fn string) string { @@ -189,18 +179,20 @@ func readStringFile(t *testing.T, fn string) string { return string(c) } -func newRepo(t *testing.T, userID int64, repoName string, initOpts *tests.DeclarativeRepoOptions, fileChanges []FileChanges, setup SetupRepo) func() { +func newRepo(t *testing.T, userID int64, repoName string, enabledUnits map[unit_model.Type]convert.Conversion, fileChanges []FileChanges, setup SetupRepo) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: userID}) - opts := tests.DeclarativeRepoOptions{} - if initOpts != nil { - opts = *initOpts + somerepo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{ + Name: repoName, + Files: forgery.FilesInit{}, + }) + if len(enabledUnits) == 0 { + forgery.EnableRepoUnit(t, somerepo, unit_model.TypeCode, nil) + forgery.EnableRepoUnit(t, somerepo, unit_model.TypeIssues, nil) } - opts.Name = optional.Some(repoName) - if !opts.EnabledUnits.Has() { - opts.EnabledUnits = optional.Some([]unit_model.Type{unit_model.TypeCode, unit_model.TypeIssues}) + for unit, config := range enabledUnits { + forgery.EnableRepoUnit(t, somerepo, unit, config) } - somerepo, _, cleanupFunc := tests.CreateDeclarativeRepoWithOptions(t, user, opts) var lastCommitID string for _, file := range fileChanges { @@ -252,8 +244,6 @@ func newRepo(t *testing.T, userID int64, repoName string, initOpts *tests.Declar err := stats.UpdateRepoIndexer(somerepo) require.NoError(t, err) - - return cleanupFunc } func addCommitToBranch(t *testing.T, user *user_model.User, repo *repo_model.Repository, oldBranch, newBranch, filename, lastSha, content string) string { diff --git a/tests/e2e/e2e_test.go b/tests/e2e/e2e_test.go index 9168cb8b51..5ce6029f07 100644 --- a/tests/e2e/e2e_test.go +++ b/tests/e2e/e2e_test.go @@ -120,7 +120,7 @@ func TestE2e(t *testing.T) { // Default 2 minute timeout onForgejoRun(t, func(*testing.T, *url.URL) { - defer DeclareGitRepos(t)() + DeclareGitRepos(t) thisTest := runArgs // when all tests are run, use unique artifacts directories per test to preserve artifacts from other tests if testVisual { diff --git a/tests/forgery/fs.go b/tests/forgery/fs.go new file mode 100644 index 0000000000..f41b193702 --- /dev/null +++ b/tests/forgery/fs.go @@ -0,0 +1,112 @@ +// Copyright 2026 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package forgery + +import ( + "fmt" + "io" + "io/fs" + "strings" + "testing/fstest" + "time" + + repo_model "forgejo.org/models/repo" + user_model "forgejo.org/models/user" + "forgejo.org/modules/git" + files_service "forgejo.org/services/repository/files" +) + +type MapFS = fstest.MapFS + +// when a file has one of this mode, it needs specific git handling +// other non-zero modes are rejected +const ( + modeSubmodule = fs.ModeNamedPipe // hacky, but + modeSymlink = fs.ModeSymlink +) + +func MapFile(data string) *fstest.MapFile { + return &fstest.MapFile{ + Data: []byte(data), + } +} + +func MapSymlink(target string) *fstest.MapFile { + return &fstest.MapFile{ + Data: []byte(target), + Mode: modeSymlink, + } +} + +func MapSubmodule(sha string) *fstest.MapFile { + return &fstest.MapFile{ + Data: []byte(sha), + Mode: modeSubmodule, + } +} + +func initRepo(doer *user_model.User, repo *repo_model.Repository, format git.ObjectFormat, fsys fs.FS, commitMessage string) (string, error) { + t, err := files_service.NewTemporaryUploadRepository(git.DefaultContext, repo) + if err != nil { + return "", err + } + defer t.Close() + if err := t.Init(format.Name()); err != nil { + return "", err + } + + if err := fs.WalkDir(fsys, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil || d.IsDir() { + return err + } + + var content io.Reader + mode := git.EntryModeBlob + switch d.Type() { + case modeSymlink: + target, err := fs.ReadLink(fsys, path) + if err != nil { + return err + } + content = strings.NewReader(target) + mode = git.EntryModeSymlink + case modeSubmodule: + mode = git.EntryModeCommit + fallthrough + case 0: + f, err := fsys.Open(path) + if err != nil { + return err + } + defer f.Close() + + content = f + default: + return fmt.Errorf("unexpected file type in forgery.CreateRepository %s: %s", path, d.Type()) + } + + // add object to the database + objectHash, err := t.HashObject(content) + if err != nil { + return err + } + // Add the object to the index + return t.AddObjectToIndex(mode.String(), objectHash, path) + }); err != nil { + return "", err + } + + treeHash, err := t.WriteTree() + if err != nil { + return "", err + } + + now := time.Now() + commitHash, err := t.CommitTreeWithDate("", doer, doer, treeHash, commitMessage, false, now, now) + if err != nil { + return "", err + } + + return commitHash, t.Push(doer, commitHash, repo.DefaultBranch) +} diff --git a/tests/forgery/repo.go b/tests/forgery/repo.go new file mode 100644 index 0000000000..bfa0a51681 --- /dev/null +++ b/tests/forgery/repo.go @@ -0,0 +1,138 @@ +// Copyright 2026 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package forgery + +import ( + "cmp" + "io/fs" + "testing" + + repo_model "forgejo.org/models/repo" + unit_model "forgejo.org/models/unit" + user_model "forgejo.org/models/user" + "forgejo.org/modules/git" + repo_service "forgejo.org/services/repository" + wiki_service "forgejo.org/services/wiki" + + "github.com/stretchr/testify/require" + "xorm.io/xorm/convert" +) + +type CreateRepositoryOptions struct { + Name string // if nil a unique name (derived from the test name) will be generated + + // Content of the initial commit, if nil the git repo will be left uninitialized. + // Use [MapFS] or [FilesInit] to setup the initial files. + Files fs.FS + + ObjectFormat git.ObjectFormat // If nil, SHA1 + IsTemplate bool + IsPrivate bool + + LatestSha *string // if not nil, the commit sha after initializing the repo with the Files will be written to this ref + SkipCleanup bool // if true the repo will not be deleted at the end of the test (can be useful to debug locally) +} + +// FilesInit specifies the templates to use upon repository initialization. +type FilesInit struct { + Readme string + Gitignores string + License string +} + +func (FilesInit) Open(name string) (fs.File, error) { + panic("FilesInit is only a sentinel value") +} + +// CreateRepository returns the repo, owner and opts can be nil +func CreateRepository(t testing.TB, owner *user_model.User, opts *CreateRepositoryOptions) *repo_model.Repository { + t.Helper() + + if owner == nil { + owner = CreateUser(t, nil) // if specific options are needed, create the owner manually + } + if opts == nil { + opts = &CreateRepositoryOptions{} + } + + repoName := opts.Name + if repoName == "" { + repoName = "repo-" + uniqueSafeName(t.Name()) + } + + gitFormat := cmp.Or(opts.ObjectFormat, git.Sha1ObjectFormat) + + // Create the repository + createOptions := repo_service.CreateRepoOptions{ + Name: repoName, + Description: "Test Repo", + DefaultBranch: "main", + IsTemplate: opts.IsTemplate, + ObjectFormatName: gitFormat.Name(), + IsPrivate: opts.IsPrivate, + } + if fi, ok := opts.Files.(FilesInit); ok { + createOptions.AutoInit = true + createOptions.Readme = cmp.Or(fi.Readme, "Default") + createOptions.Gitignores = fi.Gitignores + createOptions.License = fi.License + } + repo, err := repo_service.CreateRepositoryDirectly(t.Context(), owner, owner, createOptions) + require.NoError(t, err) + if !opts.SkipCleanup { + t.Cleanup(func() { + _ = repo_service.DeleteRepository(t.Context(), owner, repo, false) + }) + } + require.NotEmpty(t, repo) + + if !createOptions.AutoInit && opts.Files != nil { + sha, err := initRepo(owner, repo, gitFormat, opts.Files, "init") + require.NoError(t, err) + if opts.LatestSha != nil { + *opts.LatestSha = sha + } + + // reload the repo since pushing a commit might update the model via the push_update queue (IsEmpty for instance) + repo, err = repo_model.GetRepositoryByID(t.Context(), repo.ID) + require.NoError(t, err) + } + repo.Owner = owner + + return repo +} + +func InitWiki(t testing.TB, repo *repo_model.Repository, branch string) { + // Set the wiki branch in the database first + repo.WikiBranch = branch + err := repo_model.UpdateRepositoryCols(t.Context(), repo, "wiki_branch") + require.NoError(t, err) + + // Initialize the wiki + err = wiki_service.InitWiki(t.Context(), repo) + require.NoError(t, err) + + // Add a new wiki page + err = wiki_service.AddWikiPage(t.Context(), repo.Owner, repo, "Home", "Welcome to the wiki!", "Add a Home page") + require.NoError(t, err) +} + +// config may be nil +func EnableRepoUnit(t testing.TB, repo *repo_model.Repository, unit unit_model.Type, config convert.Conversion) { + t.Helper() + + err := repo_service.UpdateRepositoryUnits(t.Context(), repo, []repo_model.RepoUnit{{ + RepoID: repo.ID, + Type: unit, + Config: config, + }}, nil) + require.NoError(t, err) +} + +func DisableRepoUnits(t testing.TB, repo *repo_model.Repository, units ...unit_model.Type) { + t.Helper() + + err := repo_service.UpdateRepositoryUnits(t.Context(), repo, nil, units) + require.NoError(t, err) +} diff --git a/tests/forgery/user.go b/tests/forgery/user.go new file mode 100644 index 0000000000..1175297497 --- /dev/null +++ b/tests/forgery/user.go @@ -0,0 +1,66 @@ +// Copyright 2026 The Forgejo Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package forgery + +import ( + "math/rand/v2" + "regexp" + "strconv" + "testing" + + org_model "forgejo.org/models/organization" + user_model "forgejo.org/models/user" + + "github.com/stretchr/testify/require" +) + +var nameCleaner = regexp.MustCompile(`[^a-zA-Z0-9-]+`) // exclude "_", to prevent multiple consecutive dashes + +// uniqueSafeName replaces specials chars with _ and appends a random hex suffix +func uniqueSafeName(testName string) string { + return nameCleaner.ReplaceAllLiteralString(testName, "_") + "-" + strconv.FormatUint(uint64(rand.Uint32()), 16) +} + +type CreateUserOptions struct { + IsAdmin bool +} + +const userPassword = "password" + +func CreateUser(t testing.TB, opts *CreateUserOptions) *user_model.User { + t.Helper() + + if opts == nil { + opts = &CreateUserOptions{} + } + u := &user_model.User{} + + name := "user-" + uniqueSafeName(t.Name()) + + u.Name = name + u.Email = name + "@test.forgejo.org" + u.Passwd = userPassword + u.IsAdmin = opts.IsAdmin + + err := user_model.CreateUser(t.Context(), u) + require.NoError(t, err) + return u +} + +func CreateOrganisation(t testing.TB, owner *user_model.User) *org_model.Organization { + t.Helper() + + if owner == nil { + owner = CreateUser(t, nil) // if specific options are needed, create the owner manually + } + o := &org_model.Organization{} + + name := "org-" + uniqueSafeName(t.Name()) + + o.Name = name + + err := org_model.CreateOrganization(t.Context(), o, owner) + require.NoError(t, err) + return o +} diff --git a/tests/integration/actions_trigger_test.go b/tests/integration/actions_trigger_test.go index 914acadf14..f5898682ce 100644 --- a/tests/integration/actions_trigger_test.go +++ b/tests/integration/actions_trigger_test.go @@ -36,6 +36,7 @@ import ( repo_service "forgejo.org/services/repository" files_service "forgejo.org/services/repository/files" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -1212,17 +1213,13 @@ jobs: user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // create the repo - repo, sha, f := tests.CreateDeclarativeRepo(t, user2, "repo-workflow-dispatch", - []unit_model.Type{unit_model.TypeActions}, nil, - []*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: fmt.Sprintf("%s/%s", testCase.workflowDirectory, testCase.workflowID), - ContentReader: strings.NewReader(testCase.workflowContent), - }, + var sha string + repo := forgery.CreateRepository(t, user2, &forgery.CreateRepositoryOptions{ + Files: forgery.MapFS{ + fmt.Sprintf("%s/%s", testCase.workflowDirectory, testCase.workflowID): forgery.MapFile(testCase.workflowContent), }, - ) - defer f() + LatestSha: &sha, + }) schedules, err := db.Find[actions_model.ActionSchedule](t.Context(), actions_model.FindScheduleOptions{RepoID: repo.ID}) require.NoError(t, err) diff --git a/tests/integration/api_activitypub_person_inbox_useractivity_test.go b/tests/integration/api_activitypub_person_inbox_useractivity_test.go index 025bba024a..458627127d 100644 --- a/tests/integration/api_activitypub_person_inbox_useractivity_test.go +++ b/tests/integration/api_activitypub_person_inbox_useractivity_test.go @@ -21,7 +21,7 @@ import ( "forgejo.org/routers" "forgejo.org/services/contexttest" "forgejo.org/services/federation" - "forgejo.org/tests" + "forgejo.org/tests/forgery" ap "github.com/go-ap/activitypub" "github.com/stretchr/testify/assert" @@ -122,8 +122,7 @@ func TestActivityPubPersonInboxNoteToDistant(t *testing.T) { localSession2 := loginUser(t, localUser2.LoginName) localSecssion2Token := getTokenForLoggedInUser(t, localSession2, auth_model.AccessTokenScopeWriteIssue) - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, localUser2, tests.DeclarativeRepoOptions{}) - defer f() + repo := forgery.CreateRepository(t, localUser2, nil) // follow (distant follows local) followActivity := fmt.Appendf(nil, diff --git a/tests/integration/api_issue_test.go b/tests/integration/api_issue_test.go index 7f601fa303..512ebf56e4 100644 --- a/tests/integration/api_issue_test.go +++ b/tests/integration/api_issue_test.go @@ -20,15 +20,14 @@ import ( "forgejo.org/models/unit" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" api "forgejo.org/modules/structs" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "xorm.io/xorm/convert" ) func TestAPIListIssues(t *testing.T) { @@ -752,35 +751,28 @@ func TestAPISearchIssuesAccessTokenResources(t *testing.T) { func TestAPIInternalAndExternalIssueTracker(t *testing.T) { defer tests.PrepareTestEnv(t)() - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - otherUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) + repoOptions := &forgery.CreateRepositoryOptions{ + Files: forgery.FilesInit{}, // some tests will fail with 404 if the repository is empty + } + user := forgery.CreateUser(t, &forgery.CreateUserOptions{ + IsAdmin: true, + }) + otherUser := forgery.CreateUser(t, nil) token := getUserToken(t, user.Name, auth_model.AccessTokenScopeAll) - internalIssueRepo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("internal-issues"), - EnabledUnits: optional.Some([]unit.Type{unit.TypeIssues}), - DisabledUnits: optional.Some([]unit.Type{unit.TypeExternalTracker}), - UnitConfig: optional.Some(map[unit.Type]convert.Conversion{ - unit.TypeIssues: &repo_model.IssuesConfig{ - EnableTimetracker: true, - EnableDependencies: true, - }, - }), + internalIssueRepo := forgery.CreateRepository(t, user, repoOptions) + forgery.DisableRepoUnits(t, internalIssueRepo, unit.TypeExternalTracker) + forgery.EnableRepoUnit(t, internalIssueRepo, unit.TypeIssues, &repo_model.IssuesConfig{ + EnableTimetracker: true, + EnableDependencies: true, }) - defer reset() - externalIssueRepo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("external-issues"), - EnabledUnits: optional.Some([]unit.Type{unit.TypeExternalTracker}), - DisabledUnits: optional.Some([]unit.Type{unit.TypeIssues}), - }) - defer reset() + externalIssueRepo := forgery.CreateRepository(t, user, repoOptions) + forgery.DisableRepoUnits(t, externalIssueRepo, unit.TypeIssues) + forgery.EnableRepoUnit(t, internalIssueRepo, unit.TypeExternalTracker, nil) - disabledIssueRepo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("disabled-issues"), - DisabledUnits: optional.Some([]unit.Type{unit.TypeIssues, unit.TypeExternalTracker}), - }) - defer reset() + disabledIssueRepo := forgery.CreateRepository(t, user, repoOptions) + forgery.DisableRepoUnits(t, disabledIssueRepo, unit.TypeIssues, unit.TypeExternalTracker) runTest := func(t *testing.T, repo *repo_model.Repository, requestAllowed bool) { t.Helper() @@ -937,15 +929,13 @@ func TestAPIIssueDependencyPermissions(t *testing.T) { actingUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 4}) token := getUserToken(t, actingUser.Name, auth_model.AccessTokenScopeAll) - actingUserRepo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, actingUser, tests.DeclarativeRepoOptions{}) - defer reset() + actingUserRepo := forgery.CreateRepository(t, actingUser, nil) actingUserIssue := createIssue(t, actingUser, actingUserRepo, "source issue", "some content") otherUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - otherUserRepo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, otherUser, tests.DeclarativeRepoOptions{ - IsPrivate: optional.Some(true), + otherUserRepo := forgery.CreateRepository(t, otherUser, &forgery.CreateRepositoryOptions{ + IsPrivate: true, }) - defer reset() otherUserIssue := createIssue(t, otherUser, otherUserRepo, "target issue", "some content") apiEndpoint := fmt.Sprintf("/api/v1/repos/%s/%s/issues/%d/dependencies", actingUserRepo.OwnerName, actingUserRepo.Name, actingUserIssue.Index) diff --git a/tests/integration/api_org_variables_test.go b/tests/integration/api_org_variables_test.go index 982c2f8fa5..0f0347f1fd 100644 --- a/tests/integration/api_org_variables_test.go +++ b/tests/integration/api_org_variables_test.go @@ -10,10 +10,9 @@ import ( actions_model "forgejo.org/models/actions" auth_model "forgejo.org/models/auth" - org_model "forgejo.org/models/organization" - "forgejo.org/models/unittest" api "forgejo.org/modules/structs" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -22,8 +21,9 @@ import ( func TestAPIOrgVariablesCreateOrganizationVariable(t *testing.T) { defer tests.PrepareTestEnv(t)() - org := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{Name: "org3"}) - session := loginUser(t, "user2") + owner := forgery.CreateUser(t, nil) + org := forgery.CreateOrganisation(t, owner) + session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) cases := []struct { @@ -98,8 +98,9 @@ func TestAPIOrgVariablesCreateOrganizationVariable(t *testing.T) { func TestAPIOrgVariablesUpdateOrganizationVariable(t *testing.T) { defer tests.PrepareTestEnv(t)() - org := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{Name: "org3"}) - session := loginUser(t, "user2") + owner := forgery.CreateUser(t, nil) + org := forgery.CreateOrganisation(t, owner) + session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) variableName := "test_update_var" @@ -194,10 +195,12 @@ func TestAPIOrgVariablesUpdateOrganizationVariable(t *testing.T) { func TestAPIOrgVariablesDeleteOrganizationVariable(t *testing.T) { defer tests.PrepareTestEnv(t)() - org := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{Name: "org3"}) + owner := forgery.CreateUser(t, nil) + org := forgery.CreateOrganisation(t, owner) + variable, err := actions_model.InsertVariable(t.Context(), org.ID, 0, "FORGEJO_FORBIDDEN", "illegal") require.NoError(t, err) - session := loginUser(t, "user2") + session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) variableName := "test_delete_var" @@ -226,8 +229,9 @@ func TestAPIOrgVariablesDeleteOrganizationVariable(t *testing.T) { func TestAPIOrgVariablesGetSingleOrganizationVariable(t *testing.T) { defer tests.PrepareTestEnv(t)() - org := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{Name: "org3"}) - session := loginUser(t, "user2") + owner := forgery.CreateUser(t, nil) + org := forgery.CreateOrganisation(t, owner) + session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) name := "some_variable" @@ -258,8 +262,9 @@ func TestAPIOrgVariablesGetSingleOrganizationVariable(t *testing.T) { func TestAPIOrgVariablesGetAllOrganizationVariables(t *testing.T) { defer tests.PrepareTestEnv(t)() - org := unittest.AssertExistsAndLoadBean(t, &org_model.Organization{Name: "org3"}) - session := loginUser(t, "user2") + owner := forgery.CreateUser(t, nil) + org := forgery.CreateOrganisation(t, owner) + session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteOrganization) variables := map[string]string{"second": "Dolor sit amet", "first": "Lorem ipsum"} diff --git a/tests/integration/api_private_serv_test.go b/tests/integration/api_private_serv_test.go index dd45f54c36..738925172c 100644 --- a/tests/integration/api_private_serv_test.go +++ b/tests/integration/api_private_serv_test.go @@ -17,7 +17,7 @@ import ( "forgejo.org/modules/private" "forgejo.org/modules/setting" "forgejo.org/modules/test" - "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -167,8 +167,7 @@ func TestAPIPrivateServAndNoServWithRequiredTwoFactor(t *testing.T) { runTest := func(t *testing.T, user *user_model.User, useTOTP, servAllowed bool) { t.Helper() - repo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{}) - defer reset() + repo := forgery.CreateRepository(t, user, nil) pubKey, err := asymkey_model.AddPublicKey(ctx, user.ID, "tmp-key-"+user.Name, "sk-ecdsa-sha2-nistp256@openssh.com AAAAInNrLWVjZHNhLXNoYTItbmlzdHAyNTZAb3BlbnNzaC5jb20AAAAIbmlzdHAyNTYAAABBBGXEEzWmm1dxb+57RoK5KVCL0w2eNv9cqJX2AGGVlkFsVDhOXHzsadS3LTK4VlEbbrDMJdoti9yM8vclA8IeRacAAAAEc3NoOg== nocomment", 0) require.NoError(t, err) diff --git a/tests/integration/api_push_mirror_test.go b/tests/integration/api_push_mirror_test.go index b31c5cc766..8abaa1b919 100644 --- a/tests/integration/api_push_mirror_test.go +++ b/tests/integration/api_push_mirror_test.go @@ -26,7 +26,6 @@ import ( "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" api "forgejo.org/modules/structs" "forgejo.org/modules/test" @@ -34,6 +33,7 @@ import ( mirror_service "forgejo.org/services/mirror" repo_service "forgejo.org/services/repository" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -313,12 +313,7 @@ func TestAPIPushMirrorSSH(t *testing.T) { assert.False(t, srcRepo.HasWiki()) session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) - pushToRepo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("push-mirror-test"), - AutoInit: optional.Some(false), - EnabledUnits: optional.Some([]unit.Type{unit.TypeCode}), - }) - defer f() + pushToRepo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{}) sshURL := fmt.Sprintf("ssh://%s@%s/%s.git", setting.SSH.User, net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)), pushToRepo.FullName()) diff --git a/tests/integration/api_quota_use_test.go b/tests/integration/api_quota_use_test.go index 1ca44cc17e..97d5cab6a2 100644 --- a/tests/integration/api_quota_use_test.go +++ b/tests/integration/api_quota_use_test.go @@ -22,7 +22,6 @@ import ( "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/migration" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" api "forgejo.org/modules/structs" "forgejo.org/modules/test" @@ -31,6 +30,7 @@ import ( "forgejo.org/services/forms" repo_service "forgejo.org/services/repository" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -281,9 +281,10 @@ func prepareQuotaEnv(t *testing.T, username string) *quotaEnv { env.cleanups = append(env.cleanups, userCleanup) // Create a repository - repo, _, repoCleanup := tests.CreateDeclarativeRepoWithOptions(t, env.User.User, tests.DeclarativeRepoOptions{}) + repo := forgery.CreateRepository(t, env.User.User, &forgery.CreateRepositoryOptions{ + Files: forgery.FilesInit{}, // some tests will fail with 404 if the repository is empty + }) env.Repo = repo - env.cleanups = append(env.cleanups, repoCleanup) return &env } @@ -476,10 +477,9 @@ func testAPIQuotaEnforcement(t *testing.T) { defer tests.PrintCurrentTest(t)() // Create a template repository - template, _, cleanup := tests.CreateDeclarativeRepoWithOptions(t, env.User.User, tests.DeclarativeRepoOptions{ - IsTemplate: optional.Some(true), + template := forgery.CreateRepository(t, env.User.User, &forgery.CreateRepositoryOptions{ + IsTemplate: true, }) - defer cleanup() // Drop the quota to 0 defer env.SetRuleLimit(t, "all", 0)() @@ -513,8 +513,7 @@ func testAPIQuotaEnforcement(t *testing.T) { t.Run("#/repos/{username}/{reponame}", func(t *testing.T) { // Lets create a new repo to play with. - repo, _, repoCleanup := tests.CreateDeclarativeRepoWithOptions(t, env.User.User, tests.DeclarativeRepoOptions{}) - defer repoCleanup() + repo := forgery.CreateRepository(t, env.User.User, nil) // Drop the quota to 0 defer env.SetRuleLimit(t, "all", 0)() @@ -1198,8 +1197,7 @@ func testAPIQuotaEnforcement(t *testing.T) { defer tests.PrintCurrentTest(t)() // Create a repository to transfer - repo, _, cleanup := tests.CreateDeclarativeRepoWithOptions(t, env.User.User, tests.DeclarativeRepoOptions{}) - defer cleanup() + repo := forgery.CreateRepository(t, env.User.User, nil) // Initiate repo transfer req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer", env.User.User.Name, repo.Name), api.TransferRepoOption{ @@ -1233,8 +1231,7 @@ func testAPIQuotaEnforcement(t *testing.T) { defer env.SetRuleLimit(t, "deny-all", -1)() // Create a repository to transfer - repo, _, cleanup := tests.CreateDeclarativeRepoWithOptions(t, env.User.User, tests.DeclarativeRepoOptions{}) - defer cleanup() + repo := forgery.CreateRepository(t, env.User.User, nil) // Initiate repo transfer req := NewRequestWithJSON(t, "POST", fmt.Sprintf("/api/v1/repos/%s/%s/transfer", env.User.User.Name, repo.Name), api.TransferRepoOption{ diff --git a/tests/integration/api_repo_activities_test.go b/tests/integration/api_repo_activities_test.go index 08e10ad79e..43e813ba83 100644 --- a/tests/integration/api_repo_activities_test.go +++ b/tests/integration/api_repo_activities_test.go @@ -9,10 +9,10 @@ import ( "testing" auth_model "forgejo.org/models/auth" - "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" api "forgejo.org/modules/structs" + notify_service "forgejo.org/services/notify" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" ) @@ -20,9 +20,9 @@ import ( func TestAPIRepoActivityFeeds(t *testing.T) { defer tests.PrepareTestEnv(t)() - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, owner, tests.DeclarativeRepoOptions{}) - defer f() + repo := forgery.CreateRepository(t, nil, nil) + owner := repo.Owner + notify_service.CreateRepository(t.Context(), owner, owner, repo) feedURL := fmt.Sprintf("/api/v1/repos/%s/activities/feeds", repo.FullName()) assertAndReturnActivities := func(t *testing.T, length int) []api.Activity { @@ -66,7 +66,7 @@ func TestAPIRepoActivityFeeds(t *testing.T) { t.Run("a new watcher, no new activities", func(t *testing.T) { defer tests.PrintCurrentTest(t)() - watcher := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + watcher := forgery.CreateUser(t, nil) watcherSession := loginUser(t, watcher.Name) watcherToken := getTokenForLoggedInUser(t, watcherSession, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeReadUser) diff --git a/tests/integration/api_wiki_test.go b/tests/integration/api_wiki_test.go index d1a4102060..9639621591 100644 --- a/tests/integration/api_wiki_test.go +++ b/tests/integration/api_wiki_test.go @@ -16,10 +16,10 @@ import ( unit_model "forgejo.org/models/unit" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" - "forgejo.org/modules/optional" api "forgejo.org/modules/structs" repo_service "forgejo.org/services/repository" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -342,11 +342,7 @@ func TestAPISetWikiGlobalEditability(t *testing.T) { token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) // Create a new repository for testing purposes - repo, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit_model.Type{ - unit_model.TypeCode, - unit_model.TypeWiki, - }, nil, nil) - defer f() + repo := forgery.CreateRepository(t, user, nil) urlStr := fmt.Sprintf("/api/v1/repos/%s", repo.FullName()) assertGlobalEditability := func(t *testing.T, editability bool) { @@ -433,11 +429,8 @@ func TestAPIListPageRevisions(t *testing.T) { func TestAPIWikiNonMasterBranch(t *testing.T) { onApplicationRun(t, func(t *testing.T, _ *url.URL) { - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - WikiBranch: optional.Some("main"), - }) - defer f() + repo := forgery.CreateRepository(t, nil, nil) + forgery.InitWiki(t, repo, "main") uris := []string{ "revisions/Home", diff --git a/tests/integration/compare_test.go b/tests/integration/compare_test.go index 070f7e1b20..57c31a0dca 100644 --- a/tests/integration/compare_test.go +++ b/tests/integration/compare_test.go @@ -15,13 +15,11 @@ import ( repo_model "forgejo.org/models/repo" unit_model "forgejo.org/models/unit" "forgejo.org/models/unittest" - user_model "forgejo.org/models/user" "forgejo.org/modules/gitrepo" - "forgejo.org/modules/optional" "forgejo.org/modules/test" repo_service "forgejo.org/services/repository" - files_service "forgejo.org/services/repository/files" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -343,22 +341,16 @@ func TestCompareCrossRepo(t *testing.T) { func TestCompareCodeExpand(t *testing.T) { onApplicationRun(t, func(t *testing.T, u *url.URL) { - owner := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - // Create a new repository, with a file that has many lines - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, owner, tests.DeclarativeRepoOptions{ - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: "docs.md", - ContentReader: strings.NewReader("01\n02\n03\n04\n05\n06\n07\n08\n09\n0a\n0b\n0c\n0d\n0e\n0f\n10\n11\n12\n12\n13\n14\n15\n16\n17\n18\n19\n1a\n1b\n1c\n1d\n1e\n1f\n20\n"), - }, - }), + repo := forgery.CreateRepository(t, nil, &forgery.CreateRepositoryOptions{ + Files: forgery.MapFS{ + "docs.md": forgery.MapFile("01\n02\n03\n04\n05\n06\n07\n08\n09\n0a\n0b\n0c\n0d\n0e\n0f\n10\n11\n12\n12\n13\n14\n15\n16\n17\n18\n19\n1a\n1b\n1c\n1d\n1e\n1f\n20\n"), + }, }) - defer f() + owner := repo.Owner // Fork the repository - forker := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) + forker := forgery.CreateUser(t, nil) session := loginUser(t, forker.Name) testRepoFork(t, session, owner.Name, repo.Name, forker.Name, repo.Name+"-copy") testCreateBranch(t, session, forker.Name, repo.Name+"-copy", "branch/main", "code-expand", http.StatusSeeOther) diff --git a/tests/integration/issue_test.go b/tests/integration/issue_test.go index c0ecf6b3bc..5285e83df6 100644 --- a/tests/integration/issue_test.go +++ b/tests/integration/issue_test.go @@ -26,16 +26,15 @@ import ( "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/indexer/issues" - "forgejo.org/modules/optional" "forgejo.org/modules/references" "forgejo.org/modules/setting" api "forgejo.org/modules/structs" "forgejo.org/modules/test" "forgejo.org/modules/translation" repo_service "forgejo.org/services/repository" - files_service "forgejo.org/services/repository/files" user_service "forgejo.org/services/user" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -489,8 +488,7 @@ func TestIssueDependencies(t *testing.T) { session := loginUser(t, owner.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteIssue) - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, owner, tests.DeclarativeRepoOptions{}) - defer f() + repo := forgery.CreateRepository(t, owner, nil) createIssue := func(t *testing.T, title string) api.Issue { t.Helper() @@ -1359,13 +1357,9 @@ func TestIssueForm(t *testing.T) { onApplicationRun(t, func(t *testing.T, u *url.URL) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user2.Name) - repo, _, f := tests.CreateDeclarativeRepo(t, user2, "", - []unit_model.Type{unit_model.TypeCode, unit_model.TypeIssues}, nil, - []*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: ".forgejo/issue_template/test.yaml", - ContentReader: strings.NewReader(`name: Test + repo := forgery.CreateRepository(t, user2, &forgery.CreateRepositoryOptions{ + Files: forgery.MapFS{ + ".forgejo/issue_template/test.yaml": forgery.MapFile(`name: Test about: Hello World body: - type: checkboxes @@ -1375,10 +1369,8 @@ body: options: - label: This is a label `), - }, }, - ) - defer f() + }) t.Run("Choose list", func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -1407,10 +1399,7 @@ body: func TestIssueUnsubscription(t *testing.T) { onApplicationRun(t, func(t *testing.T, u *url.URL) { user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - AutoInit: optional.Some(false), - }) - defer f() + repo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{}) session := loginUser(t, user.Name) issueURL := testNewIssue(t, session, user.Name, repo.Name, "Issue title", "Description") diff --git a/tests/integration/migrate_test.go b/tests/integration/migrate_test.go index 7d244ce60f..8f609a2bfe 100644 --- a/tests/integration/migrate_test.go +++ b/tests/integration/migrate_test.go @@ -20,13 +20,13 @@ import ( "forgejo.org/models/unit" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" "forgejo.org/modules/structs" "forgejo.org/modules/test" "forgejo.org/modules/translation" "forgejo.org/services/migrations" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -196,11 +196,9 @@ func TestMigrateWithWiki(t *testing.T) { defer test.MockVariableValue(&setting.AppVer, "1.16.0")() require.NoError(t, migrations.Init()) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - WikiBranch: optional.Some("obscure-name"), - }) - defer f() + repo := forgery.CreateRepository(t, nil, nil) + forgery.InitWiki(t, repo, "obscure-name") + user := repo.Owner session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository, auth_model.AccessTokenScopeReadMisc) diff --git a/tests/integration/mirror_pull_test.go b/tests/integration/mirror_pull_test.go index 9a520ae5a5..9b831f4beb 100644 --- a/tests/integration/mirror_pull_test.go +++ b/tests/integration/mirror_pull_test.go @@ -22,7 +22,6 @@ import ( "forgejo.org/modules/git" "forgejo.org/modules/gitrepo" "forgejo.org/modules/migration" - "forgejo.org/modules/optional" "forgejo.org/modules/process" "forgejo.org/modules/setting" "forgejo.org/modules/structs" @@ -34,6 +33,7 @@ import ( repo_service "forgejo.org/services/repository" files_service "forgejo.org/services/repository/files" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/google/uuid" @@ -183,19 +183,14 @@ func TestMirrorPull(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) // Create the source repository that will be mirrored. - sourceRepo, sourceRepoSha, cleanupSource := tests.CreateDeclarativeRepoWithOptions(t, user2, - tests.DeclarativeRepoOptions{ - IsPrivate: optional.Some(mc.privateSource), - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: "docs.md", - ContentReader: strings.NewReader("hello, world"), - }, - }), + var sourceRepoSha string + sourceRepo := forgery.CreateRepository(t, user2, &forgery.CreateRepositoryOptions{ + IsPrivate: mc.privateSource, + Files: forgery.MapFS{ + "docs.md": forgery.MapFile("hello, world"), }, - ) - defer cleanupSource() + LatestSha: &sourceRepoSha, + }) require.NotEmpty(t, sourceRepoSha) // Create pull mirror @@ -239,10 +234,7 @@ func TestMirrorPull(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - mirrorRepo, _, cleanupMirror := tests.CreateDeclarativeRepoWithOptions(t, user2, - tests.DeclarativeRepoOptions{}, - ) - defer cleanupMirror() + mirrorRepo := forgery.CreateRepository(t, user2, nil) // Write to the repo a config file that would have plausibly existed before EncryptedRemoteAddress was // introduced: @@ -343,8 +335,8 @@ func createPullMirrorViaWeb(t *testing.T, sourceRepo *repo_model.Repository, aut body := resp.Body.String() lastBody = body // Looking for the repo page to be fully populated indicating that the migration is complete: - // Check that the first commit message is present: - if !strings.Contains(body, "Initial commit") { + // Check that the committed file is present: + if !strings.Contains(body, "docs.md") { return false } // Check that the fork button is present: diff --git a/tests/integration/mirror_push_test.go b/tests/integration/mirror_push_test.go index 3f5a8223c8..95981c9ce6 100644 --- a/tests/integration/mirror_push_test.go +++ b/tests/integration/mirror_push_test.go @@ -21,12 +21,10 @@ import ( auth_model "forgejo.org/models/auth" "forgejo.org/models/db" repo_model "forgejo.org/models/repo" - "forgejo.org/models/unit" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" "forgejo.org/modules/gitrepo" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" api "forgejo.org/modules/structs" "forgejo.org/modules/test" @@ -37,6 +35,7 @@ import ( mirror_service "forgejo.org/services/mirror" repo_service "forgejo.org/services/repository" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -228,12 +227,7 @@ func TestSSHPushMirror(t *testing.T) { assert.False(t, srcRepo.HasWiki()) sess := loginUser(t, user.Name) - pushToRepo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("push-mirror-misc-test"), - AutoInit: optional.Some(false), - EnabledUnits: optional.Some([]unit.Type{unit.TypeCode}), - }) - defer f() + pushToRepo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{}) sshURL := fmt.Sprintf("ssh://%s@%s/%s.git", setting.SSH.User, net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)), pushToRepo.FullName()) t.Run("Mutual exclusive", func(t *testing.T) { @@ -286,12 +280,7 @@ func TestSSHPushMirror(t *testing.T) { testMirrorPush := func(t *testing.T, srcRepo *repo_model.Repository, expectedSHA string) { t.Helper() - pushToRepo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("push-mirror-test"), - AutoInit: optional.Some(false), - EnabledUnits: optional.Some([]unit.Type{unit.TypeCode}), - }) - defer f() + pushToRepo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{}) sshURL := fmt.Sprintf("ssh://%s@%s/%s.git", setting.SSH.User, net.JoinHostPort(setting.SSH.ListenHost, strconv.Itoa(setting.SSH.ListenPort)), pushToRepo.FullName()) var pushMirror *repo_model.PushMirror @@ -404,8 +393,7 @@ func TestPushMirrorBranchFilterWebUI(t *testing.T) { srcRepo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1}) sess := loginUser(t, user.Name) - mirrorRepo, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit.Type{unit.TypeCode}, nil, nil) - defer f() + mirrorRepo := forgery.CreateRepository(t, user, nil) ctx := NewAPITestContext(t, user.LowerName, srcRepo.Name, auth_model.AccessTokenScopeReadRepository) ctx.Session = sess @@ -595,12 +583,8 @@ func TestPushMirrorSettings(t *testing.T) { srcRepo2 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 3}) assert.False(t, srcRepo.HasWiki()) sess := loginUser(t, user.Name) - pushToRepo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some("push-mirror-test"), - AutoInit: optional.Some(false), - EnabledUnits: optional.Some([]unit.Type{unit.TypeCode}), - }) - defer f() + + pushToRepo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{}) t.Run("Adding", func(t *testing.T) { defer tests.PrintCurrentTest(t)() @@ -904,8 +888,7 @@ func TestPushMirrorWebUIToAPIIntegration(t *testing.T) { session := loginUser(t, user.Name) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeAll) - mirrorRepo, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit.Type{unit.TypeCode}, nil, nil) - defer f() + mirrorRepo := forgery.CreateRepository(t, user, nil) ctx := NewAPITestContext(t, user.LowerName, srcRepo.Name, auth_model.AccessTokenScopeReadRepository) ctx.Session = session @@ -941,8 +924,7 @@ func TestPushMirrorWebUIToAPIIntegration(t *testing.T) { defer tests.PrintCurrentTest(t)() // Create another mirror repo for this test - mirrorRepo2, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit.Type{unit.TypeCode}, nil, nil) - defer f() + mirrorRepo2 := forgery.CreateRepository(t, user, nil) remoteAddress2 := fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(user.Name), url.PathEscape(mirrorRepo2.Name)) // Create push mirror with empty branch filter via web UI @@ -967,8 +949,7 @@ func TestPushMirrorWebUIToAPIIntegration(t *testing.T) { defer tests.PrintCurrentTest(t)() // Create another mirror repo for this test - mirrorRepo3, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit.Type{unit.TypeCode}, nil, nil) - defer f() + mirrorRepo3 := forgery.CreateRepository(t, user, nil) remoteAddress3 := fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(user.Name), url.PathEscape(mirrorRepo3.Name)) // Create push mirror with complex branch filter via web UI @@ -994,8 +975,7 @@ func TestPushMirrorWebUIToAPIIntegration(t *testing.T) { defer tests.PrintCurrentTest(t)() // Create another mirror repo for this test - mirrorRepo4, _, f := tests.CreateDeclarativeRepo(t, user, "", []unit.Type{unit.TypeCode}, nil, nil) - defer f() + mirrorRepo4 := forgery.CreateRepository(t, user, nil) remoteAddress4 := fmt.Sprintf("%s%s/%s", u.String(), url.PathEscape(user.Name), url.PathEscape(mirrorRepo4.Name)) // First create a push mirror via API with initial branch filter diff --git a/tests/integration/patch_status_test.go b/tests/integration/patch_status_test.go index 9ada94bfc0..1acce03d6b 100644 --- a/tests/integration/patch_status_test.go +++ b/tests/integration/patch_status_test.go @@ -10,22 +10,19 @@ import ( "net/url" "os" "path/filepath" - "strings" "testing" "time" issues_model "forgejo.org/models/issues" repo_model "forgejo.org/models/repo" - unit_model "forgejo.org/models/unit" "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" - "forgejo.org/modules/optional" "forgejo.org/modules/test" pull_service "forgejo.org/services/pull" - files_service "forgejo.org/services/repository/files" shared_automerge "forgejo.org/services/shared/automerge" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -36,24 +33,17 @@ func TestPatchStatus(t *testing.T) { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) session := loginUser(t, user2.Name) - var objectFormat optional.Option[string] + var objectFormat git.ObjectFormat if git.SupportHashSha256 { - objectFormat = optional.Some("sha256") + objectFormat = git.Sha256ObjectFormat } - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user2, tests.DeclarativeRepoOptions{ - AutoInit: optional.Some(true), - EnabledUnits: optional.Some([]unit_model.Type{unit_model.TypeCode}), + repo := forgery.CreateRepository(t, user2, &forgery.CreateRepositoryOptions{ + Files: forgery.MapFS{ + ".spokeperson": forgery.MapFile("n0toose"), + }, ObjectFormat: objectFormat, - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: ".spokeperson", - ContentReader: strings.NewReader("n0toose"), - }, - }), }) - defer f() testAutomergeQueued := func(t *testing.T, pr *issues_model.PullRequest, expected issues_model.PullRequestStatus) { t.Helper() diff --git a/tests/integration/pull_review_test.go b/tests/integration/pull_review_test.go index 8c7b302c68..3c0f4344f1 100644 --- a/tests/integration/pull_review_test.go +++ b/tests/integration/pull_review_test.go @@ -38,6 +38,7 @@ import ( repo_service "forgejo.org/services/repository" files_service "forgejo.org/services/repository/files" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/google/uuid" @@ -1816,21 +1817,14 @@ func newPullRequestCommentPlacementTester(t *testing.T) *PullRequestCommentPlace content.WriteString(fmt.Sprintf("Line %d\n", i+1)) // +1 -> make "Line N" appear on the Nth line and avoid off-by-one confusions } - repo, initialSHA, reset := tests.CreateDeclarativeRepoWithOptions(t, user2, tests.DeclarativeRepoOptions{ - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: "file1.md", - ContentReader: strings.NewReader(content.String()), - }, - { - Operation: "create", - TreePath: "file2.md", - ContentReader: strings.NewReader(content.String()), - }, - }), + var initialSHA string + repo := forgery.CreateRepository(t, user2, &forgery.CreateRepositoryOptions{ + Files: forgery.MapFS{ + "file1.md": forgery.MapFile(content.String()), + "file2.md": forgery.MapFile(content.String()), + }, + LatestSha: &initialSHA, }) - t.Cleanup(reset) return &PullRequestCommentPlacementTester{ t: t, diff --git a/tests/integration/quota_use_test.go b/tests/integration/quota_use_test.go index dd5afd1aed..fb9619adee 100644 --- a/tests/integration/quota_use_test.go +++ b/tests/integration/quota_use_test.go @@ -19,7 +19,6 @@ import ( org_model "forgejo.org/models/organization" quota_model "forgejo.org/models/quota" repo_model "forgejo.org/models/repo" - "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" "forgejo.org/modules/setting" @@ -29,8 +28,8 @@ import ( app_context "forgejo.org/services/context" repo_service "forgejo.org/services/repository" "forgejo.org/tests" + "forgejo.org/tests/forgery" - gouuid "github.com/google/uuid" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1025,13 +1024,13 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv { user := quotaWebEnvUser{} // Create the user - userName := gouuid.NewString() - apiCreateUser(t, userName) - user.User = unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) - user.Session = loginUser(t, userName) + user.User = forgery.CreateUser(t, nil) + user.Session = loginUser(t, user.User.Name) // Create a repository for the user - repo, _, _ := tests.CreateDeclarativeRepoWithOptions(t, user.User, tests.DeclarativeRepoOptions{}) + repo := forgery.CreateRepository(t, user.User, &forgery.CreateRepositoryOptions{ + Files: forgery.FilesInit{}, + }) user.Repo = repo return user @@ -1072,25 +1071,21 @@ func createQuotaWebEnv(t *testing.T) *quotaWebEnv { org := quotaWebEnvOrg{} // Create the org - userName := gouuid.NewString() - org.Org = &org_model.Organization{ - Name: userName, - } - err := org_model.CreateOrganization(db.DefaultContext, org.Org, owner) - require.NoError(t, err) + org.Org = forgery.CreateOrganisation(t, owner) // Create a repository for the org - orgUser := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: org.Org.ID}) - repo, _, _ := tests.CreateDeclarativeRepoWithOptions(t, orgUser, tests.DeclarativeRepoOptions{}) + repo := forgery.CreateRepository(t, org.Org.AsUser(), &forgery.CreateRepositoryOptions{ + Files: forgery.FilesInit{}, + }) org.Repo = repo // Create a quota group for them - group, err := quota_model.CreateGroup(db.DefaultContext, userName) + group, err := quota_model.CreateGroup(db.DefaultContext, org.Org.Name) require.NoError(t, err) org.QuotaGroup = group // Create a rule - rule, err := quota_model.CreateRule(db.DefaultContext, userName, limit, quota_model.LimitSubjects{quota_model.LimitSubjectSizeAll}) + rule, err := quota_model.CreateRule(db.DefaultContext, org.Org.Name, limit, quota_model.LimitSubjects{quota_model.LimitSubjectSizeAll}) require.NoError(t, err) org.QuotaRule = rule diff --git a/tests/integration/repo_generate_test.go b/tests/integration/repo_generate_test.go index 637f0a478d..aec2a89719 100644 --- a/tests/integration/repo_generate_test.go +++ b/tests/integration/repo_generate_test.go @@ -17,12 +17,11 @@ import ( "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" "forgejo.org/modules/test" "forgejo.org/modules/translation" - files_service "forgejo.org/services/repository/files" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/stretchr/testify/assert" ) @@ -243,40 +242,27 @@ func TestRepoGenerateTemplating(t *testing.T) { expected := `# %s This is a Repo By %s ThisIsThe%sInAnInlineWay` - templateName := "my_template" - generatedName := "my_generated" - userName := "user1" - session := loginUser(t, userName) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) - - template, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some(templateName), - IsTemplate: optional.Some(true), - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: ".forgejo/template", - ContentReader: strings.NewReader("**/Readme.md"), - }, - { - Operation: "create", - TreePath: "dira-${REPO_NAME}/dirb-${REPO_NAME}/Readme.md", - ContentReader: strings.NewReader(input), - }, - }), + template := forgery.CreateRepository(t, nil, &forgery.CreateRepositoryOptions{ + IsTemplate: true, + Files: forgery.MapFS{ + ".forgejo/template": forgery.MapFile("**/Readme.md"), + "dira-${REPO_NAME}/dirb-${REPO_NAME}/Readme.md": forgery.MapFile(input), + }, }) - defer f() + user := template.Owner + session := loginUser(t, user.Name) // The repo.TemplateID field is not initialized. Luckily, the ID field holds the expected value templateID := strconv.FormatInt(template.ID, 10) + generatedName := "my_generated" testRepoGenerateSuccess( t, session, templateID, user.Name, - templateName, + template.Name, user, user, generatedName, @@ -310,9 +296,10 @@ func TestRepoGenerateTemplating(t *testing.T) { func TestRepoGenerateTemplatingSymlink(t *testing.T) { onApplicationRun(t, func(t *testing.T, u *url.URL) { - userName := "user1" - session := loginUser(t, userName) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) + user := forgery.CreateUser(t, &forgery.CreateUserOptions{ + IsAdmin: true, // required to see the detailed error message on the error response + }) + session := loginUser(t, user.Name) testCases := []struct { name string @@ -337,34 +324,18 @@ func TestRepoGenerateTemplatingSymlink(t *testing.T) { for i, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - templateName := fmt.Sprintf("my_template-%d", i) - generatedName := fmt.Sprintf("my_generated-%d", i) - template, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some(templateName), - IsTemplate: optional.Some(true), - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: ".forgejo/template", - ContentReader: strings.NewReader("**/Readme.md"), - }, - { - Operation: "create", - TreePath: "actual-contents.txt", - ContentReader: strings.NewReader("Here are some contents. $REPO_NAME"), - }, - { - Operation: "create", - TreePath: "problem/Readme.md", - ContentReader: strings.NewReader(tc.symlinkTarget), - Options: files_service.RepoFileOptionMode(git.EntryModeSymlink), - }, - }), + template := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{ + IsTemplate: true, + Files: forgery.MapFS{ + ".forgejo/template": forgery.MapFile("**/Readme.md"), + "actual-contents.txt": forgery.MapFile("Here are some contents. $REPO_NAME"), + "problem/Readme.md": forgery.MapSymlink(tc.symlinkTarget), + }, }) - defer f() // The repo.TemplateID field is not initialized. Luckily, the ID field holds the expected value templateID := strconv.FormatInt(template.ID, 10) + generatedName := fmt.Sprintf("my_generated-%d", i) if tc.expectedError != "" { resp := testRepoGenerateFailure( @@ -372,7 +343,7 @@ func TestRepoGenerateTemplatingSymlink(t *testing.T) { session, templateID, user.Name, - templateName, + template.Name, user, user, generatedName, @@ -384,7 +355,7 @@ func TestRepoGenerateTemplatingSymlink(t *testing.T) { session, templateID, user.Name, - templateName, + template.Name, user, user, generatedName, @@ -419,36 +390,28 @@ func TestRepoGenerateTemplatingSymlink(t *testing.T) { func TestRepoGenerateTemplatingSymlinkGlobFile(t *testing.T) { onApplicationRun(t, func(t *testing.T, u *url.URL) { - templateName := "my_template" - generatedName := "my_generated" - - userName := "user1" - session := loginUser(t, userName) - user := unittest.AssertExistsAndLoadBean(t, &user_model.User{Name: userName}) - - template, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some(templateName), - IsTemplate: optional.Some(true), - Files: optional.Some([]*files_service.ChangeRepoFile{ - { - Operation: "create", - TreePath: ".forgejo/template", - ContentReader: strings.NewReader("/etc/passwd"), - Options: files_service.RepoFileOptionMode(git.EntryModeSymlink), - }, - }), + user := forgery.CreateUser(t, &forgery.CreateUserOptions{ + IsAdmin: true, // required to see the detailed error message on the error response + }) + session := loginUser(t, user.Name) + + template := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{ + IsTemplate: true, + Files: forgery.MapFS{ + ".forgejo/template": forgery.MapSymlink("/etc/passwd"), + }, }) - defer f() // The repo.TemplateID field is not initialized. Luckily, the ID field holds the expected value templateID := strconv.FormatInt(template.ID, 10) + generatedName := "my_generated" resp := testRepoGenerateFailure( t, session, templateID, user.Name, - templateName, + template.Name, user, user, generatedName, diff --git a/tests/integration/repo_test.go b/tests/integration/repo_test.go index 299299ff0b..16dc7cd483 100644 --- a/tests/integration/repo_test.go +++ b/tests/integration/repo_test.go @@ -24,7 +24,6 @@ import ( "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" - "forgejo.org/modules/optional" "forgejo.org/modules/setting" api "forgejo.org/modules/structs" "forgejo.org/modules/test" @@ -32,6 +31,7 @@ import ( repo_service "forgejo.org/services/repository" files_service "forgejo.org/services/repository/files" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/stretchr/testify/assert" @@ -1369,21 +1369,17 @@ func TestInitInstructions(t *testing.T) { forEachObjectFormat(t, func(t *testing.T, objectFormat git.ObjectFormat) { defer tests.PrintCurrentTest(t)() - name := objectFormat.Name() + var init string - if name == "sha1" { + if objectFormat == git.Sha1ObjectFormat { init = "git init" } else { - init = fmt.Sprintf("git init --object-format=%s", name) + init = fmt.Sprintf("git init --object-format=%s", objectFormat.Name()) } - repo, _, f := tests.CreateDeclarativeRepoWithOptions(t, user, tests.DeclarativeRepoOptions{ - Name: optional.Some(name + "-instruction"), - AutoInit: optional.Some(false), - EnabledUnits: optional.Some([]unit_model.Type{unit_model.TypeCode}), - ObjectFormat: optional.Some(name), + repo := forgery.CreateRepository(t, user, &forgery.CreateRepositoryOptions{ + ObjectFormat: objectFormat, }) - defer f() portMatcher := regexp.MustCompile(`localhost:\d+`) resp := session.MakeRequest(t, NewRequest(t, "GET", "/"+repo.FullName()), http.StatusOK) @@ -1394,7 +1390,7 @@ func TestInitInstructions(t *testing.T) { git switch -c main git add README.md git commit -m "first commit" -git remote add origin http://localhost/user2/%s-instruction.git -git push -u origin main`, init, name), portMatcher.ReplaceAllString(htmlDoc.Find(".empty-repo-guide code").First().Text(), "localhost")) +git remote add origin http://localhost/user2/%s.git +git push -u origin main`, init, repo.Name), portMatcher.ReplaceAllString(htmlDoc.Find(".empty-repo-guide code").First().Text(), "localhost")) }) } diff --git a/tests/integration/wiki_test.go b/tests/integration/wiki_test.go index 1fd9378852..efccd20ef8 100644 --- a/tests/integration/wiki_test.go +++ b/tests/integration/wiki_test.go @@ -20,10 +20,10 @@ import ( "forgejo.org/models/unittest" user_model "forgejo.org/models/user" "forgejo.org/modules/git" - "forgejo.org/modules/optional" api "forgejo.org/modules/structs" "forgejo.org/modules/util" "forgejo.org/tests" + "forgejo.org/tests/forgery" "github.com/PuerkitoBio/goquery" "github.com/google/uuid" @@ -95,11 +95,10 @@ func doRepoWikiGitOperation(t *testing.T, serverURL *url.URL, method RepoWikiMet repo := "repo1" if target == RepoWikiPrivate { user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2}) - privateRepo, _, reset := tests.CreateDeclarativeRepoWithOptions(t, user2, tests.DeclarativeRepoOptions{ - IsPrivate: optional.Some(true), - EnabledUnits: optional.Some([]unit_model.Type{unit_model.TypeWiki}), + privateRepo := forgery.CreateRepository(t, user2, &forgery.CreateRepositoryOptions{ + IsPrivate: true, }) - defer reset() + forgery.EnableRepoUnit(t, privateRepo, unit_model.TypeWiki, nil) session := loginUser(t, user2.LoginName) token := getTokenForLoggedInUser(t, session, auth_model.AccessTokenScopeWriteRepository) diff --git a/tests/test_utils.go b/tests/test_utils.go index 5e5b04c860..8314e8c58a 100644 --- a/tests/test_utils.go +++ b/tests/test_utils.go @@ -15,10 +15,10 @@ import ( "path" "path/filepath" "runtime" - "slices" "strings" "sync/atomic" "testing" + "testing/fstest" "time" "forgejo.org/models/db" @@ -29,10 +29,9 @@ import ( user_model "forgejo.org/models/user" "forgejo.org/modules/base" "forgejo.org/modules/git" - "forgejo.org/modules/gitrepo" "forgejo.org/modules/graceful" "forgejo.org/modules/log" - "forgejo.org/modules/optional" + "forgejo.org/modules/options" "forgejo.org/modules/process" repo_module "forgejo.org/modules/repository" "forgejo.org/modules/setting" @@ -40,12 +39,10 @@ import ( "forgejo.org/modules/testlogger" "forgejo.org/modules/util" "forgejo.org/routers" - repo_service "forgejo.org/services/repository" + "forgejo.org/services/notify" files_service "forgejo.org/services/repository/files" - wiki_service "forgejo.org/services/wiki" + "forgejo.org/tests/forgery" - "github.com/google/uuid" - "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "xorm.io/xorm/convert" @@ -386,169 +383,74 @@ func Printf(format string, args ...any) { testlogger.Printf(format, args...) } -type DeclarativeRepoOptions struct { - Name optional.Option[string] - EnabledUnits optional.Option[[]unit_model.Type] - DisabledUnits optional.Option[[]unit_model.Type] - UnitConfig optional.Option[map[unit_model.Type]convert.Conversion] - Files optional.Option[[]*files_service.ChangeRepoFile] - WikiBranch optional.Option[string] - AutoInit optional.Option[bool] - IsTemplate optional.Option[bool] - ObjectFormat optional.Option[string] - IsPrivate optional.Option[bool] -} - -func CreateDeclarativeRepoWithOptions(t *testing.T, owner *user_model.User, opts DeclarativeRepoOptions) (*repo_model.Repository, string, func()) { - t.Helper() - - // Not using opts.Name.ValueOrDefault() here to avoid unnecessarily - // generating an UUID when a name is specified. - var repoName string - if has, value := opts.Name.Get(); has { - repoName = value - } else { - repoName = uuid.NewString() - } - - var autoInit bool - if has, value := opts.AutoInit.Get(); has { - autoInit = value - } else { - autoInit = true - } - - // Create the repository - repo, err := repo_service.CreateRepository(db.DefaultContext, owner, owner, repo_service.CreateRepoOptions{ - Name: repoName, - Description: "Temporary Repo", - AutoInit: autoInit, - Gitignores: "", - License: "WTFPL", - Readme: "Default", - DefaultBranch: "main", - IsTemplate: opts.IsTemplate.ValueOrZeroValue(), - ObjectFormatName: opts.ObjectFormat.ValueOrZeroValue(), - IsPrivate: opts.IsPrivate.ValueOrZeroValue(), - }) - require.NoError(t, err) - assert.NotEmpty(t, repo) - - // Populate `enabledUnits` if we have any enabled. - var enabledUnits []repo_model.RepoUnit - if has, units := opts.EnabledUnits.Get(); has { - enabledUnits = make([]repo_model.RepoUnit, len(units)) - - for i, unitType := range units { - var config convert.Conversion - if cfg, ok := opts.UnitConfig.ValueOrZeroValue()[unitType]; ok { - config = cfg - } - enabledUnits[i] = repo_model.RepoUnit{ - RepoID: repo.ID, - Type: unitType, - Config: config, - } - } - } - - // Adjust the repo units according to our parameters. - if opts.EnabledUnits.Has() || opts.DisabledUnits.Has() { - err := repo_service.UpdateRepositoryUnits(db.DefaultContext, repo, enabledUnits, opts.DisabledUnits.ValueOrDefault(nil)) - require.NoError(t, err) - } - - // Add files, if any. - var sha string - if has, files := opts.Files.Get(); has { - assert.True(t, autoInit, "Files cannot be specified if AutoInit is disabled") - - commitID, err := gitrepo.GetBranchCommitID(git.DefaultContext, repo, "main") - require.NoError(t, err) - - resp, err := files_service.ChangeRepoFiles(git.DefaultContext, repo, owner, &files_service.ChangeRepoFilesOptions{ - Files: files, - Message: "add files", - OldBranch: "main", - NewBranch: "main", - Author: &files_service.IdentityOptions{ - Name: owner.Name, - Email: owner.Email, - }, - Committer: &files_service.IdentityOptions{ - Name: owner.Name, - Email: owner.Email, - }, - Dates: &files_service.CommitDateOptions{ - Author: time.Now(), - Committer: time.Now(), - }, - LastCommitID: commitID, - }) - require.NoError(t, err) - assert.NotEmpty(t, resp) - - sha = resp.Commit.SHA - } - - // If there's a Wiki branch specified, create a wiki, and a default wiki page. - if has, value := opts.WikiBranch.Get(); has { - // Set the wiki branch in the database first - repo.WikiBranch = value - err := repo_model.UpdateRepositoryCols(db.DefaultContext, repo, "wiki_branch") - require.NoError(t, err) - - // Initialize the wiki - err = wiki_service.InitWiki(db.DefaultContext, repo) - require.NoError(t, err) - - // Add a new wiki page - err = wiki_service.AddWikiPage(db.DefaultContext, owner, repo, "Home", "Welcome to the wiki!", "Add a Home page") - require.NoError(t, err) - } - - // Return the repo, the top commit, and a defer-able function to delete the - // repo. - return repo, sha, func() { - _ = repo_service.DeleteRepository(db.DefaultContext, owner, repo, false) - } -} - +// Deprecated: use forgery.CreateRepository instead func CreateDeclarativeRepo(t *testing.T, owner *user_model.User, name string, enabledUnits, disabledUnits []unit_model.Type, files []*files_service.ChangeRepoFile) (*repo_model.Repository, string, func()) { t.Helper() - var opts DeclarativeRepoOptions - - if name != "" { - opts.Name = optional.Some(name) + opts := &forgery.CreateRepositoryOptions{ + LatestSha: new(string), + Name: name, } - if enabledUnits != nil { - opts.EnabledUnits = optional.Some(enabledUnits) - if slices.Contains(enabledUnits, unit_model.TypePullRequests) { - opts.UnitConfig = optional.Some(map[unit_model.Type]convert.Conversion{ - unit_model.TypePullRequests: &repo_model.PullRequestsConfig{ - AllowMerge: true, - AllowRebase: true, - AllowRebaseMerge: true, - AllowSquash: true, - AllowFastForwardOnly: true, - AllowManualMerge: true, - AllowRebaseUpdate: true, - DefaultMergeStyle: repo_model.MergeStyleMerge, - DefaultUpdateStyle: repo_model.UpdateStyleMerge, - }, - }) + if len(files) > 0 { + licenseData, err := options.License("CC0-1.0") + require.NoError(t, err) + mfs := forgery.MapFS{ + "README.md": forgery.MapFile("# " + t.Name() + "\n\nThis is a test repo created via test_utils"), + "LICENSE": &fstest.MapFile{Data: licenseData}, } + for _, f := range files { + require.Empty(t, f.FromTreePath, f.TreePath) + if f.Operation != "create" { + require.Equal(t, "README.md", f.TreePath, "%q operation only expected on README.md", f.Operation) + if f.Operation == "delete" { + delete(mfs, f.TreePath) + continue + } + require.Equal(t, "update", f.Operation, "only update/delete operations are supported on README.md") + } + if f.SHA != "" { + require.Nil(t, f.ContentReader, f.TreePath) + mfs[f.TreePath] = forgery.MapSubmodule(f.SHA) + } else { + require.Nil(t, f.Options, f.TreePath) + + data, err := io.ReadAll(f.ContentReader) + require.NoError(t, err) + mfs[f.TreePath] = &fstest.MapFile{ + Data: data, + } + } + } + opts.Files = mfs + } else { + opts.Files = forgery.FilesInit{} + } + + repo := forgery.CreateRepository(t, owner, opts) + notify.CreateRepository(t.Context(), owner, owner, repo) // CreateDeclarativeRepoWithOptions didn't call CreateRepositoryDirectly; notify manually to keep the same behavior + + for _, unitType := range enabledUnits { + var config convert.Conversion + if unitType == unit_model.TypePullRequests { + config = &repo_model.PullRequestsConfig{ + AllowMerge: true, + AllowRebase: true, + AllowRebaseMerge: true, + AllowSquash: true, + AllowFastForwardOnly: true, + AllowManualMerge: true, + AllowRebaseUpdate: true, + DefaultMergeStyle: repo_model.MergeStyleMerge, + DefaultUpdateStyle: repo_model.UpdateStyleMerge, + } + } + forgery.EnableRepoUnit(t, repo, unitType, config) } if disabledUnits != nil { - opts.DisabledUnits = optional.Some(disabledUnits) + forgery.DisableRepoUnits(t, repo, disabledUnits...) } - if files != nil { - opts.Files = optional.Some(files) - } - - return CreateDeclarativeRepoWithOptions(t, owner, opts) + return repo, *opts.LatestSha, func() {} } func WriteImageBody(t *testing.T, buff bytes.Buffer, filename string, body *bytes.Buffer) string {