github comment set header without uppercase set
This commit is contained in:
parent
50ffb7980b
commit
6129354cbd
@ -118,7 +118,7 @@ func doDiffForLocalProfiles(cmd *cobra.Command, args []string) {
|
|||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
table.Append([]string{row.FileName, row.BasePer, row.NewPer, row.DeltaPer})
|
table.Append([]string{row.FileName, row.BasePer, row.NewPer, row.DeltaPer})
|
||||||
}
|
}
|
||||||
totalDelta := cover.PercentStr(cover.TotalDelta(*localP, *baseP))
|
totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP))
|
||||||
table.Append([]string{"Total", baseP.TotalPercentage(), localP.TotalPercentage(), totalDelta})
|
table.Append([]string{"Total", baseP.TotalPercentage(), localP.TotalPercentage(), totalDelta})
|
||||||
table.Render()
|
table.Render()
|
||||||
}
|
}
|
||||||
|
106
cmd/diff_test.go
Normal file
106
cmd/diff_test.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Qiniu Cloud (qiniu.com)
|
||||||
|
|
||||||
|
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 cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
type diffFunc func(cmd *cobra.Command, args []string)
|
||||||
|
|
||||||
|
func captureStdout(f diffFunc, cmd *cobra.Command, args []string) string {
|
||||||
|
r, w, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatal("os pipe fail")
|
||||||
|
}
|
||||||
|
stdout := os.Stdout
|
||||||
|
os.Stdout = w
|
||||||
|
defer func() {
|
||||||
|
os.Stdout = stdout
|
||||||
|
}()
|
||||||
|
|
||||||
|
f(cmd, args)
|
||||||
|
w.Close()
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
io.Copy(&buf, r)
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDoDiffForLocalProfiles(t *testing.T) {
|
||||||
|
items := []struct {
|
||||||
|
newCovFile string
|
||||||
|
newProfile string
|
||||||
|
baseCovFile string
|
||||||
|
baseProfile string
|
||||||
|
expectOutput string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
newCovFile: "new.cov",
|
||||||
|
baseCovFile: "base.cov",
|
||||||
|
newProfile: "mode: atomic\n" +
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30\n" +
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 1\n",
|
||||||
|
baseProfile: "mode: atomic\n" +
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30\n" +
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0\n",
|
||||||
|
expectOutput: `+-----------------------------------------+---------------+--------------+-------+
|
||||||
|
| File | Base Coverage | New Coverage | Delta |
|
||||||
|
+-----------------------------------------+---------------+--------------+-------+
|
||||||
|
| qiniu.com/kodo/apiserver/server/main.go | 50.0% | 100.0% | 50.0% |
|
||||||
|
| Total | 50.0% | 100.0% | 50.0% |
|
||||||
|
+-----------------------------------------+---------------+--------------+-------+
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range items {
|
||||||
|
err := ioutil.WriteFile(tc.newCovFile, []byte(tc.newProfile), 0644)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("write file %s failed", tc.newCovFile)
|
||||||
|
}
|
||||||
|
err = ioutil.WriteFile(tc.baseCovFile, []byte(tc.baseProfile), 0644)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("write file %s failed", tc.baseCovFile)
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
os.Remove(tc.newCovFile)
|
||||||
|
os.Remove(tc.baseCovFile)
|
||||||
|
}()
|
||||||
|
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("get pwd failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
diffCmd.Flags().Set("new-profile", fmt.Sprintf("%s/%s", pwd, tc.newCovFile))
|
||||||
|
diffCmd.Flags().Set("base-profile", fmt.Sprintf("%s/%s", pwd, tc.baseCovFile))
|
||||||
|
out := captureStdout(doDiffForLocalProfiles, diffCmd, nil)
|
||||||
|
assert.Equal(t, out, tc.expectOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1
go.mod
1
go.mod
@ -6,6 +6,7 @@ require (
|
|||||||
github.com/gin-gonic/gin v1.6.3
|
github.com/gin-gonic/gin v1.6.3
|
||||||
github.com/google/go-github v17.0.0+incompatible
|
github.com/google/go-github v17.0.0+incompatible
|
||||||
github.com/julienschmidt/httprouter v1.2.0
|
github.com/julienschmidt/httprouter v1.2.0
|
||||||
|
github.com/magiconair/properties v1.8.1
|
||||||
github.com/mattn/go-runewidth v0.0.9 // indirect
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.4
|
github.com/olekukonko/tablewriter v0.0.4
|
||||||
github.com/onsi/ginkgo v1.11.0
|
github.com/onsi/ginkgo v1.11.0
|
||||||
|
1
go.sum
1
go.sum
@ -470,6 +470,7 @@ github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9
|
|||||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||||
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
|
@ -272,7 +272,7 @@ type codeBlock struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//convert profile to CoverageList struct
|
//convert profile to CoverageList struct
|
||||||
func CovList(f io.Reader) (g *CoverageList, err error) {
|
func CovList(f io.Reader) (g CoverageList, err error) {
|
||||||
scanner := bufio.NewScanner(f)
|
scanner := bufio.NewScanner(f)
|
||||||
scanner.Scan() // discard first line
|
scanner.Scan() // discard first line
|
||||||
g = NewCoverageList()
|
g = NewCoverageList()
|
||||||
@ -283,13 +283,13 @@ func CovList(f io.Reader) (g *CoverageList, err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
blk.addToGroupCov(g)
|
blk.addToGroupCov(&g)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// covert profile file to CoverageList struct
|
// covert profile file to CoverageList struct
|
||||||
func ReadFileToCoverList(path string) (g *CoverageList, err error) {
|
func ReadFileToCoverList(path string) (g CoverageList, err error) {
|
||||||
f, err := ioutil.ReadFile(path)
|
f, err := ioutil.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("Open file %s failed!", path)
|
logrus.Errorf("Open file %s failed!", path)
|
||||||
@ -300,8 +300,8 @@ func ReadFileToCoverList(path string) (g *CoverageList, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCoverageList return empty CoverageList
|
// NewCoverageList return empty CoverageList
|
||||||
func NewCoverageList() *CoverageList {
|
func NewCoverageList() CoverageList {
|
||||||
return &CoverageList{}
|
return CoverageList{}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,12 +339,12 @@ func (blk *codeBlock) addToGroupCov(g *CoverageList) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *CoverageList) size() int {
|
func (g CoverageList) size() int {
|
||||||
return len(*g)
|
return len(g)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *CoverageList) lastElement() *Coverage {
|
func (g CoverageList) lastElement() *Coverage {
|
||||||
return &(*g)[(*g).size()-1]
|
return &g[g.size()-1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *CoverageList) append(c *Coverage) {
|
func (g *CoverageList) append(c *Coverage) {
|
||||||
@ -352,13 +352,13 @@ func (g *CoverageList) append(c *Coverage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sort CoverageList with filenames
|
// sort CoverageList with filenames
|
||||||
func (g *CoverageList) Sort() {
|
func (g CoverageList) Sort() {
|
||||||
sort.SliceStable(g, func(i, j int) bool {
|
sort.SliceStable(g, func(i, j int) bool {
|
||||||
return (*g)[i].Name() < (*g)[j].Name()
|
return g[i].Name() < g[j].Name()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *CoverageList) TotalPercentage() string {
|
func (g CoverageList) TotalPercentage() string {
|
||||||
ratio, err := g.TotalRatio()
|
ratio, err := g.TotalRatio()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return PercentStr(ratio)
|
return PercentStr(ratio)
|
||||||
@ -366,9 +366,9 @@ func (g *CoverageList) TotalPercentage() string {
|
|||||||
return "N/A"
|
return "N/A"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *CoverageList) TotalRatio() (ratio float32, err error) {
|
func (g CoverageList) TotalRatio() (ratio float32, err error) {
|
||||||
var total Coverage
|
var total Coverage
|
||||||
for _, c := range *g {
|
for _, c := range g {
|
||||||
total.NCoveredStmts += c.NCoveredStmts
|
total.NCoveredStmts += c.NCoveredStmts
|
||||||
total.NAllStmts += c.NAllStmts
|
total.NAllStmts += c.NAllStmts
|
||||||
}
|
}
|
||||||
@ -377,9 +377,9 @@ func (g *CoverageList) TotalRatio() (ratio float32, err error) {
|
|||||||
|
|
||||||
// Map returns maps the file name to its coverage for faster retrieval
|
// Map returns maps the file name to its coverage for faster retrieval
|
||||||
// & membership check
|
// & membership check
|
||||||
func (g *CoverageList) Map() map[string]Coverage {
|
func (g CoverageList) Map() map[string]Coverage {
|
||||||
m := make(map[string]Coverage)
|
m := make(map[string]Coverage)
|
||||||
for _, c := range *g {
|
for _, c := range g {
|
||||||
m[c.Name()] = c
|
m[c.Name()] = c
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
|
@ -42,7 +42,7 @@ func TestCoverageRatio(t *testing.T) {
|
|||||||
func TestRatioErr(t *testing.T) {
|
func TestRatioErr(t *testing.T) {
|
||||||
c := &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 0}
|
c := &Coverage{FileName: "fake-coverage", NCoveredStmts: 200, NAllStmts: 0}
|
||||||
_, err := c.Ratio()
|
_, err := c.Ratio()
|
||||||
assert.NotNil(t, err)
|
assert.NotEqual(t, err, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPercentageNA(t *testing.T) {
|
func TestPercentageNA(t *testing.T) {
|
||||||
@ -83,8 +83,8 @@ func TestCovList(t *testing.T) {
|
|||||||
r := strings.NewReader(tc.profile)
|
r := strings.NewReader(tc.profile)
|
||||||
c, err := CovList(r)
|
c, err := CovList(r)
|
||||||
c.Sort()
|
c.Sort()
|
||||||
assert.Nil(t, err)
|
assert.Equal(t, err, nil)
|
||||||
for k, v := range *c {
|
for k, v := range c {
|
||||||
assert.Equal(t, tc.expectPer[k], v.Percentage())
|
assert.Equal(t, tc.expectPer[k], v.Percentage())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ type DeltaCov struct {
|
|||||||
type DeltaCovList []DeltaCov
|
type DeltaCovList []DeltaCov
|
||||||
|
|
||||||
// get full delta coverage between new and base profile
|
// get full delta coverage between new and base profile
|
||||||
func GetFullDeltaCov(newList *CoverageList, baseList *CoverageList) (delta DeltaCovList) {
|
func GetFullDeltaCov(newList CoverageList, baseList CoverageList) (delta DeltaCovList) {
|
||||||
newMap := newList.Map()
|
newMap := newList.Map()
|
||||||
baseMap := baseList.Map()
|
baseMap := baseList.Map()
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ func GetFullDeltaCov(newList *CoverageList, baseList *CoverageList) (delta Delta
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get two profile diff cov
|
//get two profile diff cov
|
||||||
func GetDeltaCov(newList *CoverageList, baseList *CoverageList) (delta DeltaCovList) {
|
func GetDeltaCov(newList CoverageList, baseList CoverageList) (delta DeltaCovList) {
|
||||||
d := GetFullDeltaCov(newList, baseList)
|
d := GetFullDeltaCov(newList, baseList)
|
||||||
for _, v := range d {
|
for _, v := range d {
|
||||||
if v.DeltaPer == "0.0%" {
|
if v.DeltaPer == "0.0%" {
|
||||||
@ -77,7 +77,7 @@ func GetDeltaCov(newList *CoverageList, baseList *CoverageList) (delta DeltaCovL
|
|||||||
}
|
}
|
||||||
|
|
||||||
//get two profile diff cov of changed files
|
//get two profile diff cov of changed files
|
||||||
func GetChFileDeltaCov(newList *CoverageList, baseList *CoverageList, changedFiles []string) (list DeltaCovList) {
|
func GetChFileDeltaCov(newList CoverageList, baseList CoverageList, changedFiles []string) (list DeltaCovList) {
|
||||||
d := GetFullDeltaCov(newList, baseList)
|
d := GetFullDeltaCov(newList, baseList)
|
||||||
dMap := d.Map()
|
dMap := d.Map()
|
||||||
for _, file := range changedFiles {
|
for _, file := range changedFiles {
|
||||||
@ -103,18 +103,18 @@ func TotalDelta(new CoverageList, base CoverageList) float32 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map returns maps the file name to its DeltaCov for faster retrieval & membership check
|
// Map returns maps the file name to its DeltaCov for faster retrieval & membership check
|
||||||
func (d *DeltaCovList) Map() map[string]DeltaCov {
|
func (d DeltaCovList) Map() map[string]DeltaCov {
|
||||||
m := make(map[string]DeltaCov)
|
m := make(map[string]DeltaCov)
|
||||||
for _, c := range *d {
|
for _, c := range d {
|
||||||
m[c.FileName] = c
|
m[c.FileName] = c
|
||||||
}
|
}
|
||||||
return m
|
return m
|
||||||
}
|
}
|
||||||
|
|
||||||
// sort DeltaCovList with filenames
|
// sort DeltaCovList with filenames
|
||||||
func (d *DeltaCovList) Sort() {
|
func (d DeltaCovList) Sort() {
|
||||||
sort.SliceStable(d, func(i, j int) bool {
|
sort.SliceStable(d, func(i, j int) bool {
|
||||||
return (*d)[i].Name() < (*d)[j].Name()
|
return d[i].Name() < d[j].Name()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package cover
|
package cover
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -25,37 +24,37 @@ import (
|
|||||||
|
|
||||||
func TestGetDeltaCov(t *testing.T) {
|
func TestGetDeltaCov(t *testing.T) {
|
||||||
items := []struct {
|
items := []struct {
|
||||||
newList *CoverageList
|
newList CoverageList
|
||||||
baseList *CoverageList
|
baseList CoverageList
|
||||||
expectDelta DeltaCovList
|
expectDelta DeltaCovList
|
||||||
rows int
|
rows int
|
||||||
}{
|
}{
|
||||||
//coverage increase
|
//coverage increase
|
||||||
{
|
{
|
||||||
newList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
||||||
baseList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 10, NAllStmts: 20}},
|
baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 10, NAllStmts: 20}},
|
||||||
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "50.0%", NewPer: "75.0%", DeltaPer: "25.0%"}},
|
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "50.0%", NewPer: "75.0%", DeltaPer: "25.0%"}},
|
||||||
rows: 1,
|
rows: 1,
|
||||||
},
|
},
|
||||||
//coverage decrease
|
//coverage decrease
|
||||||
{
|
{
|
||||||
newList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
||||||
baseList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 20, NAllStmts: 20}},
|
baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 20, NAllStmts: 20}},
|
||||||
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "100.0%", NewPer: "75.0%", DeltaPer: "-25.0%"}},
|
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "100.0%", NewPer: "75.0%", DeltaPer: "-25.0%"}},
|
||||||
rows: 1,
|
rows: 1,
|
||||||
},
|
},
|
||||||
//diff file
|
//diff file
|
||||||
{
|
{
|
||||||
newList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
||||||
baseList: &CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}},
|
baseList: CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}},
|
||||||
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"},
|
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"},
|
||||||
{FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}},
|
{FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}},
|
||||||
rows: 2,
|
rows: 2,
|
||||||
},
|
},
|
||||||
//one file has same coverage rate
|
//one file has same coverage rate
|
||||||
{
|
{
|
||||||
newList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
||||||
baseList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20},
|
baseList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20},
|
||||||
Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}},
|
Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}},
|
||||||
expectDelta: DeltaCovList{{FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}},
|
expectDelta: DeltaCovList{{FileName: "fake-coverage-v1", BasePer: "50.0%", NewPer: "None", DeltaPer: "-50.0%"}},
|
||||||
rows: 1,
|
rows: 1,
|
||||||
@ -71,14 +70,14 @@ func TestGetDeltaCov(t *testing.T) {
|
|||||||
|
|
||||||
func TestGetChFileDeltaCov(t *testing.T) {
|
func TestGetChFileDeltaCov(t *testing.T) {
|
||||||
items := []struct {
|
items := []struct {
|
||||||
newList *CoverageList
|
newList CoverageList
|
||||||
baseList *CoverageList
|
baseList CoverageList
|
||||||
changedFiles []string
|
changedFiles []string
|
||||||
expectDelta DeltaCovList
|
expectDelta DeltaCovList
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
newList: &CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
newList: CoverageList{Coverage{FileName: "fake-coverage", NCoveredStmts: 15, NAllStmts: 20}},
|
||||||
baseList: &CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}},
|
baseList: CoverageList{Coverage{FileName: "fake-coverage-v1", NCoveredStmts: 10, NAllStmts: 20}},
|
||||||
changedFiles: []string{"fake-coverage"},
|
changedFiles: []string{"fake-coverage"},
|
||||||
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"}},
|
expectDelta: DeltaCovList{{FileName: "fake-coverage", BasePer: "None", NewPer: "75.0%", DeltaPer: "75.0%"}},
|
||||||
},
|
},
|
||||||
@ -125,9 +124,10 @@ func TestMapAndSort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range items {
|
for _, tc := range items {
|
||||||
assert.True(t, reflect.DeepEqual(tc.expectMap, tc.dList.Map()))
|
assert.Equal(t, tc.expectMap, tc.dList.Map())
|
||||||
tc.dList.Sort()
|
tc.dList.Sort()
|
||||||
assert.True(t, reflect.DeepEqual(tc.expectSort, tc.dList))
|
assert.Equal(t, tc.expectSort, tc.dList)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -161,6 +161,7 @@ func GenCommentContent(commentPrefix string, delta cover.DeltaCovList) string {
|
|||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
table := tablewriter.NewWriter(&buf)
|
table := tablewriter.NewWriter(&buf)
|
||||||
table.SetHeader([]string{"File", "BASE Coverage", "New Coverage", "Delta"})
|
table.SetHeader([]string{"File", "BASE Coverage", "New Coverage", "Delta"})
|
||||||
|
table.SetAutoFormatHeaders(false)
|
||||||
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
|
table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false})
|
||||||
table.SetCenterSeparator("|")
|
table.SetCenterSeparator("|")
|
||||||
table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER})
|
table.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER, tablewriter.ALIGN_CENTER})
|
||||||
|
@ -23,7 +23,6 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-github/github"
|
"github.com/google/go-github/github"
|
||||||
@ -108,10 +107,8 @@ func TestCreateGithubComment(t *testing.T) {
|
|||||||
router.HandlerFunc("POST", "/repos/qiniu/goc/issues/1/comments", func(w http.ResponseWriter, r *http.Request) {
|
router.HandlerFunc("POST", "/repos/qiniu/goc/issues/1/comments", func(w http.ResponseWriter, r *http.Request) {
|
||||||
v := new(github.IssueComment)
|
v := new(github.IssueComment)
|
||||||
json.NewDecoder(r.Body).Decode(v)
|
json.NewDecoder(r.Body).Decode(v)
|
||||||
|
assert.Equal(t, v, comment)
|
||||||
|
|
||||||
if !reflect.DeepEqual(v, comment) {
|
|
||||||
t.Errorf("Request body = %+v, want %+v", v, comment)
|
|
||||||
}
|
|
||||||
fmt.Fprint(w, `{"id":1}`)
|
fmt.Fprint(w, `{"id":1}`)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -160,6 +157,6 @@ func TestGetPrChangedFiles(t *testing.T) {
|
|||||||
GithubClient: client,
|
GithubClient: client,
|
||||||
}
|
}
|
||||||
changedFiles, err := p.GetPrChangedFiles()
|
changedFiles, err := p.GetPrChangedFiles()
|
||||||
assert.Nil(t, err)
|
assert.Equal(t, err, nil)
|
||||||
assert.True(t, reflect.DeepEqual(changedFiles, expectFiles))
|
assert.Equal(t, changedFiles, expectFiles)
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,10 @@ func (j *Job) RunPresubmit() error {
|
|||||||
if j.GithubComment.CommentFlag != "" {
|
if j.GithubComment.CommentFlag != "" {
|
||||||
commentPrefix = fmt.Sprintf("**%s** ", j.GithubComment.CommentFlag) + commentPrefix
|
commentPrefix = fmt.Sprintf("**%s** ", j.GithubComment.CommentFlag) + commentPrefix
|
||||||
}
|
}
|
||||||
|
if len(deltaCovList) > 0 {
|
||||||
|
totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP))
|
||||||
|
deltaCovList = append(deltaCovList, cover.DeltaCov{FileName: "Total", BasePer: baseP.TotalPercentage(), NewPer: localP.TotalPercentage(), DeltaPer: totalDelta})
|
||||||
|
}
|
||||||
err = j.GithubComment.CreateGithubComment(commentPrefix, deltaCovList)
|
err = j.GithubComment.CreateGithubComment(commentPrefix, deltaCovList)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatalf("Post comment to github failed.")
|
logrus.WithError(err).Fatalf("Post comment to github failed.")
|
||||||
|
@ -15,3 +15,127 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
package prow
|
package prow
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/qiniu/goc/pkg/github"
|
||||||
|
"github.com/qiniu/goc/pkg/qiniu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTrimGhFileToProfile(t *testing.T) {
|
||||||
|
items := []struct {
|
||||||
|
inputFiles []string
|
||||||
|
expectFiles []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
inputFiles: []string{"src/qiniu.com/kodo/io/io/io_svr.go", "README.md"},
|
||||||
|
expectFiles: []string{"qiniu.com/kodo/io/io/io_svr.go", "README.md"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range items {
|
||||||
|
f := trimGhFileToProfile(tc.inputFiles)
|
||||||
|
assert.Equal(t, f, tc.expectFiles)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setup(path, content string) {
|
||||||
|
err := ioutil.WriteFile(path, []byte(content), 0644)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("write file %s failed", path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestWriteChangedCov(t *testing.T) {
|
||||||
|
path := "local.cov"
|
||||||
|
savePath := qiniu.ChangedProfileName
|
||||||
|
content := `mode: atomic
|
||||||
|
qiniu.com/kodo/bd/bdgetter/source.go:19.118,22.2 2 0
|
||||||
|
qiniu.com/kodo/bd/bdgetter/source.go:37.34,39.2 1 0
|
||||||
|
qiniu.com/kodo/bd/pfd/locker/app/qboxbdlocker/main.go:50.2,53.52 4 1
|
||||||
|
qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0`
|
||||||
|
changedFiles := []string{"qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go"}
|
||||||
|
expectContent := `mode: atomic
|
||||||
|
qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0
|
||||||
|
`
|
||||||
|
|
||||||
|
setup(path, content)
|
||||||
|
defer os.Remove(path)
|
||||||
|
defer os.Remove(savePath)
|
||||||
|
j := &Job{
|
||||||
|
LocalProfilePath: path,
|
||||||
|
LocalArtifacts: &qiniu.Artifacts{ChangedProfileName: savePath},
|
||||||
|
}
|
||||||
|
j.WriteChangedCov(changedFiles)
|
||||||
|
|
||||||
|
r, err := ioutil.ReadFile(savePath)
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("read file %s failed", path)
|
||||||
|
}
|
||||||
|
assert.Equal(t, string(r), expectContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunPresubmitFulldiff(t *testing.T) {
|
||||||
|
//param
|
||||||
|
org := "qbox"
|
||||||
|
repo := "kodo"
|
||||||
|
prNum := "1"
|
||||||
|
buildId := "1266322425771986946"
|
||||||
|
jobName := "kodo-pull-integration-test"
|
||||||
|
robotName := "qiniu-bot"
|
||||||
|
githubCommentPrefix := ""
|
||||||
|
githubTokenPath := "token"
|
||||||
|
|
||||||
|
//mock local profile
|
||||||
|
pwd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
logrus.WithError(err).Fatalf("get pwd failed")
|
||||||
|
}
|
||||||
|
localPath := "local.cov"
|
||||||
|
localProfileContent := `mode: atomic
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0`
|
||||||
|
setup(localPath, localProfileContent)
|
||||||
|
defer os.Remove(path.Join(pwd, localPath))
|
||||||
|
|
||||||
|
// mock qiniu
|
||||||
|
conf := qiniu.Config{
|
||||||
|
Bucket: "artifacts",
|
||||||
|
}
|
||||||
|
qc, router, _, teardown := qiniu.MockQiniuServer(&conf)
|
||||||
|
defer teardown()
|
||||||
|
qiniu.MockRouterAPI(router, localProfileContent)
|
||||||
|
|
||||||
|
ChangedProfilePath := "changed.cov"
|
||||||
|
defer os.Remove(path.Join(pwd, ChangedProfilePath))
|
||||||
|
|
||||||
|
//mock github client
|
||||||
|
setup(githubTokenPath, "")
|
||||||
|
defer os.Remove(path.Join(pwd, githubTokenPath))
|
||||||
|
prClient := github.NewPrClient(githubTokenPath, org, repo, prNum, robotName, githubCommentPrefix)
|
||||||
|
|
||||||
|
j := &Job{
|
||||||
|
JobName: jobName,
|
||||||
|
Org: org,
|
||||||
|
RepoName: repo,
|
||||||
|
PRNumStr: prNum,
|
||||||
|
BuildId: buildId,
|
||||||
|
PostSubmitJob: "kodo-postsubmits-go-st-coverage",
|
||||||
|
PostSubmitCoverProfile: "filterd.cov",
|
||||||
|
LocalProfilePath: localPath,
|
||||||
|
LocalArtifacts: &qiniu.Artifacts{ChangedProfileName: ChangedProfilePath},
|
||||||
|
QiniuClient: qc,
|
||||||
|
GithubComment: prClient,
|
||||||
|
FullDiff: true,
|
||||||
|
}
|
||||||
|
defer os.Remove(path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile()))
|
||||||
|
|
||||||
|
j.RunPresubmit()
|
||||||
|
}
|
||||||
|
77
pkg/qiniu/mock.go
Normal file
77
pkg/qiniu/mock.go
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Qiniu Cloud (qiniu.com)
|
||||||
|
|
||||||
|
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 qiniu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/qiniu/api.v7/v7/storage"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MockQiniuServer(config *Config) (client *Client, router *httprouter.Router, serverURL string, teardown func()) {
|
||||||
|
// router is the HTTP request multiplexer used with the test server.
|
||||||
|
router = httprouter.New()
|
||||||
|
|
||||||
|
// server is a test HTTP server used to provide mock API responses.
|
||||||
|
server := httptest.NewServer(router)
|
||||||
|
|
||||||
|
config.Domain = server.URL
|
||||||
|
client = NewClient(config)
|
||||||
|
client.BucketManager.Cfg = &storage.Config{
|
||||||
|
RsfHost: server.URL,
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Infof("server url is: %s", server.URL)
|
||||||
|
return client, router, server.URL, server.Close
|
||||||
|
}
|
||||||
|
|
||||||
|
func MockRouterAPI(router *httprouter.Router, profile string) {
|
||||||
|
// mock rsf /v2/list
|
||||||
|
router.HandlerFunc("POST", "/v2/list", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
logrus.Infof("request url is: %s", r.URL.String())
|
||||||
|
|
||||||
|
fmt.Fprint(w, `{
|
||||||
|
"item": {
|
||||||
|
"key": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json",
|
||||||
|
"hash": "FkBhdo9odL2Xjvu-YdwtDIw79fIL",
|
||||||
|
"fsize": 51523,
|
||||||
|
"mimeType": "application/octet-stream",
|
||||||
|
"putTime": 15909068578047958,
|
||||||
|
"type": 0,
|
||||||
|
"status": 0,
|
||||||
|
"md5": "e0bd20e97ea1c6a5e2480192ee3ae884"
|
||||||
|
},
|
||||||
|
"marker": "",
|
||||||
|
"dir": "logs/kodo-postsubmits-go-st-coverage/1181915661132107776/"
|
||||||
|
}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// mock io get statusJSON file
|
||||||
|
router.HandlerFunc("GET", "/logs/kodo-postsubmits-go-st-coverage/1181915661132107776/finished.json", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprint(w, `{"timestamp":1590750306,"passed":true,"result":"SUCCESS","repo-version":"76433418ea48aae57af028f9cb2fa3735ce08c7d"}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
// mock io get remote coverage profile
|
||||||
|
router.HandlerFunc("GET", "/logs/kodo-postsubmits-go-st-coverage/1181915661132107776/artifacts/filterd.cov", func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
fmt.Fprint(w, profile)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
41
pkg/qiniu/qnPresubmit_test.go
Normal file
41
pkg/qiniu/qnPresubmit_test.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2020 Qiniu Cloud (qiniu.com)
|
||||||
|
|
||||||
|
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 qiniu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFindBaseProfileFromQiniu(t *testing.T) {
|
||||||
|
conf := Config{
|
||||||
|
Bucket: "artifacts",
|
||||||
|
}
|
||||||
|
qc, router, _, teardown := MockQiniuServer(&conf)
|
||||||
|
defer teardown()
|
||||||
|
prowJobName := "kodo-postsubmits-go-st-coverage"
|
||||||
|
covProfileName := "filterd.cov"
|
||||||
|
mockProfileContent := `mode: atomic
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30
|
||||||
|
"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0`
|
||||||
|
|
||||||
|
MockRouterAPI(router, mockProfileContent)
|
||||||
|
getProfile, err := FindBaseProfileFromQiniu(qc, prowJobName, covProfileName)
|
||||||
|
assert.Equal(t, err, nil)
|
||||||
|
assert.Equal(t, string(getProfile), mockProfileContent)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user