Skip to content

Commit f6bab25

Browse files
committed
Add go test transformer for Flakeguard
1 parent e53a303 commit f6bab25

File tree

7 files changed

+1672
-0
lines changed

7 files changed

+1672
-0
lines changed
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Go Test Transform
2+
3+
This utility transforms the output of Go's test JSON format to handle subtest failures more intelligently. It prevents parent tests from failing when only their subtests fail, while preserving the original test structure and output format.
4+
5+
## Features
6+
7+
- Transforms Go test JSON output to modify how test failures propagate
8+
- Parent tests won't fail if they only have failing subtests but no direct failures
9+
- Maintains the original JSON format for compatibility with other tools
10+
11+
## Key Behavior
12+
13+
- **Subtest Failure Handling**: When a subtest fails, the parent test will not be marked as failed unless the parent itself has a direct failure
14+
- **Important Note**: If a parent test has both log messages (`t.Log()`) and failing subtests, it will still be marked as failed, as seen in the `TestLogMessagesNotDirectFailures` test
15+
16+
## Usage
17+
18+
```bash
19+
go test -json ./... | go-test-transform -ignore-all
20+
```
21+
22+
This will transform the test output to prevent parent tests from failing when only their subtests fail.
23+
24+
## Options
25+
26+
- `-ignore-all`: Ignore all subtest failures
27+
- `-input`: Input file (default: stdin)
28+
- `-output`: Output file (default: stdout)
29+
30+
## Example
31+
32+
For a test structure like:
33+
34+
```go
35+
func TestParent(t *testing.T) {
36+
t.Run("Subtest1", func(t *testing.T) {
37+
t.Error("Subtest 1 failed")
38+
})
39+
}
40+
```
41+
42+
The transformed output will be:
43+
44+
```json
45+
{"Time":"2023-05-10T15:04:05.123Z","Action":"run","Package":"example/pkg","Test":"TestParent"}
46+
{"Time":"2023-05-10T15:04:05.124Z","Action":"run","Package":"example/pkg","Test":"TestParent/Subtest1"}
47+
{"Time":"2023-05-10T15:04:05.125Z","Action":"output","Package":"example/pkg","Test":"TestParent/Subtest1","Output":" subtest1_test.go:12: Subtest 1 failed\n"}
48+
{"Time":"2023-05-10T15:04:05.126Z","Action":"fail","Package":"example/pkg","Test":"TestParent/Subtest1","Elapsed":0.001}
49+
{"Time":"2023-05-10T15:04:05.127Z","Action":"pass","Package":"example/pkg","Test":"TestParent","Elapsed":0.004}
50+
{"Time":"2023-05-10T15:04:05.128Z","Action":"output","Package":"example/pkg","Output":"FAIL\texample/pkg\t0.004s\n"}
51+
{"Time":"2023-05-10T15:04:05.129Z","Action":"fail","Package":"example/pkg","Elapsed":0.005}
52+
```
53+
54+
Note that in the original output, both `TestParent/Subtest1` and `TestParent` would be marked as failed. After transformation, `TestParent/Subtest1` remains failed, but `TestParent` is changed to pass since it doesn't have a direct failure.
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package main
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"io"
7+
"os"
8+
9+
"github.com/smartcontractkit/chainlink-testing-framework/tools/flakeguard/go-test-transform/pkg/transformer"
10+
)
11+
12+
func main() {
13+
// Parse command-line flags
14+
var (
15+
ignoreAll bool
16+
inputFile string
17+
outputFile string
18+
)
19+
20+
flag.BoolVar(&ignoreAll, "ignore-all", false, "Ignore all subtest failures")
21+
flag.StringVar(&inputFile, "input", "", "Input JSON file (if not provided, reads from stdin)")
22+
flag.StringVar(&outputFile, "output", "", "File to write the report to (default: stdout)")
23+
flag.Parse()
24+
25+
// Set up options
26+
opts := transformer.NewOptions(ignoreAll)
27+
28+
// Determine input source
29+
var input io.Reader
30+
if inputFile != "" {
31+
// Read from file
32+
file, err := os.Open(inputFile)
33+
if err != nil {
34+
fmt.Fprintf(os.Stderr, "Error opening input file: %v\n", err)
35+
os.Exit(1)
36+
}
37+
defer file.Close()
38+
input = file
39+
} else {
40+
// Read from stdin
41+
input = os.Stdin
42+
}
43+
44+
// Determine output destination
45+
var output io.Writer
46+
if outputFile != "" {
47+
// Write to file
48+
file, err := os.Create(outputFile)
49+
if err != nil {
50+
fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
51+
os.Exit(1)
52+
}
53+
defer file.Close()
54+
output = file
55+
} else {
56+
// Write to stdout
57+
output = os.Stdout
58+
}
59+
60+
// Transform the output
61+
exitCode, err := transformer.TransformJSON(input, output, opts)
62+
if err != nil {
63+
fmt.Fprintf(os.Stderr, "Error transforming JSON: %v\n", err)
64+
os.Exit(1)
65+
}
66+
67+
// Exit with the appropriate code
68+
os.Exit(exitCode)
69+
}
2.91 MB
Binary file not shown.

0 commit comments

Comments
 (0)