cli/pkg/cmd/api/api_test.go

307 lines
6.7 KiB
Go

package api
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"testing"
"github.com/cli/cli/pkg/cmdutil"
"github.com/cli/cli/pkg/iostreams"
"github.com/google/shlex"
"github.com/stretchr/testify/assert"
)
func Test_NewCmdApi(t *testing.T) {
f := &cmdutil.Factory{}
tests := []struct {
name string
cli string
wants ApiOptions
wantsErr bool
}{
{
name: "no flags",
cli: "graphql",
wants: ApiOptions{
RequestMethod: "GET",
RequestMethodPassed: false,
RequestPath: "graphql",
RawFields: []string(nil),
MagicFields: []string(nil),
RequestHeaders: []string(nil),
ShowResponseHeaders: false,
},
wantsErr: false,
},
{
name: "override method",
cli: "repos/octocat/Spoon-Knife -XDELETE",
wants: ApiOptions{
RequestMethod: "DELETE",
RequestMethodPassed: true,
RequestPath: "repos/octocat/Spoon-Knife",
RawFields: []string(nil),
MagicFields: []string(nil),
RequestHeaders: []string(nil),
ShowResponseHeaders: false,
},
wantsErr: false,
},
{
name: "with fields",
cli: "graphql -f query=QUERY -F body=@file.txt",
wants: ApiOptions{
RequestMethod: "GET",
RequestMethodPassed: false,
RequestPath: "graphql",
RawFields: []string{"query=QUERY"},
MagicFields: []string{"body=@file.txt"},
RequestHeaders: []string(nil),
ShowResponseHeaders: false,
},
wantsErr: false,
},
{
name: "with headers",
cli: "user -H 'accept: text/plain' -i",
wants: ApiOptions{
RequestMethod: "GET",
RequestMethodPassed: false,
RequestPath: "user",
RawFields: []string(nil),
MagicFields: []string(nil),
RequestHeaders: []string{"accept: text/plain"},
ShowResponseHeaders: true,
},
wantsErr: false,
},
{
name: "no arguments",
cli: "",
wantsErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
cmd := NewCmdApi(f, func(o *ApiOptions) error {
assert.Equal(t, tt.wants.RequestMethod, o.RequestMethod)
assert.Equal(t, tt.wants.RequestMethodPassed, o.RequestMethodPassed)
assert.Equal(t, tt.wants.RequestPath, o.RequestPath)
assert.Equal(t, tt.wants.RawFields, o.RawFields)
assert.Equal(t, tt.wants.MagicFields, o.MagicFields)
assert.Equal(t, tt.wants.RequestHeaders, o.RequestHeaders)
assert.Equal(t, tt.wants.ShowResponseHeaders, o.ShowResponseHeaders)
return nil
})
argv, err := shlex.Split(tt.cli)
assert.NoError(t, err)
cmd.SetArgs(argv)
cmd.SetIn(&bytes.Buffer{})
cmd.SetOut(&bytes.Buffer{})
cmd.SetErr(&bytes.Buffer{})
_, err = cmd.ExecuteC()
if tt.wantsErr {
assert.Error(t, err)
return
}
assert.NoError(t, err)
})
}
}
func Test_apiRun(t *testing.T) {
tests := []struct {
name string
options ApiOptions
httpResponse *http.Response
err error
stdout string
stderr string
}{
{
name: "success",
httpResponse: &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString(`bam!`)),
},
err: nil,
stdout: `bam!`,
stderr: ``,
},
{
name: "show response headers",
options: ApiOptions{
ShowResponseHeaders: true,
},
httpResponse: &http.Response{
StatusCode: 200,
Body: ioutil.NopCloser(bytes.NewBufferString(`body`)),
Header: http.Header{"Content-Type": []string{"text/plain"}},
},
err: nil,
stdout: "Content-Type: text/plain\r\n\r\nbody",
stderr: ``,
},
{
name: "success 204",
httpResponse: &http.Response{
StatusCode: 204,
Body: nil,
},
err: nil,
stdout: ``,
stderr: ``,
},
{
name: "failure",
httpResponse: &http.Response{
StatusCode: 502,
Body: ioutil.NopCloser(bytes.NewBufferString(`gateway timeout`)),
},
err: cmdutil.SilentError,
stdout: `gateway timeout`,
stderr: ``,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
io, _, stdout, stderr := iostreams.Test()
tt.options.IO = io
tt.options.HttpClient = func() (*http.Client, error) {
var tr roundTripper = func(req *http.Request) (*http.Response, error) {
resp := tt.httpResponse
resp.Request = req
return resp, nil
}
return &http.Client{Transport: tr}, nil
}
err := apiRun(&tt.options)
if err != tt.err {
t.Errorf("expected error %v, got %v", tt.err, err)
}
if stdout.String() != tt.stdout {
t.Errorf("expected output %q, got %q", tt.stdout, stdout.String())
}
if stderr.String() != tt.stderr {
t.Errorf("expected error output %q, got %q", tt.stderr, stderr.String())
}
})
}
}
func Test_parseFields(t *testing.T) {
io, stdin, _, _ := iostreams.Test()
fmt.Fprint(stdin, "pasted contents")
opts := ApiOptions{
IO: io,
RawFields: []string{
"robot=Hubot",
"destroyer=false",
"helper=true",
"location=@work",
},
MagicFields: []string{
"input=@-",
"enabled=true",
"victories=123",
},
}
params, err := parseFields(&opts)
if err != nil {
t.Fatalf("parseFields error: %v", err)
}
expect := map[string]interface{}{
"robot": "Hubot",
"destroyer": "false",
"helper": "true",
"location": "@work",
"input": []byte("pasted contents"),
"enabled": true,
"victories": 123,
}
assert.Equal(t, expect, params)
}
func Test_magicFieldValue(t *testing.T) {
f, err := ioutil.TempFile("", "gh-test")
if err != nil {
t.Fatal(err)
}
fmt.Fprint(f, "file contents")
f.Close()
t.Cleanup(func() { os.Remove(f.Name()) })
type args struct {
v string
stdin io.ReadCloser
}
tests := []struct {
name string
args args
want interface{}
wantErr bool
}{
{
name: "string",
args: args{v: "hello"},
want: "hello",
wantErr: false,
},
{
name: "bool true",
args: args{v: "true"},
want: true,
wantErr: false,
},
{
name: "bool false",
args: args{v: "false"},
want: false,
wantErr: false,
},
{
name: "null",
args: args{v: "null"},
want: nil,
wantErr: false,
},
{
name: "file",
args: args{v: "@" + f.Name()},
want: []byte("file contents"),
wantErr: false,
},
{
name: "file error",
args: args{v: "@"},
want: nil,
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := magicFieldValue(tt.args.v, tt.args.stdin)
if (err != nil) != tt.wantErr {
t.Errorf("magicFieldValue() error = %v, wantErr %v", err, tt.wantErr)
return
}
if tt.wantErr {
return
}
assert.Equal(t, tt.want, got)
})
}
}