mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? (1) Generate JSON test summary, too (2) Tweak summary detail capture esp for `Await` ## Why? Allow AI agents to easily/quickly/cheaply inspect CI results. <img width="1582" height="707" alt="Screenshot 2026-05-25 at 6 46 13 PM" src="https://github.com/user-attachments/assets/ca232f52-4f6f-45cb-9b52-450d32999d0c" /> <img width="2158" height="254" alt="Screenshot 2026-05-25 at 6 47 03 PM" src="https://github.com/user-attachments/assets/447ccf28-bec7-424b-a961-630c44a02cb0" />
196 lines
7.2 KiB
Go
196 lines
7.2 KiB
Go
package testrunner
|
|
|
|
import (
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNewSummaryFromReports_RendersAssertionFailureRow(t *testing.T) {
|
|
report := mustReadReportFixture(t, "testdata/junit-assertion-failure.xml")
|
|
|
|
summary := mustNewMergedSummary(t, report)
|
|
require.Equal(t, []summaryRow{{
|
|
Kind: failureTypeFailed,
|
|
Name: "TestBar",
|
|
Details: " bar_test.go:9:\n Error Trace:\t__SOURCE__:2\n Error: \tNot equal:\n \texpected: 1\n \tactual : 2",
|
|
}}, summary.Rows)
|
|
}
|
|
|
|
func TestNewSummaryFromReports_EmptyWhenNoFailures(t *testing.T) {
|
|
s := newSummaryFromReports([]*junitReport{mustReadReportFixture(t, "testdata/junit-empty.xml")})
|
|
require.Empty(t, s.Rows)
|
|
}
|
|
|
|
func TestNewSummaryFromReports_KeepsFailureAndAlertRows(t *testing.T) {
|
|
failureReport := mustReadReportFixture(t, "testdata/junit-single-failure.xml")
|
|
failureReport.Suites[0].Testcases[0].Name = "TestFoo"
|
|
failureReport.Suites[0].Testcases[0].Failure.Data = "FAIL\n"
|
|
|
|
alertReport := mustReadReportFixture(t, "testdata/junit-alert-panic.xml")
|
|
|
|
summary := mustNewMergedSummary(t, failureReport, alertReport)
|
|
require.Equal(t, []summaryRow{
|
|
{Kind: failureTypeFailed, Name: "TestFoo", Details: "FAIL\n"},
|
|
{Kind: failureTypePanic, Name: "panic test (retry 1) (final)", Details: "panic: boom", Final: true},
|
|
}, summary.Rows)
|
|
}
|
|
|
|
func TestNewSummaryFromReports_RendersTrimmedFailureBodyRow(t *testing.T) {
|
|
report := mustReadReportFixture(t, "testdata/junit-unexpected-call-failure.xml")
|
|
|
|
summary := mustNewMergedSummary(t, report)
|
|
require.Equal(t, []summaryRow{{
|
|
Kind: failureTypeFailed,
|
|
Name: "TestBaz",
|
|
Details: " mock_file.go:42: Unexpected call to SomeMethod(...)\n expected call at foo_test.go:10 doesn't match argument at index 0.\n Got: \"actual\"\n Want: is equal to \"expected\"",
|
|
}}, summary.Rows)
|
|
}
|
|
|
|
func TestNewSummaryFromReports_RendersAlertRow(t *testing.T) {
|
|
report := mustReadReportFixture(t, "testdata/junit-alert-data-race.xml")
|
|
|
|
s := newSummaryFromReports([]*junitReport{report})
|
|
require.Equal(t, []summaryRow{{
|
|
Kind: failureTypeDataRace,
|
|
Name: "DATA RACE: Data race detected in TestFoo",
|
|
Details: "WARNING: DATA RACE\nWrite at 0x00c000123456 by goroutine 7:\n main.TestFoo()\n /path/to/foo_test.go:42 +0x123\n\nPrevious read at 0x00c000123456 by goroutine 8:\n main.TestFoo()\n /path/to/foo_test.go:43 +0x456",
|
|
}}, s.Rows)
|
|
}
|
|
|
|
func TestNewSummaryFromReports_MergesMultipleReports(t *testing.T) {
|
|
reportOld := mustReadReportFixture(t, "testdata/junit-single-failure.xml")
|
|
reportOld.Suites[0].Name = "SuiteA"
|
|
reportOld.Suites[0].Testcases[0].Name = "TestOld"
|
|
reportOld.Suites[0].Testcases[0].Failure.Data = "old failure"
|
|
|
|
reportNew := mustReadReportFixture(t, "testdata/junit-single-failure.xml")
|
|
reportNew.Suites[0].Name = "SuiteB"
|
|
reportNew.Suites[0].Testcases[0].Name = "TestNew"
|
|
reportNew.Suites[0].Testcases[0].Failure.Data = "new failure"
|
|
|
|
summary := newSummaryFromReports([]*junitReport{reportOld, reportNew})
|
|
require.Equal(t, []summaryRow{
|
|
{Kind: failureTypeFailed, Name: "TestNew", Details: "new failure"},
|
|
{Kind: failureTypeFailed, Name: "TestOld", Details: "old failure"},
|
|
}, summary.Rows)
|
|
}
|
|
|
|
func TestNewSummaryRow_TruncatesOversizedDetail(t *testing.T) {
|
|
detail := "head" + strings.Repeat("x", summaryMaxDetailBytes) + "tail"
|
|
|
|
row := newSummaryRow(failureTypeFailed, "TestStandalone", detail)
|
|
require.Equal(t, failureTypeFailed, row.Kind)
|
|
require.Equal(t, "TestStandalone", row.Name)
|
|
require.LessOrEqual(t, len(row.Details), summaryMaxDetailBytes)
|
|
require.Contains(t, row.Details, "head")
|
|
require.Contains(t, row.Details, "tail")
|
|
require.Contains(t, row.Details, summaryTruncatedMarker)
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_Markdown_RendersFailureRows(t *testing.T) {
|
|
failureReport := mustReadReportFixture(t, "testdata/junit-single-failure.xml")
|
|
failureReport.Suites[0].Testcases[0].Name = "TestFoo"
|
|
failureReport.Suites[0].Testcases[0].Failure.Data = "FAIL\n"
|
|
|
|
alertReport := mustReadReportFixture(t, "testdata/junit-alert-panic.xml")
|
|
|
|
s := mustNewMergedSummary(t, failureReport, alertReport).Markdown()
|
|
require.Contains(t, s, "<table>")
|
|
require.NotContains(t, s, "<th>Details</th>")
|
|
require.Contains(t, s, "<details><summary>TestFoo</summary>")
|
|
require.Contains(t, s, "<pre>FAIL\n</pre>")
|
|
require.Contains(t, s, "<details><summary>panic test (retry 1) (final)</summary>")
|
|
require.Contains(t, s, "❌ PANIC")
|
|
require.Equal(t, 2, strings.Count(s, "<tr><td>"))
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_Markdown_RendersTrimmedFailureBody(t *testing.T) {
|
|
report := mustReadReportFixture(t, "testdata/junit-unexpected-call-failure.xml")
|
|
|
|
s := mustNewMergedSummary(t, report).Markdown()
|
|
require.Contains(t, s, "<details><summary>TestBaz</summary>")
|
|
require.Contains(t, s, "Unexpected call to SomeMethod")
|
|
require.NotContains(t, s, "some setup log")
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_Markdown_RendersAlertRow(t *testing.T) {
|
|
report := mustReadReportFixture(t, "testdata/junit-alert-data-race.xml")
|
|
|
|
rendered := newSummaryFromReports([]*junitReport{report}).Markdown()
|
|
require.Contains(t, rendered, failureTypeDataRace)
|
|
require.Contains(t, rendered, "Write at 0x00c000123456 by goroutine 7")
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_Markdown_EmptyWhenNoFailures(t *testing.T) {
|
|
s := newSummaryFromReports([]*junitReport{mustReadReportFixture(t, "testdata/junit-empty.xml")})
|
|
require.Empty(t, s.Markdown())
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_Markdown_ShowsTruncatedDetail(t *testing.T) {
|
|
detail := "head" + strings.Repeat("x", summaryMaxDetailBytes) + "tail"
|
|
summary := summary{
|
|
Rows: []summaryRow{newSummaryRow(failureTypeFailed, "TestStandalone", detail)},
|
|
}
|
|
|
|
s := summary.Markdown()
|
|
require.Contains(t, s, "truncated")
|
|
require.Contains(t, s, "head")
|
|
require.Contains(t, s, "tail")
|
|
require.Less(t, len(s), summaryMarkdownMaxBytes)
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_Markdown_OmitsRowsWhenBudgetExceeded(t *testing.T) {
|
|
n := summaryMarkdownMaxBytes/summaryMaxDetailBytes + 1
|
|
rows := make([]summaryRow, n)
|
|
for i := range n {
|
|
rows[i] = summaryRow{
|
|
Kind: failureTypeFailed,
|
|
Name: "Test" + strconv.Itoa(i),
|
|
Details: strings.Repeat("x", summaryMaxDetailBytes),
|
|
}
|
|
}
|
|
|
|
s := (summary{Rows: rows}).Markdown()
|
|
require.Less(t, len(s), summaryMarkdownMaxBytes+len("</table>\n")+200)
|
|
require.Contains(t, s, "not shown")
|
|
require.Contains(t, s, "</table>")
|
|
}
|
|
|
|
func TestRenderSummaryFromReports_JSON(t *testing.T) {
|
|
failureReport := mustReadReportFixture(t, "testdata/junit-single-failure.xml")
|
|
failureReport.Suites[0].Testcases[0].Name = "TestFoo"
|
|
failureReport.Suites[0].Testcases[0].Failure.Data = "FAIL\n"
|
|
|
|
alertReport := mustReadReportFixture(t, "testdata/junit-alert-panic.xml")
|
|
|
|
summary := mustNewMergedSummary(t, failureReport, alertReport)
|
|
content, err := summary.JSON()
|
|
require.NoError(t, err)
|
|
|
|
require.JSONEq(t, `{
|
|
"rows": [
|
|
{
|
|
"kind": "Failed",
|
|
"name": "TestFoo",
|
|
"details": "FAIL\n"
|
|
},
|
|
{
|
|
"kind": "PANIC",
|
|
"name": "panic test (retry 1) (final)",
|
|
"details": "panic: boom",
|
|
"final": true
|
|
}
|
|
]
|
|
}`, string(content))
|
|
}
|
|
|
|
func mustNewMergedSummary(t *testing.T, reports ...*junitReport) summary {
|
|
t.Helper()
|
|
merged, err := mergeReports(reports)
|
|
require.NoError(t, err)
|
|
return newSummaryFromReports([]*junitReport{merged})
|
|
}
|