feat: support combine mock and core server together (#390)
Co-authored-by: rick <linuxsuren@users.noreply.github.com>
This commit is contained in:
parent
1943e7d82e
commit
f4f1d4c312
|
@ -37,6 +37,7 @@ import (
|
|||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/linuxsuren/api-testing/pkg/logging"
|
||||
"github.com/linuxsuren/api-testing/pkg/mock"
|
||||
"github.com/linuxsuren/api-testing/pkg/oauth"
|
||||
template "github.com/linuxsuren/api-testing/pkg/render"
|
||||
"github.com/linuxsuren/api-testing/pkg/server"
|
||||
|
@ -88,6 +89,7 @@ func createServerCmd(execer fakeruntime.Execer, httpServer server.HTTPServer) (c
|
|||
flags.StringVarP(&opt.clientID, "client-id", "", os.Getenv("OAUTH_CLIENT_ID"), "ClientID is the application's ID")
|
||||
flags.StringVarP(&opt.clientSecret, "client-secret", "", os.Getenv("OAUTH_CLIENT_SECRET"), "ClientSecret is the application's secret")
|
||||
flags.BoolVarP(&opt.dryRun, "dry-run", "", false, "Do not really start a gRPC server")
|
||||
flags.StringArrayVarP(&opt.mockConfig, "mock-config", "", nil, "The mock config files")
|
||||
|
||||
// gc related flags
|
||||
flags.IntVarP(&opt.gcPercent, "gc-percent", "", 100, "The GC percent of Go")
|
||||
|
@ -121,6 +123,8 @@ type serverOption struct {
|
|||
oauthSkipTls bool
|
||||
oauthGroup []string
|
||||
|
||||
mockConfig []string
|
||||
|
||||
gcPercent int
|
||||
|
||||
dryRun bool
|
||||
|
@ -283,10 +287,24 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
|
|||
promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}).ServeHTTP(w, r)
|
||||
})
|
||||
|
||||
combineHandlers := server.NewDefaultCombineHandler()
|
||||
combineHandlers.PutHandler("", mux)
|
||||
|
||||
if len(o.mockConfig) > 0 {
|
||||
cmd.Println("currently only one mock config is supported, will take the first one")
|
||||
var mockServerHandler http.Handler
|
||||
if mockServerHandler, err = mock.NewInMemoryServer(0).
|
||||
SetupHandler(mock.NewLocalFileReader(o.mockConfig[0])); err != nil {
|
||||
return
|
||||
}
|
||||
combineHandlers.PutHandler("/mock", mockServerHandler)
|
||||
}
|
||||
|
||||
debugHandler(mux, remoteServer)
|
||||
o.httpServer.WithHandler(mux)
|
||||
o.httpServer.WithHandler(combineHandlers.GetHandler())
|
||||
serverLogger.Info("HTTP server listening at", "addr", httplis.Addr())
|
||||
serverLogger.Info("Server is running.")
|
||||
|
||||
err = o.httpServer.Serve(httplis)
|
||||
err = util.IgnoreErrServerClosed(err)
|
||||
}
|
||||
|
|
|
@ -57,6 +57,18 @@ func TestPrintProto(t *testing.T) {
|
|||
verify: func(t *testing.T, buf *bytes.Buffer, err error) {
|
||||
assert.Nil(t, err)
|
||||
},
|
||||
}, {
|
||||
name: "mock server, not found config",
|
||||
args: []string{"server", "--mock-config=fake", "-p=0", "--http-port=0"},
|
||||
verify: func(t *testing.T, buffer *bytes.Buffer, err error) {
|
||||
assert.Error(t, err)
|
||||
},
|
||||
}, {
|
||||
name: "mock server, normal",
|
||||
args: []string{"server", "--mock-config=testdata/invalid-api.yaml", "-p=0", "--http-port=0"},
|
||||
verify: func(t *testing.T, buffer *bytes.Buffer, err error) {
|
||||
assert.NoError(t, err)
|
||||
},
|
||||
}}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
|
4
go.mod
4
go.mod
|
@ -14,8 +14,6 @@ require (
|
|||
github.com/go-logr/zapr v1.3.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0
|
||||
github.com/gorilla/mux v1.8.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
|
||||
github.com/h2non/gock v1.2.0
|
||||
github.com/invopop/jsonschema v0.7.0
|
||||
github.com/jhump/protoreflect v1.15.3
|
||||
|
@ -48,8 +46,6 @@ require (
|
|||
github.com/gofrs/uuid v4.2.0+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/uuid v1.3.0 // 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-memdb v1.3.2 // indirect
|
||||
|
|
|
@ -49,7 +49,7 @@ func NewInMemoryServer(port int) DynamicServer {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *inMemoryServer) Start(reader Reader) (err error) {
|
||||
func (s *inMemoryServer) SetupHandler(reader Reader) (handler http.Handler, err error) {
|
||||
var server *Server
|
||||
if server, err = reader.Parse(); err != nil {
|
||||
return
|
||||
|
@ -57,7 +57,8 @@ func (s *inMemoryServer) Start(reader Reader) (err error) {
|
|||
|
||||
// init the data
|
||||
s.data = make(map[string][]map[string]interface{})
|
||||
s.mux = mux.NewRouter()
|
||||
s.mux = mux.NewRouter().PathPrefix("/mock").Subrouter()
|
||||
handler = s.mux
|
||||
|
||||
memLogger.Info("start to run all the APIs from objects")
|
||||
for _, obj := range server.Objects {
|
||||
|
@ -69,10 +70,18 @@ func (s *inMemoryServer) Start(reader Reader) (err error) {
|
|||
for _, item := range server.Items {
|
||||
s.startItem(item)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (s *inMemoryServer) Start(reader Reader) (err error) {
|
||||
var handler http.Handler
|
||||
if handler, err = s.SetupHandler(reader); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.listener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.port))
|
||||
go func() {
|
||||
err = http.Serve(s.listener, s.mux)
|
||||
err = http.Serve(s.listener, handler)
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ func TestInMemoryServer(t *testing.T) {
|
|||
server.Stop()
|
||||
}()
|
||||
|
||||
api := "http://localhost:" + server.GetPort()
|
||||
api := "http://localhost:" + server.GetPort() + "/mock"
|
||||
|
||||
_, err = http.Post(api+"/team", "", bytes.NewBufferString(`{
|
||||
"name": "test",
|
||||
|
|
|
@ -15,8 +15,11 @@ limitations under the License.
|
|||
*/
|
||||
package mock
|
||||
|
||||
import "net/http"
|
||||
|
||||
type DynamicServer interface {
|
||||
Start(reader Reader) error
|
||||
SetupHandler(reader Reader) (http.Handler, error)
|
||||
Stop() error
|
||||
GetPort() string
|
||||
}
|
||||
|
|
|
@ -1,9 +1,25 @@
|
|||
/*
|
||||
Copyright 2024 API Testing Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package server
|
||||
|
||||
import (
|
||||
context "context"
|
||||
"net"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HTTPServer is an interface for serving HTTP requests
|
||||
|
@ -13,6 +29,11 @@ type HTTPServer interface {
|
|||
Shutdown(ctx context.Context) error
|
||||
}
|
||||
|
||||
type CombineHandler interface {
|
||||
PutHandler(string, http.Handler)
|
||||
GetHandler() http.Handler
|
||||
}
|
||||
|
||||
type defaultHTTPServer struct {
|
||||
server *http.Server
|
||||
handler http.Handler
|
||||
|
@ -37,6 +58,42 @@ func (s *defaultHTTPServer) Shutdown(ctx context.Context) error {
|
|||
return s.server.Shutdown(ctx)
|
||||
}
|
||||
|
||||
type defaultCombineHandler struct {
|
||||
handlerMapping map[string]http.Handler
|
||||
defaultHandler http.Handler
|
||||
}
|
||||
|
||||
func NewDefaultCombineHandler() CombineHandler {
|
||||
return &defaultCombineHandler{
|
||||
handlerMapping: make(map[string]http.Handler),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *defaultCombineHandler) PutHandler(name string, handler http.Handler) {
|
||||
if name == "" {
|
||||
s.defaultHandler = handler
|
||||
} else {
|
||||
s.handlerMapping[name] = handler
|
||||
}
|
||||
}
|
||||
|
||||
func (s *defaultCombineHandler) GetHandler() http.Handler {
|
||||
if len(s.handlerMapping) == 0 {
|
||||
return s.defaultHandler
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *defaultCombineHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
for prefix, handler := range s.handlerMapping {
|
||||
if strings.HasPrefix(r.URL.Path, prefix) {
|
||||
handler.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
}
|
||||
s.defaultHandler.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
type fakeHandler struct{}
|
||||
|
||||
// NewFakeHTTPServer creates a fake HTTP server
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
/*
|
||||
Copyright 2024 API Testing Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
package server_test
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/linuxsuren/api-testing/pkg/server"
|
||||
|
@ -19,3 +35,28 @@ func TestHTTPServer(t *testing.T) {
|
|||
defaultHTTPServer := server.NewDefaultHTTPServer()
|
||||
defaultHTTPServer.WithHandler(nil)
|
||||
}
|
||||
|
||||
func TestCombineHandler(t *testing.T) {
|
||||
defaultHandler := http.NewServeMux()
|
||||
fakeHandler := http.NewServeMux()
|
||||
|
||||
t.Run("correct default handler", func(t *testing.T) {
|
||||
combineHandler := server.NewDefaultCombineHandler()
|
||||
|
||||
combineHandler.PutHandler("", defaultHandler)
|
||||
combineHandler.PutHandler("/fake", fakeHandler)
|
||||
|
||||
assert.NotEqual(t, defaultHandler, combineHandler.GetHandler())
|
||||
|
||||
fakeServer := server.NewFakeHTTPServer()
|
||||
assert.Nil(t, fakeServer.Shutdown(nil))
|
||||
})
|
||||
|
||||
t.Run("only one default handler", func(t *testing.T) {
|
||||
combineHandler := server.NewDefaultCombineHandler()
|
||||
|
||||
combineHandler.PutHandler("", defaultHandler)
|
||||
|
||||
assert.Equal(t, defaultHandler, combineHandler.GetHandler())
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue