k8s.io/test-infra@v0.0.0-20240520184403-27c6b4c223d8/gopherage/pkg/cov/junit/xmlwriter.go (about)

     1  /*
     2  Copyright 2018 The Kubernetes 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 takes coverage profile file as input and produces junit xml that is consumable by TestGrid
    18  
    19  package junit
    20  
    21  import (
    22  	"encoding/xml"
    23  	"fmt"
    24  
    25  	"golang.org/x/tools/cover"
    26  
    27  	"k8s.io/test-infra/gopherage/pkg/cov/junit/calculation"
    28  )
    29  
    30  // Property defines the xml element that stores the value of code coverage
    31  type Property struct {
    32  	Name  string `xml:"name,attr"`
    33  	Value string `xml:"value,attr"`
    34  }
    35  
    36  // Properties defines the xml element that stores the a list of properties that associated with one testcase
    37  type Properties struct {
    38  	PropertyList []Property `xml:"property"`
    39  }
    40  
    41  // TestCase defines the xml element that stores all information associated with one test case
    42  type TestCase struct {
    43  	ClassName    string     `xml:"class_name,attr"`
    44  	Name         string     `xml:"name,attr"`
    45  	Time         string     `xml:"time,attr"`
    46  	Failure      string     `xml:"failure,omitempty"`
    47  	PropertyList Properties `xml:"properties"`
    48  }
    49  
    50  // Testsuite defines the outer-most xml element that contains all test cases
    51  type Testsuite struct {
    52  	XMLName   string     `xml:"testsuite"`
    53  	Testcases []TestCase `xml:"testcase"`
    54  }
    55  
    56  func (ts *Testsuite) addTestCase(coverageTargetName string, ratio, threshold float32) {
    57  	testCase := TestCase{
    58  		ClassName: "go_coverage",
    59  		Name:      coverageTargetName,
    60  		Time:      "0",
    61  		PropertyList: Properties{
    62  			PropertyList: []Property{
    63  				{
    64  					Name:  "coverage",
    65  					Value: fmt.Sprintf("%.1f", ratio*100),
    66  				},
    67  			},
    68  		},
    69  	}
    70  	if ratio < threshold {
    71  		testCase.Failure = fmt.Sprintf("code coverage of %.0f%% is below threshold of %.0f%%", 100*ratio, 100*threshold)
    72  	}
    73  	ts.Testcases = append(ts.Testcases, testCase)
    74  }
    75  
    76  // toTestsuite populates Testsuite struct with data from CoverageList and actual file
    77  // directories from OS
    78  func toTestsuite(covList *calculation.CoverageList, coverageThreshold float32) Testsuite {
    79  	ts := Testsuite{}
    80  	ts.addTestCase("OVERALL", covList.Ratio(), coverageThreshold)
    81  
    82  	for _, cov := range covList.Group {
    83  		ts.addTestCase(cov.Name, cov.Ratio(), coverageThreshold)
    84  	}
    85  
    86  	for _, dir := range covList.ListDirectories() {
    87  		dirCov := covList.Subset(dir)
    88  		ts.addTestCase(dir, dirCov.Ratio(), coverageThreshold)
    89  	}
    90  	return ts
    91  }
    92  
    93  // ProfileToTestsuiteXML uses coverage profile to produce junit xml
    94  // which serves as the input for test coverage testgrid
    95  func ProfileToTestsuiteXML(profiles []*cover.Profile, coverageThreshold float32) ([]byte, error) {
    96  	covList := calculation.ProduceCovList(profiles)
    97  
    98  	ts := toTestsuite(covList, coverageThreshold)
    99  	return xml.MarshalIndent(ts, "", "    ")
   100  }