Skip to content

Commit f4f1d4c

Browse files
authored
feat: support combine mock and core server together (#390)
Co-authored-by: rick <[email protected]>
1 parent 1943e7d commit f4f1d4c

File tree

8 files changed

+145
-9
lines changed

8 files changed

+145
-9
lines changed

cmd/server.go

+19-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737

3838
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
3939
"github.com/linuxsuren/api-testing/pkg/logging"
40+
"github.com/linuxsuren/api-testing/pkg/mock"
4041
"github.com/linuxsuren/api-testing/pkg/oauth"
4142
template "github.com/linuxsuren/api-testing/pkg/render"
4243
"github.com/linuxsuren/api-testing/pkg/server"
@@ -88,6 +89,7 @@ func createServerCmd(execer fakeruntime.Execer, httpServer server.HTTPServer) (c
8889
flags.StringVarP(&opt.clientID, "client-id", "", os.Getenv("OAUTH_CLIENT_ID"), "ClientID is the application's ID")
8990
flags.StringVarP(&opt.clientSecret, "client-secret", "", os.Getenv("OAUTH_CLIENT_SECRET"), "ClientSecret is the application's secret")
9091
flags.BoolVarP(&opt.dryRun, "dry-run", "", false, "Do not really start a gRPC server")
92+
flags.StringArrayVarP(&opt.mockConfig, "mock-config", "", nil, "The mock config files")
9193

9294
// gc related flags
9395
flags.IntVarP(&opt.gcPercent, "gc-percent", "", 100, "The GC percent of Go")
@@ -121,6 +123,8 @@ type serverOption struct {
121123
oauthSkipTls bool
122124
oauthGroup []string
123125

126+
mockConfig []string
127+
124128
gcPercent int
125129

126130
dryRun bool
@@ -283,10 +287,24 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
283287
promhttp.HandlerFor(reg, promhttp.HandlerOpts{Registry: reg}).ServeHTTP(w, r)
284288
})
285289

290+
combineHandlers := server.NewDefaultCombineHandler()
291+
combineHandlers.PutHandler("", mux)
292+
293+
if len(o.mockConfig) > 0 {
294+
cmd.Println("currently only one mock config is supported, will take the first one")
295+
var mockServerHandler http.Handler
296+
if mockServerHandler, err = mock.NewInMemoryServer(0).
297+
SetupHandler(mock.NewLocalFileReader(o.mockConfig[0])); err != nil {
298+
return
299+
}
300+
combineHandlers.PutHandler("/mock", mockServerHandler)
301+
}
302+
286303
debugHandler(mux, remoteServer)
287-
o.httpServer.WithHandler(mux)
304+
o.httpServer.WithHandler(combineHandlers.GetHandler())
288305
serverLogger.Info("HTTP server listening at", "addr", httplis.Addr())
289306
serverLogger.Info("Server is running.")
307+
290308
err = o.httpServer.Serve(httplis)
291309
err = util.IgnoreErrServerClosed(err)
292310
}

