Skip to content

Commit 3b4dea9

Browse files
committed
feat: add a HTTP request collector as atest extension
1 parent b0b9bf8 commit 3b4dea9

File tree

10 files changed

+481
-18
lines changed

10 files changed

+481
-18
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ bin/
33
coverage.out
44
dist/
55
.vscode/launch.json
6+
sample.yaml

extensions/collector/cmd/collect.go

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"net/http"
8+
"os"
9+
"os/signal"
10+
"strings"
11+
"syscall"
12+
13+
"github.com/elazarl/goproxy"
14+
"github.com/linuxsuren/api-testing/extensions/collector/pkg"
15+
"github.com/linuxsuren/api-testing/extensions/collector/pkg/filter"
16+
atestpkg "github.com/linuxsuren/api-testing/pkg/testing"
17+
"github.com/spf13/cobra"
18+
"gopkg.in/yaml.v2"
19+
)
20+
21+
type option struct {
22+
port int
23+
filterPath string
24+
output string
25+
}
26+
27+
func NewRootCmd() (c *cobra.Command) {
28+
opt := &option{}
29+
c = &cobra.Command{
30+
Use: "atest-collector",
31+
Short: "A collector for API testing, it will start a HTTP proxy server",
32+
RunE: opt.runE,
33+
}
34+
flags := c.Flags()
35+
flags.IntVarP(&opt.port, "port", "p", 8080, "The port for the proxy")
36+
flags.StringVarP(&opt.filterPath, "filter-path", "", "", "The path prefix for filtering")
37+
flags.StringVarP(&opt.output, "output", "o", "sample.yaml", "The output file")
38+
39+
cobra.MarkFlagRequired(flags, "filter-path")
40+
return
41+
}
42+
43+
func (o *option) runE(cmd *cobra.Command, args []string) (err error) {
44+
urlFilter := &filter.URLPathFilter{PathPrefix: o.filterPath}
45+
collects := pkg.NewCollects()
46+
47+
proxy := goproxy.NewProxyHttpServer()
48+
proxy.Verbose = true
49+
proxy.OnRequest().DoFunc(
50+
func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
51+
if urlFilter.Filter(r.URL) {
52+
collects.Add(r.Clone(context.TODO()))
53+
}
54+
return r, nil
55+
})
56+
57+
exporter := &sampleExporter{
58+
testSuite: atestpkg.TestSuite{
59+
Name: "sample",
60+
},
61+
}
62+
collects.AddEvent(exporter.add)
63+
64+
srv := &http.Server{
65+
Addr: fmt.Sprintf(":%d", o.port),
66+
Handler: proxy,
67+
}
68+
69+
sig := make(chan os.Signal, 1)
70+
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
71+
go func() {
72+
<-sig
73+
collects.Stop()
74+
srv.Shutdown(context.Background())
75+
}()
76+
77+
cmd.Println("Starting the proxy server with port", o.port)
78+
srv.ListenAndServe()
79+
var data string
80+
if data, err = exporter.export(); err == nil {
81+
err = os.WriteFile(o.output, []byte(data), 0644)
82+
}
83+
return
84+
}
85+
86+
type sampleExporter struct {
87+
testSuite atestpkg.TestSuite
88+
}
89+
90+
func (e *sampleExporter) add(r *http.Request) {
91+
body := r.Body
92+
data, _ := io.ReadAll(body)
93+
94+
fmt.Println("receive", r.URL.Path)
95+
req := atestpkg.Request{
96+
API: r.URL.String(),
97+
Method: r.Method,
98+
Header: map[string]string{},
99+
Body: string(data),
100+
}
101+
102+
testCase := atestpkg.TestCase{
103+
Request: req,
104+
Expect: atestpkg.Response{
105+
StatusCode: 200,
106+
},
107+
}
108+
109+
specs := strings.Split(r.URL.Path, "/")
110+
if len(specs) > 0 {
111+
testCase.Name = specs[len(specs)-1]
112+
}
113+
114+
if val := r.Header.Get("Content-Type"); val != "" {
115+
req.Header["Content-Type"] = val
116+
}
117+
118+
e.testSuite.Items = append(e.testSuite.Items, testCase)
119+
}
120+
121+
var prefix = `#!api-testing
122+
# yaml-language-server: $schema=https://gitee.com/linuxsuren/api-testing/raw/master/sample/api-testing-schema.json
123+
`
124+
125+
func (e *sampleExporter) export() (string, error) {
126+
marker := map[string]int{}
127+
128+
for i, item := range e.testSuite.Items {
129+
if _, ok := marker[item.Name]; ok {
130+
marker[item.Name]++
131+
e.testSuite.Items[i].Name = fmt.Sprintf("%s-%d", item.Name, marker[item.Name])
132+
} else {
133+
marker[item.Name] = 0
134+
}
135+
}
136+
137+
data, err := yaml.Marshal(e.testSuite)
138+
return prefix + string(data), err
139+
}

extensions/collector/go.mod

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module github.com/linuxsuren/api-testing/extensions/collector
2+
3+
go 1.19
4+
5+
require (
6+
github.com/Masterminds/goutils v1.1.1 // indirect
7+
github.com/Masterminds/semver/v3 v3.2.0 // indirect
8+
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
9+
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 // indirect
10+
github.com/antonmedv/expr v1.12.1 // indirect
11+
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 // indirect
12+
github.com/ghodss/yaml v1.0.0 // indirect
13+
github.com/golang/protobuf v1.5.2 // indirect
14+
github.com/google/uuid v1.3.0 // indirect
15+
github.com/huandu/xstrings v1.3.3 // indirect
16+
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
17+
github.com/imdario/mergo v0.3.11 // indirect
18+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
19+
github.com/invopop/jsonschema v0.7.0 // indirect
20+
github.com/linuxsuren/api-testing v0.0.11 // indirect
21+
github.com/linuxsuren/go-fake-runtime v0.0.0-20230413085645-15e77ab55dbd // indirect
22+
github.com/linuxsuren/unstructured v0.0.1 // indirect
23+
github.com/mitchellh/copystructure v1.0.0 // indirect
24+
github.com/mitchellh/reflectwalk v1.0.0 // indirect
25+
github.com/sergi/go-diff v1.2.0 // indirect
26+
github.com/shopspring/decimal v1.2.0 // indirect
27+
github.com/spf13/cast v1.3.1 // indirect
28+
github.com/spf13/cobra v1.7.0 // indirect
29+
github.com/spf13/pflag v1.0.5 // indirect
30+
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
31+
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
32+
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
33+
golang.org/x/crypto v0.3.0 // indirect
34+
golang.org/x/net v0.8.0 // indirect
35+
golang.org/x/sync v0.1.0 // indirect
36+
golang.org/x/sys v0.6.0 // indirect
37+
golang.org/x/text v0.8.0 // indirect
38+
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
39+
google.golang.org/grpc v1.54.0 // indirect
40+
google.golang.org/protobuf v1.30.0 // indirect
41+
gopkg.in/yaml.v2 v2.3.0 // indirect
42+
)
43+
44+
replace github.com/linuxsuren/api-testing => ../../.

0 commit comments

Comments
 (0)