cli/internal/featuredetection/feature_detection_test.go

389 lines
9.1 KiB
Go

package featuredetection
import (
"net/http"
"testing"
"github.com/MakeNowJust/heredoc"
"github.com/cli/cli/v2/internal/gh"
"github.com/cli/cli/v2/pkg/httpmock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestIssueFeatures(t *testing.T) {
tests := []struct {
name string
hostname string
queryResponse map[string]string
wantFeatures IssueFeatures
wantErr bool
}{
{
name: "github.com",
hostname: "github.com",
wantFeatures: IssueFeatures{
StateReason: true,
ActorIsAssignable: true,
},
wantErr: false,
},
{
name: "ghec data residency (ghe.com)",
hostname: "stampname.ghe.com",
wantFeatures: IssueFeatures{
StateReason: true,
ActorIsAssignable: true,
},
wantErr: false,
},
{
name: "GHE empty response",
hostname: "git.my.org",
queryResponse: map[string]string{
`query Issue_fields\b`: `{"data": {}}`,
},
wantFeatures: IssueFeatures{
StateReason: false,
ActorIsAssignable: false,
},
wantErr: false,
},
{
name: "GHE has state reason field",
hostname: "git.my.org",
queryResponse: map[string]string{
`query Issue_fields\b`: heredoc.Doc(`
{ "data": { "Issue": { "fields": [
{"name": "stateReason"}
] } } }
`),
},
wantFeatures: IssueFeatures{
StateReason: true,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
httpClient := &http.Client{}
httpmock.ReplaceTripper(httpClient, reg)
for query, resp := range tt.queryResponse {
reg.Register(httpmock.GraphQL(query), httpmock.StringResponse(resp))
}
detector := detector{host: tt.hostname, httpClient: httpClient}
gotFeatures, err := detector.IssueFeatures()
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wantFeatures, gotFeatures)
})
}
}
func TestPullRequestFeatures(t *testing.T) {
tests := []struct {
name string
hostname string
queryResponse map[string]string
wantFeatures PullRequestFeatures
wantErr bool
}{
{
name: "github.com with all features",
hostname: "github.com",
queryResponse: map[string]string{
`query PullRequest_fields\b`: heredoc.Doc(`
{
"data": {
"PullRequest": {
"fields": [
{"name": "isInMergeQueue"},
{"name": "isMergeQueueEnabled"}
]
},
"StatusCheckRollupContextConnection": {
"fields": [
{"name": "checkRunCount"},
{"name": "checkRunCountsByState"},
{"name": "statusContextCount"},
{"name": "statusContextCountsByState"}
]
}
}
}`),
`query PullRequest_fields2\b`: heredoc.Doc(`
{
"data": {
"WorkflowRun": {
"fields": [
{"name": "event"}
]
}
}
}`),
},
wantFeatures: PullRequestFeatures{
MergeQueue: true,
CheckRunAndStatusContextCounts: true,
CheckRunEvent: true,
},
wantErr: false,
},
{
name: "github.com with no merge queue",
hostname: "github.com",
queryResponse: map[string]string{
`query PullRequest_fields\b`: heredoc.Doc(`
{
"data": {
"PullRequest": {
"fields": []
},
"StatusCheckRollupContextConnection": {
"fields": [
{"name": "checkRunCount"},
{"name": "checkRunCountsByState"},
{"name": "statusContextCount"},
{"name": "statusContextCountsByState"}
]
}
}
}`),
`query PullRequest_fields2\b`: heredoc.Doc(`
{
"data": {
"WorkflowRun": {
"fields": [
{"name": "event"}
]
}
}
}`),
},
wantFeatures: PullRequestFeatures{
MergeQueue: false,
CheckRunAndStatusContextCounts: true,
CheckRunEvent: true,
},
wantErr: false,
},
{
name: "GHE with all features",
hostname: "git.my.org",
queryResponse: map[string]string{
`query PullRequest_fields\b`: heredoc.Doc(`
{
"data": {
"PullRequest": {
"fields": [
{"name": "isInMergeQueue"},
{"name": "isMergeQueueEnabled"}
]
},
"StatusCheckRollupContextConnection": {
"fields": [
{"name": "checkRunCount"},
{"name": "checkRunCountsByState"},
{"name": "statusContextCount"},
{"name": "statusContextCountsByState"}
]
}
}
}`),
`query PullRequest_fields2\b`: heredoc.Doc(`
{
"data": {
"WorkflowRun": {
"fields": [
{"name": "event"}
]
}
}
}`),
},
wantFeatures: PullRequestFeatures{
MergeQueue: true,
CheckRunAndStatusContextCounts: true,
CheckRunEvent: true,
},
wantErr: false,
},
{
name: "GHE with no features",
hostname: "git.my.org",
queryResponse: map[string]string{
`query PullRequest_fields\b`: heredoc.Doc(`
{
"data": {
"PullRequest": {
"fields": []
},
"StatusCheckRollupContextConnection": {
"fields": []
}
}
}`),
`query PullRequest_fields2\b`: heredoc.Doc(`
{
"data": {
"WorkflowRun": {
"fields": []
}
}
}`),
},
wantFeatures: PullRequestFeatures{
MergeQueue: false,
CheckRunAndStatusContextCounts: false,
CheckRunEvent: false,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
httpClient := &http.Client{}
httpmock.ReplaceTripper(httpClient, reg)
for query, resp := range tt.queryResponse {
reg.Register(httpmock.GraphQL(query), httpmock.StringResponse(resp))
}
detector := detector{host: tt.hostname, httpClient: httpClient}
gotFeatures, err := detector.PullRequestFeatures()
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wantFeatures, gotFeatures)
})
}
}
func TestRepositoryFeatures(t *testing.T) {
tests := []struct {
name string
hostname string
queryResponse map[string]string
wantFeatures RepositoryFeatures
wantErr bool
}{
{
name: "github.com",
hostname: "github.com",
wantFeatures: RepositoryFeatures{
PullRequestTemplateQuery: true,
VisibilityField: true,
AutoMerge: true,
},
wantErr: false,
},
{
name: "ghec data residency (ghe.com)",
hostname: "stampname.ghe.com",
wantFeatures: RepositoryFeatures{
PullRequestTemplateQuery: true,
VisibilityField: true,
AutoMerge: true,
},
wantErr: false,
},
{
name: "GHE empty response",
hostname: "git.my.org",
queryResponse: map[string]string{
`query Repository_fields\b`: `{"data": {}}`,
},
wantFeatures: RepositoryFeatures{
PullRequestTemplateQuery: false,
},
wantErr: false,
},
{
name: "GHE has pull request template query",
hostname: "git.my.org",
queryResponse: map[string]string{
`query Repository_fields\b`: heredoc.Doc(`
{ "data": { "Repository": { "fields": [
{"name": "pullRequestTemplates"}
] } } }
`),
},
wantFeatures: RepositoryFeatures{
PullRequestTemplateQuery: true,
},
wantErr: false,
},
{
name: "GHE has visibility field",
hostname: "git.my.org",
queryResponse: map[string]string{
`query Repository_fields\b`: heredoc.Doc(`
{ "data": { "Repository": { "fields": [
{"name": "visibility"}
] } } }
`),
},
wantFeatures: RepositoryFeatures{
VisibilityField: true,
},
wantErr: false,
},
{
name: "GHE has automerge field",
hostname: "git.my.org",
queryResponse: map[string]string{
`query Repository_fields\b`: heredoc.Doc(`
{ "data": { "Repository": { "fields": [
{"name": "autoMergeAllowed"}
] } } }
`),
},
wantFeatures: RepositoryFeatures{
AutoMerge: true,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
reg := &httpmock.Registry{}
httpClient := &http.Client{}
httpmock.ReplaceTripper(httpClient, reg)
for query, resp := range tt.queryResponse {
reg.Register(httpmock.GraphQL(query), httpmock.StringResponse(resp))
}
detector := detector{host: tt.hostname, httpClient: httpClient}
gotFeatures, err := detector.RepositoryFeatures()
if tt.wantErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
assert.Equal(t, tt.wantFeatures, gotFeatures)
})
}
}
func TestProjectV1Support(t *testing.T) {
t.Parallel()
t.Run("when the host is enterprise, project v1 is supported", func(t *testing.T) {
detector := detector{host: "my.ghes.com"}
isProjectV1Supported := detector.ProjectsV1()
require.Equal(t, gh.ProjectsV1Supported, isProjectV1Supported)
})
t.Run("when the host is not enterprise, project v1 is not supported", func(t *testing.T) {
detector := detector{host: "github.com"}
isProjectV1Supported := detector.ProjectsV1()
require.Equal(t, gh.ProjectsV1Unsupported, isProjectV1Supported)
})
}