cmd/server_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,18 @@ func TestPrintProto(t *testing.T) {
5757
verify: func(t *testing.T, buf *bytes.Buffer, err error) {
5858
assert.Nil(t, err)
5959
},
60+
}, {
61+
name: "mock server, not found config",
62+
args: []string{"server", "--mock-config=fake", "-p=0", "--http-port=0"},
63+
verify: func(t *testing.T, buffer *bytes.Buffer, err error) {
64+
assert.Error(t, err)
65+
},
66+
}, {
67+
name: "mock server, normal",
68+
args: []string{"server", "--mock-config=testdata/invalid-api.yaml", "-p=0", "--http-port=0"},
69+
verify: func(t *testing.T, buffer *bytes.Buffer, err error) {
70+
assert.NoError(t, err)
71+
},
6072
}}
6173
for _, tt := range tests {
6274
t.Run(tt.name, func(t *testing.T) {

go.mod

-4
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ require (
1414
github.com/go-logr/zapr v1.3.0
1515
github.com/gorilla/mux v1.8.1
1616
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0
17-
github.com/gorilla/mux v1.8.1
18-
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0
1917
github.com/h2non/gock v1.2.0
2018
github.com/invopop/jsonschema v0.7.0
2119
github.com/jhump/protoreflect v1.15.3
@@ -48,8 +46,6 @@ require (
4846
github.com/gofrs/uuid v4.2.0+incompatible // indirect
4947
github.com/golang/protobuf v1.5.4 // indirect
5048
github.com/google/uuid v1.6.0 // indirect
51-
github.com/golang/protobuf v1.5.3 // indirect
52-
github.com/google/uuid v1.3.0 // indirect
5349
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 // indirect
5450
github.com/hashicorp/go-immutable-radix v1.3.1 // indirect
5551
github.com/hashicorp/go-memdb v1.3.2 // indirect

pkg/mock/in_memory.go

+12-3
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,16 @@ func NewInMemoryServer(port int) DynamicServer {
4949
}
5050
}
5151

52-
func (s *inMemoryServer) Start(reader Reader) (err error) {
52+
func (s *inMemoryServer) SetupHandler(reader Reader) (handler http.Handler, err error) {
5353
var server *Server
5454
if server, err = reader.Parse(); err != nil {
5555
return
5656
}
5757

5858
// init the data
5959
s.data = make(map[string][]map[string]interface{})
60-
s.mux = mux.NewRouter()
60+
s.mux = mux.NewRouter().PathPrefix("/mock").Subrouter()
61+
handler = s.mux
6162

6263
memLogger.Info("start to run all the APIs from objects")
6364
for _, obj := range server.Objects {
@@ -69,10 +70,18 @@ func (s *inMemoryServer) Start(reader Reader) (err error) {
6970
for _, item := range server.Items {
7071
s.startItem(item)
7172
}
73+
return
74+
}
75+
76+
func (s *inMemoryServer) Start(reader Reader) (err error) {
77+
var handler http.Handler
78+
if handler, err = s.SetupHandler(reader); err != nil {
79+
return
80+
}
7281

7382
s.listener, err = net.Listen("tcp", fmt.Sprintf(":%d", s.port))
7483
go func() {
75-
err = http.Serve(s.listener, s.mux)
84+
err = http.Serve(s.listener, handler)
7685
}()
7786
return
7887
}

pkg/mock/in_memory_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func TestInMemoryServer(t *testing.T) {
3333
server.Stop()
3434
}()
3535

36-
api := "http://localhost:" + server.GetPort()
36+
api := "http://localhost:" + server.GetPort() + "/mock"
3737

3838
_, err = http.Post(api+"/team", "", bytes.NewBufferString(`{
3939
"name": "test",

pkg/mock/server.go

+3
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,11 @@ limitations under the License.
1515
*/
1616
package mock
1717

18+
import "net/http"
19+
1820
type DynamicServer interface {
1921
Start(reader Reader) error
22+
SetupHandler(reader Reader) (http.Handler, error)
2023
Stop() error
2124
GetPort() string
2225
}

pkg/server/http.go

+57
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
116
package server
217

318
import (
419
context "context"
520
"net"
621
"net/http"
22+
"strings"
723
)
824

925
// HTTPServer is an interface for serving HTTP requests
@@ -13,6 +29,11 @@ type HTTPServer interface {
1329
Shutdown(ctx context.Context) error
1430
}
1531

32+
type CombineHandler interface {
33+
PutHandler(string, http.Handler)
34+
GetHandler() http.Handler
35+
}
36+
1637
type defaultHTTPServer struct {
1738
server *http.Server
1839
handler http.Handler
@@ -37,6 +58,42 @@ func (s *defaultHTTPServer) Shutdown(ctx context.Context) error {
3758
return s.server.Shutdown(ctx)
3859
}
3960

61+
type defaultCombineHandler struct {
62+
handlerMapping map[string]http.Handler
63+
defaultHandler http.Handler
64+
}
65+
66+
func NewDefaultCombineHandler() CombineHandler {
67+
return &defaultCombineHandler{
68+
handlerMapping: make(map[string]http.Handler),
69+
}
70+
}
71+
72+
func (s *defaultCombineHandler) PutHandler(name string, handler http.Handler) {
73+
if name == "" {
74+
s.defaultHandler = handler
75+
} else {
76+
s.handlerMapping[name] = handler
77+
}
78+
}
79+
80+
func (s *defaultCombineHandler) GetHandler() http.Handler {
81+
if len(s.handlerMapping) == 0 {
82+
return s.defaultHandler
83+
}
84+
return s
85+
}
86+
87+
func (s *defaultCombineHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
88+
for prefix, handler := range s.handlerMapping {
89+
if strings.HasPrefix(r.URL.Path, prefix) {
90+
handler.ServeHTTP(w, r)
91+
return
92+
}
93+
}
94+
s.defaultHandler.ServeHTTP(w, r)
95+
}
96+
4097
type fakeHandler struct{}
4198

4299
// NewFakeHTTPServer creates a fake HTTP server

pkg/server/http_test.go

+41
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
116
package server_test
217

318
import (
419
"net"
20+
"net/http"
521
"testing"
622

723
"github.com/linuxsuren/api-testing/pkg/server"
@@ -19,3 +35,28 @@ func TestHTTPServer(t *testing.T) {
1935
defaultHTTPServer := server.NewDefaultHTTPServer()
2036
defaultHTTPServer.WithHandler(nil)
2137
}
38+
39+
func TestCombineHandler(t *testing.T) {
40+
defaultHandler := http.NewServeMux()
41+
fakeHandler := http.NewServeMux()
42+
43+
t.Run("correct default handler", func(t *testing.T) {
44+
combineHandler := server.NewDefaultCombineHandler()
45+
46+
combineHandler.PutHandler("", defaultHandler)
47+
combineHandler.PutHandler("/fake", fakeHandler)
48+
49+
assert.NotEqual(t, defaultHandler, combineHandler.GetHandler())
50+
51+
fakeServer := server.NewFakeHTTPServer()
52+
assert.Nil(t, fakeServer.Shutdown(nil))
53+
})
54+
55+
t.Run("only one default handler", func(t *testing.T) {
56+
combineHandler := server.NewDefaultCombineHandler()
57+
58+
combineHandler.PutHandler("", defaultHandler)
59+
60+
assert.Equal(t, defaultHandler, combineHandler.GetHandler())
61+
})
62+
}

0 commit comments

Comments
 (0)