Timeline events will contain Reviews and ReviewRequests and ReviewDismissed events. We need to handle this at event parsing time and not to punt this to the query functions later on. If the last event is an actual review, we use this. If no review, check if last event associated with the reviewer is Dismissed or Requested Review but not if a dismissed Review preceeds it.
238 lines
8.5 KiB
Go
238 lines
8.5 KiB
Go
package common_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
|
|
"src.opensuse.org/autogits/common"
|
|
"src.opensuse.org/autogits/common/gitea-generated/models"
|
|
mock_common "src.opensuse.org/autogits/common/mock"
|
|
)
|
|
|
|
func TestReviews(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
reviews []*models.PullReview
|
|
timeline []*models.TimelineComment
|
|
reviewers []string
|
|
fetchErr error
|
|
isApproved bool
|
|
isReviewedByTest1 bool
|
|
isPendingByTest1 bool
|
|
}{
|
|
{
|
|
name: "Reviews of PR with no review requirements",
|
|
isApproved: true,
|
|
},
|
|
{
|
|
name: "Single reviewer done",
|
|
reviews: []*models.PullReview{&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}}},
|
|
reviewers: []string{"user1"},
|
|
isApproved: true,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Two reviewer, one not approved",
|
|
reviews: []*models.PullReview{&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}}},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Two reviewer, one stale approved",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}, Stale: true},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Two reviewer, one is pending",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateRequestReview, User: &models.User{UserName: "user1"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isPendingByTest1: true,
|
|
},
|
|
{
|
|
name: "Two reviewer, one stale and pending",
|
|
reviews: []*models.PullReview{
|
|
{State: common.ReviewStateRequestReview, User: &models.User{UserName: "user1"}, Stale: true},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isPendingByTest1: true,
|
|
isReviewedByTest1: false,
|
|
},
|
|
{
|
|
name: "Two reviewer, one stale and pending, other done",
|
|
reviews: []*models.PullReview{
|
|
{State: common.ReviewStateRequestReview, User: &models.User{UserName: "user1"}},
|
|
{State: common.ReviewStateRequestChanges, User: &models.User{UserName: "user1"}},
|
|
{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isPendingByTest1: true,
|
|
isReviewedByTest1: false,
|
|
},
|
|
{
|
|
name: "Two reviewer approved",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: true,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Two reviewer approved, one is dismissed",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}, Dismissed: true},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Two reviewer approved, but fetch error",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
fetchErr: errors.New("System error fetching reviews."),
|
|
isApproved: true,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Extra reviewers are ignored",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user4"}},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: true,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Review ignored before push",
|
|
reviews: []*models.PullReview{
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user1"}, ID: 1001},
|
|
&models.PullReview{State: common.ReviewStateApproved, User: &models.User{UserName: "user2"}, ID: 1000},
|
|
},
|
|
timeline: []*models.TimelineComment{
|
|
&models.TimelineComment{Type: common.TimelineCommentType_Review, ReviewID: 1001},
|
|
&models.TimelineComment{Type: common.TimelineCommentType_PushPull},
|
|
&models.TimelineComment{Type: common.TimelineCommentType_Review, ReviewID: 1000},
|
|
},
|
|
reviewers: []string{"user1", "user2"},
|
|
isApproved: false,
|
|
isReviewedByTest1: true,
|
|
},
|
|
{
|
|
name: "Ghost user review",
|
|
reviews: []*models.PullReview{
|
|
{State: common.ReviewStateApproved, User: nil},
|
|
},
|
|
reviewers: []string{"user1"},
|
|
isApproved: false,
|
|
},
|
|
{
|
|
name: "ReviewRequested predates PushPull should be seen as pending",
|
|
reviews: []*models.PullReview{},
|
|
timeline: []*models.TimelineComment{
|
|
{Type: common.TimelineCommentType_PushPull},
|
|
{Type: common.TimelineCommentType_ReviewRequested, Assignee: &models.User{UserName: "user1"}},
|
|
},
|
|
reviewers: []string{"user1"},
|
|
isPendingByTest1: true,
|
|
},
|
|
{
|
|
name: "ReviewRequested postdates PushPull but blocked by older dismiss",
|
|
reviews: []*models.PullReview{},
|
|
timeline: []*models.TimelineComment{
|
|
{Type: common.TimelineCommentType_ReviewRequested, Assignee: &models.User{UserName: "user1"}},
|
|
{Type: common.TimelineCommentType_PushPull},
|
|
{Type: common.TimelineCommentType_ReviewDismissed, Assignee: &models.User{UserName: "user1"}},
|
|
},
|
|
reviewers: []string{"user1"},
|
|
isPendingByTest1: true,
|
|
},
|
|
{
|
|
name: "ReviewRequested predates PushPull should be seen as pending",
|
|
reviews: []*models.PullReview{
|
|
{ID: 101, State: common.ReviewStateRequestReview, User: &models.User{UserName: "user1"}},
|
|
},
|
|
timeline: []*models.TimelineComment{
|
|
{Type: common.TimelineCommentType_PushPull},
|
|
{Type: common.TimelineCommentType_ReviewRequested, Assignee: &models.User{UserName: "user1"}},
|
|
},
|
|
reviewers: []string{"user1"},
|
|
isPendingByTest1: true,
|
|
},
|
|
{
|
|
name: "Review requested, review, then push needs re-requesting",
|
|
reviews: []*models.PullReview{
|
|
{ID: 100, State: common.ReviewStateRequestChanges, User: &models.User{UserName: "user1"}},
|
|
},
|
|
timeline: []*models.TimelineComment{
|
|
{Type: common.TimelineCommentType_PushPull},
|
|
{Type: common.TimelineCommentType_Review, ReviewID: 100},
|
|
{Type: common.TimelineCommentType_ReviewRequested, Assignee: &models.User{UserName: "user1"}},
|
|
},
|
|
reviewers: []string{"user1"},
|
|
isReviewedByTest1: false, // Should be stale
|
|
isPendingByTest1: false, // Should be stale
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
ctl := NewController(t)
|
|
rf := mock_common.NewMockGiteaReviewTimelineFetcher(ctl)
|
|
|
|
if test.timeline == nil {
|
|
test.timeline = reviewsToTimeline(test.reviews)
|
|
}
|
|
rf.EXPECT().GetTimeline("test", "pr", int64(1)).Return(test.timeline, nil)
|
|
rf.EXPECT().GetPullRequestReviews("test", "pr", int64(1)).Return(test.reviews, test.fetchErr)
|
|
|
|
reviews, err := common.FetchGiteaReviews(rf, "test", "pr", 1)
|
|
|
|
if test.fetchErr != nil {
|
|
if err != test.fetchErr {
|
|
t.Fatal("FetchReviews() failed with unexpected error:", err)
|
|
}
|
|
return
|
|
}
|
|
reviews.SetRequiredReviewers(test.reviewers)
|
|
|
|
if r := reviews.IsApproved(); r != test.isApproved {
|
|
t.Fatal("Unexpected IsReviewed():", r, "vs. expected", test.isApproved)
|
|
}
|
|
|
|
if r := reviews.HasPendingReviewBy("user1"); r != test.isPendingByTest1 {
|
|
t.Fatal("Unexpected IsReviewPendingBy(user1):", r)
|
|
}
|
|
if r := reviews.IsReviewedBy("user1"); r != test.isReviewedByTest1 {
|
|
t.Fatal("Unexpected IsReviewedBy(user1):", r)
|
|
}
|
|
|
|
if r := reviews.HasPendingReviewBy("random"); r {
|
|
t.Fatal("Unexpected IsReviewPendingBy(random):", r)
|
|
}
|
|
if r := reviews.IsReviewedBy("random"); r {
|
|
t.Fatal("Unexpected IsReviewedBy(random):", r)
|
|
}
|
|
})
|
|
}
|
|
}
|