Files
gitea/services/pull/review_test.go
T
2026-10-20 11:03:34 -07:00

162 lines
6.1 KiB
Go

// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT
package pull_test
import (
"fmt"
"strings"
"testing"
issues_model "gitea.dev/models/issues"
"gitea.dev/models/unittest"
user_model "gitea.dev/models/user"
"gitea.dev/modules/git"
"gitea.dev/modules/util"
pull_service "gitea.dev/services/pull"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestDismissReview(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
pull := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{})
assert.NoError(t, pull.LoadIssue(t.Context()))
issue := pull.Issue
assert.NoError(t, issue.LoadRepo(t.Context()))
reviewer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 1})
review, err := issues_model.CreateReview(t.Context(), issues_model.CreateReviewOptions{
Issue: issue,
Reviewer: reviewer,
Type: issues_model.ReviewTypeReject,
})
assert.NoError(t, err)
issue.IsClosed = true
pull.HasMerged = false
assert.NoError(t, issues_model.UpdateIssueCols(t.Context(), issue, "is_closed"))
assert.NoError(t, pull.UpdateCols(t.Context(), "has_merged"))
_, err = pull_service.DismissReview(t.Context(), review.ID, issue.RepoID, "", &user_model.User{}, false, false)
assert.Error(t, err)
assert.True(t, pull_service.IsErrDismissRequestOnClosedPR(err))
pull.HasMerged = true
pull.Issue.IsClosed = false
assert.NoError(t, issues_model.UpdateIssueCols(t.Context(), issue, "is_closed"))
assert.NoError(t, pull.UpdateCols(t.Context(), "has_merged"))
_, err = pull_service.DismissReview(t.Context(), review.ID, issue.RepoID, "", &user_model.User{}, false, false)
assert.Error(t, err)
assert.True(t, pull_service.IsErrDismissRequestOnClosedPR(err))
}
func TestCreateCodeCommentContextOfUnchangedLine(t *testing.T) {
require.NoError(t, unittest.PrepareTestDatabase())
ctx := t.Context()
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 6})
require.NoError(t, pr.LoadBaseRepo(ctx))
numberedLines := func(prefix string, count int) string {
var sb strings.Builder
for i := range count {
_, _ = fmt.Fprintf(&sb, "%s %d\n", prefix, i+1)
}
return sb.String()
}
// "old 10" was last changed by the first commit (line 10), it is line 15 in the merge base and line 17 in the PR head
const treePath = "unchanged-line.txt"
oldLines := numberedLines("old", 20)
baseLines := numberedLines("base", 5) + oldLines
headLines := numberedLines("head", 2) + baseLines
headRef := pr.GetGitHeadRefName()
require.NoError(t, git.ForceFastImport(ctx, pr.BaseRepo, []git.FastImportCommit{
{Ref: headRef, Files: []git.FastImportFile{{Path: treePath, Content: oldLines}}},
{Ref: headRef, Parent: ":1", Files: []git.FastImportFile{{Path: treePath, Content: baseLines}}},
{Ref: headRef, Parent: ":2", Files: []git.FastImportFile{{Path: treePath, Content: headLines}}},
}))
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo)
require.NoError(t, err)
defer gitRepo.Close()
headCommit, err := gitRepo.GetCommit(ctx, headRef)
require.NoError(t, err)
mergeBase, err := headCommit.ParentID(0)
require.NoError(t, err)
mergeBaseCommit, err := gitRepo.GetCommit(ctx, mergeBase.String())
require.NoError(t, err)
lineCommitID, err := mergeBaseCommit.ParentID(0)
require.NoError(t, err)
pr.MergeBase = mergeBase.String()
require.NoError(t, pr.UpdateCols(ctx, "merge_base"))
for _, c := range []struct {
name string
line int64
doerID int64
commitID string
}{
{"NewSide", 17, 2, ""},
{"OldSide", -15, 2, ""},
{"UnknownReviewCommit", 17, 4, strings.Repeat("a", 40)},
} {
t.Run(c.name, func(t *testing.T) {
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: c.doerID})
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: pr.IssueID})
require.NoError(t, issue.LoadRepo(ctx))
comment, err := pull_service.CreateCodeComment(ctx, doer, gitRepo, issue, c.line, "test", treePath, true, 0, c.commitID, nil)
require.NoError(t, err)
assert.True(t, strings.HasSuffix(comment.Patch, "\n old 10\n"), "patch: %q", comment.Patch)
if c.line > 0 {
assert.Equal(t, lineCommitID.String(), comment.CommitSHA)
require.NoError(t, pull_service.InvalidateCodeComments(ctx, issues_model.PullRequestList{pr}, pr.BaseRepo, headRef))
comment = unittest.AssertExistsAndLoadBean(t, &issues_model.Comment{ID: comment.ID})
assert.False(t, comment.Invalidated)
}
})
}
}
func TestCreateCodeCommentUnknownCommitID(t *testing.T) {
unittest.PrepareTestEnv(t)
ctx := t.Context()
doer := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
// org3/repo3.git: "test_branch" exists, but "refs/pull/2/head" (PR ID: 6) doesn't exist yet
pr := unittest.AssertExistsAndLoadBean(t, &issues_model.PullRequest{ID: 6})
require.NoError(t, pr.LoadBaseRepo(ctx))
issue := unittest.AssertExistsAndLoadBean(t, &issues_model.Issue{ID: pr.IssueID})
require.NoError(t, issue.LoadRepo(ctx))
gitRepo, err := git.OpenRepository(ctx, pr.BaseRepo)
require.NoError(t, err)
defer gitRepo.Close()
const treePath = "file.txt"
t.Run("RollbackOnFailure", func(t *testing.T) {
// the PR head ref doesn't exist yet, so creating the comment fails
_, err := gitRepo.GetCommit(ctx, pr.GetGitHeadRefName())
require.ErrorIs(t, err, util.ErrNotExist)
_, err = pull_service.CreateCodeComment(ctx, doer, gitRepo, issue, 1, "test", treePath, true, 0, "", nil)
require.Error(t, err)
_, err = issues_model.GetCurrentReview(ctx, doer, issue)
assert.True(t, issues_model.IsErrReviewNotExist(err), "got: %v", err)
})
t.Run("FallbackToHead", func(t *testing.T) {
headCommitID, err := gitRepo.GetBranchCommitID(ctx, pr.HeadBranch)
require.NoError(t, err)
require.NoError(t, git.UpdateRef(ctx, gitRepo, pr.GetGitHeadRefName(), headCommitID))
// the first comment creates the pending review with the unknown commit, the second one reuses it
for i, commitID := range []string{strings.Repeat("a", 40), headCommitID} {
comment, err := pull_service.CreateCodeComment(ctx, doer, gitRepo, issue, int64(i+1), "test", treePath, true, 0, commitID, nil)
require.NoError(t, err)
assert.Equal(t, headCommitID, comment.CommitSHA)
}
})
}