Update hack/jenkins/test-flake-chart/report_flakes/report_flake.go

Co-authored-by: Steven Powell <44844360+spowelljr@users.noreply.github.com>
pull/19217/head
錦南路之花 2024-06-25 22:08:38 +02:00 committed by Medya Ghazizadeh
parent 60ab0cdad8
commit c2422d7337
2 changed files with 28 additions and 24 deletions

View File

@ -25,7 +25,7 @@ import (
) )
const ( const (
MAX_ITEM_ENV = 10 MaxItemEnv = 10
) )
// This program requires three arguments // This program requires three arguments
@ -33,6 +33,7 @@ const (
// $2 is the ROOT_JOB // $2 is the ROOT_JOB
// $3 is the file containing a list of finished environments, one item per line // $3 is the file containing a list of finished environments, one item per line
func main() { func main() {
ctx := context.Background()
client, err := storage.NewClient(context.Background()) client, err := storage.NewClient(context.Background())
if err != nil { if err != nil {
fmt.Printf("failed to connect to gcp: %v\n", err) fmt.Printf("failed to connect to gcp: %v\n", err)
@ -53,15 +54,15 @@ func main() {
os.Exit(1) os.Exit(1)
} }
// fetch the test results // fetch the test results
testSummaries, err := GetTestSummariesFromGcp(pr, rootJob, envList, client) testSummaries, err := TestSummariesFromGCP(ctx, pr, rootJob, envList, client)
if err != nil { if err != nil {
fmt.Printf("failed to load summaries: %v\n", err) fmt.Printf("failed to load summaries: %v\n", err)
os.Exit(1) os.Exit(1)
} }
// fetch the pre-calculated flake rates // fetch the pre-calculated flake rates
flakeRates, err := GetFlakeRate(client) flakeRates, err := GetFlakeRate(ctx, client)
if err != nil { if err != nil {
fmt.Println("failed to load flake rates: %v", err) fmt.Printf("failed to load flake rates: %v\n", err)
os.Exit(1) os.Exit(1)
} }
// generate and send the message // generate and send the message

View File

@ -20,6 +20,7 @@ import (
"context" "context"
"encoding/csv" "encoding/csv"
"encoding/json" "encoding/json"
"errors"
"fmt" "fmt"
"io" "io"
"os" "os"
@ -59,10 +60,10 @@ func ParseEnvironmentList(listFile string) ([]string, error) {
return strings.Split(strings.TrimSpace(string(data)), "\n"), nil return strings.Split(strings.TrimSpace(string(data)), "\n"), nil
} }
func TestSummariesFromGCP(pr, rootJob string, envList []string, client *storage.Client) (map[string]*ShortSummary, error) { func TestSummariesFromGCP(ctx context.Context, pr, rootJob string, envList []string, client *storage.Client) (map[string]*ShortSummary, error) {
envToSummaries := map[string]*ShortSummary{} envToSummaries := map[string]*ShortSummary{}
for _, env := range envList { for _, env := range envList {
if summary, err := getTestSummaryFromGCP(pr, rootJob, env, client); err == nil { if summary, err := testSummaryFromGCP(ctx, pr, rootJob, env, client); err == nil {
if summary != nil { if summary != nil {
// if the summary is nil(missing) we just skip it // if the summary is nil(missing) we just skip it
envToSummaries[env] = summary envToSummaries[env] = summary
@ -74,19 +75,18 @@ func TestSummariesFromGCP(pr, rootJob string, envList []string, client *storage.
return envToSummaries, nil return envToSummaries, nil
} }
// getFromSummary get the summary of a test on the specified env from the specified summary. // testFromSummary get the summary of a test on the specified env from the specified summary.
func getTestSummaryFromGCP(pr, rootJob, env string, client *storage.Client) (*ShortSummary, error) { func testSummaryFromGCP(ctx context.Context, pr, rootJob, env string, client *storage.Client) (*ShortSummary, error) {
ctx := context.TODO()
btk := client.Bucket("minikube-builds") btk := client.Bucket("minikube-builds")
obj := btk.Object(fmt.Sprintf("logs/%s/%s/%s_summary.json", pr, rootJob, env)) obj := btk.Object(fmt.Sprintf("logs/%s/%s/%s_summary.json", pr, rootJob, env))
reader, err := obj.NewReader(ctx) reader, err := obj.NewReader(ctx)
if errors.Is(err, storage.ErrObjectNotExist) {
// if this file does not exist, just skip it
return nil, nil
}
if err != nil { if err != nil {
if err == storage.ErrObjectNotExist {
// if this file does not exist, just skip it
return nil, nil
}
return nil, err return nil, err
} }
// read the file // read the file
@ -104,10 +104,10 @@ func getTestSummaryFromGCP(pr, rootJob, env string, client *storage.Client) (*Sh
} }
// GetFlakeRate downloaded recent flake rate from gcs, and return the map{env->map{testname->flake rate}} // GetFlakeRate downloaded recent flake rate from gcs, and return the map{env->map{testname->flake rate}}
func GetFlakeRate(client *storage.Client) (map[string]map[string]float64, error) { func GetFlakeRate(ctx context.Context, client *storage.Client) (map[string]map[string]float64, error) {
btk := client.Bucket("minikube-flake-rate") btk := client.Bucket("minikube-flake-rate")
obj := btk.Object("flake_rates.csv") obj := btk.Object("flake_rates.csv")
reader, err := obj.NewReader(context.Background()) reader, err := obj.NewReader(ctx)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read the flake rate file: %v", err) return nil, fmt.Errorf("failed to read the flake rate file: %v", err)
} }
@ -119,6 +119,10 @@ func GetFlakeRate(client *storage.Client) (map[string]map[string]float64, error)
result := map[string]map[string]float64{} result := map[string]map[string]float64{}
for i := 1; i < len(records); i++ { for i := 1; i < len(records); i++ {
// for each line in csv we extract env, test name and flake rate // for each line in csv we extract env, test name and flake rate
if len(records[i]) < 2 {
// the csv must have at least 2 columns
continue
}
env := records[i][0] env := records[i][0]
test := records[i][1] test := records[i][1]
flakeRate, err := strconv.ParseFloat(records[i][2], 64) flakeRate, err := strconv.ParseFloat(records[i][2], 64)
@ -134,7 +138,6 @@ func GetFlakeRate(client *storage.Client) (map[string]map[string]float64, error)
} }
func GenerateCommentMessage(summaries map[string]*ShortSummary, flakeRates map[string]map[string]float64, pr, rootJob string) string { func GenerateCommentMessage(summaries map[string]*ShortSummary, flakeRates map[string]map[string]float64, pr, rootJob string) string {
//builder := strings.Builder{}
type failedTest struct { type failedTest struct {
flakeRate float64 flakeRate float64
env string env string
@ -172,10 +175,10 @@ func GenerateCommentMessage(summaries map[string]*ShortSummary, flakeRates map[s
{"Environment", "Test Name", "Flake Rate"}, {"Environment", "Test Name", "Flake Rate"},
} }
// if an env has too much failures we will just skip it and print a message in the end // if an env has too much failures we will just skip it and print a message in the end
tooMuchFailure := []string{} tooManyFailures := []string{}
for env, list := range envFailedTestList { for env, list := range envFailedTestList {
if len(list) > MAX_ITEM_ENV { if len(list) > MaxItemEnv {
tooMuchFailure = append(tooMuchFailure, env) tooManyFailures = append(tooManyFailures, env)
continue continue
} }
for _, item := range list { for _, item := range list {
@ -193,13 +196,13 @@ func GenerateCommentMessage(summaries map[string]*ShortSummary, flakeRates map[s
builder := strings.Builder{} builder := strings.Builder{}
builder.WriteString( builder.WriteString(
fmt.Sprintf("Here are the number of top %d failed tests in each environments with lowest flake rate.\n\n", MAX_ITEM_ENV)) fmt.Sprintf("Here are the number of top %d failed tests in each environments with lowest flake rate.\n\n", MaxItemEnv))
builder.WriteString(generateMarkdownTable(table)) builder.WriteString(generateMarkdownTable(table))
if len(tooMuchFailure) > 0 { if len(tooManyFailures) > 0 {
builder.WriteString("\n\n Besides the following environments have too much failed tests:") builder.WriteString("\n\n Besides the following environments have too much failed tests:")
for _, env := range tooMuchFailure { for _, env := range tooManyFailures {
builder.WriteString(fmt.Sprintf("\n\n - %s: %d failed", env, len(envFailedTestList[env]))) builder.WriteString(fmt.Sprintf("\n\n - %s: %d failed %s ", env, len(envFailedTestList[env]), gopoghMDLink(pr, rootJob, env, "")))
} }
} }
builder.WriteString("\n\nTo see the flake rates of all tests by environment, click [here](https://minikube.sigs.k8s.io/docs/contrib/test_flakes/).") builder.WriteString("\n\nTo see the flake rates of all tests by environment, click [here](https://minikube.sigs.k8s.io/docs/contrib/test_flakes/).")
@ -231,7 +234,7 @@ func generateMarkdownTable(table [][]string) string {
if i != 0 { if i != 0 {
continue continue
} }
// generate the hyphens seperator // generate the hyphens separator
builder.WriteString("|") builder.WriteString("|")
for j := 0; j < len(group); j++ { for j := 0; j < len(group); j++ {
builder.WriteString(" ---- |") builder.WriteString(" ---- |")