Skip to content

Commit b085a16

Browse files
committed
add more document of mock
1 parent 79419ff commit b085a16

File tree

8 files changed

+162
-107
lines changed

8 files changed

+162
-107
lines changed

docs/site/content/zh/about/index.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ linkTitle: 关于
55

66
{{% blocks/cover title="About API Testing" height="auto" %}}
77

8-
API Testing 是一个接口调试和测试工具的开源项目。
8+
API Testing (atest)是一个接口调试和测试工具的开源项目。
99

1010
请继续阅读以了解更多信息,或访问我们的 [文档](/latest/) 开始使用!
1111

@@ -20,4 +20,3 @@ API Testing 是一个接口调试和测试工具的开源项目。
2020
// TBD.
2121

2222
{{% /blocks/section %}}
23-

docs/site/content/zh/latest/tasks/mock-server.md

Lines changed: 0 additions & 17 deletions
This file was deleted.

docs/site/content/zh/latest/tasks/mock.md

Lines changed: 83 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,56 +16,120 @@ atest mock --prefix / --port 9090 mock.yaml
1616

1717
在 UI 上可以实现和命令行相同的功能,并可以通过页面编辑的方式修改、加载 Mock 服务配置。
1818

19+
## Mock Docker Registry
20+
21+
您可以通过执行下面的命令 mock 一个容器仓库服务[container registry](https://distribution.github.io/distribution/):
22+
23+
```shell
24+
atest mock --prefix / mock/image-registry.yaml
25+
```
26+
27+
之后,您可以通过使用如下的命令使用 mock 功能。
28+
29+
```shell
30+
docker pull localhost:6060/repo/name:tag
31+
```
32+
1933
## 语法
2034

2135
从整体上来看,我们的写法和 HTTP 的名称基本保持一致,用户无需再了解额外的名词。此外,提供两种描述 Mock 服务的方式:
2236

23-
* 针对某个数据对象的 CRUD
24-
* 任意 HTTP 服务
37+
* 面向对象的 CRUD
38+
* 自定义 HTTP 服务
2539

26-
下面是一个具体的例子:
40+
### 面对对象
2741

2842
```yaml
2943
#!api-testing-mock
3044
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
3145
objects:
32-
- name: repo
33-
fields:
34-
- name: name
35-
kind: string
36-
- name: url
37-
kind: string
3846
- name: projects
3947
initCount: 3
4048
sample: |
4149
{
42-
"name": "api-testing",
50+
"name": "atest",
4351
"color": "{{ randEnum "blue" "read" "pink" }}"
4452
}
53+
```
54+
55+
上面 `projects` 的配置,会自动提供该对象的 CRUD(创建、查找、更新、删除)的 API,你可以通过 `atest` 或类似工具发出 HTTP 请求。例如:
56+
57+
```shell
58+
curl http://localhost:6060/mock/projects
59+
60+
curl http://localhost:6060/mock/projects/atest
61+
62+
curl http://localhost:6060/mock/projects -X POST -d '{"name": "new"}'
63+
64+
curl http://localhost:6060/mock/projects -X PUT -d '{"name": "new", "remark": "this is a project"}'
65+
66+
curl http://localhost:6060/mock/projects/atest -X DELETE
67+
```
68+
69+
> `initCount` 是指按照 `sample` 给定的数据初始化多少个对象;如果没有指定的话,则默认值为 1.
70+
71+
### 自定义
72+
73+
```yaml
74+
#!api-testing-mock
75+
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
4576
items:
46-
- name: base64
47-
request:
48-
path: /v1/base64
49-
response:
50-
body: aGVsbG8=
51-
encoder: base64
5277
- name: prList
5378
request:
5479
path: /v1/repos/{repo}/prs
55-
header:
56-
name: rick
5780
response:
5881
header:
5982
server: mock
83+
Content-Type: application/json
6084
body: |
6185
{
6286
"count": 1,
6387
"items": [{
64-
"title": "fix: there is a bug on page {{ randEnum "one" }}",
88+
"title": "fix: there is a bug on page {{ randEnum "one", "two" }}",
6589
"number": 123,
6690
"message": "{{.Response.Header.server}}",
6791
"author": "someone",
6892
"status": "success"
6993
}]
7094
}
7195
```
96+
97+
启动 Mock 服务后,我们就可以发起如下的请求:
98+
99+
```shell
100+
curl http://localhost:6060/mock/v1/repos/atest/prs -v
101+
```
102+
103+
另外,为了满足复杂的场景,还可以对 Response Body 做特定的解码,目前支持:`base64`、`url`:
104+
105+
```yaml
106+
#!api-testing-mock
107+
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
108+
items:
109+
- name: base64
110+
request:
111+
path: /v1/base64
112+
response:
113+
body: aGVsbG8=
114+
encoder: base64
115+
```
116+
117+
上面 Body 的内容是经过 `base64` 编码的,这可以用于不希望直接明文显示,或者是图片的场景:
118+
119+
```shell
120+
curl http://localhost:6060/mock/v1/base64
121+
```
122+
123+
如果你的 Body 内容可以通过另外一个 HTTP 请求(GET)获得,那么你可以这么写:
124+
125+
```
126+
#!api-testing-mock
127+
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
128+
items:
129+
- name: baidu
130+
request:
131+
path: /v1/baidu
132+
response:
133+
body: https://baidu.com
134+
encoder: url
135+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#!api-testing-mock
2+
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
3+
objects:
4+
- name: projects
5+
initCount: 3
6+
sample: |
7+
{
8+
"name": "atest",
9+
"color": "{{ randEnum "blue" "read" "pink" }}"
10+
}
Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
11
#!api-testing-mock
22
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
3-
objects:
4-
- name: users
5-
initCount: 1
6-
sample: |
7-
{
8-
"username": "sss",
9-
"email": "{{randEmail}}",
10-
"age": 12
11-
}
12-
- name: roles
13-
sample: |
14-
{
15-
"name": "admin",
16-
"description": "this is a role"
17-
}
3+
items:
4+
- name: prList
5+
request:
6+
path: /v1/repos/{repo}/prs
7+
response:
8+
header:
9+
server: mock
10+
body: |
11+
{
12+
"count": 1,
13+
"items": [{
14+
"title": "fix: there is a bug on page {{ randEnum "one" }}",
15+
"number": 123,
16+
"message": "{{.Response.Header.server}}",
17+
"author": "someone",
18+
"status": "success"
19+
}]
20+
}
21+
- name: base64
22+
request:
23+
path: /v1/base64
24+
response:
25+
body: aGVsbG8=
26+
encoder: base64
27+
- name: baidu
28+
request:
29+
path: /v1/baidu
30+
response:
31+
body: https://baidu.com
32+
encoder: url

pkg/mock/in_memory.go

Lines changed: 31 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -122,43 +122,6 @@ func (s *inMemoryServer) Start(reader Reader, prefix string) (err error) {
122122

123123
func (s *inMemoryServer) startObject(obj Object) {
124124
// create a simple CRUD server
125-
s.mux.HandleFunc(fmt.Sprintf("/%s/{%s}", obj.Name, obj.Name), func(w http.ResponseWriter, req *http.Request) {
126-
fmt.Println("mock server received request", req.URL.Path)
127-
method := req.Method
128-
w.Header().Set(util.ContentType, util.JSON)
129-
130-
objName := strings.TrimPrefix(req.URL.Path, s.prefix+"/"+obj.Name+"/")
131-
132-
switch method {
133-
case http.MethodGet:
134-
// list all items
135-
for _, item := range s.data[obj.Name] {
136-
if item["name"] == objName {
137-
data, err := json.Marshal(item)
138-
writeResponse(w, data, err)
139-
return
140-
}
141-
}
142-
case http.MethodDelete:
143-
// delete an item
144-
for i, item := range s.data[obj.Name] {
145-
if item["name"] == objName {
146-
if len(s.data[obj.Name]) == i+1 {
147-
s.data[obj.Name] = s.data[obj.Name][:i]
148-
} else {
149-
s.data[obj.Name] = append(s.data[obj.Name][:i], s.data[obj.Name][i+1])
150-
}
151-
152-
writeResponse(w, []byte(`{"msg": "deleted"}`), nil)
153-
return
154-
}
155-
}
156-
default:
157-
w.WriteHeader(http.StatusMethodNotAllowed)
158-
return
159-
}
160-
writeResponse(w, []byte(`{"msg": "not found"}`), fmt.Errorf("not found"))
161-
})
162125
s.mux.HandleFunc("/"+obj.Name, func(w http.ResponseWriter, req *http.Request) {
163126
fmt.Println("mock server received request", req.URL.Path)
164127
method := req.Method
@@ -174,7 +137,7 @@ func (s *inMemoryServer) startObject(obj Object) {
174137
exclude := false
175138

176139
for k, v := range req.URL.Query() {
177-
if v == nil || len(v) == 0 {
140+
if len(v) == 0 {
178141
continue
179142
}
180143

@@ -238,29 +201,48 @@ func (s *inMemoryServer) startObject(obj Object) {
238201
}
239202
})
240203

241-
// get a single object
204+
// handle a single object
242205
s.mux.HandleFunc(fmt.Sprintf("/%s/{name:[a-z]+}", obj.Name), func(w http.ResponseWriter, req *http.Request) {
243-
if req.Method != http.MethodGet {
244-
w.WriteHeader(http.StatusMethodNotAllowed)
245-
return
246-
}
247-
248206
w.Header().Set(util.ContentType, util.JSON)
249207
objects := s.data[obj.Name]
250208
if objects != nil {
251209
name := mux.Vars(req)["name"]
252-
210+
var data []byte
253211
for _, obj := range objects {
254212
if obj["name"] == name {
255213

256-
data, err := json.Marshal(obj)
257-
writeResponse(w, data, err)
258-
return
214+
data, _ = json.Marshal(obj)
215+
break
216+
}
217+
}
218+
219+
if len(data) == 0 {
220+
w.WriteHeader(http.StatusNotFound)
221+
return
222+
}
223+
224+
method := req.Method
225+
switch method {
226+
case http.MethodGet:
227+
writeResponse(w, data, nil)
228+
case http.MethodDelete:
229+
for i, item := range s.data[obj.Name] {
230+
if item["name"] == name {
231+
if len(s.data[obj.Name]) == i+1 {
232+
s.data[obj.Name] = s.data[obj.Name][:i]
233+
} else {
234+
s.data[obj.Name] = append(s.data[obj.Name][:i], s.data[obj.Name][i+1])
235+
}
236+
237+
writeResponse(w, []byte(`{"msg": "deleted"}`), nil)
238+
}
259239
}
240+
default:
241+
w.WriteHeader(http.StatusMethodNotAllowed)
260242
}
243+
261244
}
262245
})
263-
return
264246
}
265247

266248
func (s *inMemoryServer) startItem(item Item) {

pkg/mock/in_memory_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,7 @@ func TestInMemoryServer(t *testing.T) {
9595
})
9696

9797
// delete object
98-
delReq, err := http.NewRequest(http.MethodDelete, api+"/team", bytes.NewBufferString(`{
99-
"name": "test",
100-
"members": []
101-
}`))
98+
delReq, err := http.NewRequest(http.MethodDelete, api+"/team/test", nil)
10299
assert.NoError(t, err)
103100
resp, err = http.DefaultClient.Do(delReq)
104101
assert.NoError(t, err)
@@ -111,6 +108,11 @@ func TestInMemoryServer(t *testing.T) {
111108
assert.NoError(t, err)
112109
assert.Equal(t, `[{"name":"someone"}]`, string(data))
113110
}
111+
112+
resp, err = http.Get(api + "/team/test")
113+
if assert.NoError(t, err) {
114+
assert.Equal(t, http.StatusNotFound, resp.StatusCode)
115+
}
114116
})
115117

116118
t.Run("invalid request method", func(t *testing.T) {
@@ -122,7 +124,7 @@ func TestInMemoryServer(t *testing.T) {
122124
})
123125

124126
t.Run("only accept GET method in getting a single object", func(t *testing.T) {
125-
wrongMethodReq, err := http.NewRequest(http.MethodPut, api+"/team/test", nil)
127+
wrongMethodReq, err := http.NewRequest(http.MethodPut, api+"/team/someone", nil)
126128
assert.NoError(t, err)
127129
resp, err = http.DefaultClient.Do(wrongMethodReq)
128130
assert.NoError(t, err)

0 commit comments

Comments
 (0)