Skip to content

Commit a11b7ff

Browse files
authored
fix: not work when grpc port is a random one (#467)
Co-authored-by: rick <[email protected]>
1 parent b9533ee commit a11b7ff

File tree

9 files changed

+117
-24
lines changed

9 files changed

+117
-24
lines changed

cmd/server.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -262,10 +262,13 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
262262
_ = o.httpServer.Shutdown(ctx)
263263
}()
264264

265+
gRPCServerPort := util.GetPort(lis)
266+
gRPCServerAddr := fmt.Sprintf("127.0.0.1:%s", gRPCServerPort)
267+
265268
mux := runtime.NewServeMux(runtime.WithMetadata(server.MetadataStoreFunc))
266269
err = errors.Join(
267-
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, "127.0.0.1:7070", []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}),
268-
server.RegisterMockHandlerFromEndpoint(ctx, mux, "127.0.0.1:7070", []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}))
270+
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}),
271+
server.RegisterMockHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}))
269272
if err == nil {
270273
mux.HandlePath(http.MethodGet, "/", frontEndHandlerWithLocation(o.consolePath))
271274
mux.HandlePath(http.MethodGet, "/assets/{asset}", frontEndHandlerWithLocation(o.consolePath))

cmd/server_test.go

+53-14
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package cmd
1717

1818
import (
1919
"bytes"
20+
"context"
2021
_ "embed"
2122
"errors"
2223
"fmt"
@@ -27,6 +28,7 @@ import (
2728
"path/filepath"
2829
"strings"
2930
"testing"
31+
"time"
3032

3133
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
3234
"github.com/h2non/gock"
@@ -214,7 +216,7 @@ func TestFrontEndHandlerWithLocation(t *testing.T) {
214216

215217
func TestProxy(t *testing.T) {
216218
t.Run("normal", func(t *testing.T) {
217-
gock.Off()
219+
defer gock.Off()
218220

219221
gock.New("http://localhost:8080").Post("/api/v1/echo").Reply(http.StatusOK)
220222
gock.New("http://localhost:9090").Post("/api/v1/echo").Reply(http.StatusOK)
@@ -228,7 +230,7 @@ func TestProxy(t *testing.T) {
228230
})
229231

230232
t.Run("no proxy", func(t *testing.T) {
231-
gock.Off()
233+
defer gock.Off()
232234

233235
gock.New("http://localhost:8080").Post("/api/v1/echo").Reply(http.StatusOK)
234236

@@ -286,18 +288,55 @@ func TestStartPlugins(t *testing.T) {
286288
err = os.WriteFile(filepath.Join(dir, "stores.yaml"), []byte(sampleStores), 0644)
287289
assert.NoError(t, err)
288290

289-
rootCmd := &cobra.Command{
290-
Use: "atest",
291-
}
292-
rootCmd.SetOut(io.Discard)
293-
rootCmd.AddCommand(createServerCmd(
294-
fakeruntime.FakeExecer{ExpectOS: "linux", ExpectLookPathError: errors.New("not-found")},
295-
server.NewFakeHTTPServer(),
296-
))
297-
298-
rootCmd.SetArgs([]string{"server", "--config-dir", dir, "--dry-run", "--port=0", "--http-port=0"})
299-
err = rootCmd.Execute()
300-
assert.NoError(t, err)
291+
t.Run("dry-run", func(t *testing.T) {
292+
rootCmd := &cobra.Command{
293+
Use: "atest",
294+
}
295+
rootCmd.SetOut(io.Discard)
296+
rootCmd.AddCommand(createServerCmd(
297+
fakeruntime.FakeExecer{ExpectOS: "linux", ExpectLookPathError: errors.New("not-found")},
298+
server.NewFakeHTTPServer(),
299+
))
300+
301+
rootCmd.SetArgs([]string{"server", "--config-dir", dir, "--dry-run", "--port=0", "--http-port=0"})
302+
err = rootCmd.Execute()
303+
assert.NoError(t, err)
304+
})
305+
306+
t.Run("normal", func(t *testing.T) {
307+
httpServer := server.NewDefaultHTTPServer()
308+
rootCmd := &cobra.Command{
309+
Use: "atest",
310+
}
311+
rootCmd.SetOut(io.Discard)
312+
rootCmd.AddCommand(createServerCmd(
313+
fakeruntime.FakeExecer{ExpectOS: "linux", ExpectLookPathError: errors.New("not-found")},
314+
httpServer,
315+
))
316+
317+
rootCmd.SetArgs([]string{"server", "--config-dir", dir, "--port=0", "--http-port=0"})
318+
go func() {
319+
err = rootCmd.Execute()
320+
assert.NoError(t, err)
321+
}()
322+
323+
for httpServer.GetPort() == "" {
324+
time.Sleep(time.Second)
325+
}
326+
327+
defer func() {
328+
httpServer.Shutdown(context.Background())
329+
}()
330+
resp, err := http.Post(fmt.Sprintf("http://localhost:%s/server.Runner/GetSuites", httpServer.GetPort()), util.JSON, nil)
331+
if assert.NoError(t, err) {
332+
assert.Equal(t, http.StatusOK, resp.StatusCode)
333+
}
334+
335+
resp, err = http.Get(fmt.Sprintf("http://localhost:%s/metrics", httpServer.GetPort()))
336+
if assert.NoError(t, err) {
337+
assert.Equal(t, http.StatusOK, resp.StatusCode)
338+
}
339+
})
301340
}
302341

303342
type fakeResponseWriter struct {

console/atest-desktop/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@ const startServer = () => {
185185
serverProcess = spawn(atestFromHome, [
186186
"server",
187187
"--http-port", server.getPort(),
188+
"--port=0",
188189
"--local-storage", path.join(homeData, "*.yaml")
189190
])
190191
serverProcess.stdout.on('data', (data) => {

e2e/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
You can build the image locally in the repository root directory:
22

3+
If you are a Linux/MacOS user, you can use the following command:
34
```shell
45
REGISTRY=ghcr.io TAG=master make image
56
```
7+
8+
If you are a Windows user, you can use the following command:
9+
```powershell
10+
Set-Content -Path "env:REGISTRY" -Value "ghcr.io"
11+
Set-Content -Path "env:TAG" -Value "master"
12+
make image
13+
```

pkg/mock/in_memory.go

+1-3
Original file line numberDiff line numberDiff line change
@@ -424,9 +424,7 @@ func jsonStrToInterface(jsonStr string) (objData map[string]interface{}, err err
424424
}
425425

426426
func (s *inMemoryServer) GetPort() string {
427-
addr := s.listener.Addr().String()
428-
items := strings.Split(addr, ":")
429-
return items[len(items)-1]
427+
return util.GetPort(s.listener)
430428
}
431429

432430
func (s *inMemoryServer) Stop() (err error) {

pkg/runner/http_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ func TestGetSuggestedAPIs(t *testing.T) {
545545
assert.Empty(t, result)
546546

547547
// swagger
548-
gock.Off()
548+
defer gock.Off()
549549
gock.New(urlFoo).Get("swagger.json").Reply(http.StatusOK).File("testdata/swagger.json")
550550
result, err = runner.GetSuggestedAPIs(&atest.TestSuite{
551551
Spec: atest.APISpec{

pkg/server/http.go

+16-2
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ import (
2020
"net"
2121
"net/http"
2222
"strings"
23+
24+
"github.com/linuxsuren/api-testing/pkg/util"
2325
)
2426

2527
// HTTPServer is an interface for serving HTTP requests
2628
type HTTPServer interface {
2729
Serve(lis net.Listener) error
2830
WithHandler(handler http.Handler)
2931
Shutdown(ctx context.Context) error
32+
GetPort() string
3033
}
3134

3235
type CombineHandler interface {
@@ -35,8 +38,9 @@ type CombineHandler interface {
3538
}
3639

3740
type defaultHTTPServer struct {
38-
server *http.Server
39-
handler http.Handler
41+
listener net.Listener
42+
server *http.Server
43+
handler http.Handler
4044
}
4145

4246
// NewDefaultHTTPServer creates a default HTTP server
@@ -45,6 +49,7 @@ func NewDefaultHTTPServer() HTTPServer {
4549
}
4650

4751
func (s *defaultHTTPServer) Serve(lis net.Listener) (err error) {
52+
s.listener = lis
4853
s.server = &http.Server{Handler: s.handler}
4954
err = s.server.Serve(lis)
5055
return
@@ -58,6 +63,10 @@ func (s *defaultHTTPServer) Shutdown(ctx context.Context) error {
5863
return s.server.Shutdown(ctx)
5964
}
6065

66+
func (s *defaultHTTPServer) GetPort() string {
67+
return util.GetPort(s.listener)
68+
}
69+
6170
type defaultCombineHandler struct {
6271
handlerMapping map[string]http.Handler
6372
defaultHandler http.Handler
@@ -114,3 +123,8 @@ func (s *fakeHandler) Shutdown(ctx context.Context) error {
114123
// do nothing due to this is a fake method
115124
return nil
116125
}
126+
127+
func (s *fakeHandler) GetPort() string {
128+
// do nothing due to this is a fake method
129+
return ""
130+
}

pkg/server/remote_server_test.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ func TestGetSuggestedAPIs(t *testing.T) {
626626
})
627627

628628
t.Run("with swagger URL, not accessed", func(t *testing.T) {
629-
gock.Off()
629+
defer gock.Off()
630630
name := fmt.Sprintf("fake-%d", time.Now().Second())
631631
_, err := server.CreateTestSuite(ctx, &TestSuiteIdentity{
632632
Name: name,
@@ -648,7 +648,7 @@ func TestGetSuggestedAPIs(t *testing.T) {
648648
})
649649

650650
t.Run("normal", func(t *testing.T) {
651-
gock.Off()
651+
defer gock.Off()
652652
randomName := fmt.Sprintf("fake-%d", time.Now().Nanosecond())
653653
_, err := server.CreateTestSuite(ctx, &TestSuiteIdentity{
654654
Name: randomName,

pkg/util/net.go

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
Copyright 2024 API Testing Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
7+
http://www.apache.org/licenses/LICENSE-2.0
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
*/
15+
package util
16+
17+
import (
18+
"net"
19+
"strings"
20+
)
21+
22+
// GetPort returns the port of the listener
23+
func GetPort(listener net.Listener) string {
24+
if listener == nil {
25+
return ""
26+
}
27+
addr := listener.Addr().String()
28+
items := strings.Split(addr, ":")
29+
return items[len(items)-1]
30+
}

0 commit comments

Comments
 (0)