feat: support form request (#8)
Co-authored-by: rick <LinuxSuRen@users.noreply.github.com>
This commit is contained in:
parent
d07c7f2a99
commit
e1270c748e
3
Makefile
3
Makefile
|
@ -1,6 +1,7 @@
|
||||||
build:
|
build:
|
||||||
mkdir -p bin
|
mkdir -p bin
|
||||||
go build -o bin/atest cmd/*.go
|
rm -rf bin/atest
|
||||||
|
go build -o bin/atest main.go
|
||||||
|
|
||||||
copy: build
|
copy: build
|
||||||
cp bin/atest /usr/local/bin/
|
cp bin/atest /usr/local/bin/
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -3,7 +3,11 @@ module github.com/linuxsuren/api-testing
|
||||||
go 1.17
|
go 1.17
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/Masterminds/sprig/v3 v3.2.3
|
||||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
|
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
|
||||||
|
github.com/antonmedv/expr v1.12.1
|
||||||
|
github.com/h2non/gock v1.2.0
|
||||||
|
github.com/linuxsuren/unstructured v0.0.1
|
||||||
github.com/spf13/cobra v1.4.0
|
github.com/spf13/cobra v1.4.0
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.2
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
@ -12,16 +16,12 @@ require (
|
||||||
require (
|
require (
|
||||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||||
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
|
|
||||||
github.com/antonmedv/expr v1.12.1 // indirect
|
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/google/uuid v1.1.1 // indirect
|
github.com/google/uuid v1.1.1 // indirect
|
||||||
github.com/h2non/gock v1.2.0 // indirect
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
||||||
github.com/huandu/xstrings v1.3.3 // indirect
|
github.com/huandu/xstrings v1.3.3 // indirect
|
||||||
github.com/imdario/mergo v0.3.11 // indirect
|
github.com/imdario/mergo v0.3.11 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/linuxsuren/unstructured v0.0.1 // indirect
|
|
||||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
|
3
go.sum
3
go.sum
|
@ -35,6 +35,7 @@ github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMK
|
||||||
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
|
||||||
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||||
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
@ -53,9 +54,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -50,6 +51,20 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(testcase.Request.Form) > 0 {
|
||||||
|
if testcase.Request.Header["Content-Type"] == "multipart/form-data" {
|
||||||
|
multiBody := &bytes.Buffer{}
|
||||||
|
writer := multipart.NewWriter(multiBody)
|
||||||
|
for key, val := range testcase.Request.Form {
|
||||||
|
writer.WriteField(key, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = writer.Close()
|
||||||
|
requestBody = multiBody
|
||||||
|
testcase.Request.Header["Content-Type"] = writer.FormDataContentType()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var request *http.Request
|
var request *http.Request
|
||||||
if request, err = http.NewRequest(testcase.Request.Method, testcase.Request.API, requestBody); err != nil {
|
if request, err = http.NewRequest(testcase.Request.Method, testcase.Request.API, requestBody); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -68,8 +83,14 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var responseBodyData []byte
|
||||||
|
if responseBodyData, err = io.ReadAll(resp.Body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if testcase.Expect.StatusCode != 0 {
|
if testcase.Expect.StatusCode != 0 {
|
||||||
if err = expectInt(testcase.Name, testcase.Expect.StatusCode, resp.StatusCode); err != nil {
|
if err = expectInt(testcase.Name, testcase.Expect.StatusCode, resp.StatusCode); err != nil {
|
||||||
|
err = fmt.Errorf("error is: %v\n%s", err, string(responseBodyData))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,10 +102,6 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var responseBodyData []byte
|
|
||||||
if responseBodyData, err = io.ReadAll(resp.Body); err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if testcase.Expect.Body != "" {
|
if testcase.Expect.Body != "" {
|
||||||
if string(responseBodyData) != strings.TrimSpace(testcase.Expect.Body) {
|
if string(responseBodyData) != strings.TrimSpace(testcase.Expect.Body) {
|
||||||
err = fmt.Errorf("case: %s, got different response body, diff: \n%s", testcase.Name,
|
err = fmt.Errorf("case: %s, got different response body, diff: \n%s", testcase.Name,
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
_ "embed"
|
_ "embed"
|
||||||
|
|
||||||
"github.com/h2non/gock"
|
"github.com/h2non/gock"
|
||||||
atest "github.com/linuxsuren/api-testing/pkg/testing"
|
atest "github.com/linuxsuren/api-testing/pkg/testing"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -314,6 +315,27 @@ func TestTestCase(t *testing.T) {
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
assert.Contains(t, err.Error(), "template: api:1:")
|
assert.Contains(t, err.Error(), "template: api:1:")
|
||||||
},
|
},
|
||||||
|
}, {
|
||||||
|
name: "form request",
|
||||||
|
testCase: &atest.TestCase{
|
||||||
|
Request: atest.Request{
|
||||||
|
API: "http://localhost/foo",
|
||||||
|
Method: http.MethodPost,
|
||||||
|
Header: map[string]string{
|
||||||
|
"Content-Type": "multipart/form-data",
|
||||||
|
},
|
||||||
|
Form: map[string]string{
|
||||||
|
"key": "value",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
prepare: func() {
|
||||||
|
gock.New("http://localhost").
|
||||||
|
Post("/foo").Reply(http.StatusOK).BodyString(`{"items":[]}`)
|
||||||
|
},
|
||||||
|
verify: func(t *testing.T, output interface{}, err error) {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ type Request struct {
|
||||||
Method string `yaml:"method"`
|
Method string `yaml:"method"`
|
||||||
Query map[string]string `yaml:"query"`
|
Query map[string]string `yaml:"query"`
|
||||||
Header map[string]string `yaml:"header"`
|
Header map[string]string `yaml:"header"`
|
||||||
|
Form map[string]string `yaml:"form"`
|
||||||
Body string `yaml:"body"`
|
Body string `yaml:"body"`
|
||||||
BodyFromFile string `yaml:"bodyFromFile"`
|
BodyFromFile string `yaml:"bodyFromFile"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,5 +49,15 @@ func (r *Request) Render(ctx interface{}) (err error) {
|
||||||
r.Body = buf.String()
|
r.Body = buf.String()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// template the form
|
||||||
|
for key, val := range r.Form {
|
||||||
|
if tpl, err = template.New("form").Funcs(sprig.FuncMap()).Parse(val); err == nil {
|
||||||
|
buf = new(bytes.Buffer)
|
||||||
|
if err = tpl.Execute(buf, ctx); err == nil {
|
||||||
|
r.Form[key] = buf.String()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,6 +92,18 @@ func TestRender(t *testing.T) {
|
||||||
},
|
},
|
||||||
ctx: TestCase{},
|
ctx: TestCase{},
|
||||||
hasErr: true,
|
hasErr: true,
|
||||||
|
}, {
|
||||||
|
name: "form render",
|
||||||
|
request: &Request{
|
||||||
|
Form: map[string]string{
|
||||||
|
"key": "{{.Name}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ctx: TestCase{Name: "linuxsuren"},
|
||||||
|
verify: func(t *testing.T, req *Request) {
|
||||||
|
assert.Equal(t, "linuxsuren", req.Form["key"])
|
||||||
|
},
|
||||||
|
hasErr: false,
|
||||||
}}
|
}}
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue