Merge pull request #120 from tongjingran/1082
Support configuring the persistence file path
This commit is contained in:
commit
e831a002be
@ -33,7 +33,7 @@ var registerCmd = &cobra.Command{
|
|||||||
goc register [flags]
|
goc register [flags]
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
s := cover.Service{
|
s := cover.ServiceUnderTest{
|
||||||
Name: name,
|
Name: name,
|
||||||
Address: address,
|
Address: address,
|
||||||
}
|
}
|
||||||
|
10
cmd/run.go
10
cmd/run.go
@ -50,12 +50,16 @@ goc run . [--buildflags] [--exec] [--arguments]
|
|||||||
gocBuild.GoRunArguments = goRunArguments
|
gocBuild.GoRunArguments = goRunArguments
|
||||||
defer gocBuild.Clean()
|
defer gocBuild.Clean()
|
||||||
|
|
||||||
// only save services in memory
|
server := cover.NewMemoryBasedServer() // only save services in memory
|
||||||
cover.DefaultStore = cover.NewMemoryStore()
|
|
||||||
|
|
||||||
// start goc server
|
// start goc server
|
||||||
var l = newLocalListener()
|
var l = newLocalListener()
|
||||||
go cover.GocServer(ioutil.Discard).RunListener(l)
|
go func() {
|
||||||
|
err = server.Route(ioutil.Discard).RunListener(l)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Start goc server failed: %v", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
gocServer := fmt.Sprintf("http://%s", l.Addr().String())
|
gocServer := fmt.Sprintf("http://%s", l.Addr().String())
|
||||||
fmt.Printf("[goc] goc server started: %s \n", gocServer)
|
fmt.Printf("[goc] goc server started: %s \n", gocServer)
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"github.com/qiniu/goc/pkg/cover"
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
var serverCmd = &cobra.Command{
|
var serverCmd = &cobra.Command{
|
||||||
@ -36,13 +37,18 @@ goc server --port=:8080
|
|||||||
goc server --port=localhost:8080
|
goc server --port=localhost:8080
|
||||||
`,
|
`,
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
cover.Run(port)
|
server, err := cover.NewFileBasedServer(localPersistence)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("New file based server failed, err: %v", err)
|
||||||
|
}
|
||||||
|
server.Run(port)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var port string
|
var port, localPersistence string
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
serverCmd.Flags().StringVarP(&port, "port", "", ":7777", "listen port to start a coverage host center")
|
serverCmd.Flags().StringVarP(&port, "port", "", ":7777", "listen port to start a coverage host center")
|
||||||
|
serverCmd.Flags().StringVarP(&localPersistence, "local-persistence", "", "_svrs_address.txt", "the file to save services address information")
|
||||||
rootCmd.AddCommand(serverCmd)
|
rootCmd.AddCommand(serverCmd)
|
||||||
}
|
}
|
||||||
|
2
go.mod
2
go.mod
@ -20,6 +20,6 @@ require (
|
|||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
|
||||||
golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c
|
golang.org/x/tools v0.0.0-20200730221956-1ac65761fe2c
|
||||||
k8s.io/kubernetes v1.13.0
|
k8s.io/kubernetes v1.13.0 // indirect
|
||||||
k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055
|
k8s.io/test-infra v0.0.0-20200511080351-8ac9dbfab055
|
||||||
)
|
)
|
||||||
|
1
go.sum
1
go.sum
@ -464,6 +464,7 @@ github.com/klauspost/pgzip v1.2.1/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQ
|
|||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
@ -36,7 +36,7 @@ type Action interface {
|
|||||||
Clear(param ProfileParam) ([]byte, error)
|
Clear(param ProfileParam) ([]byte, error)
|
||||||
InitSystem() ([]byte, error)
|
InitSystem() ([]byte, error)
|
||||||
ListServices() ([]byte, error)
|
ListServices() ([]byte, error)
|
||||||
RegisterService(svr Service) ([]byte, error)
|
RegisterService(svr ServiceUnderTest) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -69,7 +69,7 @@ func NewWorker(host string) Action {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *client) RegisterService(srv Service) ([]byte, error) {
|
func (c *client) RegisterService(srv ServiceUnderTest) ([]byte, error) {
|
||||||
if _, err := url.ParseRequestURI(srv.Address); err != nil {
|
if _, err := url.ParseRequestURI(srv.Address); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,9 @@ import (
|
|||||||
|
|
||||||
func TestClientAction(t *testing.T) {
|
func TestClientAction(t *testing.T) {
|
||||||
// mock goc server
|
// mock goc server
|
||||||
ts := httptest.NewServer(GocServer(os.Stdout))
|
server, err := NewFileBasedServer("_svrs_address.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
ts := httptest.NewServer(server.Route(os.Stdout))
|
||||||
defer ts.Close()
|
defer ts.Close()
|
||||||
var client = NewWorker(ts.URL)
|
var client = NewWorker(ts.URL)
|
||||||
|
|
||||||
@ -46,15 +48,15 @@ func TestClientAction(t *testing.T) {
|
|||||||
}))
|
}))
|
||||||
defer profileErrMockSvr.Close()
|
defer profileErrMockSvr.Close()
|
||||||
|
|
||||||
// regsiter service into goc server
|
// register service into goc server
|
||||||
var src Service
|
var src ServiceUnderTest
|
||||||
src.Name = "serviceSuccess"
|
src.Name = "serviceSuccess"
|
||||||
src.Address = profileSuccessMockSvr.URL
|
src.Address = profileSuccessMockSvr.URL
|
||||||
res, err := client.RegisterService(src)
|
res, err := client.RegisterService(src)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, string(res), "success")
|
assert.Contains(t, string(res), "success")
|
||||||
|
|
||||||
// do list and check service
|
// do list and check server
|
||||||
res, err = client.ListServices()
|
res, err = client.ListServices()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Contains(t, string(res), src.Address)
|
assert.Contains(t, string(res), src.Address)
|
||||||
@ -63,64 +65,64 @@ func TestClientAction(t *testing.T) {
|
|||||||
// get profile from goc server
|
// get profile from goc server
|
||||||
tcs := []struct {
|
tcs := []struct {
|
||||||
name string
|
name string
|
||||||
service Service
|
service ServiceUnderTest
|
||||||
param ProfileParam
|
param ProfileParam
|
||||||
expected string
|
expected string
|
||||||
expectedErr bool
|
expectedErr bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "both service and address existed",
|
name: "both server and address existed",
|
||||||
service: Service{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
||||||
param: ProfileParam{Force: false, Service: []string{"serviceOK"}, Address: []string{profileSuccessMockSvr.URL}},
|
param: ProfileParam{Force: false, Service: []string{"serviceOK"}, Address: []string{profileSuccessMockSvr.URL}},
|
||||||
expectedErr: true,
|
expectedErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid test with no service flag provide",
|
name: "valid test with no server flag provide",
|
||||||
service: Service{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
||||||
param: ProfileParam{},
|
param: ProfileParam{},
|
||||||
expected: "mockService/main.go:30.13,48.33 13 1",
|
expected: "mockService/main.go:30.13,48.33 13 1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid test with service flag provide",
|
name: "valid test with server flag provide",
|
||||||
service: Service{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
||||||
param: ProfileParam{Service: []string{"serviceOK"}},
|
param: ProfileParam{Service: []string{"serviceOK"}},
|
||||||
expected: "mockService/main.go:30.13,48.33 13 1",
|
expected: "mockService/main.go:30.13,48.33 13 1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid test with address flag provide",
|
name: "valid test with address flag provide",
|
||||||
service: Service{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
||||||
param: ProfileParam{Address: []string{profileSuccessMockSvr.URL}},
|
param: ProfileParam{Address: []string{profileSuccessMockSvr.URL}},
|
||||||
expected: "mockService/main.go:30.13,48.33 13 1",
|
expected: "mockService/main.go:30.13,48.33 13 1",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid test with invalid service flag provide",
|
name: "invalid test with invalid server flag provide",
|
||||||
service: Service{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
||||||
param: ProfileParam{Service: []string{"unknown"}},
|
param: ProfileParam{Service: []string{"unknown"}},
|
||||||
expected: "service [unknown] not found",
|
expected: "server [unknown] not found",
|
||||||
expectedErr: true,
|
expectedErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid test with invalid profile got by service",
|
name: "invalid test with invalid profile got by server",
|
||||||
service: Service{Name: "serviceErr", Address: profileErrMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceErr", Address: profileErrMockSvr.URL},
|
||||||
expected: "bad mode line: error",
|
expected: "bad mode line: error",
|
||||||
expectedErr: true,
|
expectedErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid test with disconnected service",
|
name: "invalid test with disconnected server",
|
||||||
service: Service{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"},
|
service: ServiceUnderTest{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"},
|
||||||
expected: "connection refused",
|
expected: "connection refused",
|
||||||
expectedErr: true,
|
expectedErr: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "invalid test with empty profile",
|
name: "invalid test with empty profile",
|
||||||
service: Service{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"},
|
service: ServiceUnderTest{Name: "serviceNotExist", Address: "http://172.0.0.2:7777"},
|
||||||
param: ProfileParam{Force: true},
|
param: ProfileParam{Force: true},
|
||||||
expectedErr: true,
|
expectedErr: true,
|
||||||
expected: "no profiles",
|
expected: "no profiles",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid test with coverfile flag provide",
|
name: "valid test with coverfile flag provide",
|
||||||
service: Service{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
service: ServiceUnderTest{Name: "serviceOK", Address: profileSuccessMockSvr.URL},
|
||||||
param: ProfileParam{CoverFilePatterns: []string{"b.go$"}},
|
param: ProfileParam{CoverFilePatterns: []string{"b.go$"}},
|
||||||
expected: "b/b.go",
|
expected: "b/b.go",
|
||||||
},
|
},
|
||||||
@ -150,7 +152,7 @@ func TestClientAction(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// init system and check service again
|
// init system and check server again
|
||||||
_, err = client.InitSystem()
|
_, err = client.InitSystem()
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
res, err = client.ListServices()
|
res, err = client.ListServices()
|
||||||
@ -162,7 +164,7 @@ func TestClientRegisterService(t *testing.T) {
|
|||||||
c := &client{}
|
c := &client{}
|
||||||
|
|
||||||
// client register with empty address
|
// client register with empty address
|
||||||
testService1 := Service{
|
testService1 := ServiceUnderTest{
|
||||||
Address: "",
|
Address: "",
|
||||||
Name: "abc",
|
Name: "abc",
|
||||||
}
|
}
|
||||||
@ -170,7 +172,7 @@ func TestClientRegisterService(t *testing.T) {
|
|||||||
assert.Contains(t, err.Error(), "empty url")
|
assert.Contains(t, err.Error(), "empty url")
|
||||||
|
|
||||||
// client register with empty name
|
// client register with empty name
|
||||||
testService2 := Service{
|
testService2 := ServiceUnderTest{
|
||||||
Address: "http://127.0.0.1:444",
|
Address: "http://127.0.0.1:444",
|
||||||
Name: "",
|
Name: "",
|
||||||
}
|
}
|
||||||
|
@ -33,18 +33,35 @@ import (
|
|||||||
"k8s.io/test-infra/gopherage/pkg/cov"
|
"k8s.io/test-infra/gopherage/pkg/cov"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultStore implements the IPersistence interface
|
|
||||||
var DefaultStore Store
|
|
||||||
|
|
||||||
// LogFile a file to save log.
|
// LogFile a file to save log.
|
||||||
const LogFile = "goc.log"
|
const LogFile = "goc.log"
|
||||||
|
|
||||||
func init() {
|
type server struct {
|
||||||
DefaultStore = NewFileStore()
|
PersistenceFile string
|
||||||
|
Store Store
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewFileBasedServer new a file based server with persistenceFile
|
||||||
|
func NewFileBasedServer(persistenceFile string) (*server, error) {
|
||||||
|
store, err := NewFileStore(persistenceFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &server{
|
||||||
|
PersistenceFile: persistenceFile,
|
||||||
|
Store: store,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMemoryBasedServer new a memory based server without persistenceFile
|
||||||
|
func NewMemoryBasedServer() *server {
|
||||||
|
return &server{
|
||||||
|
Store: NewMemoryStore(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run starts coverage host center
|
// Run starts coverage host center
|
||||||
func Run(port string) {
|
func (s *server) Run(port string) {
|
||||||
f, err := os.Create(LogFile)
|
f, err := os.Create(LogFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to create log file %s, err: %v", LogFile, err)
|
log.Fatalf("failed to create log file %s, err: %v", LogFile, err)
|
||||||
@ -52,34 +69,34 @@ func Run(port string) {
|
|||||||
|
|
||||||
// both log to stdout and file by default
|
// both log to stdout and file by default
|
||||||
mw := io.MultiWriter(f, os.Stdout)
|
mw := io.MultiWriter(f, os.Stdout)
|
||||||
r := GocServer(mw)
|
r := s.Route(mw)
|
||||||
log.Fatal(r.Run(port))
|
log.Fatal(r.Run(port))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GocServer init goc server engine
|
// Router init goc server engine
|
||||||
func GocServer(w io.Writer) *gin.Engine {
|
func (s *server) Route(w io.Writer) *gin.Engine {
|
||||||
if w != nil {
|
if w != nil {
|
||||||
gin.DefaultWriter = w
|
gin.DefaultWriter = w
|
||||||
}
|
}
|
||||||
r := gin.Default()
|
r := gin.Default()
|
||||||
// api to show the registered services
|
// api to show the registered services
|
||||||
r.StaticFile(PersistenceFile, "./"+PersistenceFile)
|
r.StaticFile("static", "./"+s.PersistenceFile)
|
||||||
|
|
||||||
v1 := r.Group("/v1")
|
v1 := r.Group("/v1")
|
||||||
{
|
{
|
||||||
v1.POST("/cover/register", registerService)
|
v1.POST("/cover/register", s.registerService)
|
||||||
v1.GET("/cover/profile", profile)
|
v1.GET("/cover/profile", s.profile)
|
||||||
v1.POST("/cover/profile", profile)
|
v1.POST("/cover/profile", s.profile)
|
||||||
v1.POST("/cover/clear", clear)
|
v1.POST("/cover/clear", s.clear)
|
||||||
v1.POST("/cover/init", initSystem)
|
v1.POST("/cover/init", s.initSystem)
|
||||||
v1.GET("/cover/list", listServices)
|
v1.GET("/cover/list", s.listServices)
|
||||||
}
|
}
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// Service is a entry under being tested
|
// ServiceUnderTest is a entry under being tested
|
||||||
type Service struct {
|
type ServiceUnderTest struct {
|
||||||
Name string `form:"name" json:"name" binding:"required"`
|
Name string `form:"name" json:"name" binding:"required"`
|
||||||
Address string `form:"address" json:"address" binding:"required"`
|
Address string `form:"address" json:"address" binding:"required"`
|
||||||
}
|
}
|
||||||
@ -93,13 +110,13 @@ type ProfileParam struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//listServices list all the registered services
|
//listServices list all the registered services
|
||||||
func listServices(c *gin.Context) {
|
func (s *server) listServices(c *gin.Context) {
|
||||||
services := DefaultStore.GetAll()
|
services := s.Store.GetAll()
|
||||||
c.JSON(http.StatusOK, services)
|
c.JSON(http.StatusOK, services)
|
||||||
}
|
}
|
||||||
|
|
||||||
func registerService(c *gin.Context) {
|
func (s *server) registerService(c *gin.Context) {
|
||||||
var service Service
|
var service ServiceUnderTest
|
||||||
if err := c.ShouldBind(&service); err != nil {
|
if err := c.ShouldBind(&service); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
@ -122,9 +139,9 @@ func registerService(c *gin.Context) {
|
|||||||
service.Address = fmt.Sprintf("http://%s:%s", realIP, port)
|
service.Address = fmt.Sprintf("http://%s:%s", realIP, port)
|
||||||
}
|
}
|
||||||
|
|
||||||
address := DefaultStore.Get(service.Name)
|
address := s.Store.Get(service.Name)
|
||||||
if !contains(address, service.Address) {
|
if !contains(address, service.Address) {
|
||||||
if err := DefaultStore.Add(service); err != nil {
|
if err := s.Store.Add(service); err != nil && err != ErrServiceAlreadyRegistered {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -137,14 +154,14 @@ func registerService(c *gin.Context) {
|
|||||||
// profile API examples:
|
// profile API examples:
|
||||||
// POST /v1/cover/profile
|
// POST /v1/cover/profile
|
||||||
// { "force": "true", "service":["a","b"], "address":["c","d"],"coverfile":["e","f"] }
|
// { "force": "true", "service":["a","b"], "address":["c","d"],"coverfile":["e","f"] }
|
||||||
func profile(c *gin.Context) {
|
func (s *server) profile(c *gin.Context) {
|
||||||
var body ProfileParam
|
var body ProfileParam
|
||||||
if err := c.ShouldBind(&body); err != nil {
|
if err := c.ShouldBind(&body); err != nil {
|
||||||
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
allInfos := DefaultStore.GetAll()
|
allInfos := s.Store.GetAll()
|
||||||
filterAddrList, err := filterAddrs(body.Service, body.Address, body.Force, allInfos)
|
filterAddrList, err := filterAddrs(body.Service, body.Address, body.Force, allInfos)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
||||||
@ -216,13 +233,13 @@ func filterProfile(coverFile []string, profiles []*cover.Profile) ([]*cover.Prof
|
|||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func clear(c *gin.Context) {
|
func (s *server) clear(c *gin.Context) {
|
||||||
var body ProfileParam
|
var body ProfileParam
|
||||||
if err := c.ShouldBind(&body); err != nil {
|
if err := c.ShouldBind(&body); err != nil {
|
||||||
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
svrsUnderTest := DefaultStore.GetAll()
|
svrsUnderTest := s.Store.GetAll()
|
||||||
filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest)
|
filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
|
||||||
@ -239,8 +256,8 @@ func clear(c *gin.Context) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func initSystem(c *gin.Context) {
|
func (s *server) initSystem(c *gin.Context) {
|
||||||
if err := DefaultStore.Init(); err != nil {
|
if err := s.Store.Init(); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -313,6 +330,6 @@ func filterAddrs(serviceList, addressList []string, force bool, allInfos map[str
|
|||||||
filterAddrList = addressAll
|
filterAddrList = addressAll
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return all servers when all param is nil
|
// Return all services when all param is nil
|
||||||
return filterAddrList, nil
|
return filterAddrList, nil
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ type MockStore struct {
|
|||||||
mock.Mock
|
mock.Mock
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MockStore) Add(s Service) error {
|
func (m *MockStore) Add(s ServiceUnderTest) error {
|
||||||
args := m.Called(s)
|
args := m.Called(s)
|
||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
@ -113,7 +113,9 @@ func TestFilterAddrs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRegisterService(t *testing.T) {
|
func TestRegisterService(t *testing.T) {
|
||||||
router := GocServer(os.Stdout)
|
server, err := NewFileBasedServer("_svrs_address.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
router := server.Route(os.Stdout)
|
||||||
|
|
||||||
// register with empty service struct
|
// register with empty service struct
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -147,7 +149,7 @@ func TestRegisterService(t *testing.T) {
|
|||||||
assert.Contains(t, w.Body.String(), "missing port in address")
|
assert.Contains(t, w.Body.String(), "missing port in address")
|
||||||
|
|
||||||
// register with store failure
|
// register with store failure
|
||||||
expectedS := Service{
|
expectedS := ServiceUnderTest{
|
||||||
Name: "foo",
|
Name: "foo",
|
||||||
Address: "http://:64444", // the real IP is empty in unittest, so server will get a empty one
|
Address: "http://:64444", // the real IP is empty in unittest, so server will get a empty one
|
||||||
}
|
}
|
||||||
@ -155,7 +157,7 @@ func TestRegisterService(t *testing.T) {
|
|||||||
testObj.On("Get", "foo").Return([]string{"http://127.0.0.1:66666"})
|
testObj.On("Get", "foo").Return([]string{"http://127.0.0.1:66666"})
|
||||||
testObj.On("Add", expectedS).Return(fmt.Errorf("lala error"))
|
testObj.On("Add", expectedS).Return(fmt.Errorf("lala error"))
|
||||||
|
|
||||||
DefaultStore = testObj
|
server.Store = testObj
|
||||||
|
|
||||||
w = httptest.NewRecorder()
|
w = httptest.NewRecorder()
|
||||||
data.Set("name", expectedS.Name)
|
data.Set("name", expectedS.Name)
|
||||||
@ -169,7 +171,9 @@ func TestRegisterService(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestProfileService(t *testing.T) {
|
func TestProfileService(t *testing.T) {
|
||||||
router := GocServer(os.Stdout)
|
server, err := NewFileBasedServer("_svrs_address.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
router := server.Route(os.Stdout)
|
||||||
|
|
||||||
// get profile with invalid force parameter
|
// get profile with invalid force parameter
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -184,9 +188,10 @@ func TestClearService(t *testing.T) {
|
|||||||
testObj := new(MockStore)
|
testObj := new(MockStore)
|
||||||
testObj.On("GetAll").Return(map[string][]string{"foo": {"http://127.0.0.1:66666"}})
|
testObj.On("GetAll").Return(map[string][]string{"foo": {"http://127.0.0.1:66666"}})
|
||||||
|
|
||||||
DefaultStore = testObj
|
server := &server{
|
||||||
|
Store: testObj,
|
||||||
router := GocServer(os.Stdout)
|
}
|
||||||
|
router := server.Route(os.Stdout)
|
||||||
|
|
||||||
// clear profile with non-exist port
|
// clear profile with non-exist port
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
@ -224,9 +229,10 @@ func TestInitService(t *testing.T) {
|
|||||||
testObj := new(MockStore)
|
testObj := new(MockStore)
|
||||||
testObj.On("Init").Return(fmt.Errorf("lala error"))
|
testObj.On("Init").Return(fmt.Errorf("lala error"))
|
||||||
|
|
||||||
DefaultStore = testObj
|
server := &server{
|
||||||
|
Store: testObj,
|
||||||
router := GocServer(os.Stdout)
|
}
|
||||||
|
router := server.Route(os.Stdout)
|
||||||
|
|
||||||
// get profile with invalid force parameter
|
// get profile with invalid force parameter
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
@ -18,18 +18,21 @@ package cover
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
log "github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var ErrServiceAlreadyRegistered = errors.New("service already registered")
|
||||||
|
|
||||||
// Store persistents the registered service information
|
// Store persistents the registered service information
|
||||||
type Store interface {
|
type Store interface {
|
||||||
// Add adds the given service to store
|
// Add adds the given service to store
|
||||||
Add(s Service) error
|
Add(s ServiceUnderTest) error
|
||||||
|
|
||||||
// Get returns the registered service information with the given service's name
|
// Get returns the registered service information with the given service's name
|
||||||
Get(name string) []string
|
Get(name string) []string
|
||||||
@ -44,9 +47,6 @@ type Store interface {
|
|||||||
Set(services map[string][]string)
|
Set(services map[string][]string)
|
||||||
}
|
}
|
||||||
|
|
||||||
// PersistenceFile is the file to save services address information
|
|
||||||
const PersistenceFile = "_svrs_address.txt"
|
|
||||||
|
|
||||||
// fileStore holds the registered services into memory and persistent to a local file
|
// fileStore holds the registered services into memory and persistent to a local file
|
||||||
type fileStore struct {
|
type fileStore struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
@ -56,9 +56,17 @@ type fileStore struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewFileStore creates a store using local file
|
// NewFileStore creates a store using local file
|
||||||
func NewFileStore() Store {
|
func NewFileStore(persistenceFile string) (store Store, err error) {
|
||||||
|
path, err := filepath.Abs(persistenceFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = os.MkdirAll(filepath.Dir(path), os.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
l := &fileStore{
|
l := &fileStore{
|
||||||
persistentFile: PersistenceFile,
|
persistentFile: path,
|
||||||
memoryStore: NewMemoryStore(),
|
memoryStore: NewMemoryStore(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,12 +74,14 @@ func NewFileStore() Store {
|
|||||||
log.Fatalf("load failed, file: %s, err: %v", l.persistentFile, err)
|
log.Fatalf("load failed, file: %s, err: %v", l.persistentFile, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return l
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add adds the given service to file Store
|
// Add adds the given service to file Store
|
||||||
func (l *fileStore) Add(s Service) error {
|
func (l *fileStore) Add(s ServiceUnderTest) error {
|
||||||
l.memoryStore.Add(s)
|
if err := l.memoryStore.Add(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// persistent to local store
|
// persistent to local store
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
@ -147,7 +157,7 @@ func (l *fileStore) Set(services map[string][]string) {
|
|||||||
panic("TO BE IMPLEMENTED")
|
panic("TO BE IMPLEMENTED")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *fileStore) appendToFile(s Service) error {
|
func (l *fileStore) appendToFile(s ServiceUnderTest) error {
|
||||||
f, err := os.OpenFile(l.persistentFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
f, err := os.OpenFile(l.persistentFile, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -163,7 +173,7 @@ func (l *fileStore) appendToFile(s Service) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func format(s Service) string {
|
func format(s ServiceUnderTest) string {
|
||||||
return fmt.Sprintf("%s&%s", s.Name, s.Address)
|
return fmt.Sprintf("%s&%s", s.Name, s.Address)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,7 +195,7 @@ func NewMemoryStore() Store {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add adds the given service to MemoryStore
|
// Add adds the given service to MemoryStore
|
||||||
func (l *memoryStore) Add(s Service) error {
|
func (l *memoryStore) Add(s ServiceUnderTest) error {
|
||||||
l.mu.Lock()
|
l.mu.Lock()
|
||||||
defer l.mu.Unlock()
|
defer l.mu.Unlock()
|
||||||
// load to memory
|
// load to memory
|
||||||
@ -193,7 +203,7 @@ func (l *memoryStore) Add(s Service) error {
|
|||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
if addr == s.Address {
|
if addr == s.Address {
|
||||||
log.Printf("service registered already, name: %s, address: %s", s.Name, s.Address)
|
log.Printf("service registered already, name: %s, address: %s", s.Name, s.Address)
|
||||||
return nil
|
return ErrServiceAlreadyRegistered
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addrs = append(addrs, s.Address)
|
addrs = append(addrs, s.Address)
|
||||||
|
@ -17,31 +17,34 @@
|
|||||||
package cover
|
package cover
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLocalStore(t *testing.T) {
|
func TestLocalStore(t *testing.T) {
|
||||||
localStore := NewFileStore()
|
localStore, err := NewFileStore("_svrs_address.txt")
|
||||||
var tc1 = Service{
|
assert.NoError(t, err)
|
||||||
|
var tc1 = ServiceUnderTest{
|
||||||
Name: "a",
|
Name: "a",
|
||||||
Address: "http://127.0.0.1",
|
Address: "http://127.0.0.1",
|
||||||
}
|
}
|
||||||
var tc2 = Service{
|
var tc2 = ServiceUnderTest{
|
||||||
Name: "b",
|
Name: "b",
|
||||||
Address: "http://127.0.0.2",
|
Address: "http://127.0.0.2",
|
||||||
}
|
}
|
||||||
var tc3 = Service{
|
var tc3 = ServiceUnderTest{
|
||||||
Name: "c",
|
Name: "c",
|
||||||
Address: "http://127.0.0.3",
|
Address: "http://127.0.0.3",
|
||||||
}
|
}
|
||||||
var tc4 = Service{
|
var tc4 = ServiceUnderTest{
|
||||||
Name: "a",
|
Name: "a",
|
||||||
Address: "http://127.0.0.4",
|
Address: "http://127.0.0.4",
|
||||||
}
|
}
|
||||||
localStore.Add(tc1)
|
assert.NoError(t, localStore.Add(tc1))
|
||||||
localStore.Add(tc2)
|
assert.Equal(t, localStore.Add(tc1), ErrServiceAlreadyRegistered)
|
||||||
localStore.Add(tc3)
|
assert.NoError(t, localStore.Add(tc2))
|
||||||
localStore.Add(tc4)
|
assert.NoError(t, localStore.Add(tc3))
|
||||||
|
assert.NoError(t, localStore.Add(tc4))
|
||||||
addrs := localStore.Get(tc1.Name)
|
addrs := localStore.Get(tc1.Name)
|
||||||
if len(addrs) != 2 {
|
if len(addrs) != 2 {
|
||||||
t.Error("unexpected result")
|
t.Error("unexpected result")
|
||||||
@ -57,6 +60,10 @@ func TestLocalStore(t *testing.T) {
|
|||||||
t.Error("local store check failed")
|
t.Error("local store check failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
localStoreNew, err := NewFileStore("_svrs_address.txt")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Equal(t, localStore.GetAll(), localStoreNew.GetAll())
|
||||||
|
|
||||||
localStore.Init()
|
localStore.Init()
|
||||||
if len(localStore.GetAll()) != 0 {
|
if len(localStore.GetAll()) != 0 {
|
||||||
t.Error("local store init failed")
|
t.Error("local store init failed")
|
||||||
|
@ -22,7 +22,7 @@ setup_file() {
|
|||||||
sleep 2
|
sleep 2
|
||||||
goc init
|
goc init
|
||||||
# run covered goc
|
# run covered goc
|
||||||
gocc server --port=:60001 --debug 3>&- &
|
gocc server --port=:60001 --local-persistence="persistence/servicesAll.txt" --debug 3>&- &
|
||||||
GOCC_PID=$!
|
GOCC_PID=$!
|
||||||
sleep 2
|
sleep 2
|
||||||
info "goc gocc server started"
|
info "goc gocc server started"
|
||||||
@ -57,4 +57,11 @@ teardown_file() {
|
|||||||
# connect to covered goc
|
# connect to covered goc
|
||||||
run goc profile --center=http://127.0.0.1:60001
|
run goc profile --center=http://127.0.0.1:60001
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
|
|
||||||
|
# verify the persistence file exist
|
||||||
|
[ -f "$WORKDIR/persistence/servicesAll.txt" ]
|
||||||
|
# remove goc persistence file
|
||||||
|
run goc init --center=http://127.0.0.1:60001
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
[ ! -f "$WORKDIR/persistence/servicesAll.txt" ]
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user