Skip to content

Commit

Permalink
feat: add a HTTP request collector as atest extension
Browse files Browse the repository at this point in the history
  • Loading branch information
LinuxSuRen committed Jun 4, 2023
1 parent b0b9bf8 commit 3b4dea9
Show file tree
Hide file tree
Showing 10 changed files with 481 additions and 18 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ bin/
coverage.out
dist/
.vscode/launch.json
sample.yaml
139 changes: 139 additions & 0 deletions extensions/collector/cmd/collect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package cmd

import (
"context"
"fmt"
"io"
"net/http"
"os"
"os/signal"
"strings"
"syscall"

"github.com/elazarl/goproxy"
"github.com/linuxsuren/api-testing/extensions/collector/pkg"
"github.com/linuxsuren/api-testing/extensions/collector/pkg/filter"
atestpkg "github.com/linuxsuren/api-testing/pkg/testing"
"github.com/spf13/cobra"
"gopkg.in/yaml.v2"
)

type option struct {
port int
filterPath string
output string
}

func NewRootCmd() (c *cobra.Command) {
opt := &option{}
c = &cobra.Command{
Use: "atest-collector",
Short: "A collector for API testing, it will start a HTTP proxy server",
RunE: opt.runE,
}
flags := c.Flags()
flags.IntVarP(&opt.port, "port", "p", 8080, "The port for the proxy")
flags.StringVarP(&opt.filterPath, "filter-path", "", "", "The path prefix for filtering")
flags.StringVarP(&opt.output, "output", "o", "sample.yaml", "The output file")

cobra.MarkFlagRequired(flags, "filter-path")
return
}

func (o *option) runE(cmd *cobra.Command, args []string) (err error) {
urlFilter := &filter.URLPathFilter{PathPrefix: o.filterPath}
collects := pkg.NewCollects()

proxy := goproxy.NewProxyHttpServer()
proxy.Verbose = true
proxy.OnRequest().DoFunc(
func(r *http.Request, ctx *goproxy.ProxyCtx) (*http.Request, *http.Response) {
if urlFilter.Filter(r.URL) {
collects.Add(r.Clone(context.TODO()))
}
return r, nil
})

exporter := &sampleExporter{
testSuite: atestpkg.TestSuite{
Name: "sample",
},
}
collects.AddEvent(exporter.add)

srv := &http.Server{
Addr: fmt.Sprintf(":%d", o.port),
Handler: proxy,
}

sig := make(chan os.Signal, 1)
signal.Notify(sig, os.Interrupt, syscall.SIGTERM)
go func() {
<-sig
collects.Stop()
srv.Shutdown(context.Background())
}()

cmd.Println("Starting the proxy server with port", o.port)
srv.ListenAndServe()
var data string
if data, err = exporter.export(); err == nil {
err = os.WriteFile(o.output, []byte(data), 0644)
}
return
}

type sampleExporter struct {
testSuite atestpkg.TestSuite
}

func (e *sampleExporter) add(r *http.Request) {
body := r.Body
data, _ := io.ReadAll(body)

fmt.Println("receive", r.URL.Path)
req := atestpkg.Request{
API: r.URL.String(),
Method: r.Method,
Header: map[string]string{},
Body: string(data),
}

testCase := atestpkg.TestCase{
Request: req,
Expect: atestpkg.Response{
StatusCode: 200,
},
}

specs := strings.Split(r.URL.Path, "/")
if len(specs) > 0 {
testCase.Name = specs[len(specs)-1]
}

if val := r.Header.Get("Content-Type"); val != "" {
req.Header["Content-Type"] = val
}

e.testSuite.Items = append(e.testSuite.Items, testCase)
}

var prefix = `#!api-testing
# yaml-language-server: $schema=https://gitee.com/linuxsuren/api-testing/raw/master/sample/api-testing-schema.json
`

func (e *sampleExporter) export() (string, error) {
marker := map[string]int{}

for i, item := range e.testSuite.Items {
if _, ok := marker[item.Name]; ok {
marker[item.Name]++
e.testSuite.Items[i].Name = fmt.Sprintf("%s-%d", item.Name, marker[item.Name])
} else {
marker[item.Name] = 0
}
}

data, err := yaml.Marshal(e.testSuite)
return prefix + string(data), err
}
44 changes: 44 additions & 0 deletions extensions/collector/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
module github.com/linuxsuren/api-testing/extensions/collector

go 1.19

require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/Masterminds/sprig/v3 v3.2.3 // indirect
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 // indirect
github.com/antonmedv/expr v1.12.1 // indirect
github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 // indirect
github.com/imdario/mergo v0.3.11 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/invopop/jsonschema v0.7.0 // indirect
github.com/linuxsuren/api-testing v0.0.11 // indirect
github.com/linuxsuren/go-fake-runtime v0.0.0-20230413085645-15e77ab55dbd // indirect
github.com/linuxsuren/unstructured v0.0.1 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
github.com/sergi/go-diff v1.2.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
github.com/spf13/cobra v1.7.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
golang.org/x/crypto v0.3.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect
google.golang.org/grpc v1.54.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
)

replace github.com/linuxsuren/api-testing => ../../.
Loading

0 comments on commit 3b4dea9

Please sign in to comment.