mirror of
https://github.com/jstemmer/go-junit-report.git
synced 2025-04-05 21:18:08 -05:00
Use test level failure to indicate build failure
- Use single regex for package result line - Add capturing of package build failure output
This commit is contained in:
parent
3c05bc8cb6
commit
d10c0632c7
@ -37,7 +37,7 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if setExitCode && report.Failed() {
|
if setExitCode && report.Failures() > 0 {
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 160,
|
Time: 160,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestZ",
|
Name: "TestZ",
|
||||||
@ -54,9 +53,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 151,
|
Time: 151,
|
||||||
Result: parser.FAIL,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -86,9 +84,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 150,
|
Time: 150,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -115,9 +112,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 160,
|
Time: 160,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -142,9 +138,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 160,
|
Time: 160,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -170,9 +165,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name1",
|
Name: "package/name1",
|
||||||
Time: 160,
|
Time: 160,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -189,9 +183,8 @@ var testCases = []TestCase{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "package/name2",
|
Name: "package/name2",
|
||||||
Time: 151,
|
Time: 151,
|
||||||
Result: parser.FAIL,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -222,9 +215,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "test/package",
|
Name: "test/package",
|
||||||
Time: 160,
|
Time: 160,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -250,9 +242,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "github.com/dmitris/test-go-junit-report",
|
Name: "github.com/dmitris/test-go-junit-report",
|
||||||
Time: 440,
|
Time: 440,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestDoFoo",
|
Name: "TestDoFoo",
|
||||||
@ -277,9 +268,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 160,
|
Time: 160,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestZ",
|
Name: "TestZ",
|
||||||
@ -305,9 +295,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package1/foo",
|
Name: "package1/foo",
|
||||||
Time: 400,
|
Time: 400,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestA",
|
Name: "TestA",
|
||||||
@ -325,9 +314,8 @@ var testCases = []TestCase{
|
|||||||
CoveragePct: "10.0",
|
CoveragePct: "10.0",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "package2/bar",
|
Name: "package2/bar",
|
||||||
Time: 4200,
|
Time: 4200,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestC",
|
Name: "TestC",
|
||||||
@ -347,9 +335,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 50,
|
Time: 50,
|
||||||
Result: parser.PASS,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -374,9 +361,8 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name",
|
||||||
Time: 50,
|
Time: 50,
|
||||||
Result: parser.FAIL,
|
|
||||||
Tests: []*parser.Test{
|
Tests: []*parser.Test{
|
||||||
{
|
{
|
||||||
Name: "TestOne",
|
Name: "TestOne",
|
||||||
@ -507,9 +493,54 @@ var testCases = []TestCase{
|
|||||||
report: &parser.Report{
|
report: &parser.Report{
|
||||||
Packages: []parser.Package{
|
Packages: []parser.Package{
|
||||||
{
|
{
|
||||||
Name: "package/name",
|
Name: "package/name/passing1",
|
||||||
Result: parser.FAIL,
|
Time: 100,
|
||||||
Tests: []*parser.Test{},
|
Tests: []*parser.Test{
|
||||||
|
{
|
||||||
|
Name: "TestA",
|
||||||
|
Time: 100,
|
||||||
|
Result: parser.PASS,
|
||||||
|
Output: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "package/name/passing2",
|
||||||
|
Time: 100,
|
||||||
|
Tests: []*parser.Test{
|
||||||
|
{
|
||||||
|
Name: "TestB",
|
||||||
|
Time: 100,
|
||||||
|
Result: parser.PASS,
|
||||||
|
Output: []string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "package/name/failing1",
|
||||||
|
Tests: []*parser.Test{
|
||||||
|
{
|
||||||
|
Name: "build failed",
|
||||||
|
Time: 0,
|
||||||
|
Result: parser.FAIL,
|
||||||
|
Output: []string{
|
||||||
|
"failing1/failing_test.go:15: undefined: x",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "package/name/failing2",
|
||||||
|
Tests: []*parser.Test{
|
||||||
|
{
|
||||||
|
Name: "build failed",
|
||||||
|
Time: 0,
|
||||||
|
Result: parser.FAIL,
|
||||||
|
Output: []string{
|
||||||
|
"failing2/another_failing_test.go:20: undefined: y",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -29,7 +29,6 @@ type Package struct {
|
|||||||
Time int
|
Time int
|
||||||
Tests []*Test
|
Tests []*Test
|
||||||
CoveragePct string
|
CoveragePct string
|
||||||
Result Result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test contains the results of a single test.
|
// Test contains the results of a single test.
|
||||||
@ -41,11 +40,11 @@ type Test struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
regexStatus = regexp.MustCompile(`^\s*--- (PASS|FAIL|SKIP): (.+) \((\d+\.\d+)(?: seconds|s)\)$`)
|
regexStatus = regexp.MustCompile(`^\s*--- (PASS|FAIL|SKIP): (.+) \((\d+\.\d+)(?: seconds|s)\)$`)
|
||||||
regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+\.\d+)%\s+of\s+statements$`)
|
regexCoverage = regexp.MustCompile(`^coverage:\s+(\d+\.\d+)%\s+of\s+statements$`)
|
||||||
regexResult = regexp.MustCompile(`^(ok|FAIL)\s+(.+)\s(\d+\.\d+)s(?:\s+coverage:\s+(\d+\.\d+)%\s+of\s+statements)?$`)
|
regexResult = regexp.MustCompile(`^(ok|FAIL)\s+([^ ]+)\s+(?:(\d+\.\d+)s|(\[build failed]))(?:\s+coverage:\s+(\d+\.\d+)%\sof\sstatements)?$`)
|
||||||
regexBuildFailure = regexp.MustCompile(`^FAIL\s+(.+)\s\[build failed]$`)
|
regexOutput = regexp.MustCompile(`( )*\t(.*)`)
|
||||||
regexOutput = regexp.MustCompile(`( )*\t(.*)`)
|
regexCapture = regexp.MustCompile(`^#\s(.+)`)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Parse parses go test output from reader r and returns a report with the
|
// Parse parses go test output from reader r and returns a report with the
|
||||||
@ -68,8 +67,11 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
|
|||||||
// coverage percentage report for current package
|
// coverage percentage report for current package
|
||||||
var coveragePct string
|
var coveragePct string
|
||||||
|
|
||||||
// whole package test result
|
// stores mapping between package name and output of build failures
|
||||||
packageResult := FAIL
|
var packageCaptures = map[string][]string{}
|
||||||
|
|
||||||
|
// the name of the package which it's build failure output is being captured
|
||||||
|
var capturedPackage string
|
||||||
|
|
||||||
// parse lines
|
// parse lines
|
||||||
for {
|
for {
|
||||||
@ -90,33 +92,39 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
|
|||||||
Result: FAIL,
|
Result: FAIL,
|
||||||
Output: make([]string, 0),
|
Output: make([]string, 0),
|
||||||
})
|
})
|
||||||
} else if matches := regexResult.FindStringSubmatch(line); len(matches) == 5 {
|
|
||||||
if matches[4] != "" {
|
// clear the current build package, so output lines won't be added to that build
|
||||||
coveragePct = matches[4]
|
capturedPackage = ""
|
||||||
if matches[0] == "ok" {
|
} else if matches := regexResult.FindStringSubmatch(line); len(matches) == 6 {
|
||||||
packageResult = PASS
|
if matches[5] != "" {
|
||||||
}
|
coveragePct = matches[5]
|
||||||
}
|
}
|
||||||
|
|
||||||
// all tests in this package are finished
|
// all tests in this package are finished
|
||||||
report.Packages = append(report.Packages, Package{
|
pack := Package{
|
||||||
Name: matches[2],
|
Name: matches[2],
|
||||||
|
CoveragePct: coveragePct,
|
||||||
Time: parseTime(matches[3]),
|
Time: parseTime(matches[3]),
|
||||||
Tests: tests,
|
Tests: tests,
|
||||||
CoveragePct: coveragePct,
|
}
|
||||||
Result: packageResult,
|
|
||||||
})
|
|
||||||
|
|
||||||
|
if matches[4] == "[build failed]" {
|
||||||
|
// the build of the package failed, inject a dummy test into the package
|
||||||
|
// which indicate about the failure and contain the failure description.
|
||||||
|
pack.Tests = []*Test{
|
||||||
|
{
|
||||||
|
Name: "build failed",
|
||||||
|
Result: FAIL,
|
||||||
|
Output: packageCaptures[matches[2]],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
report.Packages = append(report.Packages, pack)
|
||||||
tests = make([]*Test, 0)
|
tests = make([]*Test, 0)
|
||||||
coveragePct = ""
|
coveragePct = ""
|
||||||
cur = ""
|
cur = ""
|
||||||
testsTime = 0
|
testsTime = 0
|
||||||
} else if matches := regexBuildFailure.FindStringSubmatch(line); len(matches) == 2 {
|
|
||||||
report.Packages = append(report.Packages, Package{
|
|
||||||
Name: matches[1],
|
|
||||||
Result: FAIL,
|
|
||||||
})
|
|
||||||
|
|
||||||
} else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 4 {
|
} else if matches := regexStatus.FindStringSubmatch(line); len(matches) == 4 {
|
||||||
cur = matches[2]
|
cur = matches[2]
|
||||||
test := findTest(tests, cur)
|
test := findTest(tests, cur)
|
||||||
@ -148,6 +156,12 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
test.Output = append(test.Output, matches[2])
|
test.Output = append(test.Output, matches[2])
|
||||||
|
} else if matches := regexCapture.FindStringSubmatch(line); len(matches) == 2 {
|
||||||
|
// set the current build package
|
||||||
|
capturedPackage = matches[1]
|
||||||
|
} else if capturedPackage != "" {
|
||||||
|
// current line is build failure capture for the current built package
|
||||||
|
packageCaptures[capturedPackage] = append(packageCaptures[capturedPackage], line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -158,7 +172,6 @@ func Parse(r io.Reader, pkgName string) (*Report, error) {
|
|||||||
Time: testsTime,
|
Time: testsTime,
|
||||||
Tests: tests,
|
Tests: tests,
|
||||||
CoveragePct: coveragePct,
|
CoveragePct: coveragePct,
|
||||||
Result: packageResult,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,12 +209,3 @@ func (r *Report) Failures() int {
|
|||||||
|
|
||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *Report) Failed() bool {
|
|
||||||
for _, p := range r.Packages {
|
|
||||||
if p.Result == FAIL {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
@ -1,8 +1,31 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<testsuites>
|
<testsuites>
|
||||||
<testsuite tests="0" failures="0" time="0.000" name="package/name">
|
<testsuite tests="1" failures="0" time="0.100" name="package/name/passing1">
|
||||||
<properties>
|
<properties>
|
||||||
<property name="go.version" value="1.0"></property>
|
<property name="go.version" value="1.0"></property>
|
||||||
</properties>
|
</properties>
|
||||||
|
<testcase classname="passing1" name="TestA" time="0.100"></testcase>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite tests="1" failures="0" time="0.100" name="package/name/passing2">
|
||||||
|
<properties>
|
||||||
|
<property name="go.version" value="1.0"></property>
|
||||||
|
</properties>
|
||||||
|
<testcase classname="passing2" name="TestB" time="0.100"></testcase>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite tests="1" failures="1" time="0.000" name="package/name/failing1">
|
||||||
|
<properties>
|
||||||
|
<property name="go.version" value="1.0"></property>
|
||||||
|
</properties>
|
||||||
|
<testcase classname="failing1" name="build failed" time="0.000">
|
||||||
|
<failure message="Failed" type="">failing1/failing_test.go:15: undefined: x</failure>
|
||||||
|
</testcase>
|
||||||
|
</testsuite>
|
||||||
|
<testsuite tests="1" failures="1" time="0.000" name="package/name/failing2">
|
||||||
|
<properties>
|
||||||
|
<property name="go.version" value="1.0"></property>
|
||||||
|
</properties>
|
||||||
|
<testcase classname="failing2" name="build failed" time="0.000">
|
||||||
|
<failure message="Failed" type="">failing2/another_failing_test.go:20: undefined: y</failure>
|
||||||
|
</testcase>
|
||||||
</testsuite>
|
</testsuite>
|
||||||
</testsuites>
|
</testsuites>
|
||||||
|
@ -1,2 +1,14 @@
|
|||||||
package/name/file_test.go:9: undefined: x
|
# package/name/failing1
|
||||||
FAIL package/name [build failed]
|
failing1/failing_test.go:15: undefined: x
|
||||||
|
# package/name/failing2
|
||||||
|
failing2/another_failing_test.go:20: undefined: y
|
||||||
|
=== RUN TestA
|
||||||
|
--- PASS: TestA (0.10 seconds)
|
||||||
|
PASS
|
||||||
|
ok package/name/passing1 0.100s
|
||||||
|
=== RUN TestB
|
||||||
|
--- PASS: TestB (0.10 seconds)
|
||||||
|
PASS
|
||||||
|
ok package/name/passing2 0.100s
|
||||||
|
FAIL package/name/failing1 [build failed]
|
||||||
|
FAIL package/name/failing2 [build failed]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user