Merge pull request #112 from lyyyuna/goc-103

Clear coverage by service&addr
This commit is contained in:
qiniu-bot 2020-09-14 15:36:17 +08:00 committed by GitHub
commit a217d13046
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 119 additions and 25 deletions

View File

@ -41,7 +41,7 @@ jobs:
needs: job_1 needs: job_1
strategy: strategy:
matrix: matrix:
go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x] go-version: [1.11.x, 1.12.x, 1.13.x, 1.14.x, 1.15.x]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install Go - name: Install Go

View File

@ -13,7 +13,7 @@ jobs:
name: vet and gofmt name: vet and gofmt
strategy: strategy:
matrix: matrix:
go-version: [1.13.x, 1.14.x] go-version: [1.13.x, 1.14.x, 1.15.x]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install Go - name: Install Go

View File

@ -13,7 +13,7 @@ jobs:
name: go test name: go test
strategy: strategy:
matrix: matrix:
go-version: [1.13.x, 1.14.x] go-version: [1.13.x, 1.14.x, 1.15.x]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Install Go - name: Install Go

View File

@ -18,9 +18,10 @@ package cmd
import ( import (
"fmt" "fmt"
log "github.com/sirupsen/logrus"
"os" "os"
log "github.com/sirupsen/logrus"
"github.com/qiniu/goc/pkg/cover" "github.com/qiniu/goc/pkg/cover"
"github.com/spf13/cobra" "github.com/spf13/cobra"
) )
@ -37,7 +38,11 @@ goc clear
goc clear --center=http://192.168.1.1:8080 goc clear --center=http://192.168.1.1:8080
`, `,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
res, err := cover.NewWorker(center).Clear() p := cover.ProfileParam{
Service: svrList,
Address: addrList,
}
res, err := cover.NewWorker(center).Clear(p)
if err != nil { if err != nil {
log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res)) log.Fatalf("call host %v failed, err: %v, response: %v", center, err, string(res))
} }
@ -47,5 +52,7 @@ goc clear --center=http://192.168.1.1:8080
func init() { func init() {
addBasicFlags(clearCmd.Flags()) addBasicFlags(clearCmd.Flags())
clearCmd.Flags().StringSliceVarP(&svrList, "service", "", nil, "service name to clear profile, see 'goc list' for all services.")
clearCmd.Flags().StringSliceVarP(&addrList, "address", "", nil, "address to clear profile, see 'goc list' for all addresses.")
rootCmd.AddCommand(clearCmd) rootCmd.AddCommand(clearCmd)
} }

View File

