blob: 2700122e8db0e07604dedd572b543f6587b40dd5 [file] [log] [blame]
package codereview
import (
"context"
"strconv"
"testing"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/deepequal"
"go.skia.org/infra/go/gerrit"
"go.skia.org/infra/go/gerrit/mocks"
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/testutils"
"go.skia.org/infra/go/testutils/unittest"
)
var (
// http.Client used for testing.
c = httputils.NewTimeoutClient()
)
func TestSearch(t *testing.T) {
unittest.SmallTest(t)
// Mock gerrit.
g := &mocks.GerritInterface{}
g.On("Config").Return(gerrit.ConfigChromium).Twice()
// Mock search call to CQ runs.
cqChangeID1 := int64(123)
cqChangeInfo1 := &gerrit.ChangeInfo{Issue: cqChangeID1}
g.On(
"Search",
testutils.AnyContext,
GerritOpenChangesNum,
true,
gerrit.SearchStatus(gerrit.ChangeStatusOpen),
gerrit.SearchLabel(gerrit.LabelCommitQueue, strconv.Itoa(gerrit.LabelCommitQueueSubmit)),
).Return([]*gerrit.ChangeInfo{cqChangeInfo1}, nil).Once()
g.On("GetIssueProperties", testutils.AnyContext, cqChangeID1).Return(cqChangeInfo1, nil).Once()
// Mock search call to dry-runs.
dryRunChangeID1 := int64(123) // Same ID as cqChangeID1 to test for deduplication.
dryRunChangeID2 := int64(345)
dryRunChangeID3 := int64(902)
dryRunChangeInfo1 := &gerrit.ChangeInfo{Issue: dryRunChangeID1}
dryRunChangeInfo2 := &gerrit.ChangeInfo{Issue: dryRunChangeID2}
dryRunChangeInfo3 := &gerrit.ChangeInfo{Issue: dryRunChangeID3}
g.On(
"Search",
testutils.AnyContext,
GerritOpenChangesNum,
true,
gerrit.SearchStatus(gerrit.ChangeStatusOpen),
gerrit.SearchLabel(gerrit.LabelCommitQueue, strconv.Itoa(gerrit.LabelCommitQueueDryRun)),
).Return([]*gerrit.ChangeInfo{dryRunChangeInfo1, dryRunChangeInfo2, dryRunChangeInfo3}, nil)
cr := gerritCodeReview{
gerritClient: g,
cfg: gerrit.ConfigChromium,
}
changes, err := cr.Search(context.Background())
require.NoError(t, err)
require.Len(t, changes, 3)
require.True(t, deepequal.DeepEqual([]*gerrit.ChangeInfo{cqChangeInfo1, dryRunChangeInfo2, dryRunChangeInfo3}, changes))
}
func TestRemoveFromCQ(t *testing.T) {
unittest.SmallTest(t)
comment := "SkCQ is no longer looking at this change"
notifyReason := "SkCQ run failed."
changeID := int64(123)
accountID1 := 111111
accountID2 := 222222
accountID3 := 333333
ci := &gerrit.ChangeInfo{
Issue: changeID,
Owner: &gerrit.Person{
Email: "batman@gotham.com",
},
Labels: map[string]*gerrit.LabelEntry{
gerrit.LabelCommitQueue: {
All: []*gerrit.LabelDetail{
{
Value: gerrit.LabelCommitQueueDryRun,
AccountID: accountID1,
},
{
Value: gerrit.LabelCommitQueueNone,
AccountID: accountID2,
},
{
Value: gerrit.LabelCommitQueueSubmit,
AccountID: accountID3,
},
},
},
// This should be ignored.
gerrit.LabelCodeReview: {
All: []*gerrit.LabelDetail{
{
Value: gerrit.LabelCodeReviewApprove,
AccountID: accountID1,
},
},
},
},
}
// Mock gerrit.
g := &mocks.GerritInterface{}
g.On("DeleteVote", testutils.AnyContext, changeID, gerrit.LabelCommitQueue, accountID1, gerrit.NotifyNone, true).Return(nil).Once()
g.On("DeleteVote", testutils.AnyContext, changeID, gerrit.LabelCommitQueue, accountID3, gerrit.NotifyNone, true).Return(nil).Once()
g.On("SetReview", testutils.AnyContext, ci, comment, map[string]int{}, []string{}, gerrit.NotifyOwner, mock.Anything, AutogeneratedCommentTag, 0, mock.Anything).Return(nil).Once()
cr := gerritCodeReview{
gerritClient: g,
cfg: gerrit.ConfigChromium,
}
cr.RemoveFromCQ(context.Background(), ci, comment, notifyReason)
}
func TestGetSubmittedTogether(t *testing.T) {
unittest.SmallTest(t)
changeID1 := "change1"
issue1 := int64(123)
changeID2 := "change2"
issue2 := int64(324)
changeID3 := "change3"
issue3 := int64(523)
changeInfo1 := &gerrit.ChangeInfo{
Id: changeID1,
Issue: issue1,
}
changeInfo2 := &gerrit.ChangeInfo{
Id: changeID2,
Issue: issue2,
}
changeInfo3 := &gerrit.ChangeInfo{
Id: changeID3,
Issue: issue3,
}
// Mock gerrit with a dependency chain of
// changeInfo3<-changeInfo2<-changeInfo1. changeInfo1 also has one hidden
// dependency.
g := &mocks.GerritInterface{}
g.On("SubmittedTogether", testutils.AnyContext, changeInfo1).Return([]*gerrit.ChangeInfo{changeInfo1}, 0, nil).Once()
g.On("SubmittedTogether", testutils.AnyContext, changeInfo2).Return([]*gerrit.ChangeInfo{changeInfo1, changeInfo2}, 0, nil).Once()
g.On("SubmittedTogether", testutils.AnyContext, changeInfo3).Return([]*gerrit.ChangeInfo{changeInfo1, changeInfo2, changeInfo3}, 1, nil).Once()
g.On("GetIssueProperties", testutils.AnyContext, issue1).Return(changeInfo1, nil).Once()
g.On("GetIssueProperties", testutils.AnyContext, issue2).Return(changeInfo2, nil).Once()
g.On("GetIssueProperties", testutils.AnyContext, issue3).Return(changeInfo3, nil).Once()
cr := gerritCodeReview{
gerritClient: g,
cfg: gerrit.ConfigChromium,
}
// changeInfo1 has no dependencies.
submittedTogetherChanges1, err1 := cr.GetSubmittedTogether(context.Background(), changeInfo1)
require.NoError(t, err1)
require.True(t, deepequal.DeepEqual([]*gerrit.ChangeInfo{}, submittedTogetherChanges1))
// changeInfo2 has one dependency.
submittedTogetherChanges2, err2 := cr.GetSubmittedTogether(context.Background(), changeInfo2)
require.NoError(t, err2)
require.True(t, deepequal.DeepEqual([]*gerrit.ChangeInfo{changeInfo1}, submittedTogetherChanges2))
// changeInfo3 has 2 dependencies.
submittedTogetherChanges3, err3 := cr.GetSubmittedTogether(context.Background(), changeInfo3)
require.Error(t, err3)
require.Nil(t, submittedTogetherChanges3)
}
func TestGetEquivalentPatchSetIDs(t *testing.T) {
unittest.SmallTest(t)
changeInfo := &gerrit.ChangeInfo{
// Most recent revisions are first.
Patchsets: []*gerrit.Revision{
{
Number: 1,
Kind: gerrit.PatchSetKindCodeChange,
},
{
Number: 2,
Kind: gerrit.PatchSetKindTrivialRebase,
},
{
Number: 3,
Kind: gerrit.PatchSetKindNoCodeChange,
},
{
Number: 4,
Kind: gerrit.PatchSetKindRework,
},
{
Number: 5,
Kind: gerrit.PatchSetKindCodeChange,
},
},
}
cr := gerritCodeReview{}
// #PS5 has no equivalent patch sets.
patchsetIDs := cr.GetEquivalentPatchSetIDs(changeInfo, 5)
require.True(t, deepequal.DeepEqual([]int64{5}, patchsetIDs))
// #PS4 has no equivalent patch sets.
patchsetIDs = cr.GetEquivalentPatchSetIDs(changeInfo, 4)
require.True(t, deepequal.DeepEqual([]int64{4}, patchsetIDs))
// #PS3 has 2 other equivalent patch sets.
patchsetIDs = cr.GetEquivalentPatchSetIDs(changeInfo, 3)
require.True(t, deepequal.DeepEqual([]int64{3, 2, 1}, patchsetIDs))
// #PS2 has 1 other equivalent patch sets.
patchsetIDs = cr.GetEquivalentPatchSetIDs(changeInfo, 2)
require.True(t, deepequal.DeepEqual([]int64{2, 1}, patchsetIDs))
// #PS1 has no equivalent patch sets.
patchsetIDs = cr.GetEquivalentPatchSetIDs(changeInfo, 1)
require.True(t, deepequal.DeepEqual([]int64{1}, patchsetIDs))
// Test for non-existent patch sets.
patchsetIDs = cr.GetEquivalentPatchSetIDs(changeInfo, 0)
require.Len(t, patchsetIDs, 0)
patchsetIDs = cr.GetEquivalentPatchSetIDs(changeInfo, 6)
require.Len(t, patchsetIDs, 0)
}
func TestGetChangeRef(t *testing.T) {
unittest.SmallTest(t)
changeInfo := &gerrit.ChangeInfo{
Issue: 443102,
// Most recent revisions are first.
Patchsets: []*gerrit.Revision{
{
Number: 1,
Kind: gerrit.PatchSetKindCodeChange,
},
{
Number: 2,
Kind: gerrit.PatchSetKindTrivialRebase,
},
},
}
cr := gerritCodeReview{}
require.Equal(t, "refs/changes/02/443102/2", cr.GetChangeRef(changeInfo))
}
func TestGetCQVoters(t *testing.T) {
unittest.SmallTest(t)
// Mock gerrit.
g := &mocks.GerritInterface{}
g.On("Config").Return(gerrit.ConfigChromium).Twice()
changeID := int64(123)
email1 := "batman@gotham.com"
email2 := "superman@krypton.com"
email3 := "joker@gotham.com"
email4 := "pengiun@gotham.com"
labelDetailWithCQ := []*gerrit.LabelDetail{
{
Value: gerrit.LabelCommitQueueDryRun,
Email: email1,
},
{
Value: gerrit.LabelCommitQueueNone,
Email: email2,
},
{
Value: gerrit.LabelCommitQueueSubmit,
Email: email3,
},
{
Value: gerrit.LabelCommitQueueSubmit,
Email: email4,
},
}
labelDetailWithDryRun := []*gerrit.LabelDetail{
{
Value: gerrit.LabelCommitQueueDryRun,
Email: email1,
},
{
Value: gerrit.LabelCommitQueueNone,
Email: email2,
},
}
labelDetailWithNone := []*gerrit.LabelDetail{
{
Value: gerrit.LabelCommitQueueNone,
Email: email2,
},
}
labelDetailEmpty := []*gerrit.LabelDetail{}
changeInfo := &gerrit.ChangeInfo{
Issue: changeID,
Labels: map[string]*gerrit.LabelEntry{
gerrit.LabelCommitQueue: {
All: labelDetailEmpty,
},
// This should be ignored.
gerrit.LabelCodeReview: {
All: []*gerrit.LabelDetail{
{
Value: gerrit.LabelCodeReviewApprove,
Email: email1,
},
},
},
},
}
cr := gerritCodeReview{
gerritClient: g,
cfg: gerrit.ConfigChromium,
}
tests := []struct {
labelDetails []*gerrit.LabelDetail
expectedVoters []string
}{
{
labelDetails: labelDetailEmpty,
expectedVoters: []string{},
},
{
labelDetails: labelDetailWithNone,
expectedVoters: []string{},
},
{
labelDetails: labelDetailWithDryRun,
expectedVoters: []string{email1},
},
{
labelDetails: labelDetailWithCQ,
expectedVoters: []string{email3, email4},
},
}
for _, test := range tests {
changeInfo.Labels[gerrit.LabelCommitQueue].All = test.labelDetails
voters := cr.GetCQVoters(context.Background(), changeInfo)
require.True(t, deepequal.DeepEqual(test.expectedVoters, voters))
}
}