github.com/joelanford/operator-sdk@v0.8.2/internal/pkg/scorecard/helpers.go (about) 1 // Copyright 2019 The Operator-SDK Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package scorecard 16 17 import ( 18 "fmt" 19 20 scapiv1alpha1 "github.com/operator-framework/operator-sdk/pkg/apis/scorecard/v1alpha1" 21 22 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 23 ) 24 25 // These functions should be in the public test definitions file, but they are not complete/stable, 26 // so we'll keep these here until they get fully implemented 27 28 // ResultsPassFail combines multiple test results and returns a single test results 29 // with 1 maximum point and either 0 or 1 earned points 30 func ResultsPassFail(results []TestResult) (TestResult, error) { 31 var name string 32 finalResult := TestResult{} 33 if len(results) > 0 { 34 name = results[0].Test.GetName() 35 // all results have the same test 36 finalResult.Test = results[0].Test 37 finalResult.MaximumPoints = 1 38 finalResult.EarnedPoints = 1 39 } 40 for _, result := range results { 41 if result.Test.IsCumulative() { 42 return finalResult, fmt.Errorf("cumulative test passed to ResultsPassFail: name (%s)", result.Test.GetName()) 43 } 44 if result.Test.GetName() != name { 45 return finalResult, fmt.Errorf("test name mismatch in ResultsPassFail: %s != %s", result.Test.GetName(), name) 46 } 47 if result.EarnedPoints != result.MaximumPoints { 48 finalResult.EarnedPoints = 0 49 } 50 finalResult.Suggestions = append(finalResult.Suggestions, result.Suggestions...) 51 finalResult.Errors = append(finalResult.Errors, result.Errors...) 52 } 53 return finalResult, nil 54 } 55 56 // ResultsCumulative takes multiple TestResults and returns a single TestResult with MaximumPoints 57 // equal to the sum of the MaximumPoints of the input and EarnedPoints as the sum of EarnedPoints 58 // of the input 59 func ResultsCumulative(results []TestResult) (TestResult, error) { 60 var name string 61 finalResult := TestResult{} 62 if len(results) > 0 { 63 name = results[0].Test.GetName() 64 // all results have the same test 65 finalResult.Test = results[0].Test 66 } 67 for _, result := range results { 68 if !result.Test.IsCumulative() { 69 return finalResult, fmt.Errorf("non-cumulative test passed to ResultsCumulative: name (%s)", result.Test.GetName()) 70 } 71 if result.Test.GetName() != name { 72 return finalResult, fmt.Errorf("test name mismatch in ResultsCumulative: %s != %s", result.Test.GetName(), name) 73 } 74 finalResult.EarnedPoints += result.EarnedPoints 75 finalResult.MaximumPoints += result.MaximumPoints 76 finalResult.Suggestions = append(finalResult.Suggestions, result.Suggestions...) 77 finalResult.Errors = append(finalResult.Errors, result.Errors...) 78 } 79 return finalResult, nil 80 } 81 82 // CalculateResult returns a ScorecardSuiteResult with the state and Tests fields set based on a slice of ScorecardTestResults 83 func CalculateResult(tests []scapiv1alpha1.ScorecardTestResult) scapiv1alpha1.ScorecardSuiteResult { 84 scorecardSuiteResult := scapiv1alpha1.ScorecardSuiteResult{} 85 scorecardSuiteResult.Tests = tests 86 scorecardSuiteResult = UpdateSuiteStates(scorecardSuiteResult) 87 return scorecardSuiteResult 88 } 89 90 // TestSuitesToScorecardOutput takes an array of test suites and generates a v1alpha1 ScorecardOutput object with the 91 // provided name, description, and log 92 func TestSuitesToScorecardOutput(suites []TestSuite, log string) scapiv1alpha1.ScorecardOutput { 93 test := scapiv1alpha1.ScorecardOutput{ 94 TypeMeta: metav1.TypeMeta{ 95 Kind: "ScorecardOutput", 96 APIVersion: "osdk.openshift.io/v1alpha1", 97 }, 98 Log: log, 99 } 100 scorecardSuiteResults := []scapiv1alpha1.ScorecardSuiteResult{} 101 for _, suite := range suites { 102 results := []scapiv1alpha1.ScorecardTestResult{} 103 for _, testResult := range suite.TestResults { 104 results = append(results, TestResultToScorecardTestResult(testResult)) 105 } 106 scorecardSuiteResult := CalculateResult(results) 107 scorecardSuiteResult.TotalScore = suite.TotalScore() 108 scorecardSuiteResult.Name = suite.GetName() 109 scorecardSuiteResult.Description = suite.GetDescription() 110 scorecardSuiteResult.Log = suite.Log 111 scorecardSuiteResults = append(scorecardSuiteResults, scorecardSuiteResult) 112 } 113 test.Results = scorecardSuiteResults 114 return test 115 } 116 117 // TestResultToScorecardTestResult is a helper function for converting from the TestResult type to the ScorecardTestResult type 118 func TestResultToScorecardTestResult(tr TestResult) scapiv1alpha1.ScorecardTestResult { 119 sctr := scapiv1alpha1.ScorecardTestResult{} 120 sctr.State = tr.State 121 sctr.Name = tr.Test.GetName() 122 sctr.Description = tr.Test.GetDescription() 123 sctr.EarnedPoints = tr.EarnedPoints 124 sctr.MaximumPoints = tr.MaximumPoints 125 sctr.Suggestions = tr.Suggestions 126 if sctr.Suggestions == nil { 127 sctr.Suggestions = []string{} 128 } 129 stringErrors := []string{} 130 for _, err := range tr.Errors { 131 stringErrors = append(stringErrors, err.Error()) 132 } 133 sctr.Errors = stringErrors 134 return sctr 135 } 136 137 // UpdateState updates the state of a TestResult. 138 func UpdateState(res scapiv1alpha1.ScorecardTestResult) scapiv1alpha1.ScorecardTestResult { 139 if res.State == scapiv1alpha1.ErrorState { 140 return res 141 } 142 if res.EarnedPoints == 0 { 143 res.State = scapiv1alpha1.FailState 144 } else if res.EarnedPoints < res.MaximumPoints { 145 res.State = scapiv1alpha1.PartialPassState 146 } else if res.EarnedPoints == res.MaximumPoints { 147 res.State = scapiv1alpha1.PassState 148 } 149 return res 150 // TODO: decide what to do if a Test incorrectly sets points (Earned > Max) 151 } 152 153 // UpdateSuiteStates update the state of each test in a suite and updates the count to the suite's states to match 154 func UpdateSuiteStates(suite scapiv1alpha1.ScorecardSuiteResult) scapiv1alpha1.ScorecardSuiteResult { 155 suite.TotalTests = len(suite.Tests) 156 // reset all state values 157 suite.Error = 0 158 suite.Fail = 0 159 suite.PartialPass = 0 160 suite.Pass = 0 161 for idx, test := range suite.Tests { 162 suite.Tests[idx] = UpdateState(test) 163 switch test.State { 164 case scapiv1alpha1.ErrorState: 165 suite.Error++ 166 case scapiv1alpha1.PassState: 167 suite.Pass++ 168 case scapiv1alpha1.PartialPassState: 169 suite.PartialPass++ 170 case scapiv1alpha1.FailState: 171 suite.Fail++ 172 } 173 } 174 return suite 175 } 176 177 func CombineScorecardOutput(outputs []scapiv1alpha1.ScorecardOutput, log string) scapiv1alpha1.ScorecardOutput { 178 output := scapiv1alpha1.ScorecardOutput{ 179 TypeMeta: metav1.TypeMeta{ 180 Kind: "ScorecardOutput", 181 APIVersion: "osdk.openshift.io/v1alpha1", 182 }, 183 Log: log, 184 } 185 for _, item := range outputs { 186 output.Results = append(output.Results, item.Results...) 187 } 188 return output 189 }