Skip to content

Commit 0ad1515

Browse files
authored
feat: add API and expect status code default value (#10)
1 parent 3ae7518 commit 0ad1515

File tree

8 files changed

+246
-27
lines changed

8 files changed

+246
-27
lines changed

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,19 @@
55
This is a API testing tool.
66

77
## Feature
8-
* Response Body fields equation check
9-
* Response Body [eval](https://expr.medv.io/)
10-
* Output reference between TestCase
8+
* Response Body fields equation check
9+
* Response Body [eval](https://expr.medv.io/)
10+
* Output reference between TestCase
1111

1212
## Template
1313
The following fields are templated with [sprig](http://masterminds.github.io/sprig/):
1414

15-
* API
16-
* Request Body
15+
* API
16+
* Request Body
17+
18+
## TODO
19+
* Reduce the size of context
20+
* Support customized context
1721

1822
## Limit
19-
* Only support to parse the response body when it's a map
23+
* Only support to parse the response body when it's a map or array

cmd/run.go

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package cmd
22

33
import (
4+
"fmt"
45
"path"
56
"path/filepath"
7+
"strings"
68

79
"github.com/linuxsuren/api-testing/pkg/runner"
810
"github.com/linuxsuren/api-testing/pkg/testing"
@@ -17,8 +19,12 @@ type runOption struct {
1719
func CreateRunCommand() (cmd *cobra.Command) {
1820
opt := &runOption{}
1921
cmd = &cobra.Command{
20-
Use: "run",
21-
RunE: opt.runE,
22+
Use: "run",
23+
Aliases: []string{"r"},
24+
Example: `atest run -p sample.yaml
25+
See also https://github.com/LinuxSuRen/api-testing/tree/master/sample`,
26+
Short: "Run the test suite",
27+
RunE: opt.runE,
2228
}
2329

2430
// set flags
@@ -30,31 +36,47 @@ func CreateRunCommand() (cmd *cobra.Command) {
3036

3137
func (o *runOption) runE(cmd *cobra.Command, args []string) (err error) {
3238
var files []string
33-
34-
ctx := map[string]interface{}{}
39+
ctx := getDefaultContext()
3540

3641
if files, err = filepath.Glob(o.pattern); err == nil {
3742
for i := range files {
3843
item := files[i]
39-
40-
var testSuite *testing.TestSuite
41-
if testSuite, err = testing.Parse(item); err != nil {
44+
fmt.Println(item, "===", o.pattern, args)
45+
if err = runSuite(item, ctx); err != nil {
4246
return
4347
}
48+
}
49+
}
50+
return
51+
}
4452

45-
for _, testCase := range testSuite.Items {
46-
setRelativeDir(item, &testCase)
47-
var output interface{}
48-
if output, err = runner.RunTestCase(&testCase, ctx); err != nil {
49-
return
50-
}
51-
ctx[testCase.Name] = output
52-
}
53+
func runSuite(suite string, ctx map[string]interface{}) (err error) {
54+
var testSuite *testing.TestSuite
55+
if testSuite, err = testing.Parse(suite); err != nil {
56+
return
57+
}
58+
59+
testSuite.API = strings.TrimSuffix(testSuite.API, "/")
60+
for _, testCase := range testSuite.Items {
61+
// reuse the API prefix
62+
if strings.HasPrefix(testCase.Request.API, "/") {
63+
testCase.Request.API = fmt.Sprintf("%s/%s", testSuite.API, testCase.Request.API)
64+
}
65+
66+
setRelativeDir(suite, &testCase)
67+
var output interface{}
68+
if output, err = runner.RunTestCase(&testCase, ctx); err != nil {
69+
return
5370
}
71+
ctx[testCase.Name] = output
5472
}
5573
return
5674
}
5775

76+
func getDefaultContext() map[string]interface{} {
77+
return map[string]interface{}{}
78+
}
79+
5880
func setRelativeDir(configFile string, testcase *testing.TestCase) {
5981
dir := filepath.Dir(configFile)
6082

cmd/run_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"net/http"
6+
"testing"
7+
8+
"github.com/h2non/gock"
9+
"github.com/spf13/cobra"
10+
"github.com/stretchr/testify/assert"
11+
)
12+
13+
func TestRunSuite(t *testing.T) {
14+
tests := []struct {
15+
name string
16+
suiteFile string
17+
prepare func()
18+
hasError bool
19+
}{{
20+
name: "simple",
21+
suiteFile: "testdata/simple-suite.yaml",
22+
prepare: func() {
23+
gock.New("http://foo").
24+
Get("/bar").
25+
Reply(http.StatusOK).
26+
JSON("{}")
27+
},
28+
hasError: false,
29+
}, {
30+
name: "response is not JSON",
31+
suiteFile: "testdata/simple-suite.yaml",
32+
prepare: func() {
33+
gock.New("http://foo").
34+
Get("/bar").
35+
Reply(http.StatusOK)
36+
},
37+
hasError: true,
38+
}, {
39+
name: "not found file",
40+
suiteFile: "testdata/fake.yaml",
41+
prepare: func() {},
42+
hasError: true,
43+
}}
44+
for _, tt := range tests {
45+
t.Run(tt.name, func(t *testing.T) {
46+
defer gock.Clean()
47+
48+
tt.prepare()
49+
ctx := getDefaultContext()
50+
err := runSuite(tt.suiteFile, ctx)
51+
assert.Equal(t, tt.hasError, err != nil, err)
52+
})
53+
}
54+
}
55+
56+
func TestRunCommand(t *testing.T) {
57+
tests := []struct {
58+
name string
59+
args []string
60+
prepare func()
61+
hasErr bool
62+
}{{
63+
name: "status code is not match",
64+
args: []string{"-p", "testdata/simple-suite.yaml"},
65+
prepare: func() {
66+
gock.New("http://foo").Get("/bar")
67+
},
68+
hasErr: true,
69+
}, {
70+
name: "file not found",
71+
args: []string{"--pattern", "fake"},
72+
prepare: func() {},
73+
hasErr: false,
74+
}, {
75+
name: "normal case",
76+
args: []string{"-p", "testdata/simple-suite.yaml"},
77+
prepare: func() {
78+
gock.New("http://foo").Get("/bar").Reply(http.StatusOK).JSON("{}")
79+
},
80+
hasErr: false,
81+
}}
82+
for _, tt := range tests {
83+
t.Run(tt.name, func(t *testing.T) {
84+
defer gock.Clean()
85+
tt.prepare()
86+
87+
root := &cobra.Command{Use: "root"}
88+
root.AddCommand(CreateRunCommand())
89+
90+
root.SetArgs(append([]string{"run"}, tt.args...))
91+
92+
fmt.Println(tt.args)
93+
err := root.Execute()
94+
assert.Equal(t, tt.hasErr, err != nil, err)
95+
})
96+
}
97+
}

cmd/testdata/simple-suite.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
name: Simple
2+
api: http://foo/
3+
items:
4+
- request:
5+
api: /bar

pkg/runner/simple.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,12 @@ func RunTestCase(testcase *testing.TestCase, ctx interface{}) (output interface{
9595
return
9696
}
9797

98-
if testcase.Expect.StatusCode != 0 {
99-
if err = expectInt(testcase.Name, testcase.Expect.StatusCode, resp.StatusCode); err != nil {
100-
err = fmt.Errorf("error is: %v\n%s", err, string(responseBodyData))
101-
return
102-
}
98+
if err = testcase.Expect.Render(nil); err != nil {
99+
return
100+
}
101+
if err = expectInt(testcase.Name, testcase.Expect.StatusCode, resp.StatusCode); err != nil {
102+
err = fmt.Errorf("error is: %v\n%s", err, string(responseBodyData))
103+
return
103104
}
104105

105106
for key, val := range testcase.Expect.Header {

pkg/testing/case.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package testing
33
// TestSuite represents a set of test cases
44
type TestSuite struct {
55
Name string `yaml:"name"`
6+
API string `yaml:"api"`
67
Items []TestCase `yaml:"items"`
78
}
89

pkg/testing/parser.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package testing
33
import (
44
"bytes"
55
"html/template"
6+
"net/http"
67
"os"
78
"strings"
89

@@ -69,5 +70,28 @@ func (r *Request) Render(ctx interface{}) (err error) {
6970
}
7071
}
7172
}
73+
74+
// setting default values
75+
r.Method = emptyThenDefault(r.Method, http.MethodGet)
7276
return
7377
}
78+
79+
// Render renders the response
80+
func (r *Response) Render(ctx interface{}) (err error) {
81+
r.StatusCode = zeroThenDefault(r.StatusCode, http.StatusOK)
82+
return
83+
}
84+
85+
func zeroThenDefault(val, defVal int) int {
86+
if val == 0 {
87+
val = defVal
88+
}
89+
return val
90+
}
91+
92+
func emptyThenDefault(val, defVal string) string {
93+
if strings.TrimSpace(val) == "" {
94+
val = defVal
95+
}
96+
return val
97+
}

pkg/testing/parser_test.go

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func TestParse(t *testing.T) {
2424
}
2525
}
2626

27-
func TestRender(t *testing.T) {
27+
func TestRequestRender(t *testing.T) {
2828
tests := []struct {
2929
name string
3030
request *Request
@@ -43,6 +43,13 @@ func TestRender(t *testing.T) {
4343
assert.Equal(t, "http://localhost/foo", req.API)
4444
assert.Equal(t, "bar", req.Body)
4545
},
46+
}, {
47+
name: "default values",
48+
request: &Request{},
49+
verify: func(t *testing.T, req *Request) {
50+
assert.Equal(t, http.MethodGet, req.Method)
51+
},
52+
hasErr: false,
4653
}, {
4754
name: "context is nil",
4855
request: &Request{},
@@ -126,3 +133,61 @@ func TestRender(t *testing.T) {
126133
})
127134
}
128135
}
136+
137+
func TestResponseRender(t *testing.T) {
138+
tests := []struct {
139+
name string
140+
response *Response
141+
verify func(t *testing.T, req *Response)
142+
ctx interface{}
143+
hasErr bool
144+
}{{
145+
name: "blank response",
146+
response: &Response{},
147+
verify: func(t *testing.T, req *Response) {
148+
assert.Equal(t, http.StatusOK, req.StatusCode)
149+
},
150+
hasErr: false,
151+
}}
152+
for _, tt := range tests {
153+
t.Run(tt.name, func(t *testing.T) {
154+
err := tt.response.Render(tt.ctx)
155+
if assert.Equal(t, tt.hasErr, err != nil, err) && tt.verify != nil {
156+
tt.verify(t, tt.response)
157+
}
158+
})
159+
}
160+
}
161+
162+
func TestEmptyThenDefault(t *testing.T) {
163+
tests := []struct {
164+
name string
165+
val string
166+
defVal string
167+
expect string
168+
}{{
169+
name: "empty string",
170+
val: "",
171+
defVal: "abc",
172+
expect: "abc",
173+
}, {
174+
name: "blank string",
175+
val: " ",
176+
defVal: "abc",
177+
expect: "abc",
178+
}, {
179+
name: "not empty or blank string",
180+
val: "abc",
181+
defVal: "def",
182+
expect: "abc",
183+
}}
184+
for _, tt := range tests {
185+
t.Run(tt.name, func(t *testing.T) {
186+
result := emptyThenDefault(tt.val, tt.defVal)
187+
assert.Equal(t, tt.expect, result, result)
188+
})
189+
}
190+
191+
assert.Equal(t, 1, zeroThenDefault(0, 1))
192+
assert.Equal(t, 1, zeroThenDefault(1, 2))
193+
}

0 commit comments

Comments
 (0)