@@ -16,6 +16,7 @@ import (
1616 "time"
1717
1818 "github.com/rs/zerolog/log"
19+ "github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/go-test-transform/pkg/transformer"
1920 "github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/reports"
2021)
2122
@@ -26,22 +27,23 @@ var (
2627
2728// Runner describes the test run parameters and raw test outputs
2829type Runner struct {
29- ProjectPath string // Path to the Go project directory.
30- prettyProjectPath string // Go project package path, formatted for pretty printing.
31- Verbose bool // If true, provides detailed logging.
32- RunCount int // Number of times to run the tests.
33- UseRace bool // Enable race detector.
34- Timeout time.Duration // Test timeout
35- Tags []string // Build tags.
36- UseShuffle bool // Enable test shuffling. -shuffle=on flag.
37- ShuffleSeed string // Set seed for test shuffling -shuffle={seed} flag. Must be used with UseShuffle.
38- FailFast bool // Stop on first test failure.
39- SkipTests []string // Test names to exclude.
40- SelectTests []string // Test names to include.
41- CollectRawOutput bool // Set to true to collect test output for later inspection.
42- OmitOutputsOnSuccess bool // Set to true to omit test outputs on success.
43- MaxPassRatio float64 // Maximum pass ratio threshold for a test to be considered flaky.
44- rawOutputs map [string ]* bytes.Buffer
30+ ProjectPath string // Path to the Go project directory.
31+ prettyProjectPath string // Go project package path, formatted for pretty printing.
32+ Verbose bool // If true, provides detailed logging.
33+ RunCount int // Number of times to run the tests.
34+ UseRace bool // Enable race detector.
35+ Timeout time.Duration // Test timeout
36+ Tags []string // Build tags.
37+ UseShuffle bool // Enable test shuffling. -shuffle=on flag.
38+ ShuffleSeed string // Set seed for test shuffling -shuffle={seed} flag. Must be used with UseShuffle.
39+ FailFast bool // Stop on first test failure.
40+ SkipTests []string // Test names to exclude.
41+ SelectTests []string // Test names to include.
42+ CollectRawOutput bool // Set to true to collect test output for later inspection.
43+ OmitOutputsOnSuccess bool // Set to true to omit test outputs on success.
44+ MaxPassRatio float64 // Maximum pass ratio threshold for a test to be considered flaky.
45+ IgnoreParentFailuresOnSubtests bool // Ignore failures in parent tests when only subtests fail.
46+ rawOutputs map [string ]* bytes.Buffer
4547}
4648
4749// RunTestPackages executes the tests for each provided package and aggregates all results.
@@ -283,6 +285,15 @@ func (e entry) String() string {
283285// Subtests add more complexity, as panics in subtests are only reported in their parent's output,
284286// and cannot be accurately attributed to the subtest that caused them.
285287func (r * Runner ) parseTestResults (filePaths []string ) ([]reports.TestResult , error ) {
288+ // If the option is enabled, transform each JSON output file before parsing.
289+ if r .IgnoreParentFailuresOnSubtests {
290+ transformedPaths , err := r .transformTestOutputFiles (filePaths )
291+ if err != nil {
292+ return nil , err
293+ }
294+ filePaths = transformedPaths
295+ }
296+
286297 var (
287298 testDetails = make (map [string ]* reports.TestResult ) // Holds run, pass counts, and other details for each test
288299 panickedPackages = map [string ]struct {}{} // Packages with tests that panicked
@@ -595,6 +606,36 @@ func (r *Runner) parseTestResults(filePaths []string) ([]reports.TestResult, err
595606 return results , nil
596607}
597608
609+ // transformTestOutputFiles transforms the test output JSON files to ignore parent failures when only subtests fail.
610+ // It returns the paths to the transformed files.
611+ func (r * Runner ) transformTestOutputFiles (filePaths []string ) ([]string , error ) {
612+ transformedPaths := make ([]string , len (filePaths ))
613+ for i , origPath := range filePaths {
614+ inFile , err := os .Open (origPath )
615+ if err != nil {
616+ return nil , fmt .Errorf ("failed to open original file %s: %w" , origPath , err )
617+ }
618+ // Create a temporary file for the transformed output.
619+ outFile , err := os .CreateTemp ("" , "transformed-output-*.json" )
620+ if err != nil {
621+ inFile .Close ()
622+ return nil , fmt .Errorf ("failed to create transformed temp file: %w" , err )
623+ }
624+ // Transform the JSON output.
625+ // The transformer option is set to ignore parent failures when only subtests fail.
626+ err = transformer .TransformJSON (inFile , outFile , transformer .NewOptions (true ))
627+ inFile .Close ()
628+ outFile .Close ()
629+ if err != nil {
630+ return nil , fmt .Errorf ("failed to transform output file %s: %v" , origPath , err )
631+ }
632+ // Use the transformed file path.
633+ transformedPaths [i ] = outFile .Name ()
634+ os .Remove (origPath )
635+ }
636+ return transformedPaths , nil
637+ }
638+
598639// attributePanicToTest properly attributes panics to the test that caused them.
599640func attributePanicToTest (panicPackage string , panicEntries []entry ) (test string , timeout bool , err error ) {
600641 regexSanitizePanicPackage := filepath .Base (panicPackage )
0 commit comments