Skip to content

Commit d7fce23

Browse files
committed
Exclude job runs with internal and external infrastrcuture failures
Ignore runs with internal and external infrastrcuture failures while calculating pass percentages.
1 parent e5fa120 commit d7fce23

1 file changed

Lines changed: 86 additions & 15 deletions

File tree

tools/codegen/cmd/featuregate-test-analyzer.go

Lines changed: 86 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -196,11 +196,14 @@ func (o *FeatureGateTestAnalyzerOptions) Run(ctx context.Context) error {
196196
// Separate warnings and blocking errors
197197
blockingErrors := []error{}
198198
warnings := []error{}
199+
var blockingResults, warningResults []ValidationResult
199200
for _, vr := range validationResults {
200201
if vr.IsWarning {
201202
warnings = append(warnings, vr.Error)
203+
warningResults = append(warningResults, vr)
202204
} else {
203205
blockingErrors = append(blockingErrors, vr.Error)
206+
blockingResults = append(blockingResults, vr)
204207
}
205208
}
206209

@@ -269,24 +272,20 @@ func (o *FeatureGateTestAnalyzerOptions) Run(ctx context.Context) error {
269272

270273
if len(warnings) > 0 {
271274
md.Textf("**Non-blocking warnings (optional variants):**\n")
272-
for _, warn := range warnings {
273-
md.Textf(" - %s\n", warn.Error())
274-
}
275+
writeGroupedValidationResults(warningResults, md)
275276
md.Text("")
276277
}
277278

278279
if len(blockingErrors) > 0 {
279280
md.Textf("**Blocking errors:**\n")
280-
for _, err := range blockingErrors {
281-
md.Textf(" - %s\n", err.Error())
282-
}
281+
writeGroupedValidationResults(blockingResults, md)
283282
md.Text("")
284283
}
285284
md.Text("")
286285
}
287286

288287
// Only add blocking errors to the error list (warnings don't fail the job)
289-
errs = append(errs, blockingErrors...)
288+
errs = append(errs, groupErrorsByCategory(blockingResults)...)
290289
featureGateHTMLData = append(featureGateHTMLData, buildHTMLFeatureGateData(enabledFeatureGate, testingResults, blockingErrors, release))
291290

292291
}
@@ -429,14 +428,20 @@ func checkIfTestingIsSufficient(featureGate string, testingResults map[JobVarian
429428
Error: fmt.Errorf("warning: variant %v includes test data from candidate-tier jobs which are not covered by Component Readiness and lack standard regression protection",
430429
jobVariant),
431430
IsWarning: true,
431+
Category: CategoryCandidateTier,
432432
})
433433
}
434434

435+
if len(testedVariant.TestResults) == 0 {
436+
continue
437+
}
438+
435439
if len(testedVariant.TestResults) < requiredNumberOfTests {
436440
results = append(results, ValidationResult{
437441
Error: fmt.Errorf("error: only %d tests found, need at least %d for %q on %v",
438442
len(testedVariant.TestResults), requiredNumberOfTests, featureGate, jobVariant),
439443
IsWarning: isOptional,
444+
Category: CategoryInsufficientTests,
440445
})
441446
}
442447

