github.com/GoogleCloudPlatform/testgrid@v0.0.174/pkg/summarizer/analyzers/baseanalyzer.go (about)

     1  /*
     2  Copyright 2020 The TestGrid Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  // Package analyzers represents ways to analyze healthiness and flakiness of tests
    18  package analyzers
    19  
    20  import (
    21  	summarypb "github.com/GoogleCloudPlatform/testgrid/pb/summary"
    22  	"github.com/GoogleCloudPlatform/testgrid/pkg/summarizer/common"
    23  	"github.com/golang/protobuf/ptypes/timestamp"
    24  )
    25  
    26  // IntString is for sorting, primarily intended for map[string]int as implemented below
    27  type IntString struct {
    28  	s string
    29  	i int
    30  }
    31  
    32  // BaseAnalyzer implements functions that calculate flakiness as a ratio of failed tests to total tests
    33  type BaseAnalyzer struct {
    34  }
    35  
    36  // GetFlakiness returns a HealthinessInfo message with data to display flakiness as a ratio of failed tests
    37  // to total tests
    38  func (na *BaseAnalyzer) GetFlakiness(gridMetrics []*common.GridMetrics, minRuns int, startDate int, endDate int, tab string) *summarypb.HealthinessInfo {
    39  	testInfoList := []*summarypb.TestInfo{}
    40  	for _, test := range gridMetrics {
    41  		testInfo, success := calculateNaiveFlakiness(test, minRuns)
    42  		if !success {
    43  			continue
    44  		}
    45  		// TODO (itsazhuhere@): Introduce name parsing into test name and env
    46  		testInfo.DisplayName = test.Name
    47  		testInfoList = append(testInfoList, testInfo)
    48  	}
    49  	// Populate Healthiness with above calculated information
    50  	healthiness := createHealthiness(startDate, endDate, testInfoList)
    51  	return healthiness
    52  }
    53  
    54  func createHealthiness(startDate int, endDate int, testInfoList []*summarypb.TestInfo) *summarypb.HealthinessInfo {
    55  	healthiness := &summarypb.HealthinessInfo{
    56  		Start: intToTimestamp(startDate),
    57  		End:   intToTimestamp(endDate),
    58  		Tests: testInfoList,
    59  	}
    60  
    61  	var averageFlakiness float32
    62  	for _, testInfo := range healthiness.Tests {
    63  		averageFlakiness += testInfo.Flakiness
    64  	}
    65  	totalTests := int32(len(healthiness.Tests))
    66  	if totalTests > 0 {
    67  		healthiness.AverageFlakiness = averageFlakiness / float32(totalTests)
    68  	}
    69  	return healthiness
    70  }
    71  
    72  func calculateNaiveFlakiness(test *common.GridMetrics, minRuns int) (*summarypb.TestInfo, bool) {
    73  	failedCount := int32(test.Failed)
    74  	totalCount := int32(test.Passed) + int32(test.Failed)
    75  	totalCountWithInfra := totalCount + int32(test.FailedInfraCount)
    76  	if totalCount <= 0 || totalCount < int32(minRuns) {
    77  		return &summarypb.TestInfo{}, false
    78  	}
    79  	// Convert from map[string]int to map[string]int32
    80  	infraFailures := map[string]int32{}
    81  	for key, value := range test.InfraFailures {
    82  		infraFailures[key] = int32(value)
    83  	}
    84  
    85  	flakiness := 100 * float32(failedCount) / float32(totalCount)
    86  	testInfo := &summarypb.TestInfo{
    87  		Flakiness:          flakiness,
    88  		TotalNonInfraRuns:  totalCount,
    89  		TotalRunsWithInfra: totalCountWithInfra,
    90  		PassedNonInfraRuns: int32(test.Passed),
    91  		FailedNonInfraRuns: int32(test.Failed),
    92  		FailedInfraRuns:    int32(test.FailedInfraCount),
    93  		InfraFailures:      infraFailures,
    94  	}
    95  	return testInfo, true
    96  
    97  }
    98  
    99  func intToTimestamp(seconds int) *timestamp.Timestamp {
   100  	timestamp := &timestamp.Timestamp{
   101  		Seconds: int64(seconds),
   102  	}
   103  	return timestamp
   104  }