feat: support detailed mock server (#377)
* feat: support detailed mock server * make the constant be private --------- Co-authored-by: rick <linuxsuren@users.noreply.github.com>
This commit is contained in:
parent
c17b3e7c89
commit
062f96f965
2
go.mod
2
go.mod
|
@ -10,6 +10,7 @@ require (
|
||||||
github.com/expr-lang/expr v1.15.6
|
github.com/expr-lang/expr v1.15.6
|
||||||
github.com/flopp/go-findfont v0.1.0
|
github.com/flopp/go-findfont v0.1.0
|
||||||
github.com/ghodss/yaml v1.0.0
|
github.com/ghodss/yaml v1.0.0
|
||||||
|
github.com/gorilla/mux v1.8.1
|
||||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
|
||||||
github.com/h2non/gock v1.2.0
|
github.com/h2non/gock v1.2.0
|
||||||
github.com/invopop/jsonschema v0.7.0
|
github.com/invopop/jsonschema v0.7.0
|
||||||
|
@ -42,7 +43,6 @@ require (
|
||||||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gorilla/mux v1.8.1 // indirect
|
|
||||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
|
||||||
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
|
||||||
github.com/hashicorp/go-memdb v1.3.2 // indirect
|
github.com/hashicorp/go-memdb v1.3.2 // indirect
|
||||||
|
|
|
@ -27,6 +27,7 @@ items:
|
||||||
path: /v1/teams/{team}/repos
|
path: /v1/teams/{team}/repos
|
||||||
method: GET
|
method: GET
|
||||||
response:
|
response:
|
||||||
|
statusCode: 200
|
||||||
body: |
|
body: |
|
||||||
{
|
{
|
||||||
"status": 0,
|
"status": 0,
|
||||||
|
@ -40,12 +41,16 @@ items:
|
||||||
request:
|
request:
|
||||||
path: /v1/repos/{repo}/prs
|
path: /v1/repos/{repo}/prs
|
||||||
response:
|
response:
|
||||||
|
headers:
|
||||||
|
- key: server
|
||||||
|
value: mock
|
||||||
body: |
|
body: |
|
||||||
{
|
{
|
||||||
"count": 1,
|
"count": 1,
|
||||||
"items": [{
|
"items": [{
|
||||||
"title": "fix: there is a bug on page one",
|
"title": "fix: there is a bug on page {{ randEnum "one" }}",
|
||||||
"number": 123,
|
"number": 123,
|
||||||
|
"message": "{{index (index .Header "Accept-Encoding") 0}}",
|
||||||
"author": "someone",
|
"author": "someone",
|
||||||
"status": "success"
|
"status": "success"
|
||||||
}]
|
}]
|
||||||
|
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
"github.com/linuxsuren/api-testing/pkg/render"
|
"github.com/linuxsuren/api-testing/pkg/render"
|
||||||
"github.com/linuxsuren/api-testing/pkg/util"
|
"github.com/linuxsuren/api-testing/pkg/util"
|
||||||
|
"github.com/linuxsuren/api-testing/pkg/version"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
@ -57,6 +58,11 @@ func (s *inMemoryServer) Start(reader Reader) (err error) {
|
||||||
s.initObjectData(obj)
|
s.initObjectData(obj)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Println("start to run all the APIs from items")
|
||||||
|
for _, item := range server.Items {
|
||||||
|
s.startItem(item)
|
||||||
|
}
|
||||||
|
|
||||||
s.listener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.port))
|
s.listener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.port))
|
||||||
go func() {
|
go func() {
|
||||||
err = http.Serve(s.listener, s.mux)
|
err = http.Serve(s.listener, s.mux)
|
||||||
|
@ -201,6 +207,25 @@ func (s *inMemoryServer) startObject(obj Object) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *inMemoryServer) startItem(item Item) {
|
||||||
|
s.mux.HandleFunc(item.Request.Path, func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
item.Response.Headers = append(item.Response.Headers, Header{
|
||||||
|
Key: headerMockServer,
|
||||||
|
Value: fmt.Sprintf("api-testing: %s", version.GetVersion()),
|
||||||
|
})
|
||||||
|
for _, header := range item.Response.Headers {
|
||||||
|
w.Header().Set(header.Key, header.Value)
|
||||||
|
}
|
||||||
|
body, err := render.Render("start-item", item.Response.Body, req)
|
||||||
|
if err == nil {
|
||||||
|
w.Write([]byte(body))
|
||||||
|
} else {
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
}
|
||||||
|
w.WriteHeader(util.ZeroThenDefault(item.Response.StatusCode, http.StatusOK))
|
||||||
|
}).Methods(util.EmptyThenDefault(item.Request.Method, http.MethodGet))
|
||||||
|
}
|
||||||
|
|
||||||
func (s *inMemoryServer) initObjectData(obj Object) {
|
func (s *inMemoryServer) initObjectData(obj Object) {
|
||||||
if obj.Sample == "" {
|
if obj.Sample == "" {
|
||||||
return
|
return
|
||||||
|
|
|
@ -20,6 +20,7 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -116,6 +117,19 @@ func TestInMemoryServer(t *testing.T) {
|
||||||
assert.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode)
|
assert.Equal(t, http.StatusMethodNotAllowed, resp.StatusCode)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("mock item", func(t *testing.T) {
|
||||||
|
resp, err := http.Get(api + "/v1/repos/test/prs")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
assert.Equal(t, "mock", resp.Header.Get("server"))
|
||||||
|
assert.NotEmpty(t, resp.Header.Get(headerMockServer))
|
||||||
|
|
||||||
|
data, err := io.ReadAll(resp.Body)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
|
||||||
|
assert.True(t, strings.Contains(string(data), `"message": "gzip"`), string(data))
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("not found config file", func(t *testing.T) {
|
t.Run("not found config file", func(t *testing.T) {
|
||||||
server := NewInMemoryServer(0)
|
server := NewInMemoryServer(0)
|
||||||
err := server.Start(NewLocalFileReader("fake"))
|
err := server.Start(NewLocalFileReader("fake"))
|
||||||
|
|
|
@ -20,3 +20,7 @@ type DynamicServer interface {
|
||||||
Stop() error
|
Stop() error
|
||||||
GetPort() string
|
GetPort() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
headerMockServer = "MockServer"
|
||||||
|
)
|
||||||
|
|
|
@ -27,6 +27,29 @@ type Field struct {
|
||||||
Kind string `yaml:"kind"`
|
Kind string `yaml:"kind"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
Request Request `yaml:"request"`
|
||||||
|
Response Response `yaml:"response"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Request struct {
|
||||||
|
Path string `yaml:"path"`
|
||||||
|
Method string `yaml:"method"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Body string `yaml:"body"`
|
||||||
|
Headers []Header `yaml:"headers"`
|
||||||
|
StatusCode int `yaml:"statusCode"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Header struct {
|
||||||
|
Key string `yaml:"key"`
|
||||||
|
Value string `yaml:"value"`
|
||||||
|
}
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
Objects []Object `yaml:"objects"`
|
Objects []Object `yaml:"objects"`
|
||||||
|
Items []Item `yaml:"items"`
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue