blob: 58b2de9d8233f3b041dbb23795d1cd1b7a416417 [file] [log] [blame]
package github_crs
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.skia.org/infra/go/mockhttpclient"
"go.skia.org/infra/go/testutils/unittest"
"go.skia.org/infra/go/vcsinfo"
"go.skia.org/infra/golden/go/code_review"
)
func TestGetChangelistSunnyDay(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
resp := mockhttpclient.MockGetDialogue([]byte(landedPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44380", resp)
c := New(m.Client(), "unit/test")
id := "44380"
ts := time.Date(2019, time.November, 7, 23, 39, 17, 0, time.UTC)
cl, err := c.GetChangelist(context.Background(), id)
require.NoError(t, err)
assert.Equal(t, code_review.Changelist{
SystemID: id,
Owner: "engine-flutter-autoroll",
Status: code_review.Landed,
Subject: "Roll engine ddceed5f7af1..629930e8887c (1 commits) (#44380)",
Updated: ts,
}, cl)
}
func TestGetChangelistOpen(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
resp := mockhttpclient.MockGetDialogue([]byte(openPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44380", resp)
c := New(m.Client(), "unit/test")
id := "44380"
ts := time.Date(2019, time.November, 7, 23, 39, 17, 0, time.UTC)
cl, err := c.GetChangelist(context.Background(), id)
require.NoError(t, err)
assert.Equal(t, code_review.Changelist{
SystemID: id,
Owner: "engine-flutter-autoroll",
Status: code_review.Open,
Subject: "Roll engine ddceed5f7af1..629930e8887c (1 commits)",
Updated: ts,
}, cl)
}
func TestGetChangelistAbandoned(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
resp := mockhttpclient.MockGetDialogue([]byte(abandonedPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44345", resp)
c := New(m.Client(), "unit/test")
id := "44345"
ts := time.Date(2019, time.November, 7, 14, 14, 0, 0, time.UTC)
cl, err := c.GetChangelist(context.Background(), id)
require.NoError(t, err)
assert.Equal(t, code_review.Changelist{
SystemID: id,
Owner: "a-user",
Status: code_review.Abandoned,
Subject: "Make BorderRadius.circular() a const constructor",
Updated: ts,
}, cl)
}
func TestGetChangelistDoesNotExist(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
// By not mocking anything, an error will be returned from GitHub,
// as we would expect for a 404
c := New(m.Client(), "unit/test")
_, err := c.GetChangelist(context.Background(), "44345")
require.Error(t, err)
assert.Equal(t, code_review.ErrNotFound, err)
}
func TestGetChangelistInvalidID(t *testing.T) {
unittest.SmallTest(t)
c := New(nil, "unit/test")
_, err := c.GetChangelist(context.Background(), "bad")
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid")
}
const omitPS = ""
const omitOrder = 0
func TestGetPatchset_OnePageResults_PatchsetExists_Success(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
fiveCommits := mockhttpclient.MockGetDialogue([]byte(fiveCommitsOnPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=1", fiveCommits)
donePaging := mockhttpclient.MockGetDialogue([]byte("[]"))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=2", donePaging)
c := New(m.Client(), "unit/test")
const clID = "44419"
const psOneID = "111119f299e91924405cb8bd244efc1a6c28e4fa"
const psFiveID = "555559b99ee360397a22cede6d9d16aacd245af1"
expectedFirstPS := code_review.Patchset{
SystemID: psOneID,
ChangelistID: clID,
Order: 1,
GitHash: psOneID,
Created: time.Date(2019, time.November, 8, 4, 18, 1, 0, time.UTC),
}
expectedFifthPS := code_review.Patchset{
SystemID: psFiveID,
ChangelistID: clID,
Order: 5,
GitHash: psFiveID,
Created: time.Date(2019, time.November, 8, 4, 18, 5, 0, time.UTC),
}
ps, err := c.GetPatchset(context.Background(), clID, psOneID, omitOrder)
require.NoError(t, err)
assert.Equal(t, expectedFirstPS, ps)
ps, err = c.GetPatchset(context.Background(), clID, omitPS, 1)
require.NoError(t, err)
assert.Equal(t, expectedFirstPS, ps)
ps, err = c.GetPatchset(context.Background(), clID, psFiveID, omitOrder)
require.NoError(t, err)
assert.Equal(t, expectedFifthPS, ps)
ps, err = c.GetPatchset(context.Background(), clID, omitPS, 5)
require.NoError(t, err)
assert.Equal(t, expectedFifthPS, ps)
}
func TestGetPatchset_TwoPageResults_PatchsetsExist_Success(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
fiveCommits := mockhttpclient.MockGetDialogue([]byte(fiveCommitsOnPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=1", fiveCommits)
twoCommits := mockhttpclient.MockGetDialogue([]byte(twoCommitsOnPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=2", twoCommits)
donePaging := mockhttpclient.MockGetDialogue([]byte("[]"))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=3", donePaging)
c := New(m.Client(), "unit/test")
const clID = "44419"
const psFiveID = "555559b99ee360397a22cede6d9d16aacd245af1" // first page
const psSevenID = "77777b5b0a55743c586708a94cbb69feb7bf32cd" // second page
expectedFifthPS := code_review.Patchset{
SystemID: psFiveID,
ChangelistID: clID,
Order: 5,
GitHash: psFiveID,
Created: time.Date(2019, time.November, 8, 4, 18, 5, 0, time.UTC),
}
expectedSeventhPS := code_review.Patchset{
SystemID: psSevenID,
ChangelistID: clID,
Order: 7,
GitHash: psSevenID,
Created: time.Date(2019, time.November, 8, 4, 18, 7, 0, time.UTC),
}
ps, err := c.GetPatchset(context.Background(), clID, psSevenID, omitOrder)
require.NoError(t, err)
assert.Equal(t, expectedSeventhPS, ps)
ps, err = c.GetPatchset(context.Background(), clID, omitPS, 7)
require.NoError(t, err)
assert.Equal(t, expectedSeventhPS, ps)
ps, err = c.GetPatchset(context.Background(), clID, psFiveID, omitOrder)
require.NoError(t, err)
assert.Equal(t, expectedFifthPS, ps)
ps, err = c.GetPatchset(context.Background(), clID, omitPS, 5)
require.NoError(t, err)
assert.Equal(t, expectedFifthPS, ps)
}
func TestGetPatchset_OnePageResults_PatchsetDoesNotExist_ReturnsNotFound(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
fiveCommits := mockhttpclient.MockGetDialogue([]byte(fiveCommitsOnPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=1", fiveCommits)
donePaging := mockhttpclient.MockGetDialogue([]byte("[]"))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=2", donePaging)
c := New(m.Client(), "unit/test")
const clID = "44419"
_, err := c.GetPatchset(context.Background(), clID, "does not exist", omitOrder)
require.Error(t, err)
assert.Equal(t, code_review.ErrNotFound, err)
_, err = c.GetPatchset(context.Background(), clID, omitPS, 10000)
require.Error(t, err)
assert.Equal(t, code_review.ErrNotFound, err)
}
func TestGetPatchset_NoPatchsetsReturned_ReturnsNotFound(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
none := mockhttpclient.MockGetDialogue([]byte("[]"))
m.Mock("https://api.github.com/repos/unit/test/pulls/44419/commits?page=1", none)
c := New(m.Client(), "unit/test")
_, err := c.GetPatchset(context.Background(), "44419", "whatever", omitOrder)
require.Error(t, err)
assert.Equal(t, code_review.ErrNotFound, err)
_, err = c.GetPatchset(context.Background(), "44419", omitPS, 4)
require.Error(t, err)
assert.Equal(t, code_review.ErrNotFound, err)
}
func TestGetPatchset_ChangelistDoesNotExist_ReturnsNotFound(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
// By not mocking anything, an error will be returned from Git,
// as we would expect for a 404
c := New(m.Client(), "unit/test")
_, err := c.GetPatchset(context.Background(), "1234", "nope", omitOrder)
require.Error(t, err)
require.Equal(t, code_review.ErrNotFound, err)
_, err = c.GetPatchset(context.Background(), "1234", omitPS, 1)
require.Error(t, err)
require.Equal(t, code_review.ErrNotFound, err)
}
func TestGetPatchset_InvalidIDForChangelist_ReturnsError(t *testing.T) {
unittest.SmallTest(t)
c := New(nil, "unit/test")
_, err := c.GetPatchset(context.Background(), "bad", "nope", omitOrder)
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid")
}
func TestGetChangelistForCommitSunnyDay(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
resp := mockhttpclient.MockGetDialogue([]byte(landedPullRequestResponse))
m.Mock("https://api.github.com/repos/unit/test/pulls/44380", resp)
c := New(m.Client(), "unit/test")
clID, err := c.GetChangelistIDForCommit(context.Background(), &vcsinfo.LongCommit{
// This is the only field the implementation cares about.
ShortCommit: &vcsinfo.ShortCommit{
Subject: "Roll engine ddceed5f7af1..629930e8887c (1 commits) (#44380)",
},
})
require.NoError(t, err)
assert.Equal(t, "44380", clID)
}
func TestGetChangelistForCommitMalformed(t *testing.T) {
unittest.SmallTest(t)
c := New(nil, "unit/test")
_, err := c.GetChangelistIDForCommit(context.Background(), &vcsinfo.LongCommit{
// This is the only field the implementation cares about.
ShortCommit: &vcsinfo.ShortCommit{
Subject: "Roll engine ddceed5f7af1..629930e8887c (1 commits)",
},
})
require.Error(t, err)
assert.Equal(t, code_review.ErrNotFound, err)
}
func TestCommentOnSunnyDay(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
expectedJSON := []byte(`{"body":"untriaged \"digests\" detected"}`)
responseJSONWeIgnoreAnyway := []byte(`{"id": 1}`)
resp := mockhttpclient.MockPostDialogueWithResponseCode("application/json", expectedJSON, responseJSONWeIgnoreAnyway, 201)
m.Mock("https://api.github.com/repos/unit/test/issues/44474/comments", resp)
c := New(m.Client(), "unit/test")
err := c.CommentOn(context.Background(), "44474", `untriaged "digests" detected`)
require.NoError(t, err)
}
func TestCommentOnError(t *testing.T) {
unittest.SmallTest(t)
m := mockhttpclient.NewURLMock()
// By not mocking anything, an error will be returned from GitHub,
// as we would expect for a Changelist not found or something.
c := New(m.Client(), "unit/test")
_, err := c.GetChangelist(context.Background(), "44345")
require.Error(t, err)
}
// There's a lot more data here, but these JSON strings contain
// only the fields which we care about.
// This is based on https://github.com/flutter/flutter/pull/44380
const landedPullRequestResponse = `
{
"title": "Roll engine ddceed5f7af1..629930e8887c (1 commits) (#44380)",
"state": "closed",
"user": {
"login": "engine-flutter-autoroll"
},
"updated_at": "2019-11-07T23:39:17Z",
"merged_at": "2019-11-07T23:39:17Z"
}`
const openPullRequestResponse = `
{
"title": "Roll engine ddceed5f7af1..629930e8887c (1 commits)",
"state": "open",
"user": {
"login": "engine-flutter-autoroll"
},
"updated_at": "2019-11-07T23:39:17Z",
"merged_at": null
}`
// This is based on https://github.com/flutter/flutter/pull/44345
const abandonedPullRequestResponse = `
{
"title": "Make BorderRadius.circular() a const constructor",
"state": "closed",
"user": {
"login": "a-user"
},
"updated_at": "2019-11-07T14:14:00Z",
"merged_at": null
}`
// This is based on https://github.com/flutter/flutter/pull/44419, with the shas changed for
// readability.
const fiveCommitsOnPullRequestResponse = `
[
{
"sha": "111119f299e91924405cb8bd244efc1a6c28e4fa",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:01Z"
}
}
},
{
"sha": "22222382b7ec0efdb7570c3e6c891cf2a20379a7",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:02Z"
}
}
},
{
"sha": "333337085723c13fa96777a1830c7113e7ffba96",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:03Z"
}
}
},
{
"sha": "44444639d8a1cca0929829b04d90f35011b50fbf",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:04Z"
}
}
},
{
"sha": "555559b99ee360397a22cede6d9d16aacd245af1",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:05Z"
}
}
}
]`
const twoCommitsOnPullRequestResponse = `
[
{
"sha": "666667ad358596996cfd8664b66a9087e3d7ee1c",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:06Z"
}
}
},
{
"sha": "77777b5b0a55743c586708a94cbb69feb7bf32cd",
"commit": {
"committer": {
"name": "engine-flutter-autoroll",
"email": "engine-flutter-autoroll@skia.org",
"date": "2019-11-08T04:18:07Z"
}
}
}
]`