From e6901130767bf2016d9ce6ec2275c2f51aa74270 Mon Sep 17 00:00:00 2001 From: rick Date: Tue, 2 Sep 2025 16:00:49 +0800 Subject: [PATCH 1/3] feat: support echo the request and response in mock server --- docs/site/content/zh/latest/tasks/mock.md | 3 + .../content/zh/latest/tasks/mock/simple.yaml | 1 + pkg/mock/in_memory.go | 16 ++++ pkg/mock/types.go | 75 ++++++++++--------- 4 files changed, 58 insertions(+), 37 deletions(-) diff --git a/docs/site/content/zh/latest/tasks/mock.md b/docs/site/content/zh/latest/tasks/mock.md index cec85f0bf..fe193884f 100644 --- a/docs/site/content/zh/latest/tasks/mock.md +++ b/docs/site/content/zh/latest/tasks/mock.md @@ -234,8 +234,11 @@ items: proxies: - path: /api/v1/{part} target: http://atest.localhost:8080 + echo: true ``` +当 echo 的值为 true 时,会把收到的请求以及响应打印出来,方便观察数据。 + 当我们发起如下的请求时,实际请求的地址为 `http://atest.localhost:8080/api/v1/projects` ```shell diff --git a/docs/site/content/zh/latest/tasks/mock/simple.yaml b/docs/site/content/zh/latest/tasks/mock/simple.yaml index 2d756f675..298c2c228 100644 --- a/docs/site/content/zh/latest/tasks/mock/simple.yaml +++ b/docs/site/content/zh/latest/tasks/mock/simple.yaml @@ -39,6 +39,7 @@ proxies: target: http://atest.localhost:8080 - path: /open-apis/bot/v2/hook/{token} target: https://open.feishu.cn/ + echo: true requestAmend: bodyPatch: | [{ diff --git a/pkg/mock/in_memory.go b/pkg/mock/in_memory.go index 4a59013a4..a8dacc66a 100644 --- a/pkg/mock/in_memory.go +++ b/pkg/mock/in_memory.go @@ -178,6 +178,16 @@ func (s *inMemoryServer) httpProxy(proxy *Proxy) { fmt.Println("after patch:", string(requestBody)) } + if proxy.Echo { + fmt.Println("Original request header:") + for k, v := range req.Header { + fmt.Println(k, ":", v) + } + fmt.Println("Original request path:", req.URL) + fmt.Println("Original request payload:") + fmt.Println(string(requestBody)) + } + targetReq, err := http.NewRequestWithContext(req.Context(), req.Method, api, bytes.NewBuffer(requestBody)) if err != nil { w.WriteHeader(http.StatusInternalServerError) @@ -206,6 +216,12 @@ func (s *inMemoryServer) httpProxy(proxy *Proxy) { for k, v := range resp.Header { w.Header().Add(k, v[0]) } + + if proxy.Echo { + fmt.Println("Original response payload:") + fmt.Println(string(data)) + } + w.Write(data) }) } diff --git a/pkg/mock/types.go b/pkg/mock/types.go index 06b490bb9..f913a1584 100644 --- a/pkg/mock/types.go +++ b/pkg/mock/types.go @@ -16,65 +16,66 @@ limitations under the License. package mock type Object struct { - Name string `yaml:"name" json:"name"` - InitCount *int `yaml:"initCount" json:"initCount"` - Sample string `yaml:"sample" json:"sample"` + Name string `yaml:"name" json:"name"` + InitCount *int `yaml:"initCount" json:"initCount"` + Sample string `yaml:"sample" json:"sample"` } type Item struct { - Name string `yaml:"name" json:"name"` - Request Request `yaml:"request" json:"request"` - Response Response `yaml:"response" json:"response"` - Param map[string]interface{} + Name string `yaml:"name" json:"name"` + Request Request `yaml:"request" json:"request"` + Response Response `yaml:"response" json:"response"` + Param map[string]interface{} } type Request struct { - Protocol string `yaml:"protocol" json:"protocol"` - Path string `yaml:"path" json:"path"` - Method string `yaml:"method" json:"method"` - Header map[string]string `yaml:"header" json:"header"` - Body string `yaml:"body" json:"body"` + Protocol string `yaml:"protocol" json:"protocol"` + Path string `yaml:"path" json:"path"` + Method string `yaml:"method" json:"method"` + Header map[string]string `yaml:"header" json:"header"` + Body string `yaml:"body" json:"body"` } type RequestWithAuth struct { - Request `yaml:",inline"` - BearerAPI string `yaml:"bearerAPI" json:"bearerAPI"` - Username string `yaml:"username" json:"username"` - Password string `yaml:"password" json:"password"` + Request `yaml:",inline"` + BearerAPI string `yaml:"bearerAPI" json:"bearerAPI"` + Username string `yaml:"username" json:"username"` + Password string `yaml:"password" json:"password"` } type Response struct { - Encoder string `yaml:"encoder" json:"encoder"` - Body string `yaml:"body" json:"body"` - BodyFromFile string `yaml:"bodyFromFile" json:"bodyFromFile"` - Header map[string]string `yaml:"header" json:"header"` - StatusCode int `yaml:"statusCode" json:"statusCode"` - BodyData []byte + Encoder string `yaml:"encoder" json:"encoder"` + Body string `yaml:"body" json:"body"` + BodyFromFile string `yaml:"bodyFromFile" json:"bodyFromFile"` + Header map[string]string `yaml:"header" json:"header"` + StatusCode int `yaml:"statusCode" json:"statusCode"` + BodyData []byte } type Webhook struct { - Name string `yaml:"name" json:"name"` - Timer string `yaml:"timer" json:"timer"` - Param map[string]string `yaml:"param" json:"param"` - Request RequestWithAuth `yaml:"request" json:"request"` + Name string `yaml:"name" json:"name"` + Timer string `yaml:"timer" json:"timer"` + Param map[string]string `yaml:"param" json:"param"` + Request RequestWithAuth `yaml:"request" json:"request"` } type Proxy struct { - Prefix string `yaml:"prefix" json:"prefix"` - Port int `yaml:"port" json:"port"` - Path string `yaml:"path" json:"path"` - Target string `yaml:"target" json:"target"` - RequestAmend RequestAmend `yaml:"requestAmend" json:"requestAmend"` - Protocol string `yaml:"protocol" json:"protocol"` + Prefix string `yaml:"prefix" json:"prefix"` + Port int `yaml:"port" json:"port"` + Path string `yaml:"path" json:"path"` + Target string `yaml:"target" json:"target"` + RequestAmend RequestAmend `yaml:"requestAmend" json:"requestAmend"` + Protocol string `yaml:"protocol" json:"protocol"` + Echo bool `yaml:"echo" json:"echo"` } type RequestAmend struct { - BodyPatch string `yaml:"bodyPatch" json:"bodyPatch"` + BodyPatch string `yaml:"bodyPatch" json:"bodyPatch"` } type Server struct { - Objects []Object `yaml:"objects" json:"objects"` - Items []Item `yaml:"items" json:"items"` - Proxies []Proxy `yaml:"proxies" json:"proxies"` - Webhooks []Webhook `yaml:"webhooks" json:"webhooks"` + Objects []Object `yaml:"objects" json:"objects"` + Items []Item `yaml:"items" json:"items"` + Proxies []Proxy `yaml:"proxies" json:"proxies"` + Webhooks []Webhook `yaml:"webhooks" json:"webhooks"` } From cdd2abbad588d0d807fb23e3a6764179dcd7b748 Mon Sep 17 00:00:00 2001 From: rick Date: Tue, 16 Sep 2025 11:24:46 +0800 Subject: [PATCH 2/3] feat: webhook support read body from file --- console/atest-desktop/forge.config.js | 20 ++++++++++++++++++++ pkg/mock/in_memory.go | 9 +++++++++ pkg/mock/types.go | 11 ++++++----- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/console/atest-desktop/forge.config.js b/console/atest-desktop/forge.config.js index 01f215bff..cd3c74359 100644 --- a/console/atest-desktop/forge.config.js +++ b/console/atest-desktop/forge.config.js @@ -51,6 +51,26 @@ module.exports = { ui: { "enabled": true, "chooseDirectory": true + }, + beforeCreate: (msiCreator) => { + // Add installation directory to system PATH + msiCreator.wixTemplate = msiCreator.wixTemplate.replace( + '', + ` + + + + + NOT Installed + REMOVE="ALL" + + + + + + + ` + ); } } } diff --git a/pkg/mock/in_memory.go b/pkg/mock/in_memory.go index 4a59013a4..f1c42ebd8 100644 --- a/pkg/mock/in_memory.go +++ b/pkg/mock/in_memory.go @@ -580,6 +580,15 @@ func runWebhook(ctx context.Context, objCtx interface{}, wh *Webhook) (err error } } + if wh.Request.BodyFromFile != "" { + if data, readErr := os.ReadFile(wh.Request.BodyFromFile); readErr != nil { + memLogger.Error(readErr, "failed to read file", "file", wh.Request.BodyFromFile) + return + } else { + wh.Request.Body = string(data) + } + } + var payload io.Reader payload, err = render.RenderAsReader("mock webhook server payload", wh.Request.Body, wh) if err != nil { diff --git a/pkg/mock/types.go b/pkg/mock/types.go index b37911757..3d4600466 100644 --- a/pkg/mock/types.go +++ b/pkg/mock/types.go @@ -29,11 +29,12 @@ type Item struct { } type Request struct { - Protocol string `yaml:"protocol" json:"protocol"` - Path string `yaml:"path" json:"path"` - Method string `yaml:"method" json:"method"` - Header map[string]string `yaml:"header" json:"header"` - Body string `yaml:"body" json:"body"` + Protocol string `yaml:"protocol" json:"protocol"` + Path string `yaml:"path" json:"path"` + Method string `yaml:"method" json:"method"` + Header map[string]string `yaml:"header" json:"header"` + Body string `yaml:"body" json:"body"` + BodyFromFile string `yaml:"bodyFromFile" json:"bodyFromFile"` } type RequestWithAuth struct { From d43820a8c13744b1608e72f3b5c96590c4e4bb62 Mon Sep 17 00:00:00 2001 From: rick Date: Tue, 16 Sep 2025 18:40:05 +0800 Subject: [PATCH 3/3] add doc of the webhooks --- docs/site/content/zh/latest/tasks/mock.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/site/content/zh/latest/tasks/mock.md b/docs/site/content/zh/latest/tasks/mock.md index fe193884f..adff4c18a 100644 --- a/docs/site/content/zh/latest/tasks/mock.md +++ b/docs/site/content/zh/latest/tasks/mock.md @@ -296,4 +296,16 @@ proxies: * HTTP * Syslog +```yaml +webhooks: + - timer: 3s + name: shakeHands + request: + method: POST + path: http://192.168.1.123:8080/api/v1 + header: + Content-Type: application/json + bodyFromFile: demo.json +``` + > 更多 URL 中通配符的用法,请参考 https://github.com/gorilla/mux