Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions internal/runner/analyze.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,13 @@ func Analyze(iterations []io.Reader, slowThreshold time.Duration) (*Report, LogM
interner := newStringInterner()
for i, r := range iterations {
if err := scanIterationJSONL(r, i, aggs, nil, slowThreshold, interner, tmpDir); err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
if err := reattributeTimeoutsIter(aggs, i, tmpDir); err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
if err := flushOutputsToDisk(i, aggs, tmpDir); err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
}
rep, logs := buildReportFromAggs(aggs, len(iterations), slowThreshold)
Expand Down Expand Up @@ -806,8 +803,7 @@ func AnalyzeResults(resultsDir string, slowThreshold time.Duration) (*Report, Lo

matches, err := filepath.Glob(filepath.Join(resultsDir, "iteration-*.log.jsonl"))
if err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
sort.Slice(matches, func(i, j int) bool {
return iterNumber(matches[i]) < iterNumber(matches[j])
Expand All @@ -823,16 +819,13 @@ func AnalyzeResults(resultsDir string, slowThreshold time.Duration) (*Report, Lo
defer func() { _ = f.Close() }()
return scanIterationJSONL(f, i, aggs, nil, slowThreshold, interner, tmpDir)
}(); err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
if err := reattributeTimeoutsIter(aggs, i, tmpDir); err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
if err := flushOutputsToDisk(i, aggs, tmpDir); err != nil {
cleanup()
return nil, nil, nil, err
return nil, nil, cleanup, err
}
}
rep, logs := buildReportFromAggs(aggs, len(matches), slowThreshold)
Expand Down
14 changes: 11 additions & 3 deletions internal/runner/analyze_bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ func BenchmarkAnalyze_RealThreeIterations(b *testing.B) {
for i, p := range payloads {
rs[i] = bytes.NewReader(p)
}
_, _, _, err := Analyze(rs, benchSlowThreshold)
_, _, cleanup, err := Analyze(rs, benchSlowThreshold)
if err != nil {
b.Fatal(err)
}
if cleanup != nil {
cleanup()
}
}
}

Expand Down Expand Up @@ -76,15 +79,20 @@ func BenchmarkAnalyzeResults_RealDir(b *testing.B) {
for _, p := range payloads {
total += int64(len(p))
}
if _, _, _, err := AnalyzeResults(dir, benchSlowThreshold); err != nil {
if _, _, cleanup, err := AnalyzeResults(dir, benchSlowThreshold); err != nil {
b.Fatalf("warm-up AnalyzeResults: %v", err)
} else if cleanup != nil {
cleanup()
}
b.ReportAllocs()
b.SetBytes(total)
for b.Loop() {
_, _, _, err := AnalyzeResults(dir, benchSlowThreshold)
_, _, cleanup, err := AnalyzeResults(dir, benchSlowThreshold)
if err != nil {
b.Fatal(err)
}
if cleanup != nil {
cleanup()
}
}
}
24 changes: 8 additions & 16 deletions internal/runner/analyze_files_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ func TestWriteLogFiles(t *testing.T) {
{"Action":"fail","Package":"github.com/foo/bar","Test":"TestFail","Elapsed":0.1}
`
dir := t.TempDir()
rep, logs, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iter), 30*time.Second)
require.Len(t, rep.Failures, 1)

require.NoError(t, WriteLogFiles(dir, rep, logs))
Expand Down Expand Up @@ -48,8 +47,7 @@ func TestWriteLogFilesWritesOnlyProblemIterations(t *testing.T) {
`,
}
dir := t.TempDir()
rep, logs, _, err := Analyze(readers(iters...), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iters...), 30*time.Second)
require.Len(t, rep.Flakes, 1)

require.NoError(t, WriteLogFiles(dir, rep, logs))
Expand Down Expand Up @@ -84,8 +82,7 @@ func TestWriteLogFilesCompressesSlowIterations(t *testing.T) {
`,
}
dir := t.TempDir()
rep, logs, _, err := Analyze(readers(iters...), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iters...), 30*time.Second)
require.Len(t, rep.Slow, 1)

require.NoError(t, WriteLogFiles(dir, rep, logs))
Expand All @@ -103,8 +100,7 @@ func TestWriteLogFilesTruncatesLongFilenames(t *testing.T) {
{"Action":"fail","Package":"github.com/foo/bar","Test":"` + longTest + `","Elapsed":0.1}
`
dir := t.TempDir()
rep, logs, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iter), 30*time.Second)
require.Len(t, rep.Failures, 1)

require.NoError(t, WriteLogFiles(dir, rep, logs))
Expand Down Expand Up @@ -155,8 +151,7 @@ func TestWriteLogFilesNoLogsForNonFlaggedTests(t *testing.T) {
{"Action":"pass","Package":"p","Test":"T","Elapsed":0.01}
`
dir := t.TempDir()
rep, logs, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iter), 30*time.Second)
assert.Empty(t, rep.Flakes)
assert.Empty(t, rep.Failures)
assert.Empty(t, rep.Timeouts)
Expand All @@ -174,8 +169,7 @@ func TestWriteLogFilesSkipsMissingTempPath(t *testing.T) {
{"Action":"fail","Package":"p","Test":"T","Elapsed":0.01}
`
dir := t.TempDir()
rep, logs, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iter), 30*time.Second)
require.Len(t, rep.Failures, 1)

