mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-26 06:16:56 +09:00
test: consolidate Go tests (#39962)
Consolidate all Go tests. Coverage is identical to before. Go tests are around 5% faster while being 7% smaller. No non-test code is touched.
This commit is contained in:
1 parent
ce7364e215
commit
8abda62312
388 files changed
+18410
-29561
No files matched your search
@@ -92,116 +92,45 @@ func TestGetCommitStatuses(t *testing.T) {
|
||||
|
||||
func Test_CalcCommitStatus(t *testing.T) {
|
||||
kases := []struct {
|
||||
statuses []*git_model.CommitStatus
|
||||
expected *git_model.CommitStatus
|
||||
statuses commitstatus.CommitStatusStates
|
||||
expected commitstatus.CommitStatusState
|
||||
}{
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusPending},
|
||||
expected: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusSuccess, commitstatus.CommitStatusPending},
|
||||
expected: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusSuccess, commitstatus.CommitStatusPending, commitstatus.CommitStatusSuccess},
|
||||
expected: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusError,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusError, commitstatus.CommitStatusPending, commitstatus.CommitStatusSuccess},
|
||||
expected: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusWarning,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusPending,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusWarning, commitstatus.CommitStatusPending, commitstatus.CommitStatusSuccess},
|
||||
expected: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusSuccess, commitstatus.CommitStatusSuccess, commitstatus.CommitStatusSuccess},
|
||||
expected: commitstatus.CommitStatusSuccess,
|
||||
},
|
||||
{
|
||||
statuses: []*git_model.CommitStatus{
|
||||
{
|
||||
State: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusError,
|
||||
},
|
||||
{
|
||||
State: commitstatus.CommitStatusWarning,
|
||||
},
|
||||
},
|
||||
expected: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
statuses: commitstatus.CommitStatusStates{commitstatus.CommitStatusFailure, commitstatus.CommitStatusError, commitstatus.CommitStatusWarning},
|
||||
expected: commitstatus.CommitStatusFailure,
|
||||
},
|
||||
}
|
||||
|
||||
for _, kase := range kases {
|
||||
assert.Equal(t, kase.expected, git_model.CalcCommitStatus(kase.statuses), "statuses: %v", kase.statuses)
|
||||
statuses := make([]*git_model.CommitStatus, len(kase.statuses))
|
||||
for i, state := range kase.statuses {
|
||||
statuses[i] = &git_model.CommitStatus{State: state}
|
||||
}
|
||||
assert.Equal(t, &git_model.CommitStatus{State: kase.expected}, git_model.CalcCommitStatus(statuses), "statuses: %v", statuses)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,29 +155,19 @@ func TestFindRepoRecentCommitStatusContexts(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
err = git_model.NewCommitStatus(t.Context(), git_model.NewCommitStatusOptions{
|
||||
Repo: repo2,
|
||||
Creator: user2,
|
||||
SHA: commit.ID,
|
||||
CommitStatus: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusFailure,
|
||||
TargetURL: "https://example.com/tests/",
|
||||
Context: "compliance/lint-backend",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = git_model.NewCommitStatus(t.Context(), git_model.NewCommitStatusOptions{
|
||||
Repo: repo2,
|
||||
Creator: user2,
|
||||
SHA: commit.ID,
|
||||
CommitStatus: &git_model.CommitStatus{
|
||||
State: commitstatus.CommitStatusSuccess,
|
||||
TargetURL: "https://example.com/tests/",
|
||||
Context: "compliance/lint-backend",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
for _, state := range []commitstatus.CommitStatusState{commitstatus.CommitStatusFailure, commitstatus.CommitStatusSuccess} {
|
||||
err = git_model.NewCommitStatus(t.Context(), git_model.NewCommitStatusOptions{
|
||||
Repo: repo2,
|
||||
Creator: user2,
|
||||
SHA: commit.ID,
|
||||
CommitStatus: &git_model.CommitStatus{
|
||||
State: state,
|
||||
TargetURL: "https://example.com/tests/",
|
||||
Context: "compliance/lint-backend",
|
||||
},
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
contexts, err := git_model.FindRepoRecentCommitStatusContexts(t.Context(), repo2.ID, time.Hour)
|
||||
assert.NoError(t, err)
|
||||
|
||||
@@ -75,65 +75,34 @@ func TestBranchRuleMatchPriority(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBranchRuleSortLegacy(t *testing.T) {
|
||||
in := []*ProtectedBranch{{
|
||||
RuleName: "b",
|
||||
CreatedUnix: 1,
|
||||
}, {
|
||||
RuleName: "b/*",
|
||||
CreatedUnix: 3,
|
||||
}, {
|
||||
RuleName: "a/*",
|
||||
CreatedUnix: 2,
|
||||
}, {
|
||||
RuleName: "c",
|
||||
CreatedUnix: 0,
|
||||
}, {
|
||||
RuleName: "a",
|
||||
CreatedUnix: 4,
|
||||
}}
|
||||
expect := []string{"c", "b", "a", "a/*", "b/*"}
|
||||
|
||||
pbr := ProtectedBranchRules(in)
|
||||
pbr.sort()
|
||||
|
||||
var got []string
|
||||
for i := range pbr {
|
||||
got = append(got, pbr[i].RuleName)
|
||||
func TestBranchRuleSort(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
rules ProtectedBranchRules
|
||||
expected []string
|
||||
}{
|
||||
{"Legacy", ProtectedBranchRules{
|
||||
{RuleName: "b", CreatedUnix: 1},
|
||||
{RuleName: "b/*", CreatedUnix: 3},
|
||||
{RuleName: "a/*", CreatedUnix: 2},
|
||||
{RuleName: "c", CreatedUnix: 0},
|
||||
{RuleName: "a", CreatedUnix: 4},
|
||||
}, []string{"c", "b", "a", "a/*", "b/*"}},
|
||||
{"Priority", ProtectedBranchRules{
|
||||
{RuleName: "b", CreatedUnix: 1, Priority: 4},
|
||||
{RuleName: "b/*", CreatedUnix: 3, Priority: 2},
|
||||
{RuleName: "a/*", CreatedUnix: 2, Priority: 1},
|
||||
{RuleName: "c", CreatedUnix: 0, Priority: 0},
|
||||
{RuleName: "a", CreatedUnix: 4, Priority: 3},
|
||||
}, []string{"c", "a/*", "b/*", "a", "b"}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
tc.rules.sort()
|
||||
var got []string
|
||||
for i := range tc.rules {
|
||||
got = append(got, tc.rules[i].RuleName)
|
||||
}
|
||||
assert.Equal(t, tc.expected, got)
|
||||
})
|
||||
}
|
||||
assert.Equal(t, expect, got)
|
||||
}
|
||||
|
||||
func TestBranchRuleSortPriority(t *testing.T) {
|
||||
in := []*ProtectedBranch{{
|
||||
RuleName: "b",
|
||||
CreatedUnix: 1,
|
||||
Priority: 4,
|
||||
}, {
|
||||
RuleName: "b/*",
|
||||
CreatedUnix: 3,
|
||||
Priority: 2,
|
||||
}, {
|
||||
RuleName: "a/*",
|
||||
CreatedUnix: 2,
|
||||
Priority: 1,
|
||||
}, {
|
||||
RuleName: "c",
|
||||
CreatedUnix: 0,
|
||||
Priority: 0,
|
||||
}, {
|
||||
RuleName: "a",
|
||||
CreatedUnix: 4,
|
||||
Priority: 3,
|
||||
}}
|
||||
expect := []string{"c", "a/*", "b/*", "a", "b"}
|
||||
|
||||
pbr := ProtectedBranchRules(in)
|
||||
pbr.sort()
|
||||
|
||||
var got []string
|
||||
for i := range pbr {
|
||||
got = append(got, pbr[i].RuleName)
|
||||
}
|
||||
assert.Equal(t, expect, got)
|
||||
}
|
||||
+184
-176
@@ -85,194 +85,202 @@ func TestBranchRuleMatch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestUpdateProtectBranchPriorities(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
func TestProtectedBranchPermissionsAndPriorities(t *testing.T) {
|
||||
setupErr := unittest.PrepareTestDatabase()
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
t.Run("CanBypassBranchProtection", func(t *testing.T) {
|
||||
assert.NoError(t, setupErr)
|
||||
|
||||
// Create some test protected branches with initial priorities
|
||||
protectedBranches := []*ProtectedBranch{
|
||||
{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "master",
|
||||
Priority: 1,
|
||||
},
|
||||
{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "develop",
|
||||
Priority: 2,
|
||||
},
|
||||
{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "feature/*",
|
||||
Priority: 3,
|
||||
},
|
||||
}
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) // not in team 1
|
||||
teamMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
for _, pb := range protectedBranches {
|
||||
_, err := db.GetEngine(t.Context()).Insert(pb)
|
||||
pb := &ProtectedBranch{
|
||||
EnableBypassAllowlist: true,
|
||||
BypassAllowlistUserIDs: []int64{user.ID},
|
||||
}
|
||||
|
||||
testBypass := func(t *testing.T, expected bool, pb *ProtectedBranch, doer *user_model.User, isAdmin bool) {
|
||||
assert.Equal(t, expected, CanBypassBranchProtection(t.Context(), pb, doer, isAdmin))
|
||||
}
|
||||
// User bypasses via explicit allowlist.
|
||||
testBypass(t, true, pb, user, false)
|
||||
|
||||
// Non-admin cannot bypass when allowlist is disabled.
|
||||
pb.EnableBypassAllowlist = false
|
||||
testBypass(t, false, pb, user, false)
|
||||
|
||||
// Repo admin can bypass independently of allowlist when not blocked.
|
||||
testBypass(t, true, pb, user, true)
|
||||
|
||||
// Admin override block still allows bypass for allowlisted users.
|
||||
pb.EnableBypassAllowlist = true
|
||||
pb.BlockAdminMergeOverride = true
|
||||
testBypass(t, true, pb, user, false)
|
||||
|
||||
// admin cannot bypass without allowlist membership.
|
||||
pb.BypassAllowlistUserIDs = nil
|
||||
testBypass(t, false, pb, user, true)
|
||||
|
||||
// admin can bypass when allowlisted.
|
||||
pb.BypassAllowlistUserIDs = []int64{user.ID}
|
||||
testBypass(t, true, pb, user, true)
|
||||
|
||||
// User bypasses via team allowlist membership.
|
||||
pb.EnableBypassAllowlist = true
|
||||
pb.BlockAdminMergeOverride = false
|
||||
pb.BypassAllowlistUserIDs = nil
|
||||
pb.BypassAllowlistTeamIDs = []int64{1} // team 1 contains user 2 in test fixtures
|
||||
testBypass(t, true, pb, teamMember, false)
|
||||
|
||||
// User does not bypass when not in allowlisted teams.
|
||||
testBypass(t, false, pb, user, false)
|
||||
})
|
||||
|
||||
t.Run("ProtectedBranchCanUserDelete", func(t *testing.T) {
|
||||
require.NoError(t, setupErr)
|
||||
writePermission := access_model.Permission{}
|
||||
writePermission.SetUnitsWithDefaultAccessMode([]*repo_model.RepoUnit{{Type: unit.TypeCode}}, perm.AccessModeWrite)
|
||||
readPermission := access_model.Permission{}
|
||||
readPermission.SetUnitsWithDefaultAccessMode([]*repo_model.RepoUnit{{Type: unit.TypeCode}}, perm.AccessModeRead)
|
||||
|
||||
for _, user := range []*user_model.User{{ID: 2, Name: "user2"}, user_model.NewActionsUser(), user_model.NewDeployKeyUser()} {
|
||||
t.Run(user.GetDisplayName(), func(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
config ProtectedBranchConfig
|
||||
want bool
|
||||
}{
|
||||
{name: "disabled by default", config: ProtectedBranchConfig{CanPush: true}},
|
||||
{name: "push disabled", config: ProtectedBranchConfig{CanDelete: true}},
|
||||
{name: "unrestricted", config: ProtectedBranchConfig{CanPush: true, CanDelete: true}, want: true},
|
||||
{name: "empty push allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true}},
|
||||
{name: "not in push allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, WhitelistUserIDs: []int64{1}}},
|
||||
{name: "empty deletion allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true}},
|
||||
{name: "not in deletion allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{1}}},
|
||||
{name: "in both allowlists", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, WhitelistUserIDs: []int64{user.ID}, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{user.ID}}, want: true},
|
||||
{name: "deletion allowlist does not grant push", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{user.ID}}},
|
||||
{name: "team member", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistTeamIDs: []int64{1}}, want: user.ID == 2},
|
||||
{name: "push team member", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, WhitelistTeamIDs: []int64{1}}, want: user.ID == 2},
|
||||
{name: "not in team", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistTeamIDs: []int64{3}}},
|
||||
{name: "user or team", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{user.ID}, DeletionAllowlistTeamIDs: []int64{3}}, want: true},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pb := &ProtectedBranch{ProtectedBranchConfig: tt.config}
|
||||
assert.Equal(t, tt.want, pb.CanUserDelete(t.Context(), user, writePermission))
|
||||
assert.False(t, pb.CanUserDelete(t.Context(), user, readPermission))
|
||||
assert.False(t, pb.CanUserDelete(t.Context(), nil, writePermission))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("UpdateProtectBranchPriorities", func(t *testing.T) {
|
||||
assert.NoError(t, setupErr)
|
||||
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
// Create some test protected branches with initial priorities
|
||||
protectedBranches := []*ProtectedBranch{
|
||||
{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "master",
|
||||
Priority: 1,
|
||||
},
|
||||
{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "develop",
|
||||
Priority: 2,
|
||||
},
|
||||
{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "feature/*",
|
||||
Priority: 3,
|
||||
},
|
||||
}
|
||||
|
||||
for _, pb := range protectedBranches {
|
||||
_, err := db.GetEngine(t.Context()).Insert(pb)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// Test updating priorities
|
||||
newPriorities := []int64{protectedBranches[2].ID, protectedBranches[0].ID, protectedBranches[1].ID}
|
||||
err := UpdateProtectBranchPriorities(t.Context(), repo, newPriorities)
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
// Test updating priorities
|
||||
newPriorities := []int64{protectedBranches[2].ID, protectedBranches[0].ID, protectedBranches[1].ID}
|
||||
err := UpdateProtectBranchPriorities(t.Context(), repo, newPriorities)
|
||||
assert.NoError(t, err)
|
||||
// Verify new priorities
|
||||
pbs, err := FindRepoProtectedBranchRules(t.Context(), repo.ID)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Verify new priorities
|
||||
pbs, err := FindRepoProtectedBranchRules(t.Context(), repo.ID)
|
||||
assert.NoError(t, err)
|
||||
expectedPriorities := map[string]int64{
|
||||
"feature/*": 1,
|
||||
"master": 2,
|
||||
"develop": 3,
|
||||
}
|
||||
|
||||
expectedPriorities := map[string]int64{
|
||||
"feature/*": 1,
|
||||
"master": 2,
|
||||
"develop": 3,
|
||||
}
|
||||
|
||||
for _, pb := range pbs {
|
||||
assert.Equal(t, expectedPriorities[pb.RuleName], pb.Priority)
|
||||
}
|
||||
for _, pb := range pbs {
|
||||
assert.Equal(t, expectedPriorities[pb.RuleName], pb.Priority)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewProtectBranchPriority(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
setupErr := unittest.PrepareTestDatabase()
|
||||
|
||||
err := UpdateProtectBranch(t.Context(), repo, &ProtectedBranch{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "branch-1",
|
||||
Priority: 1,
|
||||
}, WhitelistOptions{})
|
||||
assert.NoError(t, err)
|
||||
t.Run("NewProtectBranchPriority", func(t *testing.T) {
|
||||
assert.NoError(t, setupErr)
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
|
||||
newPB := &ProtectedBranch{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "branch-2",
|
||||
// Priority intentionally omitted
|
||||
}
|
||||
err := UpdateProtectBranch(t.Context(), repo, &ProtectedBranch{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "branch-1",
|
||||
Priority: 1,
|
||||
}, WhitelistOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = UpdateProtectBranch(t.Context(), repo, newPB, WhitelistOptions{})
|
||||
assert.NoError(t, err)
|
||||
newPB := &ProtectedBranch{
|
||||
RepoID: repo.ID,
|
||||
RuleName: "branch-2",
|
||||
// Priority intentionally omitted
|
||||
}
|
||||
|
||||
savedPB2, err := GetFirstMatchProtectedBranchRule(t.Context(), repo.ID, "branch-2")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(2), savedPB2.Priority)
|
||||
}
|
||||
|
||||
func TestCanBypassBranchProtection(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
user := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1}) // not in team 1
|
||||
teamMember := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
|
||||
|
||||
pb := &ProtectedBranch{
|
||||
EnableBypassAllowlist: true,
|
||||
BypassAllowlistUserIDs: []int64{user.ID},
|
||||
}
|
||||
|
||||
testBypass := func(t *testing.T, expected bool, pb *ProtectedBranch, doer *user_model.User, isAdmin bool) {
|
||||
assert.Equal(t, expected, CanBypassBranchProtection(t.Context(), pb, doer, isAdmin))
|
||||
}
|
||||
// User bypasses via explicit allowlist.
|
||||
testBypass(t, true, pb, user, false)
|
||||
|
||||
// Non-admin cannot bypass when allowlist is disabled.
|
||||
pb.EnableBypassAllowlist = false
|
||||
testBypass(t, false, pb, user, false)
|
||||
|
||||
// Repo admin can bypass independently of allowlist when not blocked.
|
||||
testBypass(t, true, pb, user, true)
|
||||
|
||||
// Admin override block still allows bypass for allowlisted users.
|
||||
pb.EnableBypassAllowlist = true
|
||||
pb.BlockAdminMergeOverride = true
|
||||
testBypass(t, true, pb, user, false)
|
||||
|
||||
// admin cannot bypass without allowlist membership.
|
||||
pb.BypassAllowlistUserIDs = nil
|
||||
testBypass(t, false, pb, user, true)
|
||||
|
||||
// admin can bypass when allowlisted.
|
||||
pb.BypassAllowlistUserIDs = []int64{user.ID}
|
||||
testBypass(t, true, pb, user, true)
|
||||
|
||||
// User bypasses via team allowlist membership.
|
||||
pb.EnableBypassAllowlist = true
|
||||
pb.BlockAdminMergeOverride = false
|
||||
pb.BypassAllowlistUserIDs = nil
|
||||
pb.BypassAllowlistTeamIDs = []int64{1} // team 1 contains user 2 in test fixtures
|
||||
testBypass(t, true, pb, teamMember, false)
|
||||
|
||||
// User does not bypass when not in allowlisted teams.
|
||||
testBypass(t, false, pb, user, false)
|
||||
}
|
||||
|
||||
func TestProtectedBranchConfig(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
ctx := t.Context()
|
||||
pb := &ProtectedBranch{
|
||||
RepoID: 1, RuleName: "config-test",
|
||||
ProtectedBranchConfig: ProtectedBranchConfig{
|
||||
CanDelete: true, EnableDeletionAllowlist: true,
|
||||
DeletionAllowlistUserIDs: []int64{2, 4, user_model.ActionsUserID, user_model.DeployKeyUserID}, DeletionAllowlistTeamIDs: []int64{1, 2},
|
||||
CanPush: true, WhitelistUserIDs: []int64{2, 4}, WhitelistTeamIDs: []int64{1, 2}, StatusCheckContexts: []string{},
|
||||
},
|
||||
}
|
||||
require.NoError(t, db.Insert(ctx, pb))
|
||||
loaded := unittest.AssertExistsAndLoadBean(t, &ProtectedBranch{ID: pb.ID})
|
||||
assert.Equal(t, pb.ProtectedBranchConfig, loaded.ProtectedBranchConfig)
|
||||
require.NoError(t, RemoveUserIDFromProtectedBranch(ctx, loaded, 2))
|
||||
require.NoError(t, RemoveTeamIDFromProtectedBranch(ctx, loaded, 1))
|
||||
loaded = unittest.AssertExistsAndLoadBean(t, &ProtectedBranch{ID: pb.ID})
|
||||
assert.Equal(t, []int64{4}, loaded.WhitelistUserIDs)
|
||||
assert.Equal(t, []int64{2}, loaded.WhitelistTeamIDs)
|
||||
assert.True(t, loaded.CanPush)
|
||||
assert.True(t, loaded.CanDelete)
|
||||
assert.True(t, loaded.EnableDeletionAllowlist)
|
||||
assert.Equal(t, []int64{4, user_model.ActionsUserID, user_model.DeployKeyUserID}, loaded.DeletionAllowlistUserIDs)
|
||||
assert.Equal(t, []int64{2}, loaded.DeletionAllowlistTeamIDs)
|
||||
loaded.ProtectedBranchConfig = ProtectedBranchConfig{}
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
require.NoError(t, UpdateProtectBranch(ctx, repo, loaded, WhitelistOptions{}))
|
||||
loaded = unittest.AssertExistsAndLoadBean(t, &ProtectedBranch{ID: pb.ID})
|
||||
assert.Equal(t, ProtectedBranchConfig{}, loaded.ProtectedBranchConfig)
|
||||
}
|
||||
|
||||
func TestProtectedBranchCanUserDelete(t *testing.T) {
|
||||
require.NoError(t, unittest.PrepareTestDatabase())
|
||||
writePermission := access_model.Permission{}
|
||||
writePermission.SetUnitsWithDefaultAccessMode([]*repo_model.RepoUnit{{Type: unit.TypeCode}}, perm.AccessModeWrite)
|
||||
readPermission := access_model.Permission{}
|
||||
readPermission.SetUnitsWithDefaultAccessMode([]*repo_model.RepoUnit{{Type: unit.TypeCode}}, perm.AccessModeRead)
|
||||
|
||||
for _, user := range []*user_model.User{{ID: 2, Name: "user2"}, user_model.NewActionsUser(), user_model.NewDeployKeyUser()} {
|
||||
t.Run(user.GetDisplayName(), func(t *testing.T) {
|
||||
for _, tt := range []struct {
|
||||
name string
|
||||
config ProtectedBranchConfig
|
||||
want bool
|
||||
}{
|
||||
{name: "disabled by default", config: ProtectedBranchConfig{CanPush: true}},
|
||||
{name: "push disabled", config: ProtectedBranchConfig{CanDelete: true}},
|
||||
{name: "unrestricted", config: ProtectedBranchConfig{CanPush: true, CanDelete: true}, want: true},
|
||||
{name: "empty push allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true}},
|
||||
{name: "not in push allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, WhitelistUserIDs: []int64{1}}},
|
||||
{name: "empty deletion allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true}},
|
||||
{name: "not in deletion allowlist", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{1}}},
|
||||
{name: "in both allowlists", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, WhitelistUserIDs: []int64{user.ID}, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{user.ID}}, want: true},
|
||||
{name: "deletion allowlist does not grant push", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{user.ID}}},
|
||||
{name: "team member", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistTeamIDs: []int64{1}}, want: user.ID == 2},
|
||||
{name: "push team member", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableWhitelist: true, WhitelistTeamIDs: []int64{1}}, want: user.ID == 2},
|
||||
{name: "not in team", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistTeamIDs: []int64{3}}},
|
||||
{name: "user or team", config: ProtectedBranchConfig{CanPush: true, CanDelete: true, EnableDeletionAllowlist: true, DeletionAllowlistUserIDs: []int64{user.ID}, DeletionAllowlistTeamIDs: []int64{3}}, want: true},
|
||||
} {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
pb := &ProtectedBranch{ProtectedBranchConfig: tt.config}
|
||||
assert.Equal(t, tt.want, pb.CanUserDelete(t.Context(), user, writePermission))
|
||||
assert.False(t, pb.CanUserDelete(t.Context(), user, readPermission))
|
||||
assert.False(t, pb.CanUserDelete(t.Context(), nil, writePermission))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
err = UpdateProtectBranch(t.Context(), repo, newPB, WhitelistOptions{})
|
||||
assert.NoError(t, err)
|
||||
|
||||
savedPB2, err := GetFirstMatchProtectedBranchRule(t.Context(), repo.ID, "branch-2")
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(2), savedPB2.Priority)
|
||||
})
|
||||
|
||||
t.Run("ProtectedBranchConfig", func(t *testing.T) {
|
||||
require.NoError(t, setupErr)
|
||||
ctx := t.Context()
|
||||
pb := &ProtectedBranch{
|
||||
RepoID: 1, RuleName: "config-test",
|
||||
ProtectedBranchConfig: ProtectedBranchConfig{
|
||||
CanDelete: true, EnableDeletionAllowlist: true,
|
||||
DeletionAllowlistUserIDs: []int64{2, 4, user_model.ActionsUserID, user_model.DeployKeyUserID}, DeletionAllowlistTeamIDs: []int64{1, 2},
|
||||
CanPush: true, WhitelistUserIDs: []int64{2, 4}, WhitelistTeamIDs: []int64{1, 2}, StatusCheckContexts: []string{},
|
||||
},
|
||||
}
|
||||
require.NoError(t, db.Insert(ctx, pb))
|
||||
loaded := unittest.AssertExistsAndLoadBean(t, &ProtectedBranch{ID: pb.ID})
|
||||
assert.Equal(t, pb.ProtectedBranchConfig, loaded.ProtectedBranchConfig)
|
||||
require.NoError(t, RemoveUserIDFromProtectedBranch(ctx, loaded, 2))
|
||||
require.NoError(t, RemoveTeamIDFromProtectedBranch(ctx, loaded, 1))
|
||||
loaded = unittest.AssertExistsAndLoadBean(t, &ProtectedBranch{ID: pb.ID})
|
||||
assert.Equal(t, []int64{4}, loaded.WhitelistUserIDs)
|
||||
assert.Equal(t, []int64{2}, loaded.WhitelistTeamIDs)
|
||||
assert.True(t, loaded.CanPush)
|
||||
assert.True(t, loaded.CanDelete)
|
||||
assert.True(t, loaded.EnableDeletionAllowlist)
|
||||
assert.Equal(t, []int64{4, user_model.ActionsUserID, user_model.DeployKeyUserID}, loaded.DeletionAllowlistUserIDs)
|
||||
assert.Equal(t, []int64{2}, loaded.DeletionAllowlistTeamIDs)
|
||||
loaded.ProtectedBranchConfig = ProtectedBranchConfig{}
|
||||
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||
require.NoError(t, UpdateProtectBranch(ctx, repo, loaded, WhitelistOptions{}))
|
||||
loaded = unittest.AssertExistsAndLoadBean(t, &ProtectedBranch{ID: pb.ID})
|
||||
assert.Equal(t, ProtectedBranchConfig{}, loaded.ProtectedBranchConfig)
|
||||
})
|
||||
}
|
||||
@@ -15,44 +15,31 @@ import (
|
||||
func TestIsUserAllowed(t *testing.T) {
|
||||
assert.NoError(t, unittest.PrepareTestDatabase())
|
||||
|
||||
pt := &git_model.ProtectedTag{}
|
||||
allowed, err := git_model.IsUserAllowedModifyTag(t.Context(), pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, allowed)
|
||||
checkAllowed := func(pt *git_model.ProtectedTag, userID int64, check assert.BoolAssertionFunc) {
|
||||
allowed, err := git_model.IsUserAllowedModifyTag(t.Context(), pt, userID)
|
||||
assert.NoError(t, err)
|
||||
check(t, allowed)
|
||||
}
|
||||
checkAllowed(&git_model.ProtectedTag{}, 1, assert.False)
|
||||
|
||||
pt = &git_model.ProtectedTag{
|
||||
pt := &git_model.ProtectedTag{
|
||||
AllowlistUserIDs: []int64{1},
|
||||
}
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(t.Context(), pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(t.Context(), pt, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, allowed)
|
||||
checkAllowed(pt, 1, assert.True)
|
||||
checkAllowed(pt, 2, assert.False)
|
||||
|
||||
pt = &git_model.ProtectedTag{
|
||||
AllowlistTeamIDs: []int64{1},
|
||||
}
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(t.Context(), pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.False(t, allowed)
|
||||
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(t.Context(), pt, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
checkAllowed(pt, 1, assert.False)
|
||||
checkAllowed(pt, 2, assert.True)
|
||||
|
||||
pt = &git_model.ProtectedTag{
|
||||
AllowlistUserIDs: []int64{1},
|
||||
AllowlistTeamIDs: []int64{1},
|
||||
}
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(t.Context(), pt, 1)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
|
||||
allowed, err = git_model.IsUserAllowedModifyTag(t.Context(), pt, 2)
|
||||
assert.NoError(t, err)
|
||||
assert.True(t, allowed)
|
||||
checkAllowed(pt, 1, assert.True)
|
||||
checkAllowed(pt, 2, assert.True)
|
||||
}
|
||||
|
||||
func TestIsUserAllowedToControlTag(t *testing.T) {
|
||||
@@ -118,47 +105,33 @@ func TestIsUserAllowedToControlTag(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
t.Run("Glob", func(t *testing.T) {
|
||||
protectedTags := []*git_model.ProtectedTag{
|
||||
{
|
||||
NamePattern: `*gitea`,
|
||||
AllowlistUserIDs: []int64{1},
|
||||
},
|
||||
{
|
||||
NamePattern: `v-*`,
|
||||
AllowlistUserIDs: []int64{2},
|
||||
},
|
||||
{
|
||||
NamePattern: "release",
|
||||
},
|
||||
}
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
patterns []string
|
||||
}{
|
||||
{"Glob", []string{`*gitea`, `v-*`, "release"}},
|
||||
{"Regex", []string{`/gitea\z/`, `/\Av-/`, "/release/"}},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
protectedTags := []*git_model.ProtectedTag{
|
||||
{
|
||||
NamePattern: tc.patterns[0],
|
||||
AllowlistUserIDs: []int64{1},
|
||||
},
|
||||
{
|
||||
NamePattern: tc.patterns[1],
|
||||
AllowlistUserIDs: []int64{2},
|
||||
},
|
||||
{
|
||||
NamePattern: tc.patterns[2],
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(t.Context(), protectedTags, c.name, c.userid)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Regex", func(t *testing.T) {
|
||||
protectedTags := []*git_model.ProtectedTag{
|
||||
{
|
||||
NamePattern: `/gitea\z/`,
|
||||
AllowlistUserIDs: []int64{1},
|
||||
},
|
||||
{
|
||||
NamePattern: `/\Av-/`,
|
||||
AllowlistUserIDs: []int64{2},
|
||||
},
|
||||
{
|
||||
NamePattern: "/release/",
|
||||
},
|
||||
}
|
||||
|
||||
for n, c := range cases {
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(t.Context(), protectedTags, c.name, c.userid)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n)
|
||||
}
|
||||
})
|
||||
for n, c := range cases {
|
||||
isAllowed, err := git_model.IsUserAllowedToControlTag(t.Context(), protectedTags, c.name, c.userid)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, c.allowed, isAllowed, "case %d: error should match", n)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user