Merge pull request #81 from tongjingran/diffReset
Add test case for goc diff
This commit is contained in:
commit
89dd3585d1
@ -160,7 +160,7 @@ func doDiffUnderProw(cmd *cobra.Command, args []string) {
|
|||||||
if qiniuCredential == "" {
|
if qiniuCredential == "" {
|
||||||
logrus.Fatalf("qiniu credential not provided")
|
logrus.Fatalf("qiniu credential not provided")
|
||||||
}
|
}
|
||||||
var qc *qiniu.Client
|
var qc qiniu.Client
|
||||||
var conf qiniu.Config
|
var conf qiniu.Config
|
||||||
files, err := ioutil.ReadFile(*&qiniuCredential)
|
files, err := ioutil.ReadFile(*&qiniuCredential)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -180,7 +180,7 @@ func doDiffUnderProw(cmd *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
qc = qiniu.NewClient(&conf)
|
qc = qiniu.NewClient(&conf)
|
||||||
|
|
||||||
localArtifacts := qiniu.Artifacts{
|
localArtifacts := qiniu.ProfileArtifacts{
|
||||||
Directory: artifacts,
|
Directory: artifacts,
|
||||||
ProfileName: newProfile,
|
ProfileName: newProfile,
|
||||||
ChangedProfileName: qiniu.ChangedProfileName,
|
ChangedProfileName: qiniu.ChangedProfileName,
|
||||||
|
@ -93,6 +93,12 @@ func TestCovList(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestReadFileToCoverList(t *testing.T) {
|
||||||
|
path := "unknown"
|
||||||
|
_, err := ReadFileToCoverList(path)
|
||||||
|
assert.Equal(t, err.Error(), "open unknown: no such file or directory")
|
||||||
|
}
|
||||||
|
|
||||||
func TestTotalPercentage(t *testing.T) {
|
func TestTotalPercentage(t *testing.T) {
|
||||||
items := []struct {
|
items := []struct {
|
||||||
list CoverageList
|
list CoverageList
|
||||||
|
@ -38,8 +38,17 @@ import (
|
|||||||
// It is also the flag when checking whether the target comment exists or not to avoid duplicate
|
// It is also the flag when checking whether the target comment exists or not to avoid duplicate
|
||||||
const CommentsPrefix = "The following is the coverage report on the affected files."
|
const CommentsPrefix = "The following is the coverage report on the affected files."
|
||||||
|
|
||||||
// PrComment is the entry which is able to comment on Github Pull Requests
|
// PrComment is the interface of the entry which is able to comment on Github Pull Requests
|
||||||
type PrComment struct {
|
type PrComment interface {
|
||||||
|
CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error)
|
||||||
|
PostComment(content, commentPrefix string) error
|
||||||
|
EraseHistoryComment(commentPrefix string) error
|
||||||
|
GetPrChangedFiles() (files []string, err error)
|
||||||
|
GetCommentFlag() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// GithubPrComment is the entry which is able to comment on Github Pull Requests
|
||||||
|
type GithubPrComment struct {
|
||||||
RobotUserName string
|
RobotUserName string
|
||||||
RepoOwner string
|
RepoOwner string
|
||||||
RepoName string
|
RepoName string
|
||||||
@ -51,7 +60,7 @@ type PrComment struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPrClient creates an Client which be able to comment on Github Pull Request
|
// NewPrClient creates an Client which be able to comment on Github Pull Request
|
||||||
func NewPrClient(githubTokenPath, repoOwner, repoName, prNumStr, botUserName, commentFlag string) *PrComment {
|
func NewPrClient(githubTokenPath, repoOwner, repoName, prNumStr, botUserName, commentFlag string) *GithubPrComment {
|
||||||
var client *github.Client
|
var client *github.Client
|
||||||
|
|
||||||
// performs automatic retries when connection error occurs or a 500-range response code received (except 501)
|
// performs automatic retries when connection error occurs or a 500-range response code received (except 501)
|
||||||
@ -72,7 +81,7 @@ func NewPrClient(githubTokenPath, repoOwner, repoName, prNumStr, botUserName, co
|
|||||||
tc := oauth2.NewClient(ctx, ts)
|
tc := oauth2.NewClient(ctx, ts)
|
||||||
client = github.NewClient(tc)
|
client = github.NewClient(tc)
|
||||||
|
|
||||||
return &PrComment{
|
return &GithubPrComment{
|
||||||
RobotUserName: botUserName,
|
RobotUserName: botUserName,
|
||||||
RepoOwner: repoOwner,
|
RepoOwner: repoOwner,
|
||||||
RepoName: repoName,
|
RepoName: repoName,
|
||||||
@ -85,7 +94,7 @@ func NewPrClient(githubTokenPath, repoOwner, repoName, prNumStr, botUserName, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CreateGithubComment post github comment of diff coverage
|
// CreateGithubComment post github comment of diff coverage
|
||||||
func (c *PrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) {
|
func (c *GithubPrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) {
|
||||||
if len(diffCovList) == 0 {
|
if len(diffCovList) == 0 {
|
||||||
logrus.Printf("Detect 0 files coverage diff, will not comment to github.")
|
logrus.Printf("Detect 0 files coverage diff, will not comment to github.")
|
||||||
return nil
|
return nil
|
||||||
@ -101,7 +110,7 @@ func (c *PrComment) CreateGithubComment(commentPrefix string, diffCovList cover.
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PostComment post comment on github. It erased the old one if existed to avoid duplicate
|
// PostComment post comment on github. It erased the old one if existed to avoid duplicate
|
||||||
func (c *PrComment) PostComment(content, commentPrefix string) error {
|
func (c *GithubPrComment) PostComment(content, commentPrefix string) error {
|
||||||
//step1: erase history similar comment to avoid too many comment for same job
|
//step1: erase history similar comment to avoid too many comment for same job
|
||||||
err := c.EraseHistoryComment(commentPrefix)
|
err := c.EraseHistoryComment(commentPrefix)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -121,7 +130,7 @@ func (c *PrComment) PostComment(content, commentPrefix string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EraseHistoryComment erase history similar comment before post again
|
// EraseHistoryComment erase history similar comment before post again
|
||||||
func (c *PrComment) EraseHistoryComment(commentPrefix string) error {
|
func (c *GithubPrComment) EraseHistoryComment(commentPrefix string) error {
|
||||||
comments, _, err := c.GithubClient.Issues.ListComments(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, nil)
|
comments, _, err := c.GithubClient.Issues.ListComments(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("list PR comments failed.")
|
logrus.Errorf("list PR comments failed.")
|
||||||
@ -143,7 +152,7 @@ func (c *PrComment) EraseHistoryComment(commentPrefix string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetPrChangedFiles get github pull request changes file list
|
// GetPrChangedFiles get github pull request changes file list
|
||||||
func (c *PrComment) GetPrChangedFiles() (files []string, err error) {
|
func (c *GithubPrComment) GetPrChangedFiles() (files []string, err error) {
|
||||||
var commitFiles []*github.CommitFile
|
var commitFiles []*github.CommitFile
|
||||||
for {
|
for {
|
||||||
f, resp, err := c.GithubClient.PullRequests.ListFiles(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, c.opt)
|
f, resp, err := c.GithubClient.PullRequests.ListFiles(c.Ctx, c.RepoOwner, c.RepoName, c.PrNumber, c.opt)
|
||||||
@ -165,6 +174,11 @@ func (c *PrComment) GetPrChangedFiles() (files []string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCommentFlag get CommentFlag from the GithubPrComment
|
||||||
|
func (c *GithubPrComment) GetCommentFlag() string {
|
||||||
|
return c.CommentFlag
|
||||||
|
}
|
||||||
|
|
||||||
// GenCommentContent generate github comment content based on diff coverage and commentFlag
|
// GenCommentContent generate github comment content based on diff coverage and commentFlag
|
||||||
func GenCommentContent(commentPrefix string, delta cover.DeltaCovList) string {
|
func GenCommentContent(commentPrefix string, delta cover.DeltaCovList) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
@ -121,7 +121,7 @@ func TestCreateGithubComment(t *testing.T) {
|
|||||||
router.HandlerFunc("DELETE", "/repos/qiniu/goc/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
|
router.HandlerFunc("DELETE", "/repos/qiniu/goc/issues/comments/1", func(w http.ResponseWriter, r *http.Request) {
|
||||||
})
|
})
|
||||||
|
|
||||||
p := PrComment{
|
p := GithubPrComment{
|
||||||
RobotUserName: "qiniu-bot",
|
RobotUserName: "qiniu-bot",
|
||||||
RepoOwner: "qiniu",
|
RepoOwner: "qiniu",
|
||||||
RepoName: "goc",
|
RepoName: "goc",
|
||||||
@ -135,6 +135,12 @@ func TestCreateGithubComment(t *testing.T) {
|
|||||||
p.CreateGithubComment("", coverList)
|
p.CreateGithubComment("", coverList)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateGithubCommentError(t *testing.T) {
|
||||||
|
p := &GithubPrComment{}
|
||||||
|
err := p.CreateGithubComment("", cover.DeltaCovList{})
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetPrChangedFiles(t *testing.T) {
|
func TestGetPrChangedFiles(t *testing.T) {
|
||||||
client, router, _, teardown := setup()
|
client, router, _, teardown := setup()
|
||||||
defer teardown()
|
defer teardown()
|
||||||
@ -146,7 +152,7 @@ func TestGetPrChangedFiles(t *testing.T) {
|
|||||||
fmt.Fprint(w, `[{"filename":"src/qiniu.com/kodo/s3apiv2/bucket/bucket.go"}]`)
|
fmt.Fprint(w, `[{"filename":"src/qiniu.com/kodo/s3apiv2/bucket/bucket.go"}]`)
|
||||||
})
|
})
|
||||||
|
|
||||||
p := PrComment{
|
p := GithubPrComment{
|
||||||
RobotUserName: "qiniu-bot",
|
RobotUserName: "qiniu-bot",
|
||||||
RepoOwner: "qiniu",
|
RepoOwner: "qiniu",
|
||||||
RepoName: "goc",
|
RepoName: "goc",
|
||||||
@ -160,3 +166,11 @@ func TestGetPrChangedFiles(t *testing.T) {
|
|||||||
assert.Equal(t, err, nil)
|
assert.Equal(t, err, nil)
|
||||||
assert.Equal(t, changedFiles, expectFiles)
|
assert.Equal(t, changedFiles, expectFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetCommentFlag(t *testing.T) {
|
||||||
|
p := GithubPrComment{
|
||||||
|
CommentFlag: "flag",
|
||||||
|
}
|
||||||
|
flag := p.GetCommentFlag()
|
||||||
|
assert.Equal(t, flag, p.CommentFlag)
|
||||||
|
}
|
||||||
|
@ -54,9 +54,9 @@ type Job struct {
|
|||||||
PostSubmitCoverProfile string
|
PostSubmitCoverProfile string
|
||||||
CovThreshold int
|
CovThreshold int
|
||||||
LocalProfilePath string
|
LocalProfilePath string
|
||||||
QiniuClient *qiniu.Client
|
QiniuClient qiniu.Client
|
||||||
LocalArtifacts *qiniu.Artifacts
|
LocalArtifacts qiniu.Artifacts
|
||||||
GithubComment *github.PrComment
|
GithubComment github.PrComment
|
||||||
FullDiff bool
|
FullDiff bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,32 +67,16 @@ func (j *Job) Fetch(BuildID, name string) []byte {
|
|||||||
|
|
||||||
// RunPresubmit run a presubmit job
|
// RunPresubmit run a presubmit job
|
||||||
func (j *Job) RunPresubmit() error {
|
func (j *Job) RunPresubmit() error {
|
||||||
var changedFiles []string
|
// step1: get local profile cov
|
||||||
var deltaCovList cover.DeltaCovList
|
|
||||||
|
|
||||||
// step1: get github pull request changed files' name
|
|
||||||
if !j.FullDiff {
|
|
||||||
var ghChangedFiles, err = j.GithubComment.GetPrChangedFiles()
|
|
||||||
if err != nil {
|
|
||||||
logrus.WithError(err).Fatalf("Get pull request changed file failed.")
|
|
||||||
}
|
|
||||||
if len(ghChangedFiles) == 0 {
|
|
||||||
logrus.Printf("0 files changed in github pull request, don't need to run coverage profile in presubmit.\n")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
changedFiles = trimGhFileToProfile(ghChangedFiles)
|
|
||||||
}
|
|
||||||
|
|
||||||
// step2: get local profile cov
|
|
||||||
localP, err := cover.ReadFileToCoverList(j.LocalProfilePath)
|
localP, err := cover.ReadFileToCoverList(j.LocalProfilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatalf("failed to get remote cover profile")
|
return fmt.Errorf("failed to get remote cover profile: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
//step3: find the remote healthy cover profile from qiniu bucket
|
//step2: find the remote healthy cover profile from qiniu bucket
|
||||||
remoteProfile, err := qiniu.FindBaseProfileFromQiniu(j.QiniuClient, j.PostSubmitJob, j.PostSubmitCoverProfile)
|
remoteProfile, err := qiniu.FindBaseProfileFromQiniu(j.QiniuClient, j.PostSubmitJob, j.PostSubmitCoverProfile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatalf("failed to get remote cover profile")
|
return fmt.Errorf("failed to get remote cover profile: %s", err.Error())
|
||||||
}
|
}
|
||||||
if remoteProfile == nil {
|
if remoteProfile == nil {
|
||||||
logrus.Infof("get non healthy remoteProfile, do nothing")
|
logrus.Infof("get non healthy remoteProfile, do nothing")
|
||||||
@ -100,36 +84,30 @@ func (j *Job) RunPresubmit() error {
|
|||||||
}
|
}
|
||||||
baseP, err := cover.CovList(bytes.NewReader(remoteProfile))
|
baseP, err := cover.CovList(bytes.NewReader(remoteProfile))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatalf("failed to get remote cover profile")
|
return fmt.Errorf("failed to get remote cover profile: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
// step4: calculate diff cov between local and remote profile
|
// step3: get github pull request changed files' name and calculate diff cov between local and remote profile
|
||||||
if !j.FullDiff {
|
changedFiles, deltaCovList, err := getFilesAndCovList(j.FullDiff, j.GithubComment, localP, baseP)
|
||||||
deltaCovList = cover.GetChFileDeltaCov(localP, baseP, changedFiles)
|
if err != nil {
|
||||||
} else {
|
return fmt.Errorf("Get files and covlist failed: %s", err.Error())
|
||||||
deltaCovList = cover.GetDeltaCov(localP, baseP)
|
|
||||||
logrus.Infof("get delta file name is:")
|
|
||||||
for _, d := range deltaCovList {
|
|
||||||
logrus.Infof("%s", d.FileName)
|
|
||||||
changedFiles = append(changedFiles, d.FileName)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// step5: generate changed file html coverage
|
// step4: generate changed file html coverage
|
||||||
err = j.WriteChangedCov(changedFiles)
|
err = j.WriteChangedCov(changedFiles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatalf("filter local profile to %s with changed files failed", j.LocalArtifacts.ChangedProfileName)
|
return fmt.Errorf("filter local profile to %s with changed files failed: %s", j.LocalArtifacts.GetChangedProfileName(), err.Error())
|
||||||
}
|
}
|
||||||
err = j.CreateChangedCovHtml()
|
err = j.CreateChangedCovHtml()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.WithError(err).Fatalf("create changed file related coverage html failed")
|
return fmt.Errorf("create changed file related coverage html failed: %s", err.Error())
|
||||||
}
|
}
|
||||||
j.SetDeltaCovLinks(deltaCovList)
|
j.SetDeltaCovLinks(deltaCovList)
|
||||||
|
|
||||||
// step6: post comment to github
|
// step5: post comment to github
|
||||||
commentPrefix := github.CommentsPrefix
|
commentPrefix := github.CommentsPrefix
|
||||||
if j.GithubComment.CommentFlag != "" {
|
if j.GithubComment.GetCommentFlag() != "" {
|
||||||
commentPrefix = fmt.Sprintf("**%s** ", j.GithubComment.CommentFlag) + commentPrefix
|
commentPrefix = fmt.Sprintf("**%s** ", j.GithubComment.GetCommentFlag()) + commentPrefix
|
||||||
}
|
}
|
||||||
if len(deltaCovList) > 0 {
|
if len(deltaCovList) > 0 {
|
||||||
totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP))
|
totalDelta := cover.PercentStr(cover.TotalDelta(localP, baseP))
|
||||||
@ -137,7 +115,7 @@ func (j *Job) RunPresubmit() error {
|
|||||||
}
|
}
|
||||||
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.")
|
return fmt.Errorf("Post comment to github failed: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@ -217,10 +195,10 @@ func (j *Job) SetDeltaCovLinks(c cover.DeltaCovList) {
|
|||||||
|
|
||||||
// CreateChangedCovHtml create changed file related coverage html base on the local artifact
|
// CreateChangedCovHtml create changed file related coverage html base on the local artifact
|
||||||
func (j *Job) CreateChangedCovHtml() error {
|
func (j *Job) CreateChangedCovHtml() error {
|
||||||
if j.LocalArtifacts.ChangedProfileName == "" {
|
if j.LocalArtifacts.GetChangedProfileName() == "" {
|
||||||
logrus.Errorf("param LocalArtifacts.ChangedProfileName is empty")
|
logrus.Errorf("param LocalArtifacts.ChangedProfileName is empty")
|
||||||
}
|
}
|
||||||
pathProfileCov := j.LocalArtifacts.ChangedProfileName
|
pathProfileCov := j.LocalArtifacts.GetChangedProfileName()
|
||||||
pathHtmlCov := path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile())
|
pathHtmlCov := path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile())
|
||||||
cmdTxt := fmt.Sprintf("go tool cover -html=%s -o %s", pathProfileCov, pathHtmlCov)
|
cmdTxt := fmt.Sprintf("go tool cover -html=%s -o %s", pathProfileCov, pathHtmlCov)
|
||||||
logrus.Printf("Running command '%s'\n", cmdTxt)
|
logrus.Printf("Running command '%s'\n", cmdTxt)
|
||||||
@ -231,3 +209,29 @@ func (j *Job) CreateChangedCovHtml() error {
|
|||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getFilesAndCovList(fullDiff bool, prComment github.PrComment, localP, baseP cover.CoverageList) (changedFiles []string, deltaCovList cover.DeltaCovList, err error) {
|
||||||
|
if !fullDiff {
|
||||||
|
// get github pull request changed files' name
|
||||||
|
var ghChangedFiles, err = prComment.GetPrChangedFiles()
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, fmt.Errorf("Get pull request changed file failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
if len(ghChangedFiles) == 0 {
|
||||||
|
logrus.Printf("0 files changed in github pull request, don't need to run coverage profile in presubmit.\n")
|
||||||
|
return nil, nil, nil
|
||||||
|
}
|
||||||
|
changedFiles = trimGhFileToProfile(ghChangedFiles)
|
||||||
|
|
||||||
|
// calculate diff cov between local and remote profile
|
||||||
|
deltaCovList = cover.GetChFileDeltaCov(localP, baseP, changedFiles)
|
||||||
|
logrus.Printf("Get changed files and delta cover list success. ChangedFiles: [%+v], DeltaCovList: [%+v]", changedFiles, deltaCovList)
|
||||||
|
return changedFiles, deltaCovList, nil
|
||||||
|
}
|
||||||
|
deltaCovList = cover.GetDeltaCov(localP, baseP)
|
||||||
|
for _, d := range deltaCovList {
|
||||||
|
changedFiles = append(changedFiles, d.FileName)
|
||||||
|
}
|
||||||
|
logrus.Printf("Get all files and delta cover list success. Files: [%+v], DeltaCovList: [%+v]", changedFiles, deltaCovList)
|
||||||
|
return changedFiles, deltaCovList, nil
|
||||||
|
}
|
||||||
|
@ -17,18 +17,99 @@
|
|||||||
package prow
|
package prow
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
|
"github.com/qiniu/goc/pkg/cover"
|
||||||
"github.com/qiniu/goc/pkg/github"
|
"github.com/qiniu/goc/pkg/github"
|
||||||
"github.com/qiniu/goc/pkg/qiniu"
|
"github.com/qiniu/goc/pkg/qiniu"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultContent = `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`
|
||||||
|
defaultLocalPath = "local.cov"
|
||||||
|
defaultChangedPath = "changed.cov"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MockQnClient struct {
|
||||||
|
QiniuObjectHandleRes qiniu.ObjectHandle
|
||||||
|
ReadObjectRes []byte
|
||||||
|
ReadObjectErr error
|
||||||
|
ListAllRes []string
|
||||||
|
ListAllErr error
|
||||||
|
GetAccessURLRes string
|
||||||
|
GetArtifactDetailsRes *qiniu.LogHistoryTemplate
|
||||||
|
GetArtifactDetailsErr error
|
||||||
|
ListSubDirsRes []string
|
||||||
|
ListSubDirsErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockQnClient) QiniuObjectHandle(key string) qiniu.ObjectHandle {
|
||||||
|
return s.QiniuObjectHandleRes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockQnClient) ReadObject(key string) ([]byte, error) {
|
||||||
|
return s.ReadObjectRes, s.ReadObjectErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockQnClient) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) {
|
||||||
|
return s.ListAllRes, s.ListAllErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockQnClient) GetAccessURL(key string, timeout time.Duration) string {
|
||||||
|
return s.GetAccessURLRes
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockQnClient) GetArtifactDetails(key string) (*qiniu.LogHistoryTemplate, error) {
|
||||||
|
return s.GetArtifactDetailsRes, s.GetArtifactDetailsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockQnClient) ListSubDirs(prefix string) ([]string, error) {
|
||||||
|
return s.ListSubDirsRes, s.ListSubDirsErr
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockPrComment struct {
|
||||||
|
GetPrChangedFilesRes []string
|
||||||
|
GetPrChangedFilesErr error
|
||||||
|
PostCommentErr error
|
||||||
|
EraseHistoryCommentErr error
|
||||||
|
CreateGithubCommentErr error
|
||||||
|
CommentFlag string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockPrComment) GetPrChangedFiles() (files []string, err error) {
|
||||||
|
return s.GetPrChangedFilesRes, s.GetPrChangedFilesErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockPrComment) PostComment(content, commentPrefix string) error {
|
||||||
|
return s.PostCommentErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockPrComment) EraseHistoryComment(commentPrefix string) error {
|
||||||
|
return s.EraseHistoryCommentErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockPrComment) CreateGithubComment(commentPrefix string, diffCovList cover.DeltaCovList) (err error) {
|
||||||
|
return s.CreateGithubCommentErr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockPrComment) GetCommentFlag() string {
|
||||||
|
return s.CommentFlag
|
||||||
|
}
|
||||||
|
|
||||||
func TestTrimGhFileToProfile(t *testing.T) {
|
func TestTrimGhFileToProfile(t *testing.T) {
|
||||||
items := []struct {
|
items := []struct {
|
||||||
inputFiles []string
|
inputFiles []string
|
||||||
@ -54,13 +135,9 @@ func setup(path, content string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWriteChangedCov(t *testing.T) {
|
func TestWriteChangedCov(t *testing.T) {
|
||||||
path := "local.cov"
|
path := defaultLocalPath
|
||||||
savePath := qiniu.ChangedProfileName
|
savePath := qiniu.ChangedProfileName
|
||||||
content := `mode: atomic
|
content := defaultContent
|
||||||
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"}
|
changedFiles := []string{"qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go"}
|
||||||
expectContent := `mode: atomic
|
expectContent := `mode: atomic
|
||||||
qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0
|
qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0
|
||||||
@ -71,7 +148,7 @@ qiniu.com/kodo/bd/pfd/locker/bdlocker/locker.go:33.51,35.2 1 0
|
|||||||
defer os.Remove(savePath)
|
defer os.Remove(savePath)
|
||||||
j := &Job{
|
j := &Job{
|
||||||
LocalProfilePath: path,
|
LocalProfilePath: path,
|
||||||
LocalArtifacts: &qiniu.Artifacts{ChangedProfileName: savePath},
|
LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: savePath},
|
||||||
}
|
}
|
||||||
j.WriteChangedCov(changedFiles)
|
j.WriteChangedCov(changedFiles)
|
||||||
|
|
||||||
@ -95,10 +172,8 @@ func TestRunPresubmitFulldiff(t *testing.T) {
|
|||||||
|
|
||||||
//mock local profile
|
//mock local profile
|
||||||
pwd, err := os.Getwd()
|
pwd, err := os.Getwd()
|
||||||
if err != nil {
|
assert.NoError(t, err)
|
||||||
logrus.WithError(err).Fatalf("get pwd failed")
|
localPath := defaultLocalPath
|
||||||
}
|
|
||||||
localPath := "local.cov"
|
|
||||||
localProfileContent := `mode: atomic
|
localProfileContent := `mode: atomic
|
||||||
"qiniu.com/kodo/apiserver/server/main.go:32.49,33.13 1 30
|
"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`
|
"qiniu.com/kodo/apiserver/server/main.go:42.49,43.13 1 0`
|
||||||
@ -130,12 +205,176 @@ func TestRunPresubmitFulldiff(t *testing.T) {
|
|||||||
PostSubmitJob: "kodo-postsubmits-go-st-coverage",
|
PostSubmitJob: "kodo-postsubmits-go-st-coverage",
|
||||||
PostSubmitCoverProfile: "filterd.cov",
|
PostSubmitCoverProfile: "filterd.cov",
|
||||||
LocalProfilePath: localPath,
|
LocalProfilePath: localPath,
|
||||||
LocalArtifacts: &qiniu.Artifacts{ChangedProfileName: ChangedProfilePath},
|
LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: ChangedProfilePath},
|
||||||
QiniuClient: qc,
|
QiniuClient: qc,
|
||||||
GithubComment: prClient,
|
GithubComment: prClient,
|
||||||
FullDiff: true,
|
FullDiff: true,
|
||||||
}
|
}
|
||||||
defer os.Remove(path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile()))
|
defer os.Remove(path.Join(os.Getenv("ARTIFACTS"), j.HtmlProfile()))
|
||||||
|
|
||||||
j.RunPresubmit()
|
err = j.RunPresubmit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunPresubmitError(t *testing.T) {
|
||||||
|
items := []struct {
|
||||||
|
prepare bool // prepare local profile
|
||||||
|
j Job
|
||||||
|
err string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
prepare: false,
|
||||||
|
j: Job{
|
||||||
|
LocalProfilePath: "unkown",
|
||||||
|
},
|
||||||
|
err: "no such file or directory",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prepare: true,
|
||||||
|
j: Job{
|
||||||
|
LocalProfilePath: defaultLocalPath,
|
||||||
|
QiniuClient: &MockQnClient{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prepare: true,
|
||||||
|
j: Job{
|
||||||
|
LocalProfilePath: defaultLocalPath,
|
||||||
|
QiniuClient: &MockQnClient{ListSubDirsErr: errors.New("mock error")},
|
||||||
|
},
|
||||||
|
err: "mock error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prepare: true,
|
||||||
|
j: Job{
|
||||||
|
LocalProfilePath: defaultLocalPath,
|
||||||
|
QiniuClient: &MockProfileQnClient{},
|
||||||
|
GithubComment: &MockPrComment{GetPrChangedFilesRes: []string{"qiniu.com/kodo/apiserver/server/main.go"}},
|
||||||
|
FullDiff: true,
|
||||||
|
LocalArtifacts: &qiniu.ProfileArtifacts{ChangedProfileName: defaultChangedPath},
|
||||||
|
},
|
||||||
|
err: "",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, tc := range items {
|
||||||
|
if tc.prepare {
|
||||||
|
path := defaultLocalPath
|
||||||
|
setup(path, defaultContent)
|
||||||
|
defer os.Remove(path)
|
||||||
|
defer os.Remove(defaultChangedPath)
|
||||||
|
}
|
||||||
|
err := tc.j.RunPresubmit()
|
||||||
|
if tc.err == "" {
|
||||||
|
assert.NoError(t, err)
|
||||||
|
} else {
|
||||||
|
assert.Contains(t, err.Error(), tc.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MockProfileQnClient struct {
|
||||||
|
*MockQnClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockProfileQnClient) ListSubDirs(prefix string) ([]string, error) {
|
||||||
|
return []string{defaultContent}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *MockProfileQnClient) ReadObject(key string) ([]byte, error) {
|
||||||
|
logrus.Info(key)
|
||||||
|
if key == "logs/1/finished.json" {
|
||||||
|
return []byte(`{"timestamp":1590750306,"passed":true,"result":"SUCCESS","repo-version":"76433418ea48aae57af028f9cb2fa3735ce08c7d"}`), nil
|
||||||
|
}
|
||||||
|
return []byte(""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetFilesAndCovList(t *testing.T) {
|
||||||
|
items := []struct {
|
||||||
|
fullDiff bool
|
||||||
|
prComment github.PrComment
|
||||||
|
localP cover.CoverageList
|
||||||
|
baseP cover.CoverageList
|
||||||
|
err string
|
||||||
|
lenFiles int
|
||||||
|
lenCovList int
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
fullDiff: true,
|
||||||
|
prComment: &MockPrComment{},
|
||||||
|
localP: cover.CoverageList{
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 2, NAllStmts: 2},
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 2, NAllStmts: 2},
|
||||||
|
},
|
||||||
|
baseP: cover.CoverageList{
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 1, NAllStmts: 2},
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 1, NAllStmts: 2},
|
||||||
|
},
|
||||||
|
lenFiles: 2,
|
||||||
|
lenCovList: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fullDiff: false,
|
||||||
|
prComment: &MockPrComment{GetPrChangedFilesErr: errors.New("mock error")},
|
||||||
|
err: "mock error",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fullDiff: false,
|
||||||
|
prComment: &MockPrComment{},
|
||||||
|
lenFiles: 0,
|
||||||
|
lenCovList: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fullDiff: false,
|
||||||
|
prComment: &MockPrComment{GetPrChangedFilesRes: []string{"qiniu.com/kodo/apiserver/server/main.go"}},
|
||||||
|
localP: cover.CoverageList{
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 2, NAllStmts: 2},
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 2, NAllStmts: 2},
|
||||||
|
},
|
||||||
|
baseP: cover.CoverageList{
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/main.go", NCoveredStmts: 1, NAllStmts: 2},
|
||||||
|
{FileName: "qiniu.com/kodo/apiserver/server/test.go", NCoveredStmts: 1, NAllStmts: 2},
|
||||||
|
},
|
||||||
|
lenFiles: 1,
|
||||||
|
lenCovList: 1,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range items {
|
||||||
|
fmt.Println(i)
|
||||||
|
files, covList, err := getFilesAndCovList(tc.fullDiff, tc.prComment, tc.localP, tc.baseP)
|
||||||
|
if err != nil {
|
||||||
|
assert.Contains(t, err.Error(), tc.err)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, len(files), tc.lenFiles)
|
||||||
|
assert.Equal(t, len(covList), tc.lenCovList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetDeltaCovLinks(t *testing.T) {
|
||||||
|
covList := cover.DeltaCovList{{FileName: "file1", BasePer: "5%", NewPer: "5%", DeltaPer: "0"}}
|
||||||
|
j := &Job{
|
||||||
|
QiniuClient: &MockQnClient{},
|
||||||
|
}
|
||||||
|
j.SetDeltaCovLinks(covList)
|
||||||
|
}
|
||||||
|
|
||||||
|
// functions to be done
|
||||||
|
|
||||||
|
func TestRunPostsubmit(t *testing.T) {
|
||||||
|
j := &Job{}
|
||||||
|
err := j.RunPostsubmit()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRunPeriodic(t *testing.T) {
|
||||||
|
j := &Job{}
|
||||||
|
err := j.RunPeriodic()
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetch(t *testing.T) {
|
||||||
|
j := &Job{}
|
||||||
|
res := j.Fetch("buidID", "name")
|
||||||
|
assert.Equal(t, res, []byte{})
|
||||||
}
|
}
|
||||||
|
@ -43,23 +43,33 @@ type Config struct {
|
|||||||
Domain string `json:"domain"`
|
Domain string `json:"domain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client for the operation with qiniu cloud
|
// Client is the interface contains the operation with qiniu cloud
|
||||||
type Client struct {
|
type Client interface {
|
||||||
|
QiniuObjectHandle(key string) ObjectHandle
|
||||||
|
ReadObject(key string) ([]byte, error)
|
||||||
|
ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error)
|
||||||
|
GetAccessURL(key string, timeout time.Duration) string
|
||||||
|
GetArtifactDetails(key string) (*LogHistoryTemplate, error)
|
||||||
|
ListSubDirs(prefix string) ([]string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QnClient for the operation with qiniu cloud
|
||||||
|
type QnClient struct {
|
||||||
cfg *Config
|
cfg *Config
|
||||||
BucketManager *storage.BucketManager
|
BucketManager *storage.BucketManager
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClient creates a new client to work with qiniu cloud
|
// NewClient creates a new QnClient to work with qiniu cloud
|
||||||
func NewClient(cfg *Config) *Client {
|
func NewClient(cfg *Config) *QnClient {
|
||||||
return &Client{
|
return &QnClient{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
BucketManager: storage.NewBucketManager(qbox.NewMac(cfg.AccessKey, cfg.SecretKey), nil),
|
BucketManager: storage.NewBucketManager(qbox.NewMac(cfg.AccessKey, cfg.SecretKey), nil),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// QiniuObjectHandle construct a object hanle to access file in qiniu
|
// QiniuObjectHandle construct a object hanle to access file in qiniu
|
||||||
func (q *Client) QiniuObjectHandle(key string) *ObjectHandle {
|
func (q *QnClient) QiniuObjectHandle(key string) ObjectHandle {
|
||||||
return &ObjectHandle{
|
return &QnObjectHandle{
|
||||||
key: key,
|
key: key,
|
||||||
cfg: q.cfg,
|
cfg: q.cfg,
|
||||||
bm: q.BucketManager,
|
bm: q.BucketManager,
|
||||||
@ -69,7 +79,7 @@ func (q *Client) QiniuObjectHandle(key string) *ObjectHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReadObject to read all the content of key
|
// ReadObject to read all the content of key
|
||||||
func (q *Client) ReadObject(key string) ([]byte, error) {
|
func (q *QnClient) ReadObject(key string) ([]byte, error) {
|
||||||
objectHandle := q.QiniuObjectHandle(key)
|
objectHandle := q.QiniuObjectHandle(key)
|
||||||
reader, err := objectHandle.NewReader(context.Background())
|
reader, err := objectHandle.NewReader(context.Background())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -80,7 +90,7 @@ func (q *Client) ReadObject(key string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ListAll to list all the files with contains the expected prefix
|
// ListAll to list all the files with contains the expected prefix
|
||||||
func (q *Client) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) {
|
func (q *QnClient) ListAll(ctx context.Context, prefix string, delimiter string) ([]string, error) {
|
||||||
var files []string
|
var files []string
|
||||||
artifacts, err := q.listEntries(prefix, delimiter)
|
artifacts, err := q.listEntries(prefix, delimiter)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -94,8 +104,8 @@ func (q *Client) ListAll(ctx context.Context, prefix string, delimiter string) (
|
|||||||
return files, nil
|
return files, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListAll to list all the entries with contains the expected prefix
|
// listEntries to list all the entries with contains the expected prefix
|
||||||
func (q *Client) listEntries(prefix string, delimiter string) ([]storage.ListItem, error) {
|
func (q *QnClient) listEntries(prefix string, delimiter string) ([]storage.ListItem, error) {
|
||||||
var marker string
|
var marker string
|
||||||
var artifacts []storage.ListItem
|
var artifacts []storage.ListItem
|
||||||
|
|
||||||
@ -124,7 +134,7 @@ func (q *Client) listEntries(prefix string, delimiter string) ([]storage.ListIte
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetAccessURL return a url which can access artifact directly in qiniu
|
// GetAccessURL return a url which can access artifact directly in qiniu
|
||||||
func (q *Client) GetAccessURL(key string, timeout time.Duration) string {
|
func (q *QnClient) GetAccessURL(key string, timeout time.Duration) string {
|
||||||
deadline := time.Now().Add(timeout).Unix()
|
deadline := time.Now().Add(timeout).Unix()
|
||||||
return storage.MakePrivateURL(qbox.NewMac(q.cfg.AccessKey, q.cfg.SecretKey), q.cfg.Domain, key, deadline)
|
return storage.MakePrivateURL(qbox.NewMac(q.cfg.AccessKey, q.cfg.SecretKey), q.cfg.Domain, key, deadline)
|
||||||
}
|
}
|
||||||
@ -143,7 +153,7 @@ type logHistoryItem struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Artifacts lists all artifacts available for the given job source
|
// Artifacts lists all artifacts available for the given job source
|
||||||
func (q *Client) GetArtifactDetails(key string) (*LogHistoryTemplate, error) {
|
func (q *QnClient) GetArtifactDetails(key string) (*LogHistoryTemplate, error) {
|
||||||
tmpl := new(LogHistoryTemplate)
|
tmpl := new(LogHistoryTemplate)
|
||||||
item := logHistoryItem{}
|
item := logHistoryItem{}
|
||||||
listStart := time.Now()
|
listStart := time.Now()
|
||||||
@ -183,7 +193,7 @@ func timeConv(ptime int64) string {
|
|||||||
return tm.Format("2006-01-02 03:04:05 PM")
|
return tm.Format("2006-01-02 03:04:05 PM")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (q *Client) ListSubDirs(prefix string) ([]string, error) {
|
func (q *QnClient) ListSubDirs(prefix string) ([]string, error) {
|
||||||
var dirs []string
|
var dirs []string
|
||||||
var marker string
|
var marker string
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// MockQiniuServer simulate qiniu cloud for testing
|
// MockQiniuServer simulate qiniu cloud for testing
|
||||||
func MockQiniuServer(config *Config) (client *Client, router *httprouter.Router, serverURL string, teardown func()) {
|
func MockQiniuServer(config *Config) (client *QnClient, router *httprouter.Router, serverURL string, teardown func()) {
|
||||||
// router is the HTTP request multiplexer used with the test server.
|
// router is the HTTP request multiplexer used with the test server.
|
||||||
router = httprouter.New()
|
router = httprouter.New()
|
||||||
|
|
||||||
|
@ -29,8 +29,14 @@ import (
|
|||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ObjectHandle provides operations on an object in a qiniu cloud bucket
|
// ObjectHandle is the interface contains the operations on an object in a qiniu cloud bucket
|
||||||
type ObjectHandle struct {
|
type ObjectHandle interface {
|
||||||
|
NewReader(ctx context.Context) (io.ReadCloser, error)
|
||||||
|
NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QnObjectHandle provides operations on an object in a qiniu cloud bucket
|
||||||
|
type QnObjectHandle struct {
|
||||||
key string
|
key string
|
||||||
cfg *Config
|
cfg *Config
|
||||||
bm *storage.BucketManager
|
bm *storage.BucketManager
|
||||||
@ -38,22 +44,16 @@ type ObjectHandle struct {
|
|||||||
client *client.Client
|
client *client.Client
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attrs get the object's metainfo
|
|
||||||
func (o *ObjectHandle) Attrs(ctx context.Context) (storage.FileInfo, error) {
|
|
||||||
//TODO(CarlJi): need retry when errors
|
|
||||||
return o.bm.Stat(o.cfg.Bucket, o.key)
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewReader creates a reader to read the contents of the object.
|
// NewReader creates a reader to read the contents of the object.
|
||||||
// ErrObjectNotExist will be returned if the object is not found.
|
// ErrObjectNotExist will be returned if the object is not found.
|
||||||
// The caller must call Close on the returned Reader when done reading.
|
// The caller must call Close on the returned Reader when done reading.
|
||||||
func (o *ObjectHandle) NewReader(ctx context.Context) (io.ReadCloser, error) {
|
func (o *QnObjectHandle) NewReader(ctx context.Context) (io.ReadCloser, error) {
|
||||||
return o.NewRangeReader(ctx, 0, -1)
|
return o.NewRangeReader(ctx, 0, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRangeReader reads parts of an object, reading at most length bytes starting
|
// NewRangeReader reads parts of an object, reading at most length bytes starting
|
||||||
// from the given offset. If length is negative, the object is read until the end.
|
// from the given offset. If length is negative, the object is read until the end.
|
||||||
func (o *ObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error) {
|
func (o *QnObjectHandle) NewRangeReader(ctx context.Context, offset, length int64) (io.ReadCloser, error) {
|
||||||
verb := "GET"
|
verb := "GET"
|
||||||
if length == 0 {
|
if length == 0 {
|
||||||
verb = "HEAD"
|
verb = "HEAD"
|
||||||
|
@ -41,7 +41,7 @@ func TestNewRangeReader(t *testing.T) {
|
|||||||
|
|
||||||
MockPrivateDomainUrl(router, 0)
|
MockPrivateDomainUrl(router, 0)
|
||||||
|
|
||||||
oh := &ObjectHandle{
|
oh := &QnObjectHandle{
|
||||||
key: "key",
|
key: "key",
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
bm: nil,
|
bm: nil,
|
||||||
@ -78,7 +78,7 @@ func TestNewRangeReaderWithTimeoutAndRecover(t *testing.T) {
|
|||||||
|
|
||||||
MockPrivateDomainUrl(router, 2)
|
MockPrivateDomainUrl(router, 2)
|
||||||
|
|
||||||
oh := &ObjectHandle{
|
oh := &QnObjectHandle{
|
||||||
key: "key",
|
key: "key",
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
bm: nil,
|
bm: nil,
|
||||||
@ -116,7 +116,7 @@ func TestNewRangeReaderWithTimeoutNoRecover(t *testing.T) {
|
|||||||
|
|
||||||
MockPrivateDomainUrl(router, 12)
|
MockPrivateDomainUrl(router, 12)
|
||||||
|
|
||||||
oh := &ObjectHandle{
|
oh := &QnObjectHandle{
|
||||||
key: "key",
|
key: "key",
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
bm: nil,
|
bm: nil,
|
||||||
|
@ -70,7 +70,7 @@ func isBuildSucceeded(jsonText []byte) bool {
|
|||||||
|
|
||||||
// FindBaseProfileFromQiniu finds the coverage profile file from the latest healthy build
|
// FindBaseProfileFromQiniu finds the coverage profile file from the latest healthy build
|
||||||
// stored in given gcs directory
|
// stored in given gcs directory
|
||||||
func FindBaseProfileFromQiniu(qc *Client, prowJobName, covProfileName string) ([]byte, error) {
|
func FindBaseProfileFromQiniu(qc Client, prowJobName, covProfileName string) ([]byte, error) {
|
||||||
dirOfJob := path.Join("logs", prowJobName)
|
dirOfJob := path.Join("logs", prowJobName)
|
||||||
prefix := dirOfJob + "/"
|
prefix := dirOfJob + "/"
|
||||||
strBuilds, err := qc.ListSubDirs(prefix)
|
strBuilds, err := qc.ListSubDirs(prefix)
|
||||||
@ -107,20 +107,27 @@ func FindBaseProfileFromQiniu(qc *Client, prowJobName, covProfileName string) ([
|
|||||||
return qc.ReadObject(profilePath)
|
return qc.ReadObject(profilePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Artifacts prepresents the rule to store test artifacts in prow
|
// Artifacts is the interface of the rule to store test artifacts in prow
|
||||||
type Artifacts struct {
|
type Artifacts interface {
|
||||||
|
ProfilePath() string
|
||||||
|
CreateChangedProfile() *os.File
|
||||||
|
GetChangedProfileName() string
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProfileArtifacts presents the rule to store test artifacts in prow
|
||||||
|
type ProfileArtifacts struct {
|
||||||
Directory string
|
Directory string
|
||||||
ProfileName string
|
ProfileName string
|
||||||
ChangedProfileName string // create temporary to save changed file related coverage profile
|
ChangedProfileName string // create temporary to save changed file related coverage profile
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProfilePath returns a full path for profile
|
// ProfilePath returns a full path for profile
|
||||||
func (a *Artifacts) ProfilePath() string {
|
func (a *ProfileArtifacts) ProfilePath() string {
|
||||||
return path.Join(a.Directory, a.ProfileName)
|
return path.Join(a.Directory, a.ProfileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateChangedProfile creates a profile in order to store the most related files based on Github Pull Request
|
// CreateChangedProfile creates a profile in order to store the most related files based on Github Pull Request
|
||||||
func (a *Artifacts) CreateChangedProfile() *os.File {
|
func (a *ProfileArtifacts) CreateChangedProfile() *os.File {
|
||||||
if a.ChangedProfileName == "" {
|
if a.ChangedProfileName == "" {
|
||||||
log.Fatalf("param Artifacts.ChangedProfileName should not be empty")
|
log.Fatalf("param Artifacts.ChangedProfileName should not be empty")
|
||||||
}
|
}
|
||||||
@ -132,3 +139,8 @@ func (a *Artifacts) CreateChangedProfile() *os.File {
|
|||||||
|
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChangedProfileName get ChangedProfileName of the ProfileArtifacts
|
||||||
|
func (a *ProfileArtifacts) GetChangedProfileName() string {
|
||||||
|
return a.ChangedProfileName
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package qiniu
|
package qiniu
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@ -39,3 +40,31 @@ func TestFindBaseProfileFromQiniu(t *testing.T) {
|
|||||||
assert.Equal(t, err, nil)
|
assert.Equal(t, err, nil)
|
||||||
assert.Equal(t, string(getProfile), mockProfileContent)
|
assert.Equal(t, string(getProfile), mockProfileContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestArtifacts_ProfilePath(t *testing.T) {
|
||||||
|
p := &ProfileArtifacts{
|
||||||
|
Directory: "directory/",
|
||||||
|
ProfileName: "profile",
|
||||||
|
}
|
||||||
|
profilePath := p.ProfilePath()
|
||||||
|
assert.Equal(t, profilePath, "directory/profile")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProfileArtifacts_CreateChangedProfile(t *testing.T) {
|
||||||
|
p := &ProfileArtifacts{
|
||||||
|
ChangedProfileName: "test.cov",
|
||||||
|
}
|
||||||
|
file := p.CreateChangedProfile()
|
||||||
|
file.Close()
|
||||||
|
defer os.Remove(p.ChangedProfileName)
|
||||||
|
_, err := os.Stat(p.ChangedProfileName)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestProfileArtifacts_GetChangedProfileName(t *testing.T) {
|
||||||
|
p := &ProfileArtifacts{
|
||||||
|
ChangedProfileName: "change.cov",
|
||||||
|
}
|
||||||
|
name := p.GetChangedProfileName()
|
||||||
|
assert.Equal(t, name, "change.cov")
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user