github.com/GoogleCloudPlatform/testgrid@v0.0.174/internal/result/results.go (about) 1 /* 2 Copyright 2019 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 result 18 19 import ( 20 "context" 21 22 configpb "github.com/GoogleCloudPlatform/testgrid/pb/config" 23 statepb "github.com/GoogleCloudPlatform/testgrid/pb/state" 24 statuspb "github.com/GoogleCloudPlatform/testgrid/pb/test_status" 25 ) 26 27 const ( 28 // IgnoreRunning maps RUNNING to NO_RESULT 29 IgnoreRunning = true 30 // ShowRunning maps RUNNING to UNKNOWN 31 ShowRunning = false 32 ) 33 34 var ( 35 statusSeverity = map[statuspb.TestStatus]int{ 36 statuspb.TestStatus_NO_RESULT: 0, 37 statuspb.TestStatus_BUILD_PASSED: 1, 38 statuspb.TestStatus_PASS: 2, 39 statuspb.TestStatus_PASS_WITH_SKIPS: 3, 40 statuspb.TestStatus_PASS_WITH_ERRORS: 4, 41 statuspb.TestStatus_RUNNING: 5, 42 statuspb.TestStatus_CATEGORIZED_ABORT: 6, 43 statuspb.TestStatus_UNKNOWN: 7, 44 statuspb.TestStatus_CANCEL: 8, 45 statuspb.TestStatus_BLOCKED: 9, 46 statuspb.TestStatus_FLAKY: 10, 47 statuspb.TestStatus_TOOL_FAIL: 11, 48 statuspb.TestStatus_TIMED_OUT: 12, 49 statuspb.TestStatus_CATEGORIZED_FAIL: 13, 50 statuspb.TestStatus_BUILD_FAIL: 14, 51 statuspb.TestStatus_FAIL: 15, 52 } 53 ) 54 55 // LTE returns if rowResult is less than or equal to compareTo. 56 func LTE(rowResult, compareTo statuspb.TestStatus) bool { 57 return statusSeverity[rowResult] <= statusSeverity[compareTo] 58 } 59 60 // GTE returns if rowResult is greater than or equal to compareTo. 61 func GTE(rowResult, compareTo statuspb.TestStatus) bool { 62 return statusSeverity[rowResult] >= statusSeverity[compareTo] 63 } 64 65 // Passing returns true if the test status is any passing status, 66 // including PASS_WITH_SKIPS, BUILD_PASSED, and more. 67 func Passing(rowResult statuspb.TestStatus) bool { 68 return GTE(rowResult, statuspb.TestStatus_BUILD_PASSED) && LTE(rowResult, statuspb.TestStatus_PASS_WITH_ERRORS) 69 } 70 71 // Failing returns true if the test status is any failing status, 72 // including CATEGORIZED_FAILURE, BUILD_FAIL, and more. 73 func Failing(rowResult statuspb.TestStatus) bool { 74 return GTE(rowResult, statuspb.TestStatus_TOOL_FAIL) && LTE(rowResult, statuspb.TestStatus_FAIL) 75 } 76 77 // Ignored returns true if the test status is any ignored status, 78 // configured via Config > DashboardTab > DashboardTabStatusCustomizationOptions > IgnoredTestStatuses 79 func Ignored(rowResult statuspb.TestStatus, opts *configpb.DashboardTabStatusCustomizationOptions) bool { 80 for _, ignoredStatus := range opts.GetIgnoredTestStatuses() { 81 if (ignoredStatus == configpb.DashboardTabStatusCustomizationOptions_CATEGORIZED_ABORT && rowResult == statuspb.TestStatus_CATEGORIZED_ABORT) || 82 (ignoredStatus == configpb.DashboardTabStatusCustomizationOptions_UNKNOWN && rowResult == statuspb.TestStatus_UNKNOWN) || 83 (ignoredStatus == configpb.DashboardTabStatusCustomizationOptions_CANCEL && rowResult == statuspb.TestStatus_CANCEL) || 84 (ignoredStatus == configpb.DashboardTabStatusCustomizationOptions_BLOCKED && rowResult == statuspb.TestStatus_BLOCKED) { 85 return true 86 } 87 } 88 return false 89 } 90 91 // Coalesce reduces the result to PASS, NO_RESULT, FAIL, FLAKY or UNKNOWN. 92 func Coalesce(result statuspb.TestStatus, ignoreRunning bool) statuspb.TestStatus { 93 // TODO(fejta): other result types, not used by k8s testgrid 94 if result == statuspb.TestStatus_NO_RESULT || result == statuspb.TestStatus_RUNNING && ignoreRunning { 95 return statuspb.TestStatus_NO_RESULT 96 } 97 if result == statuspb.TestStatus_FLAKY { 98 return result 99 } 100 if Failing(result) { 101 return statuspb.TestStatus_FAIL 102 } 103 if Passing(result) { 104 return statuspb.TestStatus_PASS 105 } 106 return statuspb.TestStatus_UNKNOWN 107 } 108 109 func iterSlow(ctx context.Context, results []int32) <-chan statuspb.TestStatus { 110 out := make(chan statuspb.TestStatus) 111 go func() { 112 defer close(out) 113 for i := 0; i+1 < len(results); i += 2 { 114 select { // Non-blocking check to see if we're done 115 case <-ctx.Done(): 116 return 117 default: 118 } 119 result := statuspb.TestStatus(results[i]) 120 count := results[i+1] 121 for count > 0 { 122 select { // Non-blocking check to see if we're done 123 case <-ctx.Done(): 124 return 125 default: 126 } 127 select { 128 case <-ctx.Done(): 129 return 130 case out <- result: 131 count-- 132 } 133 } 134 } 135 }() 136 return out 137 } 138 139 // Iter returns a function that returns the result for each column, decoding the run-length-encoding. 140 func Iter(results []int32) IterFunc { 141 return iterFast(results) 142 } 143 144 func iterFast(results []int32) IterFunc { 145 var i int 146 n := len(results) 147 var more int32 148 var status statuspb.TestStatus 149 return func() (statuspb.TestStatus, bool) { 150 for { 151 if more > 0 { 152 more-- 153 return status, true 154 } 155 if i+1 >= n { 156 return statuspb.TestStatus_NO_RESULT, false 157 } 158 status = statuspb.TestStatus(results[i]) 159 more = results[i+1] 160 i += 2 161 } 162 } 163 } 164 165 // IterFunc returns a result for each column (and then !ok). 166 // 167 // This decodes the run-length-encoding for a row's results. 168 type IterFunc func() (result statuspb.TestStatus, ok bool) 169 170 // Map returns a per-column result output channel for each row. 171 func Map(rows []*statepb.Row) map[string]IterFunc { 172 iters := map[string]IterFunc{} 173 for _, r := range rows { 174 iters[r.Name] = Iter(r.Results) 175 } 176 return iters 177 }