tests: better factory with forgery package (#11356)

### Context

Following the feedback in forgejo/discussions#170 (and my ambitious attempt in forgejo/forgejo#10985), it appears that having an easy-to-use factory package would greatly help get rid of the global fixtures.

I think that the global fixtures are quite harmful (recent example: https://codeberg.org/forgejo/forgejo/pulls/9906#issuecomment-10826066):
- hard to write (contributor must know where to add them)
- hard to change (may break some unrelated tests)
- hard to review (not located near the test code)
- they require the tests to execute sequentially

### Proposed way forward

The `forgery` package (the name represents faking/crafting and sounds good with Forgejo) is meant to replace global yaml fixtures with local go factories. The forgery can currently:
- create users
- create repos
- create organisations

This allowed me to drop `CreateDeclarativeRepoWithOptions` (and deprecate `CreateDeclarativeRepo`).

I think that further changes should be delayed to other PRs (I have a local branch to create `Project`)

### Documentation

- [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change.
- [x] I did not document these changes and I do not expect someone else to do it.

### Release notes

- [ ] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change.
- [x] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change.

*The decision if the pull request will be shown in the release notes is up to the mergers / release team.*

The content of the `release-notes/<pull request number>.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11356
Reviewed-by: limiting-factor <limiting-factor@noreply.codeberg.org>
This commit is contained in:
oliverpool 2026-05-12 20:57:02 +02:00 committed by Mathieu Fenniak
commit 88ba174119
27 changed files with 675 additions and 604 deletions

View file

@ -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
})

View file

@ -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 {

View file

@ -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 {

112
tests/forgery/fs.go Normal file
View file

@ -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)
}

138
tests/forgery/repo.go Normal file
View file

@ -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)
}

66
tests/forgery/user.go Normal file
View file

@ -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
}

View file

@ -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)

View file

@ -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,

View file

@ -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)

View file

@ -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"}

View file

@ -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)

View file

@ -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())

View file

@ -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{

View file

@ -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)

View file

@ -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",

View file

@ -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)

View file

@ -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")

View file

@ -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)

View file

@ -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:

View file

@ -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

View file

@ -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()

View file

@ -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,

View file

@ -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

View file

@ -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,

View file

@ -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"))
})
}

View file

@ -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)

View file

@ -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 {