Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hide empty packages on junit output #288

Merged
merged 2 commits into from
Dec 10, 2022
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
8 changes: 8 additions & 0 deletions cmd/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,11 @@ func (s *stringSlice) Set(raw string) error {
func (s *stringSlice) Type() string {
return "list"
}

func truthyFlag(s string) bool {
switch strings.ToLower(s) {
case "true", "yes", "1":
return true
}
return false
}
1 change: 1 addition & 0 deletions cmd/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func writeJUnitFile(opts *options, execution *testjson.Execution) error {
ProjectName: opts.junitProjectName,
FormatTestSuiteName: opts.junitTestSuiteNameFormat.Value(),
FormatTestCaseClassname: opts.junitTestCaseClassnameFormat.Value(),
HideEmptyPackages: opts.junitHideEmptyPackages,
})
}

Expand Down
4 changes: 4 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ func setupFlags(name string) (*pflag.FlagSet, *options) {
flags.StringVar(&opts.junitProjectName, "junitfile-project-name",
lookEnvWithDefault("GOTESTSUM_JUNITFILE_PROJECT_NAME", ""),
"name of the project used in the junit.xml file")
flags.BoolVar(&opts.junitHideEmptyPackages, "junitfile-hide-empty-pkg",
truthyFlag(lookEnvWithDefault("GOTESTSUM_JUNIT_HIDE_EMPTY_PKG", "")),
"omit packages with no tests from the junit.xml file")

flags.IntVar(&opts.rerunFailsMaxAttempts, "rerun-fails", 0,
"rerun failed tests until they all pass, or attempts exceeds maximum. Defaults to max 2 reruns when enabled.")
Expand Down Expand Up @@ -160,6 +163,7 @@ type options struct {
junitTestSuiteNameFormat *junitFieldFormatValue
junitTestCaseClassnameFormat *junitFieldFormatValue
junitProjectName string
junitHideEmptyPackages bool
rerunFailsMaxAttempts int
rerunFailsMaxInitialFailures int
rerunFailsReportFile string
Expand Down
1 change: 1 addition & 0 deletions cmd/testdata/gotestsum-help-text
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Flags:
--hide-summary summary hide sections of the summary: skipped,failed,errors,output (default none)
--jsonfile string write all TestEvents to file
--junitfile string write a JUnit XML file
--junitfile-hide-empty-pkg omit packages with no tests from the junit.xml file
--junitfile-project-name string name of the project used in the junit.xml file
--junitfile-testcase-classname field-format format the testcase classname field as: full, relative, short (default full)
--junitfile-testsuite-name field-format format the testsuite name field as: full, relative, short (default full)
Expand Down
4 changes: 4 additions & 0 deletions internal/junitxml/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ type Config struct {
ProjectName string
FormatTestSuiteName FormatFunc
FormatTestCaseClassname FormatFunc
HideEmptyPackages bool
// This is used for tests to have a consistent timestamp
customTimestamp string
customElapsed string
Expand Down Expand Up @@ -104,6 +105,9 @@ func generate(exec *testjson.Execution, cfg Config) JUnitTestSuites {
}
for _, pkgname := range exec.Packages() {
pkg := exec.Package(pkgname)
if cfg.HideEmptyPackages && pkg.IsEmpty() {
continue
}
junitpkg := JUnitTestSuite{
Name: cfg.FormatTestSuiteName(pkgname),
Tests: pkg.Total,
Expand Down
15 changes: 15 additions & 0 deletions internal/junitxml/report_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,21 @@ func TestWrite(t *testing.T) {
golden.Assert(t, out.String(), "junitxml-report.golden")
}

func TestWrite_HideEmptyPackages(t *testing.T) {
out := new(bytes.Buffer)
exec := createExecution(t)

env.Patch(t, "GOVERSION", "go7.7.7")
err := Write(out, exec, Config{
ProjectName: "test",
HideEmptyPackages: true,
customTimestamp: new(time.Time).Format(time.RFC3339),
customElapsed: "2.1",
})
assert.NilError(t, err)
golden.Assert(t, out.String(), "junitxml-report-skip-empty.golden")
}

func createExecution(t *testing.T) *testjson.Execution {
exec, err := testjson.ScanTestOutput(testjson.ScanConfig{
Stdout: readTestData(t, "out"),
Expand Down
119 changes: 119 additions & 0 deletions internal/junitxml/testdata/junitxml-report-skip-empty.golden
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<testsuites name="test" tests="59" failures="13" errors="1" time="2.1">
<testsuite tests="0" failures="0" time="0.001000" name="gotest.tools/gotestsum/testjson/internal/badmain" timestamp="0001-01-01T00:00:00Z">
<properties>
<property name="go.version" value="go7.7.7"></property>
</properties>
<testcase classname="" name="TestMain" time="0.000000">
<failure message="Failed" type="">sometimes main can exit 2&#xA;FAIL&#x9;gotest.tools/gotestsum/testjson/internal/badmain&#x9;0.001s&#xA;</failure>
</testcase>
</testsuite>
<testsuite tests="18" failures="0" time="0.000000" name="gotest.tools/gotestsum/testjson/internal/good" timestamp="0001-01-01T00:00:00Z">
<properties>
<property name="go.version" value="go7.7.7"></property>
</properties>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestSkipped" time="0.000000">
<skipped message="=== RUN TestSkipped&#xA; good_test.go:23: &#xA;--- SKIP: TestSkipped (0.00s)&#xA;"></skipped>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestSkippedWitLog" time="0.000000">
<skipped message="=== RUN TestSkippedWitLog&#xA; good_test.go:27: the skip message&#xA;--- SKIP: TestSkippedWitLog (0.00s)&#xA;"></skipped>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestPassed" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestPassedWithLog" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestPassedWithStdout" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestWithStderr" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/a/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/a" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/b/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/b" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/c/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/c" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/d/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess/d" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestNestedSuccess" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestParallelTheFirst" time="0.010000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestParallelTheThird" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/good" name="TestParallelTheSecond" time="0.010000"></testcase>
</testsuite>
<testsuite tests="12" failures="8" time="0.020000" name="gotest.tools/gotestsum/testjson/internal/parallelfails" timestamp="0001-01-01T00:00:00Z">
<properties>
<property name="go.version" value="go7.7.7"></property>
</properties>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestNestedParallelFailures/a" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedParallelFailures/a&#xA;=== PAUSE TestNestedParallelFailures/a&#xA;=== CONT TestNestedParallelFailures/a&#xA; fails_test.go:50: failed sub a&#xA; --- FAIL: TestNestedParallelFailures/a (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestNestedParallelFailures/d" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedParallelFailures/d&#xA;=== PAUSE TestNestedParallelFailures/d&#xA;=== CONT TestNestedParallelFailures/d&#xA; fails_test.go:50: failed sub d&#xA; --- FAIL: TestNestedParallelFailures/d (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestNestedParallelFailures/c" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedParallelFailures/c&#xA;=== PAUSE TestNestedParallelFailures/c&#xA;=== CONT TestNestedParallelFailures/c&#xA; fails_test.go:50: failed sub c&#xA; --- FAIL: TestNestedParallelFailures/c (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestNestedParallelFailures/b" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedParallelFailures/b&#xA;=== PAUSE TestNestedParallelFailures/b&#xA;=== CONT TestNestedParallelFailures/b&#xA; fails_test.go:50: failed sub b&#xA; --- FAIL: TestNestedParallelFailures/b (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestNestedParallelFailures" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedParallelFailures&#xA;--- FAIL: TestNestedParallelFailures (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestParallelTheFirst" time="0.010000">
<failure message="Failed" type="">=== RUN TestParallelTheFirst&#xA;=== PAUSE TestParallelTheFirst&#xA;=== CONT TestParallelTheFirst&#xA; fails_test.go:29: failed the first&#xA;--- FAIL: TestParallelTheFirst (0.01s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestParallelTheThird" time="0.000000">
<failure message="Failed" type="">=== RUN TestParallelTheThird&#xA;=== PAUSE TestParallelTheThird&#xA;=== CONT TestParallelTheThird&#xA; fails_test.go:41: failed the third&#xA;--- FAIL: TestParallelTheThird (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestParallelTheSecond" time="0.010000">
<failure message="Failed" type="">=== RUN TestParallelTheSecond&#xA;=== PAUSE TestParallelTheSecond&#xA;=== CONT TestParallelTheSecond&#xA; fails_test.go:35: failed the second&#xA;--- FAIL: TestParallelTheSecond (0.01s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestPassed" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestPassedWithLog" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestPassedWithStdout" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/parallelfails" name="TestWithStderr" time="0.000000"></testcase>
</testsuite>
<testsuite tests="29" failures="4" time="0.020000" name="gotest.tools/gotestsum/testjson/internal/withfails" timestamp="0001-01-01T00:00:00Z">
<properties>
<property name="go.version" value="go7.7.7"></property>
</properties>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestFailed" time="0.000000">
<failure message="Failed" type="">=== RUN TestFailed&#xA; fails_test.go:34: this failed&#xA;--- FAIL: TestFailed (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestFailedWithStderr" time="0.000000">
<failure message="Failed" type="">=== RUN TestFailedWithStderr&#xA;this is stderr&#xA; fails_test.go:43: also failed&#xA;--- FAIL: TestFailedWithStderr (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/c" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedWithFailure/c&#xA; fails_test.go:65: failed&#xA; --- FAIL: TestNestedWithFailure/c (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure" time="0.000000">
<failure message="Failed" type="">=== RUN TestNestedWithFailure&#xA;--- FAIL: TestNestedWithFailure (0.00s)&#xA;</failure>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestSkipped" time="0.000000">
<skipped message="=== RUN TestSkipped&#xA; fails_test.go:26: &#xA;--- SKIP: TestSkipped (0.00s)&#xA;"></skipped>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestSkippedWitLog" time="0.000000">
<skipped message="=== RUN TestSkippedWitLog&#xA; fails_test.go:30: the skip message&#xA;--- SKIP: TestSkippedWitLog (0.00s)&#xA;"></skipped>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestTimeout" time="0.000000">
<skipped message="=== RUN TestTimeout&#xA; timeout_test.go:13: skipping slow test&#xA;--- SKIP: TestTimeout (0.00s)&#xA;"></skipped>
</testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestPassed" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestPassedWithLog" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestPassedWithStdout" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestWithStderr" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/a/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/a" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/b/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/b" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/d/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedWithFailure/d" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/a/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/a" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/b/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/b" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/c/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/c" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/d/sub" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess/d" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestNestedSuccess" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestParallelTheFirst" time="0.010000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestParallelTheThird" time="0.000000"></testcase>
<testcase classname="gotest.tools/gotestsum/testjson/internal/withfails" name="TestParallelTheSecond" time="0.010000"></testcase>
</testsuite>
</testsuites>
2 changes: 1 addition & 1 deletion testjson/dotformat.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func (d *dotFormatter) Format(event TestEvent, exec *Execution) error {

sort.Slice(d.order, d.orderByLastUpdated)
for _, pkg := range d.order {
if d.opts.HideEmptyPackages && exec.Package(pkg).Total == 0 {
if d.opts.HideEmptyPackages && exec.Package(pkg).IsEmpty() {
continue
}

Expand Down
5 changes: 5 additions & 0 deletions testjson/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,11 @@ func (p *Package) TestMainFailed() bool {
return p.action == ActionFail && len(p.Failed) == 0
}

// IsEmpty returns true if this package contains no tests.
func (p *Package) IsEmpty() bool {
return p.Total == 0 && !p.TestMainFailed()
}

const neverFinished time.Duration = -1

// end adds any tests that were missing an ActionFail TestEvent to the list of
Expand Down