@@ -450,7 +455,8 @@ func checkIfTestingIsSufficient(featureGate string, testingResults map[JobVarian
450455
results = append(results, ValidationResult{
451456
Error: fmt.Errorf("error: %q only has %d runs, need at least %d runs for %q on %v",
452457
testResults.TestName, testResults.TotalRuns, requiredNumberOfTestRunsPerVariant, featureGate, jobVariant),
453-
IsWarning: isOptional,
458+
IsWarning: isOptional,
459+
Category: CategoryInsufficientRuns,
454460
})
455461
}
456462
if testResults.TotalRuns == 0 {
@@ -464,6 +470,7 @@ func checkIfTestingIsSufficient(featureGate string, testingResults map[JobVarian
464470
Error: fmt.Errorf("error: %q only passed %d%%, need at least %d%% for %q on %v",
465471
testResults.TestName, displayActual, displayExpected, featureGate, jobVariant),
466472
IsWarning: isOptional,
473+
Category: CategoryPassRate,
467474
})
468475
}
469476
}
@@ -476,13 +483,15 @@ func checkIfTestingIsSufficient(featureGate string, testingResults map[JobVarian
476483
Error: fmt.Errorf("warning: \"install should succeed: overall\" test not found for Install feature gate %q on %v",
477484
featureGate, jobVariant),
478485
IsWarning: true,
486+
Category: CategoryInstallTest,
479487
})
480488
} else {
481489
if installTest.TotalRuns < requiredNumberOfTestRunsPerVariant {
482490
results = append(results, ValidationResult{
483491
Error: fmt.Errorf("error: \"install should succeed: overall\" only has %d runs, need at least %d runs for %q on %v",
484492
installTest.TotalRuns, requiredNumberOfTestRunsPerVariant, featureGate, jobVariant),
485493
IsWarning: isOptional,
494+
Category: CategoryInstallTest,
486495
})
487496
}
488497
if installTest.TotalRuns > 0 {
@@ -494,6 +503,7 @@ func checkIfTestingIsSufficient(featureGate string, testingResults map[JobVarian
494503
Error: fmt.Errorf("error: \"install should succeed: overall\" only passed %d%%, need at least %d%% for %q on %v",
495504
displayActual, displayExpected, featureGate, jobVariant),
496505
IsWarning: isOptional,
506+
Category: CategoryInstallTest,
497507
})
498508
}
499509
}
@@ -504,6 +514,46 @@ func checkIfTestingIsSufficient(featureGate string, testingResults map[JobVarian
504514
return results
505515
}
506516

517+
func groupErrorsByCategory(results []ValidationResult) []error {
518+
categoryOrder := []ValidationCategory{}
519+
grouped := map[ValidationCategory][]ValidationResult{}
520+
for _, vr := range results {
521+
if _, seen := grouped[vr.Category]; !seen {
522+
categoryOrder = append(categoryOrder, vr.Category)
523+
}
524+
grouped[vr.Category] = append(grouped[vr.Category], vr)
525+
}
526+
var errs []error
527+
for i, cat := range categoryOrder {
528+
if i > 0 {
529+
errs = append(errs, fmt.Errorf(""))
530+
}
531+
for _, vr := range grouped[cat] {
532+
errs = append(errs, vr.Error)
533+
}
534+
}
535+
return errs
536+
}
537+
538+
func writeGroupedValidationResults(results []ValidationResult, md *utils.Markdown) {
539+
categoryOrder := []ValidationCategory{}
540+
grouped := map[ValidationCategory][]ValidationResult{}
541+
for _, vr := range results {
542+
if _, seen := grouped[vr.Category]; !seen {
543+
categoryOrder = append(categoryOrder, vr.Category)
544+
}
545+
grouped[vr.Category] = append(grouped[vr.Category], vr)
546+
}
547+
for i, cat := range categoryOrder {
548+
if i > 0 {
549+
md.Text("")
550+
}
551+
for _, vr := range grouped[cat] {
552+
md.Textf(" - %s\n", vr.Error.Error())
553+
}
554+
}
555+
}
556+
507557
func writeTestingMarkDown(testingResults map[JobVariant]*TestingResults, md *utils.Markdown) {
508558
jobVariantsSet := sets.KeySet(testingResults)
509559
jobVariants := jobVariantsSet.UnsortedList()
@@ -798,11 +848,22 @@ type TestResults struct {
798848
FlakedRuns int
799849
}
800850

851+
type ValidationCategory string
852+
853+
const (
854+
CategoryCandidateTier ValidationCategory = "candidate-tier"
855+
CategoryInsufficientTests ValidationCategory = "insufficient-tests"
856+
CategoryInsufficientRuns ValidationCategory = "insufficient-runs"
857+
CategoryPassRate ValidationCategory = "pass-rate"
858+
CategoryInstallTest ValidationCategory = "install-test"
859+
)
860+
801861
// ValidationResult represents a validation error or warning
802862
type ValidationResult struct {
803863
Error error
804-
IsWarning bool // if true, this is a non-blocking warning (for optional variants)
805-
IsInfo bool // if true, this is informational telemetry (e.g., install test pass percentage)
864+
IsWarning bool // if true, this is a non-blocking warning (for optional variants)
865+
IsInfo bool // if true, this is informational telemetry (e.g., install test pass percentage)
866+
Category ValidationCategory // groups related results together in output
806867
}
807868

808869
func testResultByName(results []TestResults, testName string) *TestResults {
@@ -1311,17 +1372,25 @@ func verifyJobPassRate(client *http.Client, release string, job sippy.SippyJob,
13111372
return nil, fmt.Errorf("getting job %q results from sippy: %w", job.Name, err)
13121373
}
13131374

1314-
testResults := &TestResults{
1315-
TestName: job.Name,
1316-
TotalRuns: len(jobRuns),
1317-
}
1318-
13191375
triagedTestFailures, err := getTriagedTestFailuresFromSippy(client, release, variant)
13201376
if err != nil {
13211377
return nil, fmt.Errorf("getting triaged test failures from sippy: %w", err)
13221378
}
13231379

1380+
fmt.Printf("\nIgnoring job runs that have internal or external infrastructure failures from our analysis.\n\n")
1381+
1382+
infraFailures := 0
1383+
testResults := &TestResults{
1384+
TestName: job.Name,
1385+
TotalRuns: len(jobRuns),
1386+
}
1387+
13241388
for _, jobRun := range jobRuns {
1389+
if jobRun.OverallResult == "N" || jobRun.OverallResult == "n" {
1390+
infraFailures++
1391+
continue
1392+
}
1393+
13251394
if jobRun.OverallResult == "F" && !jobRun.KnownFailure {
13261395

13271396
untriagedTestFailures := []string{}
@@ -1348,6 +1417,8 @@ func verifyJobPassRate(client *http.Client, release string, job sippy.SippyJob,
13481417
testResults.SuccessfulRuns++
13491418
}
13501419

1420+
testResults.TotalRuns -= infraFailures
1421+
13511422
return testResults, nil
13521423
}
13531424

0 commit comments

Comments
 (0)