179 lines
5.7 KiB
Go
179 lines
5.7 KiB
Go
|
/*
|
||
|
|
||
|
JUnit XML Reporter for Ginkgo
|
||
|
|
||
|
For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output
|
||
|
|
||
|
*/
|
||
|
|
||
|
package reporters
|
||
|
|
||
|
import (
|
||
|
"encoding/xml"
|
||
|
"fmt"
|
||
|
"math"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/onsi/ginkgo/config"
|
||
|
"github.com/onsi/ginkgo/types"
|
||
|
)
|
||
|
|
||
|
type JUnitTestSuite struct {
|
||
|
XMLName xml.Name `xml:"testsuite"`
|
||
|
TestCases []JUnitTestCase `xml:"testcase"`
|
||
|
Name string `xml:"name,attr"`
|
||
|
Tests int `xml:"tests,attr"`
|
||
|
Failures int `xml:"failures,attr"`
|
||
|
Errors int `xml:"errors,attr"`
|
||
|
Time float64 `xml:"time,attr"`
|
||
|
}
|
||
|
|
||
|
type JUnitTestCase struct {
|
||
|
Name string `xml:"name,attr"`
|
||
|
ClassName string `xml:"classname,attr"`
|
||
|
FailureMessage *JUnitFailureMessage `xml:"failure,omitempty"`
|
||
|
Skipped *JUnitSkipped `xml:"skipped,omitempty"`
|
||
|
Time float64 `xml:"time,attr"`
|
||
|
SystemOut string `xml:"system-out,omitempty"`
|
||
|
}
|
||
|
|
||
|
type JUnitFailureMessage struct {
|
||
|
Type string `xml:"type,attr"`
|
||
|
Message string `xml:",chardata"`
|
||
|
}
|
||
|
|
||
|
type JUnitSkipped struct {
|
||
|
Message string `xml:",chardata"`
|
||
|
}
|
||
|
|
||
|
type JUnitReporter struct {
|
||
|
suite JUnitTestSuite
|
||
|
filename string
|
||
|
testSuiteName string
|
||
|
ReporterConfig config.DefaultReporterConfigType
|
||
|
}
|
||
|
|
||
|
//NewJUnitReporter creates a new JUnit XML reporter. The XML will be stored in the passed in filename.
|
||
|
func NewJUnitReporter(filename string) *JUnitReporter {
|
||
|
return &JUnitReporter{
|
||
|
filename: filename,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) SpecSuiteWillBegin(ginkgoConfig config.GinkgoConfigType, summary *types.SuiteSummary) {
|
||
|
reporter.suite = JUnitTestSuite{
|
||
|
Name: summary.SuiteDescription,
|
||
|
TestCases: []JUnitTestCase{},
|
||
|
}
|
||
|
reporter.testSuiteName = summary.SuiteDescription
|
||
|
reporter.ReporterConfig = config.DefaultReporterConfig
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) SpecWillRun(specSummary *types.SpecSummary) {
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
|
||
|
reporter.handleSetupSummary("BeforeSuite", setupSummary)
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
|
||
|
reporter.handleSetupSummary("AfterSuite", setupSummary)
|
||
|
}
|
||
|
|
||
|
func failureMessage(failure types.SpecFailure) string {
|
||
|
return fmt.Sprintf("%s\n%s\n%s", failure.ComponentCodeLocation.String(), failure.Message, failure.Location.String())
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) handleSetupSummary(name string, setupSummary *types.SetupSummary) {
|
||
|
if setupSummary.State != types.SpecStatePassed {
|
||
|
testCase := JUnitTestCase{
|
||
|
Name: name,
|
||
|
ClassName: reporter.testSuiteName,
|
||
|
}
|
||
|
|
||
|
testCase.FailureMessage = &JUnitFailureMessage{
|
||
|
Type: reporter.failureTypeForState(setupSummary.State),
|
||
|
Message: failureMessage(setupSummary.Failure),
|
||
|
}
|
||
|
testCase.SystemOut = setupSummary.CapturedOutput
|
||
|
testCase.Time = setupSummary.RunTime.Seconds()
|
||
|
reporter.suite.TestCases = append(reporter.suite.TestCases, testCase)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
|
||
|
testCase := JUnitTestCase{
|
||
|
Name: strings.Join(specSummary.ComponentTexts[1:], " "),
|
||
|
ClassName: reporter.testSuiteName,
|
||
|
}
|
||
|
if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed {
|
||
|
testCase.SystemOut = specSummary.CapturedOutput
|
||
|
}
|
||
|
if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
|
||
|
testCase.FailureMessage = &JUnitFailureMessage{
|
||
|
Type: reporter.failureTypeForState(specSummary.State),
|
||
|
Message: failureMessage(specSummary.Failure),
|
||
|
}
|
||
|
if specSummary.State == types.SpecStatePanicked {
|
||
|
testCase.FailureMessage.Message += fmt.Sprintf("\n\nPanic: %s\n\nFull stack:\n%s",
|
||
|
specSummary.Failure.ForwardedPanic,
|
||
|
specSummary.Failure.Location.FullStackTrace)
|
||
|
}
|
||
|
testCase.SystemOut = specSummary.CapturedOutput
|
||
|
}
|
||
|
if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending {
|
||
|
testCase.Skipped = &JUnitSkipped{}
|
||
|
if specSummary.Failure.Message != "" {
|
||
|
testCase.Skipped.Message = failureMessage(specSummary.Failure)
|
||
|
}
|
||
|
}
|
||
|
testCase.Time = specSummary.RunTime.Seconds()
|
||
|
reporter.suite.TestCases = append(reporter.suite.TestCases, testCase)
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
|
||
|
reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun
|
||
|
reporter.suite.Time = math.Trunc(summary.RunTime.Seconds()*1000) / 1000
|
||
|
reporter.suite.Failures = summary.NumberOfFailedSpecs
|
||
|
reporter.suite.Errors = 0
|
||
|
if reporter.ReporterConfig.ReportFile != "" {
|
||
|
reporter.filename = reporter.ReporterConfig.ReportFile
|
||
|
fmt.Printf("\nJUnit path was configured: %s\n", reporter.filename)
|
||
|
}
|
||
|
filePath, _ := filepath.Abs(reporter.filename)
|
||
|
dirPath := filepath.Dir(filePath)
|
||
|
err := os.MkdirAll(dirPath, os.ModePerm)
|
||
|
if err != nil {
|
||
|
fmt.Printf("\nFailed to create JUnit directory: %s\n\t%s", filePath, err.Error())
|
||
|
}
|
||
|
file, err := os.Create(filePath)
|
||
|
if err != nil {
|
||
|
fmt.Fprintf(os.Stderr, "Failed to create JUnit report file: %s\n\t%s", filePath, err.Error())
|
||
|
}
|
||
|
defer file.Close()
|
||
|
file.WriteString(xml.Header)
|
||
|
encoder := xml.NewEncoder(file)
|
||
|
encoder.Indent(" ", " ")
|
||
|
err = encoder.Encode(reporter.suite)
|
||
|
if err == nil {
|
||
|
fmt.Fprintf(os.Stdout, "\nJUnit report was created: %s\n", filePath)
|
||
|
} else {
|
||
|
fmt.Fprintf(os.Stderr,"\nFailed to generate JUnit report data:\n\t%s", err.Error())
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func (reporter *JUnitReporter) failureTypeForState(state types.SpecState) string {
|
||
|
switch state {
|
||
|
case types.SpecStateFailed:
|
||
|
return "Failure"
|
||
|
case types.SpecStateTimedOut:
|
||
|
return "Timeout"
|
||
|
case types.SpecStatePanicked:
|
||
|
return "Panic"
|
||
|
default:
|
||
|
return ""
|
||
|
}
|
||
|
}
|