Skip to content

Commit 6aba80f

Browse files
committed
Generate separate test report for reruns of failed tests
1 parent d72264a commit 6aba80f

File tree

3 files changed

+42
-398
lines changed

3 files changed

+42
-398
lines changed

tools/flakeguard/cmd/run.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,29 @@ var RunTestsCmd = &cobra.Command{
148148
return
149149
}
150150

151+
// Rerun failed tests
152+
if rerunFailed > 0 {
153+
rerunReport, err := testRunner.RerunFailedTests(testReport.Results)
154+
if err != nil {
155+
log.Fatal().Err(err).Msg("Error rerunning failed tests")
156+
os.Exit(ErrorExitCode)
157+
}
158+
159+
// Filter tests that failed after reruns
160+
failedAfterRerun := reports.FilterTests(rerunReport.Results, func(tr reports.TestResult) bool {
161+
return !tr.Skipped && tr.Successes == 0
162+
})
163+
if len(failedAfterRerun) > 0 {
164+
log.Error().
165+
Int("tests", len(failedAfterRerun)).
166+
Int("reruns", rerunFailed).
167+
Msg("Tests still failing after reruns with 0 successes")
168+
os.Exit(ErrorExitCode)
169+
}
170+
171+
// TODO: save rerun test report to JSON file
172+
}
173+
151174
// Filter flaky tests using FilterTests
152175
flakyTests := reports.FilterTests(testReport.Results, func(tr reports.TestResult) bool {
153176
return !tr.Skipped && tr.PassRatio < passRatioThreshold

tools/flakeguard/runner/runner.go

Lines changed: 19 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -83,15 +83,15 @@ func (r *Runner) RunTestPackages(packages []string) (*reports.TestReport, error)
8383
}
8484

8585
// Rerun failing tests (only the unique tests).
86-
if r.RerunFailed > 0 {
87-
rerunResults, err := r.rerunFailedTests(results)
88-
if err != nil {
89-
return nil, fmt.Errorf("failed to rerun failing tests: %w", err)
90-
}
86+
// if r.RerunFailed > 0 {
87+
// rerunResults, err := r.rerunFailedTests(results)
88+
// if err != nil {
89+
// return nil, fmt.Errorf("failed to rerun failing tests: %w", err)
90+
// }
9191

92-
// Merge rerun results with initial results.
93-
mergeTestResults(&results, rerunResults)
94-
}
92+
// // Merge rerun results with initial results.
93+
// mergeTestResults(&results, rerunResults)
94+
// }
9595

9696
report := &reports.TestReport{
9797
GoProject: r.prettyProjectPath,
@@ -735,7 +735,7 @@ func prettyProjectPath(projectPath string) (string, error) {
735735
return "", fmt.Errorf("module path not found in go.mod")
736736
}
737737

738-
func (r *Runner) rerunFailedTests(results []reports.TestResult) ([]reports.TestResult, error) {
738+
func (r *Runner) RerunFailedTests(results []reports.TestResult) (*reports.TestReport, error) {
739739
// Group failing tests by package for more efficient reruns
740740
failingTestsByPackage := make(map[string][]string)
741741
for _, tr := range results {
@@ -797,7 +797,16 @@ func (r *Runner) rerunFailedTests(results []reports.TestResult) ([]reports.TestR
797797
return nil, fmt.Errorf("failed to parse rerun results: %w", err)
798798
}
799799

800-
return rerunResults, nil
800+
report := &reports.TestReport{
801+
GoProject: r.prettyProjectPath,
802+
RaceDetection: r.UseRace,
803+
ExcludedTests: r.SkipTests,
804+
SelectedTests: r.SelectTests,
805+
Results: rerunResults,
806+
MaxPassRatio: r.MaxPassRatio,
807+
}
808+
809+
return report, nil
801810
}
802811

803812
// buildGoTestCommandForTest builds a `go test` command specifically
@@ -819,82 +828,3 @@ func (r *Runner) buildGoTestCommandForTest(t reports.TestResult) []string {
819828

820829
return cmd
821830
}
822-
823-
// mergeTestResults merges additional test results into the existing results slice.
824-
func mergeTestResults(mainResults *[]reports.TestResult, additional []reports.TestResult) {
825-
for _, add := range additional {
826-
found := false
827-
for i, main := range *mainResults {
828-
if main.TestName == add.TestName && main.TestPackage == add.TestPackage {
829-
// Merge top-level stats
830-
(*mainResults)[i].Runs += add.Runs
831-
(*mainResults)[i].Successes += add.Successes
832-
(*mainResults)[i].Failures += add.Failures
833-
(*mainResults)[i].Skips += add.Skips
834-
835-
// Merge boolean flags (using OR operation)
836-
(*mainResults)[i].Panic = (*mainResults)[i].Panic || add.Panic
837-
(*mainResults)[i].Race = (*mainResults)[i].Race || add.Race
838-
(*mainResults)[i].Timeout = (*mainResults)[i].Timeout || add.Timeout
839-
(*mainResults)[i].Skipped = (*mainResults)[i].Skipped || add.Skipped
840-
(*mainResults)[i].PackagePanic = (*mainResults)[i].PackagePanic || add.PackagePanic
841-
842-
// Merge durations
843-
(*mainResults)[i].Durations = append((*mainResults)[i].Durations, add.Durations...)
844-
845-
// Merge maps for Outputs
846-
if (*mainResults)[i].Outputs == nil {
847-
(*mainResults)[i].Outputs = make(map[string][]string)
848-
}
849-
for runID, outputs := range add.Outputs {
850-
if existing, ok := (*mainResults)[i].Outputs[runID]; ok {
851-
(*mainResults)[i].Outputs[runID] = append(existing, outputs...)
852-
} else {
853-
(*mainResults)[i].Outputs[runID] = outputs
854-
}
855-
}
856-
857-
// Merge maps for PassedOutputs
858-
if (*mainResults)[i].PassedOutputs == nil {
859-
(*mainResults)[i].PassedOutputs = make(map[string][]string)
860-
}
861-
for runID, outputs := range add.PassedOutputs {
862-
if existing, ok := (*mainResults)[i].PassedOutputs[runID]; ok {
863-
(*mainResults)[i].PassedOutputs[runID] = append(existing, outputs...)
864-
} else {
865-
(*mainResults)[i].PassedOutputs[runID] = outputs
866-
}
867-
}
868-
869-
// Merge maps for FailedOutputs
870-
if (*mainResults)[i].FailedOutputs == nil {
871-
(*mainResults)[i].FailedOutputs = make(map[string][]string)
872-
}
873-
for runID, outputs := range add.FailedOutputs {
874-
if existing, ok := (*mainResults)[i].FailedOutputs[runID]; ok {
875-
(*mainResults)[i].FailedOutputs[runID] = append(existing, outputs...)
876-
} else {
877-
(*mainResults)[i].FailedOutputs[runID] = outputs
878-
}
879-
}
880-
881-
// Merge PackageOutputs
882-
(*mainResults)[i].PackageOutputs = append((*mainResults)[i].PackageOutputs, add.PackageOutputs...)
883-
884-
// Update pass ratio (consistent with parseTestResults default)
885-
if (*mainResults)[i].Runs > 0 {
886-
(*mainResults)[i].PassRatio = float64((*mainResults)[i].Successes) / float64((*mainResults)[i].Runs)
887-
} else {
888-
(*mainResults)[i].PassRatio = 1.0 // Default to 1.0 if no runs
889-
}
890-
891-
found = true
892-
break
893-
}
894-
}
895-
// If we didn't find a match, append this as a new test result
896-
if !found {
897-
*mainResults = append(*mainResults, add)
898-
}
899-
}
900-
}

0 commit comments

Comments
 (0)