Skip to content

Commit d2be86a

Browse files
committed
Add more unit tests for flakeguard
1 parent cb4c307 commit d2be86a

File tree

10 files changed

+385
-15
lines changed

10 files changed

+385
-15
lines changed

tools/flakeguard/cmd/find.go

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,6 @@ func findAffectedPackages(baseRef, projectPath string, excludes []string, levels
154154

155155
func outputResults(packages []string, jsonOutput bool) {
156156
if jsonOutput {
157-
if packages == nil {
158-
packages = make([]string, 0) // Ensure the slice is initialized to an empty array
159-
}
160157
data, err := json.Marshal(packages)
161158
if err != nil {
162159
log.Fatalf("Error marshaling test files to JSON: %v", err)

tools/flakeguard/cmd/run.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ var RunTestsCmd = &cobra.Command{
5757
if len(failedTests) > 0 {
5858
fmt.Printf("PassRatio threshold for flaky tests: %.2f\n", threshold)
5959
fmt.Printf("%d failed tests:\n", len(failedTests))
60-
reports.PrintTests(failedTests)
60+
reports.PrintTests(failedTests, os.Stdout)
6161
}
6262

6363
fmt.Printf("Summary: %d passed, %d skipped, %d failed\n", len(passedTests), len(skippedTests), len(failedTests))

tools/flakeguard/go.mod

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@ go 1.21.9
44

55
require github.com/spf13/cobra v1.8.1
66

7+
require (
8+
github.com/davecgh/go-spew v1.1.1 // indirect
9+
github.com/pmezard/go-difflib v1.0.0 // indirect
10+
gopkg.in/yaml.v3 v3.0.1 // indirect
11+
)
12+
713
require (
814
github.com/inconshreveable/mousetrap v1.1.0 // indirect
915
github.com/spf13/pflag v1.0.5 // indirect
16+
github.com/stretchr/testify v1.9.0
1017
)

tools/flakeguard/go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
35
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
6+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
7+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
48
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
59
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
610
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
711
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
812
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
13+
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
14+
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
915
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
16+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
1017
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

tools/flakeguard/golang/golang.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ func GetFilePackages(files []string) ([]string, error) {
168168
}
169169

170170
// Function to check if a package contains any test functions
171-
func hasTests(pkgName string) (bool, error) {
171+
var hasTests = func(pkgName string) (bool, error) {
172172
cmd := exec.Command("go", "test", pkgName, "-run=^$", "-list", ".")
173173

174174
var out bytes.Buffer
@@ -184,7 +184,7 @@ func hasTests(pkgName string) (bool, error) {
184184

185185
// Filter out test packages with no actual test functions
186186
func FilterPackagesWithTests(pkgs []string) []string {
187-
var testPkgs []string
187+
testPkgs := []string{}
188188
for _, pkg := range pkgs {
189189
hasT, err := hasTests(pkg)
190190
if err != nil {
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package golang
2+
3+
import (
4+
"errors"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
// Mock version of hasTests function to simulate various scenarios
11+
func mockHasTests(pkgName string) (bool, error) {
12+
switch pkgName {
13+
case "pkgWithTests":
14+
return true, nil
15+
case "pkgWithoutTests":
16+
return false, nil
17+
case "pkgWithError":
18+
return false, errors.New("test error")
19+
default:
20+
return false, nil
21+
}
22+
}
23+
24+
func TestFilterPackagesWithTests(t *testing.T) {
25+
// Replace hasTests with mock function
26+
originalHasTests := hasTests
27+
hasTests = mockHasTests
28+
defer func() { hasTests = originalHasTests }() // Restore original function after test
29+
30+
t.Run("should return packages that contain tests", func(t *testing.T) {
31+
pkgs := []string{"pkgWithTests", "pkgWithoutTests", "pkgWithError"}
32+
expected := []string{"pkgWithTests"}
33+
34+
result := FilterPackagesWithTests(pkgs)
35+
36+
assert.Equal(t, expected, result, "Expected packages with tests only")
37+
})
38+
39+
t.Run("should return an empty slice when all packages have no tests", func(t *testing.T) {
40+
pkgs := []string{"pkgWithoutTests"}
41+
expected := []string{}
42+
43+
result := FilterPackagesWithTests(pkgs)
44+
45+
assert.Equal(t, expected, result, "Expected empty slice for packages without tests")
46+
})
47+
48+
t.Run("should handle error scenarios gracefully", func(t *testing.T) {
49+
pkgs := []string{"pkgWithError"}
50+
expected := []string{}
51+
52+
result := FilterPackagesWithTests(pkgs)
53+
54+
assert.Equal(t, expected, result, "Expected empty slice for packages with errors")
55+
})
56+
}

tools/flakeguard/reports/reports.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package reports
22

33
import (
44
"fmt"
5+
"io"
56
"strings"
67
)
78

@@ -49,19 +50,19 @@ func FilterSkippedTests(results []TestResult) []TestResult {
4950
}
5051

5152
// PrintTests prints tests in a pretty format
52-
func PrintTests(tests []TestResult) {
53+
func PrintTests(tests []TestResult, w io.Writer) {
5354
for i, test := range tests {
54-
fmt.Printf("\n--- Test %d ---\n", i+1)
55-
fmt.Printf("TestName: %s\n", test.TestName)
56-
fmt.Printf("TestPackage: %s\n", test.TestPackage)
57-
fmt.Printf("PassRatio: %.2f\n", test.PassRatio)
58-
fmt.Printf("Skipped: %v\n", test.Skipped)
59-
fmt.Printf("Runs: %d\n", test.Runs)
55+
fmt.Fprintf(w, "\n--- Test %d ---\n", i+1)
56+
fmt.Fprintf(w, "TestName: %s\n", test.TestName)
57+
fmt.Fprintf(w, "TestPackage: %s\n", test.TestPackage)
58+
fmt.Fprintf(w, "PassRatio: %.2f\n", test.PassRatio)
59+
fmt.Fprintf(w, "Skipped: %v\n", test.Skipped)
60+
fmt.Fprintf(w, "Runs: %d\n", test.Runs)
6061
durationsStr := make([]string, len(test.Durations))
6162
for i, duration := range test.Durations {
6263
durationsStr[i] = fmt.Sprintf("%.2fs", duration)
6364
}
64-
fmt.Printf("Durations: %s\n", strings.Join(durationsStr, ", "))
65-
fmt.Printf("Outputs:\n%s\n", strings.Join(test.Outputs, ""))
65+
fmt.Fprintf(w, "Durations: %s\n", strings.Join(durationsStr, ", "))
66+
fmt.Fprintf(w, "Outputs:\n%s\n", strings.Join(test.Outputs, ""))
6667
}
6768
}
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package reports
2+
3+
import (
4+
"bytes"
5+
"strings"
6+
"testing"
7+
)
8+
9+
func TestFilterFailedTests(t *testing.T) {
10+
results := []TestResult{
11+
{TestName: "Test1", PassRatio: 0.5, Skipped: false},
12+
{TestName: "Test2", PassRatio: 0.9, Skipped: false},
13+
{TestName: "Test3", PassRatio: 0.3, Skipped: false},
14+
{TestName: "Test4", PassRatio: 0.8, Skipped: true}, // Skipped test
15+
}
16+
17+
failedTests := FilterFailedTests(results, 0.6)
18+
expected := []string{"Test1", "Test3"}
19+
20+
if len(failedTests) != len(expected) {
21+
t.Fatalf("expected %d failed tests, got %d", len(expected), len(failedTests))
22+
}
23+
24+
for i, test := range failedTests {
25+
if test.TestName != expected[i] {
26+
t.Errorf("expected test %s, got %s", expected[i], test.TestName)
27+
}
28+
}
29+
}
30+
31+
func TestFilterPassedTests(t *testing.T) {
32+
results := []TestResult{
33+
{TestName: "Test1", PassRatio: 0.7, Skipped: false},
34+
{TestName: "Test2", PassRatio: 1.0, Skipped: false},
35+
{TestName: "Test3", PassRatio: 0.3, Skipped: false},
36+
{TestName: "Test4", PassRatio: 0.8, Skipped: true}, // Skipped test
37+
}
38+
39+
passedTests := FilterPassedTests(results, 0.6)
40+
expected := []string{"Test1", "Test2"}
41+
42+
if len(passedTests) != len(expected) {
43+
t.Fatalf("expected %d passed tests, got %d", len(expected), len(passedTests))
44+
}
45+
46+
for i, test := range passedTests {
47+
if test.TestName != expected[i] {
48+
t.Errorf("expected test %s, got %s", expected[i], test.TestName)
49+
}
50+
}
51+
}
52+
53+
func TestFilterSkippedTests(t *testing.T) {
54+
results := []TestResult{
55+
{TestName: "Test1", PassRatio: 0.7, Skipped: false},
56+
{TestName: "Test2", PassRatio: 1.0, Skipped: true},
57+
{TestName: "Test3", PassRatio: 0.3, Skipped: false},
58+
{TestName: "Test4", PassRatio: 0.8, Skipped: true},
59+
}
60+
61+
skippedTests := FilterSkippedTests(results)
62+
expected := []string{"Test2", "Test4"}
63+
64+
if len(skippedTests) != len(expected) {
65+
t.Fatalf("expected %d skipped tests, got %d", len(expected), len(skippedTests))
66+
}
67+
68+
for i, test := range skippedTests {
69+
if test.TestName != expected[i] {
70+
t.Errorf("expected test %s, got %s", expected[i], test.TestName)
71+
}
72+
}
73+
}
74+
75+
func TestPrintTests(t *testing.T) {
76+
tests := []TestResult{
77+
{
78+
TestName: "Test1",
79+
TestPackage: "package1",
80+
PassRatio: 0.75,
81+
Skipped: false,
82+
Runs: 4,
83+
Outputs: []string{"Output1", "Output2"},
84+
Durations: []float64{1.2, 0.9, 1.1, 1.0},
85+
},
86+
}
87+
88+
// Use a buffer to capture the output
89+
var buf bytes.Buffer
90+
91+
// Call PrintTests with the buffer
92+
PrintTests(tests, &buf)
93+
94+
// Get the output as a string
95+
output := buf.String()
96+
expectedContains := []string{
97+
"TestName: Test1",
98+
"TestPackage: package1",
99+
"PassRatio: 0.75",
100+
"Skipped: false",
101+
"Runs: 4",
102+
"Durations: 1.20s, 0.90s, 1.10s, 1.00s",
103+
"Outputs:\nOutput1Output2",
104+
}
105+
106+
for _, expected := range expectedContains {
107+
if !strings.Contains(output, expected) {
108+
t.Errorf("expected output to contain %q, but it did not", expected)
109+
}
110+
}
111+
}

tools/flakeguard/utils/cmd_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package utils
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestExecuteCmd(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
cmd string
12+
args []string
13+
expectedOut string
14+
expectedErr string
15+
expectingFail bool
16+
}{
17+
{
18+
name: "successful command",
19+
cmd: "echo",
20+
args: []string{"Hello, world!"},
21+
expectedOut: "Hello, world!\n",
22+
expectedErr: "",
23+
},
24+
{
25+
name: "successful command with no args",
26+
cmd: "echo",
27+
args: []string{},
28+
expectedOut: "\n",
29+
expectedErr: "",
30+
},
31+
{
32+
name: "nonexistent command",
33+
cmd: "nonexistentcommand",
34+
args: []string{},
35+
expectedOut: "",
36+
expectingFail: true,
37+
},
38+
{
39+
name: "command with stderr",
40+
cmd: "ls",
41+
args: []string{"nonexistentfile"},
42+
expectedOut: "",
43+
expectedErr: "No such file or directory",
44+
expectingFail: true,
45+
},
46+
}
47+
48+
for _, tt := range tests {
49+
t.Run(tt.name, func(t *testing.T) {
50+
output, err := ExecuteCmd(tt.cmd, tt.args...)
51+
if (err != nil) != tt.expectingFail {
52+
t.Fatalf("expected failure: %v, got error: %v", tt.expectingFail, err)
53+
}
54+
55+
if output.Stdout.String() != tt.expectedOut {
56+
t.Errorf("unexpected stdout: expected %q, got %q", tt.expectedOut, output.Stdout.String())
57+
}
58+
59+
if !strings.Contains(output.Stderr.String(), tt.expectedErr) {
60+
t.Errorf("unexpected stderr: expected to contain %q, got %q", tt.expectedErr, output.Stderr.String())
61+
}
62+
})
63+
}
64+
}

0 commit comments

Comments
 (0)