@ -33,7 +33,7 @@ import (
// Action provides methods to contact with the covered service under test // Action provides methods to contact with the covered service under test
type Action interface { type Action interface {
Profile(param ProfileParam) ([]byte, error) Profile(param ProfileParam) ([]byte, error)
Clear() ([]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 Service) ([]byte, error)
@ -97,10 +97,9 @@ func (c *client) Profile(param ProfileParam) ([]byte, error) {
return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately") return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately")
} }
body, err := json.Marshal(param) // the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError
if err != nil { // so no need to check here
return nil, fmt.Errorf("json.Marshal failed, param: %v, err:%v", param, err) body, _ := json.Marshal(param)
}
res, profile, err := c.do("POST", u, "application/json", bytes.NewReader(body)) res, profile, err := c.do("POST", u, "application/json", bytes.NewReader(body))
if err != nil && isNetworkError(err) { if err != nil && isNetworkError(err) {
@ -113,11 +112,18 @@ func (c *client) Profile(param ProfileParam) ([]byte, error) {
return profile, err return profile, err
} }
func (c *client) Clear() ([]byte, error) { func (c *client) Clear(param ProfileParam) ([]byte, error) {
u := fmt.Sprintf("%s%s", c.Host, CoverProfileClearAPI) u := fmt.Sprintf("%s%s", c.Host, CoverProfileClearAPI)
_, resp, err := c.do("POST", u, "", nil) if len(param.Service) != 0 && len(param.Address) != 0 {
return nil, fmt.Errorf("use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately")
}
// the json.Marshal function can return two types of errors: UnsupportedTypeError or UnsupportedValueError
// so no need to check here
body, _ := json.Marshal(param)
_, resp, err := c.do("POST", u, "application/json", bytes.NewReader(body))
if err != nil && isNetworkError(err) { if err != nil && isNetworkError(err) {
_, resp, err = c.do("POST", u, "", nil) _, resp, err = c.do("POST", u, "application/json", bytes.NewReader(body))
} }
return resp, err return resp, err
} }

View File

@ -189,3 +189,16 @@ func TestClientDo(t *testing.T) {
_, _, err := c.do(" ", "http://127.0.0.1:7777", "", nil) // a invalid method _, _, err := c.do(" ", "http://127.0.0.1:7777", "", nil) // a invalid method
assert.Contains(t, err.Error(), "invalid method") assert.Contains(t, err.Error(), "invalid method")
} }
func TestClientClearWithInvalidParam(t *testing.T) {
p := ProfileParam{
Service: []string{"goc"},
Address: []string{"http://127.0.0.1:777"},
}
c := &client{
client: http.DefaultClient,
}
_, err := c.Clear(p)
assert.Error(t, err)
assert.Contains(t, err.Error(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately")
}

View File

@ -217,17 +217,26 @@ func filterProfile(coverFile []string, profiles []*cover.Profile) ([]*cover.Prof
} }
func clear(c *gin.Context) { func clear(c *gin.Context) {
svrsUnderTest := DefaultStore.GetAll() var body ProfileParam
for svc, addrs := range svrsUnderTest { if err := c.ShouldBind(&body); err != nil {
for _, addr := range addrs { c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
pp, err := NewWorker(addr).Clear() return
if err != nil {
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
return
}
fmt.Fprintf(c.Writer, "Register service %s: %s coverage counter %s", svc, addr, string(pp))
}
} }
svrsUnderTest := DefaultStore.GetAll()
filterAddrList, err := filterAddrs(body.Service, body.Address, true, svrsUnderTest)
if err != nil {
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
return
}
for _, addr := range filterAddrList {
pp, err := NewWorker(addr).Clear(ProfileParam{})
if err != nil {
c.JSON(http.StatusExpectationFailed, gin.H{"error": err.Error()})
return
}
fmt.Fprintf(c.Writer, "Register service %s coverage counter %s", addr, string(pp))
}
} }
func initSystem(c *gin.Context) { func initSystem(c *gin.Context) {

View File

@ -1,6 +1,8 @@
package cover package cover
import ( import (
"bytes"
"encoding/json"
"fmt" "fmt"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -186,13 +188,36 @@ func TestClearService(t *testing.T) {
router := GocServer(os.Stdout) router := GocServer(os.Stdout)
// get profile with invalid force parameter // clear profile with non-exist port
w := httptest.NewRecorder() w := httptest.NewRecorder()
req, _ := http.NewRequest("POST", "/v1/cover/clear", nil) req, _ := http.NewRequest("POST", "/v1/cover/clear", bytes.NewBuffer([]byte(`{}`)))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req) router.ServeHTTP(w, req)
assert.Equal(t, http.StatusExpectationFailed, w.Code) assert.Equal(t, http.StatusExpectationFailed, w.Code)
assert.Contains(t, w.Body.String(), "invalid port") assert.Contains(t, w.Body.String(), "invalid port")
// clear profile with invalid service
w = httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/v1/cover/clear", nil)
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusExpectationFailed, w.Code)
assert.Contains(t, w.Body.String(), "invalid request")
// clear profile with service and address set at at the same time
p := ProfileParam{
Service: []string{"goc"},
Address: []string{"http://127.0.0.1:3333"},
}
encoded, err := json.Marshal(p)
assert.NoError(t, err)
w = httptest.NewRecorder()
req, _ = http.NewRequest("POST", "/v1/cover/clear", bytes.NewBuffer(encoded))
req.Header.Set("Content-Type", "application/json")
router.ServeHTTP(w, req)
assert.Equal(t, http.StatusExpectationFailed, w.Code)
assert.Contains(t, w.Body.String(), "use 'service' flag and 'address' flag at the same time may cause ambiguity, please use them separately")
} }
func TestInitService(t *testing.T) { func TestInitService(t *testing.T) {

View File

@ -38,6 +38,7 @@ setup_file() {
} }
teardown_file() { teardown_file() {
rm *_profile_listen_addr
kill -9 $GOC_PID kill -9 $GOC_PID
kill -9 $GOCC_PID kill -9 $GOCC_PID
kill -9 $SAMPLE_PID kill -9 $SAMPLE_PID
@ -65,4 +66,37 @@ teardown_file() {
[[ "$output" == *"coverage counter clear call successfully"* ]] [[ "$output" == *"coverage counter clear call successfully"* ]]
wait $profile_pid wait $profile_pid
}
@test "test clear by service name" {
goc build --output=./test-service
./test-service 3>&- &
TEST_SERVICE=$!
sleep 1
# clear by wrong service name
run goc clear --service="test-servicej"
[ "$status" -eq 0 ]
[ "$output" = "" ]
# check by goc profile, as the last step is wrong
# the coverage count should be 1
run goc profile --coverfile="simple-project/a/a.go" --force
info clear3 output: $output
[ "$status" -eq 0 ]
[[ "$output" =~ "example.com/simple-project/a/a.go:4.12,6.2 1 1" ]]
# clear by right service name
run goc clear --service="test-service"
[ "$status" -eq 0 ]
[[ "$output" =~ "coverage counter clear call successfully" ]]
# check by goc profile, the coverage count should be reset to 0
run goc profile --coverfile="simple-project/a/a.go" --force
info clear4 output: $output
[ "$status" -eq 0 ]
[[ "$output" =~ "example.com/simple-project/a/a.go:4.12,6.2 1 0" ]]
kill -9 $TEST_SERVICE
} }