key := testKey{Package: "p", Test: "T"}
Expand Down Expand Up @@ -208,8 +202,7 @@ func TestWriteCSV(t *testing.T) {
`,
}
dir := t.TempDir()
rep, _, _, err := Analyze(readers(iters...), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iters...), 30*time.Second)
require.NoError(t, WriteCSV(dir, rep))

f, err := os.Open(filepath.Join(dir, "report.csv")) //nolint:gosec // G304: path from filepath.Join
Expand Down Expand Up @@ -249,8 +242,7 @@ func TestWriteCSVRenamesSlowWhenAlsoTimeout(t *testing.T) {
{"Action":"fail","Package":"p","Test":"T","Elapsed":600.0}
`
dir := t.TempDir()
rep, _, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iter), 30*time.Second)
require.NoError(t, WriteCSV(dir, rep))

b, err := os.ReadFile(filepath.Join(dir, "report.csv")) //nolint:gosec // G304: path from filepath.Join
Expand Down
3 changes: 1 addition & 2 deletions internal/runner/analyze_mem_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ func TestAnalyzeMemory_Limit(t *testing.T) {
var before, after runtime.MemStats
runtime.ReadMemStats(&before)

rep, _, _, err := Analyze(readers, 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers, 30*time.Second)

runtime.ReadMemStats(&after)

Expand Down
74 changes: 38 additions & 36 deletions internal/runner/analyze_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ func readLogMapContent(t *testing.T, path string) string {
return string(b)
}

func analyze(t *testing.T, iterations []io.Reader, slowThreshold time.Duration) (*Report, LogMap) {
t.Helper()
rep, logs, cleanup, err := Analyze(iterations, slowThreshold)
if cleanup != nil {
t.Cleanup(cleanup)
}
require.NoError(t, err)
return rep, logs
}

func analyzeResults(t *testing.T, resultsDir string, slowThreshold time.Duration) (*Report, LogMap) {
t.Helper()
rep, logs, cleanup, err := AnalyzeResults(resultsDir, slowThreshold)
if cleanup != nil {
t.Cleanup(cleanup)
}
require.NoError(t, err)
return rep, logs
}

func readers(iters ...string) []io.Reader {
rs := make([]io.Reader, len(iters))
for i, s := range iters {
Expand All @@ -43,8 +63,7 @@ func TestAnalyzePackageLevelTimeoutIterationSummary(t *testing.T) {
{"Action":"fail","Package":"pkg/hang","Elapsed":120.0}
`,
}
rep, _, _, err := Analyze(readers(iterations...), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iterations...), 30*time.Second)
require.Len(t, rep.IterationSummaries, 1)
assert.Equal(t, "timeout", rep.IterationSummaries[0].Result)
}
Expand All @@ -55,8 +74,7 @@ func TestAnalyzeHandlesLongLines(t *testing.T) {
over := strings.Repeat("x", bufio.MaxScanTokenSize+1) + "\n"
iter := `{"Action":"pass","Package":"p","Test":"T","Elapsed":0.01}` + "\n" + over +
`{"Action":"pass","Package":"p","Test":"T2","Elapsed":0.01}` + "\n"
rep, _, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iter), 30*time.Second)
require.NotNil(t, rep)
require.Len(t, rep.IterationSummaries, 1)
assert.Equal(t, "pass", rep.IterationSummaries[0].Result)
Expand All @@ -72,8 +90,7 @@ badpkg.go:1:2: undefined: MissingType
` + `{"Action":"output","Package":"example.com/badpkg","Output":"# example.com/badpkg\n"}
{"Action":"fail","Package":"example.com/badpkg","Elapsed":0.0}
`
rep, _, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iter), 30*time.Second)
require.Len(t, rep.Failures, 1)
assert.Equal(t, "example.com/badpkg", rep.Failures[0].Package)
assert.Empty(t, rep.Failures[0].Test)
Expand Down Expand Up @@ -126,8 +143,7 @@ func TestAnalyzeTestdataFiles(t *testing.T) {
require.NoError(t, err)
defer func() { _ = f.Close() }()

rep, _, _, err := Analyze([]io.Reader{f}, 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, []io.Reader{f}, 30*time.Second)

require.Len(t, rep.IterationSummaries, 1)
assert.Equal(t, tc.wantResult, rep.IterationSummaries[0].Result)
Expand Down Expand Up @@ -167,8 +183,7 @@ func TestAnalyzePackageLevelFailureIterationSummary(t *testing.T) {
iterations := []string{
`{"Action":"fail","Package":"pkg/build","Elapsed":0.0}` + "\n",
}
rep, _, _, err := Analyze(readers(iterations...), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iterations...), 30*time.Second)
require.Len(t, rep.IterationSummaries, 1)
assert.Equal(t, "fail", rep.IterationSummaries[0].Result)
assert.Equal(t, []string{"pkg/build"}, rep.IterationSummaries[0].FailingTests)
Expand Down Expand Up @@ -454,8 +469,7 @@ func TestAnalyze(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
rep, _, _, err := Analyze(readers(tc.iterations...), tc.slowThreshold)
require.NoError(t, err)
rep, _ := analyze(t, readers(tc.iterations...), tc.slowThreshold)
assert.Equal(t, len(tc.iterations), rep.Iterations)
assert.Equal(t, tc.wantFlakes, publicTestEntries(rep.Flakes), "flakes")
assert.Equal(t, tc.wantFailures, publicTestEntries(rep.Failures), "failures")
Expand Down Expand Up @@ -629,8 +643,7 @@ func TestReportSummary(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
rep, _, _, err := Analyze(readers(tc.iterations...), tc.slowThreshold)
require.NoError(t, err)
rep, _ := analyze(t, readers(tc.iterations...), tc.slowThreshold)
tc.check(t, rep.Summary)
})
}
Expand All @@ -646,11 +659,10 @@ func TestPrintSummaryOverallContains(t *testing.T) {
{
name: "flake_rates_and_slow_line",
prep: func(t *testing.T) *Report {
rep, _, _, err := Analyze(readers(
rep, _ := analyze(t, readers(
`{"Action":"fail","Package":"pkg/foo","Test":"TestX","Elapsed":0.5}`,
`{"Action":"pass","Package":"pkg/foo","Test":"TestX","Elapsed":0.4}`,
), 30*time.Second)
require.NoError(t, err)
return rep
},
needle: []string{
Expand All @@ -666,11 +678,10 @@ func TestPrintSummaryOverallContains(t *testing.T) {
{
name: "iteration_wall_clock_runtimes",
prep: func(t *testing.T) *Report {
rep, _, _, err := Analyze(
rep, _ := analyze(t,
readers(`{"Action":"pass","Package":"p","Test":"T","Elapsed":0.01}`),
30*time.Second,
)
require.NoError(t, err)
require.NotNil(t, rep.Summary)
rep.IterationSummaries[0].Duration = 5 * time.Second
fillIterationRuntimeSummary(rep)
Expand Down Expand Up @@ -699,11 +710,10 @@ func TestPrintSummaryOverallContains(t *testing.T) {

func TestPrintSummaryOverall_usesSeverityColors(t *testing.T) {
t.Parallel()
rep, _, _, err := Analyze(readers(
rep, _ := analyze(t, readers(
`{"Action":"fail","Package":"pkg/foo","Test":"TestX","Elapsed":0.5}`,
`{"Action":"pass","Package":"pkg/foo","Test":"TestX","Elapsed":0.4}`,
), 30*time.Second)
require.NoError(t, err)
require.NotNil(t, rep.Summary)
s := rep.Summary

Expand Down Expand Up @@ -798,8 +808,7 @@ func TestAnalyzeCapturesLogsForFailures(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
rep, logs, _, err := Analyze(readers(tc.iterations...), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(tc.iterations...), 30*time.Second)
var entries []TestEntry
switch tc.category {
case "flakes":
Expand Down Expand Up @@ -828,8 +837,7 @@ func TestAnalyzeReattributesTimeoutToRunningTests(t *testing.T) {
{"Action":"output","Package":"p","Test":"TestFast","Output":"goroutine 1 [chan receive]:\n"}
{"Action":"fail","Package":"p","Elapsed":5.01}
`
rep, logs, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, logs := analyze(t, readers(iter), 30*time.Second)

names := make([]string, 0, len(rep.Timeouts))
for _, e := range rep.Timeouts {
Expand All @@ -853,8 +861,7 @@ func TestAnalyzeKeepsTimeoutOnCulpritWhenItWasTheReportedTest(t *testing.T) {
{"Action":"output","Package":"p","Test":"TestSlow","Output":"\t\tTestSlow (5s)\n"}
{"Action":"fail","Package":"p","Elapsed":5.01}
`
rep, _, _, err := Analyze(readers(iter), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(iter), 30*time.Second)
require.Len(t, rep.Timeouts, 1)
assert.Equal(t, "TestSlow", rep.Timeouts[0].Test)
}
Expand Down Expand Up @@ -996,8 +1003,7 @@ func TestAnalyzeResultsRoundtrip(t *testing.T) {
must(t, os.WriteFile(filepath.Join(dir, "iteration-1.log.jsonl"),
[]byte(`{"Action":"pass","Package":"pkg/z","Test":"TestFlaky","Elapsed":0.1}`+"\n"), 0600))

rep, _, _, err := AnalyzeResults(dir, 30*time.Second)
require.NoError(t, err)
rep, _ := analyzeResults(t, dir, 30*time.Second)
require.Len(t, rep.Flakes, 1)
assert.Equal(t, "TestFlaky", rep.Flakes[0].Test)

Expand Down Expand Up @@ -1076,8 +1082,7 @@ func TestAnalyzeIterationSummaries(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
rep, _, _, err := Analyze(readers(tc.iterations...), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(tc.iterations...), 30*time.Second)
require.Len(t, rep.IterationSummaries, len(tc.want))
// Strip Duration/ShuffleSeed — set by runner, not Analyze.
got := make([]IterationSummary, len(rep.IterationSummaries))
Expand All @@ -1094,8 +1099,7 @@ func TestAnalyzeSkipsMalformedLines(t *testing.T) {
input := `not json at all
{"Action":"pass","Package":"p","Test":"T","Elapsed":0.01}
`
rep, _, _, err := Analyze(readers(input), 30*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, readers(input), 30*time.Second)
assert.Empty(t, rep.Flakes)
assert.Empty(t, rep.Failures)
}
Expand Down Expand Up @@ -1214,11 +1218,10 @@ func TestFillIterationRuntimeSummaryTable(t *testing.T) {

func TestMarshalAIDiagnoseComplete_fromAnalyze(t *testing.T) {
t.Parallel()
rep, _, _, err := Analyze(readers(
rep, _ := analyze(t, readers(
`{"Action":"fail","Package":"p","Test":"T","Elapsed":0.1}`,
`{"Action":"pass","Package":"p","Test":"T","Elapsed":0.1}`,
), 30*time.Second)
require.NoError(t, err)

raw, err := marshalAIDiagnoseComplete("/tmp/results", "/tmp/results/report.json", "/tmp/results/trace.json", rep)
require.NoError(t, err)
Expand All @@ -1237,8 +1240,7 @@ func TestAnalyzeSlowTestsNoDuplication(t *testing.T) {
iter := `{"Action":"pass","Package":"pkg/slow","Test":"TestSlow","Elapsed":10.0}
{"Action":"pass","Package":"pkg/slow","Elapsed":10.0}
`
rep, _, _, err := Analyze([]io.Reader{strings.NewReader(iter)}, 1*time.Second)
require.NoError(t, err)
rep, _ := analyze(t, []io.Reader{strings.NewReader(iter)}, 1*time.Second)

require.Len(t, rep.Slow, 1)
assert.Equal(t, "pkg/slow", rep.Slow[0].Package)
Expand Down
Loading
Loading