Skip to content

Commit

Permalink
fix: not work when grpc port is a random one (LinuxSuRen#467)
Browse files Browse the repository at this point in the history
Co-authored-by: rick <[email protected]>
  • Loading branch information
LinuxSuRen and LinuxSuRen authored May 31, 2024
1 parent b9533ee commit a11b7ff
Show file tree
Hide file tree
Showing 9 changed files with 117 additions and 24 deletions.
7 changes: 5 additions & 2 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,10 +262,13 @@ func (o *serverOption) runE(cmd *cobra.Command, args []string) (err error) {
_ = o.httpServer.Shutdown(ctx)
}()

gRPCServerPort := util.GetPort(lis)
gRPCServerAddr := fmt.Sprintf("127.0.0.1:%s", gRPCServerPort)

mux := runtime.NewServeMux(runtime.WithMetadata(server.MetadataStoreFunc))
err = errors.Join(
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, "127.0.0.1:7070", []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}),
server.RegisterMockHandlerFromEndpoint(ctx, mux, "127.0.0.1:7070", []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}))
server.RegisterRunnerHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}),
server.RegisterMockHandlerFromEndpoint(ctx, mux, gRPCServerAddr, []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}))
if err == nil {
mux.HandlePath(http.MethodGet, "/", frontEndHandlerWithLocation(o.consolePath))
mux.HandlePath(http.MethodGet, "/assets/{asset}", frontEndHandlerWithLocation(o.consolePath))
Expand Down
67 changes: 53 additions & 14 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package cmd

import (
"bytes"
"context"
_ "embed"
"errors"
"fmt"
Expand All @@ -27,6 +28,7 @@ import (
"path/filepath"
"strings"
"testing"
"time"

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

func TestProxy(t *testing.T) {
t.Run("normal", func(t *testing.T) {
gock.Off()
defer gock.Off()

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

t.Run("no proxy", func(t *testing.T) {
gock.Off()
defer gock.Off()

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

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

rootCmd := &cobra.Command{
Use: "atest",
}
rootCmd.SetOut(io.Discard)
rootCmd.AddCommand(createServerCmd(
fakeruntime.FakeExecer{ExpectOS: "linux", ExpectLookPathError: errors.New("not-found")},
server.NewFakeHTTPServer(),
))

rootCmd.SetArgs([]string{"server", "--config-dir", dir, "--dry-run", "--port=0", "--http-port=0"})
err = rootCmd.Execute()
assert.NoError(t, err)
t.Run("dry-run", func(t *testing.T) {
rootCmd := &cobra.Command{
Use: "atest",
}
rootCmd.SetOut(io.Discard)
rootCmd.AddCommand(createServerCmd(
fakeruntime.FakeExecer{ExpectOS: "linux", ExpectLookPathError: errors.New("not-found")},
server.NewFakeHTTPServer(),
))

rootCmd.SetArgs([]string{"server", "--config-dir", dir, "--dry-run", "--port=0", "--http-port=0"})
err = rootCmd.Execute()
assert.NoError(t, err)
})

t.Run("normal", func(t *testing.T) {
httpServer := server.NewDefaultHTTPServer()
rootCmd := &cobra.Command{
Use: "atest",
}
rootCmd.SetOut(io.Discard)
rootCmd.AddCommand(createServerCmd(
fakeruntime.FakeExecer{ExpectOS: "linux", ExpectLookPathError: errors.New("not-found")},
httpServer,
))

rootCmd.SetArgs([]string{"server", "--config-dir", dir, "--port=0", "--http-port=0"})
go func() {
err = rootCmd.Execute()
assert.NoError(t, err)
}()

for httpServer.GetPort() == "" {
time.Sleep(time.Second)
}

defer func() {
httpServer.Shutdown(context.Background())
}()
resp, err := http.Post(fmt.Sprintf("http://localhost:%s/server.Runner/GetSuites", httpServer.GetPort()), util.JSON, nil)
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}

resp, err = http.Get(fmt.Sprintf("http://localhost:%s/metrics", httpServer.GetPort()))
if assert.NoError(t, err) {
assert.Equal(t, http.StatusOK, resp.StatusCode)
}
})
}

type fakeResponseWriter struct {
Expand Down
1 change: 1 addition & 0 deletions console/atest-desktop/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ const startServer = () => {
serverProcess = spawn(atestFromHome, [
"server",
"--http-port", server.getPort(),
"--port=0",
"--local-storage", path.join(homeData, "*.yaml")
])
serverProcess.stdout.on('data', (data) => {
Expand Down
8 changes: 8 additions & 0 deletions e2e/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
You can build the image locally in the repository root directory:

If you are a Linux/MacOS user, you can use the following command:
```shell
REGISTRY=ghcr.io TAG=master make image
```

If you are a Windows user, you can use the following command:
```powershell
Set-Content -Path "env:REGISTRY" -Value "ghcr.io"
Set-Content -Path "env:TAG" -Value "master"
make image
```
4 changes: 1 addition & 3 deletions pkg/mock/in_memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,7 @@ func jsonStrToInterface(jsonStr string) (objData map[string]interface{}, err err
}

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

func (s *inMemoryServer) Stop() (err error) {
Expand Down
2 changes: 1 addition & 1 deletion pkg/runner/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,7 @@ func TestGetSuggestedAPIs(t *testing.T) {
assert.Empty(t, result)

// swagger
gock.Off()
defer gock.Off()
gock.New(urlFoo).Get("swagger.json").Reply(http.StatusOK).File("testdata/swagger.json")
result, err = runner.GetSuggestedAPIs(&atest.TestSuite{
Spec: atest.APISpec{
Expand Down
18 changes: 16 additions & 2 deletions pkg/server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,16 @@ import (
"net"
"net/http"
"strings"

"github.com/linuxsuren/api-testing/pkg/util"
)

// HTTPServer is an interface for serving HTTP requests
type HTTPServer interface {
Serve(lis net.Listener) error
WithHandler(handler http.Handler)
Shutdown(ctx context.Context) error
GetPort() string
}

type CombineHandler interface {
Expand All @@ -35,8 +38,9 @@ type CombineHandler interface {
}

type defaultHTTPServer struct {
server *http.Server
handler http.Handler
listener net.Listener
server *http.Server
handler http.Handler
}

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

func (s *defaultHTTPServer) Serve(lis net.Listener) (err error) {
s.listener = lis
s.server = &http.Server{Handler: s.handler}
err = s.server.Serve(lis)
return
Expand All @@ -58,6 +63,10 @@ func (s *defaultHTTPServer) Shutdown(ctx context.Context) error {
return s.server.Shutdown(ctx)
}

func (s *defaultHTTPServer) GetPort() string {
return util.GetPort(s.listener)
}

type defaultCombineHandler struct {
handlerMapping map[string]http.Handler
defaultHandler http.Handler
Expand Down Expand Up @@ -114,3 +123,8 @@ func (s *fakeHandler) Shutdown(ctx context.Context) error {
// do nothing due to this is a fake method
return nil
}

func (s *fakeHandler) GetPort() string {
// do nothing due to this is a fake method
return ""
}
4 changes: 2 additions & 2 deletions pkg/server/remote_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ func TestGetSuggestedAPIs(t *testing.T) {
})

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

t.Run("normal", func(t *testing.T) {
gock.Off()
defer gock.Off()
randomName := fmt.Sprintf("fake-%d", time.Now().Nanosecond())
_, err := server.CreateTestSuite(ctx, &TestSuiteIdentity{
Name: randomName,
Expand Down
30 changes: 30 additions & 0 deletions pkg/util/net.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
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 util

import (
"net"
"strings"
)

// GetPort returns the port of the listener
func GetPort(listener net.Listener) string {
if listener == nil {
return ""
}
addr := listener.Addr().String()
items := strings.Split(addr, ":")
return items[len(items)-1]
}

0 comments on commit a11b7ff

Please sign in to comment.