chore(refactor): run routers/api/v1/permissions/tests from tests/integration (#13157)

Changing the tests introduced in [this pull request](https://codeberg.org/forgejo/forgejo/pulls/12512) to run from the integration directory instead of running from a package, makes it possible to backport to v15.

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/13157
Reviewed-by: Mathieu Fenniak <mfenniak@noreply.codeberg.org>
This commit is contained in:
limiting-factor 2026-06-21 21:43:57 +02:00 committed by Mathieu Fenniak
commit 65e35d2ba0
44 changed files with 202 additions and 207 deletions

View file

@ -262,7 +262,7 @@ forgejo.org/routers/api/v1/permissions
Permissions.String
Permissions.Strings
forgejo.org/routers/api/v1/permissions/tests
forgejo.org/routers/api/v1/permissions/testhelpers
GetSignatureStringToSignature
GetUniquePermissionsSequences
GetShortestPermissionSequenceForEachSignature

View file

@ -156,6 +156,14 @@ linters:
- unparam
- nilnil
path: _test\.go
- linters:
- dupl
- errcheck
- gocyclo
- gosec
- staticcheck
- unparam
path: routers/api/v1/permissions/tests
- linters:
- dupl
- errcheck

View file

@ -9,7 +9,7 @@ import (
"forgejo.org/modules/setting"
"forgejo.org/modules/web/middleware"
apiv1_permissions_tests "forgejo.org/routers/api/v1/permissions/tests"
apiv1_permissions_testhelpers "forgejo.org/routers/api/v1/permissions/testhelpers"
"code.forgejo.org/go-chi/binding"
"github.com/go-chi/chi/v5"
@ -46,7 +46,7 @@ type Route struct {
// NewRoute creates a new route
func NewRoute() *Route {
if setting.IsInTesting {
apiv1_permissions_tests.Reset()
apiv1_permissions_testhelpers.Reset()
}
r := chi.NewRouter()
return &Route{R: r}
@ -68,7 +68,7 @@ func (r *Route) Group(pattern string, fn func(), middlewares ...any) {
r.curGroupPrefix += pattern
r.curMiddlewares = append(r.curMiddlewares, middlewares...)
if setting.IsInTesting {
defer apiv1_permissions_tests.RestorePermissionsSequence()()
defer apiv1_permissions_testhelpers.RestorePermissionsSequence()()
}
fn()
@ -114,8 +114,8 @@ func (r *Route) wrapMiddlewareAndHandler(h []any) ([]func(http.Handler) http.Han
func (r *Route) Methods(methods, pattern string, h ...any) {
middlewares, handlerFunc := r.wrapMiddlewareAndHandler(h)
if setting.IsInTesting {
apiv1_permissions_tests.CollectPermissionsMiddlewares(h[len(h)-1], methods, r.getPattern(pattern))
apiv1_permissions_tests.RestoreLastPermissionsSequence()
apiv1_permissions_testhelpers.CollectPermissionsMiddlewares(h[len(h)-1], methods, r.getPattern(pattern))
apiv1_permissions_testhelpers.RestoreLastPermissionsSequence()
}
fullPattern := r.getPattern(pattern)
if strings.Contains(methods, ",") {
@ -183,7 +183,7 @@ func (r *Route) NotFound(h ...any) {
// Combo delegates requests to Combo
func (r *Route) Combo(pattern string, h ...any) *Combo {
return &Combo{r, pattern, h, apiv1_permissions_tests.GetSignatures()}
return &Combo{r, pattern, h, apiv1_permissions_testhelpers.GetSignatures()}
}
// Combo represents a tiny group routes with same pattern
@ -192,40 +192,40 @@ type Combo struct {
pattern string
h []any
permissionsSequence apiv1_permissions_tests.Sequence
permissionsSequence apiv1_permissions_testhelpers.Sequence
}
// Get delegates Get method
func (c *Combo) Get(h ...any) *Combo {
c.r.Get(c.pattern, append(c.h, h...)...)
apiv1_permissions_tests.SetSignatures(c.permissionsSequence)
apiv1_permissions_testhelpers.SetSignatures(c.permissionsSequence)
return c
}
// Post delegates Post method
func (c *Combo) Post(h ...any) *Combo {
c.r.Post(c.pattern, append(c.h, h...)...)
apiv1_permissions_tests.SetSignatures(c.permissionsSequence)
apiv1_permissions_testhelpers.SetSignatures(c.permissionsSequence)
return c
}
// Delete delegates Delete method
func (c *Combo) Delete(h ...any) *Combo {
c.r.Delete(c.pattern, append(c.h, h...)...)
apiv1_permissions_tests.SetSignatures(c.permissionsSequence)
apiv1_permissions_testhelpers.SetSignatures(c.permissionsSequence)
return c
}
// Put delegates Put method
func (c *Combo) Put(h ...any) *Combo {
c.r.Put(c.pattern, append(c.h, h...)...)
apiv1_permissions_tests.SetSignatures(c.permissionsSequence)
apiv1_permissions_testhelpers.SetSignatures(c.permissionsSequence)
return c
}
// Patch delegates Patch method
func (c *Combo) Patch(h ...any) *Combo {
c.r.Patch(c.pattern, append(c.h, h...)...)
apiv1_permissions_tests.SetSignatures(c.permissionsSequence)
apiv1_permissions_testhelpers.SetSignatures(c.permissionsSequence)
return c
}

View file

@ -12,7 +12,7 @@ import (
"forgejo.org/modules/log"
"forgejo.org/modules/setting"
apiv1_permissions "forgejo.org/routers/api/v1/permissions"
apiv1_permissions_tests "forgejo.org/routers/api/v1/permissions/tests"
apiv1_permissions_testhelpers "forgejo.org/routers/api/v1/permissions/testhelpers"
"forgejo.org/routers/common"
"forgejo.org/services/auth"
auth_method "forgejo.org/services/auth/method"
@ -99,7 +99,7 @@ func apiAuthentication(authMethod auth.Method) func(*context.APIContext) {
}
func apiAuthorization() func(ctx *context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.APIAuthorization)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.APIAuthorization)
return func(ctx *context.APIContext) {
apiv1_permissions.APIAuthorization(ctx)
}

View file

@ -79,7 +79,7 @@ import (
"forgejo.org/routers/api/v1/org"
"forgejo.org/routers/api/v1/packages"
apiv1_permissions "forgejo.org/routers/api/v1/permissions"
apiv1_permissions_tests "forgejo.org/routers/api/v1/permissions/tests"
apiv1_permissions_testhelpers "forgejo.org/routers/api/v1/permissions/testhelpers"
"forgejo.org/routers/api/v1/repo"
"forgejo.org/routers/api/v1/settings"
"forgejo.org/routers/api/v1/user"
@ -125,7 +125,7 @@ func sudo() func(ctx *context.APIContext) {
}
func repoAssignment(ctx *context.APIContext) {
apiv1_permissions_tests.FollowedBy(repoAssignment, apiv1_permissions.RepoAccess)
apiv1_permissions_testhelpers.FollowedBy(repoAssignment, apiv1_permissions.RepoAccess)
userName := ctx.Params("username")
repoName := ctx.Params("reponame")
@ -184,7 +184,7 @@ func repoAccess() func(ctx *context.APIContext) {
}
func checkPermission(check func(ctx apiv1_permissions.Context)) func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(check)
apiv1_permissions_testhelpers.RecordSignature(check)
return func(ctx *context.APIContext) {
check(ctx)
}
@ -192,7 +192,7 @@ func checkPermission(check func(ctx apiv1_permissions.Context)) func(*context.AP
// must be used within a group with a call to commentAssignment() to set ctx.Comment
func reqValidCommentID() func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqValidCommentID)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqValidCommentID)
return func(ctx *context.APIContext) {
if ctx.Comment == nil {
panic("reqValidCommentID requires commentAssignment to be called first")
@ -203,7 +203,7 @@ func reqValidCommentID() func(*context.APIContext) {
// must be used within a group with a call to repoAssignment() to set ctx.Repo
func commentAssignment(idParam string) func(ctx *context.APIContext) {
apiv1_permissions_tests.FollowedBy(commentAssignment, apiv1_permissions.ReqValidCommentID)
apiv1_permissions_testhelpers.FollowedBy(commentAssignment, apiv1_permissions.ReqValidCommentID)
return func(ctx *context.APIContext) {
comment, err := issues_model.GetCommentByID(ctx, ctx.ParamsInt64(idParam))
if err != nil {
@ -227,14 +227,14 @@ func commentAssignment(idParam string) func(ctx *context.APIContext) {
}
func reqPackageAccess(accessMode perm.AccessMode) func(ctx *context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqPackageAccess, accessMode)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqPackageAccess, accessMode)
return func(ctx *context.APIContext) {
apiv1_permissions.ReqPackageAccess(ctx, accessMode)
}
}
func checkTokenPublicOnly() func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.CheckTokenPublicOnly)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.CheckTokenPublicOnly)
return func(ctx *context.APIContext) {
var packageOwner *user_model.User
if ctx.Package != nil {
@ -260,7 +260,7 @@ func requiredScopeLevel(ctx *context.APIContext) auth_model.AccessTokenScopeLeve
}
func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeCategory) func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.TokenRequiresScopes, requiredScopeCategories)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.TokenRequiresScopes, requiredScopeCategories)
return func(ctx *context.APIContext) {
apiv1_permissions.TokenRequiresScopes(ctx, requiredScopeCategories, requiredScopeLevel(ctx))
}
@ -269,7 +269,7 @@ func tokenRequiresScopes(requiredScopeCategories ...auth_model.AccessTokenScopeC
// Middleware that dynamically checks either the organization or user scope, depending on the owner type of the
// repository (requires `repoAssignment()` middleware to be used before this).
func tokenRequiresRepoOwnerScope() func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.TokenRequiresRepoOwnerScope)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.TokenRequiresRepoOwnerScope)
return func(ctx *context.APIContext) {
apiv1_permissions.TokenRequiresRepoOwnerScope(ctx, ctx.Repo.Owner, requiredScopeLevel(ctx))
}
@ -299,7 +299,7 @@ func reqSiteAdmin() func(ctx *context.APIContext) {
// reqOwner requires that the current user is either the owner of the repository or an administrator. If one or more
// unitTypes are given, it also requires that at least one the respective unitTypes is enabled.
func reqOwner(unitTypes ...unit.Type) func(ctx *context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqOwner, unitTypes)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqOwner, unitTypes)
return func(ctx *context.APIContext) {
apiv1_permissions.ReqOwner(ctx, unitTypes)
}
@ -313,7 +313,7 @@ func reqSelfOrAdmin() func(ctx *context.APIContext) {
// reqAdmin user should be an owner or a collaborator with admin write of a repository, or site admin. If one or more
// unitTypes are given, it also requires that at least one the respective unitTypes is enabled.
func reqAdmin(unitTypes ...unit.Type) func(ctx *context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqAdmin, unitTypes)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqAdmin, unitTypes)
return func(ctx *context.APIContext) {
apiv1_permissions.ReqAdmin(ctx, unitTypes)
}
@ -322,7 +322,7 @@ func reqAdmin(unitTypes ...unit.Type) func(ctx *context.APIContext) {
// reqRepoWriter requires that the current user has permission to write to a repository or that it is an administrator.
// One or more unitTypes have to be specified, and at least one of them has to be enabled.
func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqRepoWriter, unitTypes)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqRepoWriter, unitTypes)
return func(ctx *context.APIContext) {
apiv1_permissions.ReqRepoWriter(ctx, unitTypes)
}
@ -330,7 +330,7 @@ func reqRepoWriter(unitTypes ...unit.Type) func(ctx *context.APIContext) {
// reqRepoBranchWriter user should have a permission to write to a branch, or be a site admin
func reqRepoBranchWriter() func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqRepoBranchWriter)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqRepoBranchWriter)
return func(ctx *context.APIContext) {
options, ok := web.GetForm(ctx).(api.FileOptionInterface)
if !ok {
@ -343,7 +343,7 @@ func reqRepoBranchWriter() func(*context.APIContext) {
// reqRepoReader user should have specific read permission or be a repo admin or a site admin
func reqRepoReader(unitType unit.Type) func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.ReqRepoReader, unitType)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.ReqRepoReader, unitType)
return func(ctx *context.APIContext) {
apiv1_permissions.ReqRepoReader(ctx, unitType)
}
@ -431,7 +431,7 @@ func mustAllowPulls() func(ctx *context.APIContext) {
}
func mustEnableLocalIssuesIfIsIssue() func(*context.APIContext) {
apiv1_permissions_tests.RecordSignature(apiv1_permissions.MustEnableLocalIssuesIfIsIssue)
apiv1_permissions_testhelpers.RecordSignature(apiv1_permissions.MustEnableLocalIssuesIfIsIssue)
return func(ctx *context.APIContext) {
apiv1_permissions.MustEnableLocalIssuesIfIsIssue(ctx, ctx.ParamsInt64(":index"))
}

View file

@ -232,7 +232,7 @@ func SignatureToString(signature []any) string {
for _, arg := range signature[1:] {
switch typedArg := arg.(type) {
case []auth_model.AccessTokenScopeCategory:
argStrings = append(argStrings, " "+requiredScopesToString(typedArg...))
argStrings = append(argStrings, " "+RequiredScopesToString(typedArg...))
case []unit.Type:
slices.Sort(typedArg)
for _, unitType := range typedArg {
@ -295,3 +295,33 @@ func GetShortestPermissionSequenceForEachSignature() [][][]any {
})
return sequences
}
func RequiredScopesToString(scopeCategories ...auth_model.AccessTokenScopeCategory) string {
var categories []string
for _, category := range scopeCategories {
switch category {
case auth_model.AccessTokenScopeCategoryActivityPub:
categories = append(categories, "ActivityPub")
case auth_model.AccessTokenScopeCategoryAdmin:
categories = append(categories, "Admin")
case auth_model.AccessTokenScopeCategoryMisc:
categories = append(categories, "Misc")
case auth_model.AccessTokenScopeCategoryNotification:
categories = append(categories, "Notification")
case auth_model.AccessTokenScopeCategoryOrganization:
categories = append(categories, "Organization")
case auth_model.AccessTokenScopeCategoryPackage:
categories = append(categories, "Package")
case auth_model.AccessTokenScopeCategoryIssue:
categories = append(categories, "Issue")
case auth_model.AccessTokenScopeCategoryRepository:
categories = append(categories, "Repository")
case auth_model.AccessTokenScopeCategoryUser:
categories = append(categories, "User")
default:
panic(fmt.Errorf("unkwnon scope category %v", category))
}
}
slices.Sort(categories)
return strings.Join(categories, "")
}

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"fmt"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
// See README.md for a documentation of the test logic
@ -28,7 +28,7 @@ import (
"forgejo.org/modules/util"
"forgejo.org/modules/web/routing"
apiv1_permissions "forgejo.org/routers/api/v1/permissions"
apiv1_permissions_tests "forgejo.org/routers/api/v1/permissions/tests"
apiv1_permissions_testhelpers "forgejo.org/routers/api/v1/permissions/testhelpers"
"forgejo.org/services/auth"
"forgejo.org/services/authz"
issue_service "forgejo.org/services/issue"
@ -451,7 +451,7 @@ func fixtureGetComment(t *testing.T, fixtureData *fixtureData) *issues_model.Com
if !found {
return nil
}
comment.LoadIssue(t.Context())
_ = comment.LoadIssue(t.Context())
return &comment
}
@ -575,7 +575,7 @@ type functionTest struct {
}
func buildSignatureStringToFunctionTest(t *testing.T) {
for signatureString, signature := range apiv1_permissions_tests.GetSignatureStringToSignature() {
for signatureString, signature := range apiv1_permissions_testhelpers.GetSignatureStringToSignature() {
for prefix, builder := range prefixToFunctionTestBuilder {
if strings.HasPrefix(signatureString, prefix) {
builder(t, signatureString, signature)
@ -594,7 +594,7 @@ func registerFunctionTest(fun func(apiv1_permissions.Context), test functionTest
}
func registerFunctionTestWithCall(fun any, test functionTest) bool {
signatureString := apiv1_permissions_tests.SignatureToString([]any{fun})
signatureString := apiv1_permissions_testhelpers.SignatureToString([]any{fun})
if _, has := signatureStringToFunctionTest[signatureString]; has {
panic(fmt.Errorf("attempt to register %s twice", signatureString))
}

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
// See README.md for a documentation of the test logic
@ -13,12 +13,10 @@ import (
"testing"
"forgejo.org/models/unittest"
"forgejo.org/modules/setting"
"forgejo.org/modules/test"
"forgejo.org/modules/web/routing"
apiv1 "forgejo.org/routers/api/v1"
apiv1_permissions "forgejo.org/routers/api/v1/permissions"
apiv1_permissions_tests "forgejo.org/routers/api/v1/permissions/tests"
apiv1_permissions_testhelpers "forgejo.org/routers/api/v1/permissions/testhelpers"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
@ -26,7 +24,7 @@ import (
func createFixture(t *testing.T, signatures [][]any, permissions *apiv1_permissions.Permissions, data *fixtureData) {
for _, signature := range signatures[:len(signatures)-1] {
signatureString := apiv1_permissions_tests.SignatureToString(signature)
signatureString := apiv1_permissions_testhelpers.SignatureToString(signature)
functionTest, has := signatureStringToFunctionTest[signatureString]
require.True(t, has)
if functionTest.fulfillNeeds != nil {
@ -34,19 +32,18 @@ func createFixture(t *testing.T, signatures [][]any, permissions *apiv1_permissi
}
}
for _, signature := range signatures {
signatureString := apiv1_permissions_tests.SignatureToString(signature)
signatureString := apiv1_permissions_testhelpers.SignatureToString(signature)
functionTest, has := signatureStringToFunctionTest[signatureString]
require.True(t, has)
if functionTest.interpret != nil {
functionTest.interpret(t, permissions, data)
}
}
return
}
func getFunctionTest(t *testing.T, signatures [][]any) functionTest {
lastSignature := signatures[len(signatures)-1]
lastSignatureString := apiv1_permissions_tests.SignatureToString(lastSignature)
lastSignatureString := apiv1_permissions_testhelpers.SignatureToString(lastSignature)
test, has := signatureStringToFunctionTest[lastSignatureString]
require.True(t, has, lastSignatureString)
return test
@ -58,7 +55,7 @@ func getFixtures(t *testing.T, signatures [][]any) []*fixtureType {
func protectVariables(t *testing.T, signatures [][]any) {
for _, signature := range signatures {
signatureString := apiv1_permissions_tests.SignatureToString(signature)
signatureString := apiv1_permissions_testhelpers.SignatureToString(signature)
functionTest, has := signatureStringToFunctionTest[signatureString]
require.True(t, has)
for _, b := range functionTest.protectSettingsBool {
@ -69,7 +66,7 @@ func protectVariables(t *testing.T, signatures [][]any) {
func testSequence(t *testing.T, signatures [][]any, onlyForSuccess bool) int {
t.Helper()
signaturesString := apiv1_permissions_tests.SignaturesToString(signatures)
signaturesString := apiv1_permissions_testhelpers.SignaturesToString(signatures)
var fixtures []*fixtureType
if onlyForSuccess {
for _, fixture := range getFixtures(t, signatures) {
@ -90,7 +87,7 @@ func testSequence(t *testing.T, signatures [][]any, onlyForSuccess bool) int {
t.Run(runName, func(t *testing.T) {
protectVariables(t, signatures)
unittest.LoadFixtures() // reset the database to clear any side effect of running the test
_ = unittest.LoadFixtures() // reset the database to clear any side effect of running the test
permissions := &apiv1_permissions.Permissions{}
permissions.SetContext(t.Context())
t.Logf("creating fixture data from %v", fixture.data)
@ -137,7 +134,7 @@ func testSequence(t *testing.T, signatures [][]any, onlyForSuccess bool) int {
showPermissionsDiff()
var permissionsContext apiv1_permissions.Context = permissions
for i, signature := range signatures {
signatureString := apiv1_permissions_tests.SignatureToString(signature)
signatureString := apiv1_permissions_testhelpers.SignatureToString(signature)
functionTest, has := signatureStringToFunctionTest[signatureString]
require.True(t, has)
@ -165,7 +162,7 @@ func testSequence(t *testing.T, signatures [][]any, onlyForSuccess bool) int {
}
func getPermissionSequenceForFunction(t *testing.T, sequence [][]any) [][]any {
sequenceString := apiv1_permissions_tests.SignaturesToString(sequence)
sequenceString := apiv1_permissions_testhelpers.SignaturesToString(sequence)
sequenceFilter := getFunctionTest(t, sequence).sequenceFilter
if sequenceFilter == nil {
return sequence
@ -178,7 +175,7 @@ func getPermissionSequenceForFunction(t *testing.T, sequence [][]any) [][]any {
if len(sequenceFilter) == 0 {
break
}
signatureString := apiv1_permissions_tests.SignatureToString(signature)
signatureString := apiv1_permissions_testhelpers.SignatureToString(signature)
if signatureString == sequenceFilter[0] || strings.HasPrefix(signatureString, sequenceFilter[0]+" ") {
filteredSequence = append(filteredSequence, signature)
sequenceFilter = sequenceFilter[1:]
@ -191,7 +188,7 @@ func getPermissionSequenceForFunction(t *testing.T, sequence [][]any) [][]any {
panic(fmt.Errorf("%s filtered by %v is an empty sequence", sequenceString, getFunctionTest(t, sequence).sequenceFilter))
}
getPrefix := func(signature []any) string {
signatureString := apiv1_permissions_tests.SignatureToString(signature)
signatureString := apiv1_permissions_testhelpers.SignatureToString(signature)
prefix, _, _ := strings.Cut(signatureString, " ")
return prefix
}
@ -205,23 +202,13 @@ func getPermissionSequenceForFunction(t *testing.T, sequence [][]any) [][]any {
func getPermissionSequencesForFunctions(t *testing.T) [][][]any {
var sequences [][][]any
for _, sequence := range apiv1_permissions_tests.GetShortestPermissionSequenceForEachSignature() {
for _, sequence := range apiv1_permissions_testhelpers.GetShortestPermissionSequenceForEachSignature() {
sequences = append(sequences, getPermissionSequenceForFunction(t, sequence))
}
return sequences
}
func TestAPIv1Permissions(t *testing.T) {
defer test.MockVariableValue(&setting.Service.DefaultAllowCreateOrganization, true)()
defer test.MockVariableValue(&setting.IsInTesting, true)()
defer test.MockVariableValue(&setting.DisableGitHooks, false)()
unittest.PrepareTestEnv(t)
// because setting.IsInTesting == true, it will record the
// middleware sequence of each route it builds
apiv1.Routes()
func APIv1Permissions(t *testing.T) {
buildSignatureStringToFunctionTest(t)
runs := 0
@ -230,7 +217,7 @@ func TestAPIv1Permissions(t *testing.T) {
runs += testSequence(t, sequence, false)
}
t.Logf("verify all unique permission sequences can run successfully")
uniqueSequences := apiv1_permissions_tests.GetUniquePermissionsSequences()
uniqueSequences := apiv1_permissions_testhelpers.GetUniquePermissionsSequences()
for _, sequence := range uniqueSequences {
runs += testSequence(t, sequence, true)
}

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,16 +0,0 @@
// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
package tests_test
import (
"testing"
"forgejo.org/models/unittest"
_ "forgejo.org/modules/testimport"
)
func TestMain(m *testing.M) {
unittest.MainTest(m)
}

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
apiv1_permissions "forgejo.org/routers/api/v1/permissions"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
apiv1_permissions "forgejo.org/routers/api/v1/permissions"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"strings"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"strings"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"testing"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"strings"

View file

@ -1,7 +1,7 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
package tests
import (
"fmt"

View file

@ -1,42 +1,67 @@
// Copyright 2026 The Forgejo Authors. All rights reserved.
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests
import (
"fmt"
"slices"
"strings"
auth_model "forgejo.org/models/auth"
unit_model "forgejo.org/models/unit"
)
func requiredScopesToString(scopeCategories ...auth_model.AccessTokenScopeCategory) string {
var categories []string
for _, category := range scopeCategories {
switch category {
case auth_model.AccessTokenScopeCategoryActivityPub:
categories = append(categories, "ActivityPub")
case auth_model.AccessTokenScopeCategoryAdmin:
categories = append(categories, "Admin")
case auth_model.AccessTokenScopeCategoryMisc:
categories = append(categories, "Misc")
case auth_model.AccessTokenScopeCategoryNotification:
categories = append(categories, "Notification")
case auth_model.AccessTokenScopeCategoryOrganization:
categories = append(categories, "Organization")
case auth_model.AccessTokenScopeCategoryPackage:
categories = append(categories, "Package")
case auth_model.AccessTokenScopeCategoryIssue:
categories = append(categories, "Issue")
case auth_model.AccessTokenScopeCategoryRepository:
categories = append(categories, "Repository")
case auth_model.AccessTokenScopeCategoryUser:
categories = append(categories, "User")
func levelStringToLevel(levelString string) auth_model.AccessTokenScopeLevel {
level := auth_model.Read
if levelString != "" {
switch levelString {
case "read":
level = auth_model.Read
case "write":
level = auth_model.Write
case "noaccess":
level = auth_model.NoAccess
default:
panic(fmt.Errorf("unkwnon scope category %v", category))
panic(fmt.Sprintf("unexpected level '%s'", levelString))
}
}
slices.Sort(categories)
return strings.Join(categories, "")
return level
}
func unitsTypeToString(unitTypes ...unit_model.Type) string {
var unitStrings []string
for _, unitType := range unitTypes {
var unit *unit_model.Unit
for _, u := range unit_model.Units {
if u.Type == unitType {
unit = &u
break
}
}
if unit == nil {
panic(fmt.Errorf("unable to find a unit with type %v", unitType))
}
unitStrings = append(unitStrings, unit.NameKey)
}
return strings.Join(unitStrings, ",")
}
func unitsToScopes(unitTypes []unit_model.Type, levelString string) string {
var scopeStrings []string
for _, unitType := range unitTypes {
unit := strings.TrimPrefix(unitsTypeToString(unitType), "repo.")
var scope string
switch unit {
case "issues":
scope = "issue"
case "code", "pulls", "wiki", "project", "actions", "releases":
scope = "repository"
case "packages":
scope = "package"
default:
panic(fmt.Errorf("unexpected unit type %v", unitType))
}
scopeStrings = append(scopeStrings, fmt.Sprintf("%s:%s", levelString, scope))
}
return strings.Join(scopeStrings, ",")
}

View file

@ -1,67 +0,0 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package tests_test
import (
"fmt"
"strings"
auth_model "forgejo.org/models/auth"
unit_model "forgejo.org/models/unit"
)
func levelStringToLevel(levelString string) auth_model.AccessTokenScopeLevel {
level := auth_model.Read
if levelString != "" {
switch levelString {
case "read":
level = auth_model.Read
case "write":
level = auth_model.Write
case "noaccess":
level = auth_model.NoAccess
default:
panic(fmt.Sprintf("unexpected level '%s'", levelString))
}
}
return level
}
func unitsTypeToString(unitTypes ...unit_model.Type) string {
var unitStrings []string
for _, unitType := range unitTypes {
var unit *unit_model.Unit
for _, u := range unit_model.Units {
if u.Type == unitType {
unit = &u
break
}
}
if unit == nil {
panic(fmt.Errorf("unable to find a unit with type %v", unitType))
}
unitStrings = append(unitStrings, unit.NameKey)
}
return strings.Join(unitStrings, ",")
}
func unitsToScopes(unitTypes []unit_model.Type, levelString string) string {
var scopeStrings []string
for _, unitType := range unitTypes {
unit := strings.TrimPrefix(unitsTypeToString(unitType), "repo.")
var scope string
switch unit {
case "issues":
scope = "issue"
case "code", "pulls", "wiki", "project", "actions", "releases":
scope = "repository"
case "packages":
scope = "package"
default:
panic(fmt.Errorf("unexpected unit type %v", unitType))
}
scopeStrings = append(scopeStrings, fmt.Sprintf("%s:%s", levelString, scope))
}
return strings.Join(scopeStrings, ",")
}

View file

@ -0,0 +1,28 @@
// Copyright 2026 The Forgejo Authors.
// SPDX-License-Identifier: GPLv3-or-later
package integration
import (
"testing"
"forgejo.org/models/unittest"
"forgejo.org/modules/setting"
"forgejo.org/modules/test"
apiv1 "forgejo.org/routers/api/v1"
apiv1_permissions_tests "forgejo.org/routers/api/v1/permissions/tests"
)
func TestAPIv1Permissions(t *testing.T) {
defer test.MockVariableValue(&setting.Service.DefaultAllowCreateOrganization, true)()
defer test.MockVariableValue(&setting.IsInTesting, true)()
defer test.MockVariableValue(&setting.DisableGitHooks, false)()
unittest.PrepareTestEnv(t)
// because setting.IsInTesting == true, it will record the
// middleware sequence of each route it builds
apiv1.Routes()
apiv1_permissions_tests.APIv1Permissions(t)
}