mirror-to-gitea/vendor/github.com/onsi/ginkgo/reporters/junit_reporter.go
vendor/github.com/onsi/ginkgo/reporters/junit_reporter.goRaw
1/*
2
3JUnit XML Reporter for Ginkgo
4
5For usage instructions: http://onsi.github.io/ginkgo/#generating_junit_xml_output
6
7*/
8
9package reporters
10
11import (
12 "encoding/xml"
13 "fmt"
14 "math"
15 "os"
16 "path/filepath"
17 "strings"
18
19 "github.com/onsi/ginkgo/config"
20 "github.com/onsi/ginkgo/types"
21)
22
23type JUnitTestSuite struct {
24 XMLName xml.Name `xml:"testsuite"`
25 TestCases []JUnitTestCase `xml:"testcase"`
26 Name string `xml:"name,attr"`
27 Tests int `xml:"tests,attr"`
28 Failures int `xml:"failures,attr"`
29 Errors int `xml:"errors,attr"`
30 Time float64 `xml:"time,attr"`
31}
32
33type JUnitTestCase struct {
34 Name string `xml:"name,attr"`
35 ClassName string `xml:"classname,attr"`
36 FailureMessage *JUnitFailureMessage `xml:"failure,omitempty"`
37 Skipped *JUnitSkipped `xml:"skipped,omitempty"`
38 Time float64 `xml:"time,attr"`
39 SystemOut string `xml:"system-out,omitempty"`
40}
41
42type JUnitFailureMessage struct {
43 Type string `xml:"type,attr"`
44 Message string `xml:",chardata"`
45}
46
47type JUnitSkipped struct {
48 Message string `xml:",chardata"`
49}
50
51type JUnitReporter struct {
52 suite JUnitTestSuite
53 filename string
54 testSuiteName string
55 ReporterConfig config.DefaultReporterConfigType
56}
57
58//NewJUnitReporter creates a new JUnit XML reporter. The XML will be stored in the passed in filename.
59func NewJUnitReporter(filename string) *JUnitReporter {
60 return &JUnitReporter{
61 filename: filename,
62 }
63}
64
65func (reporter *JUnitReporter) SpecSuiteWillBegin(ginkgoConfig config.GinkgoConfigType, summary *types.SuiteSummary) {
66 reporter.suite = JUnitTestSuite{
67 Name: summary.SuiteDescription,
68 TestCases: []JUnitTestCase{},
69 }
70 reporter.testSuiteName = summary.SuiteDescription
71 reporter.ReporterConfig = config.DefaultReporterConfig
72}
73
74func (reporter *JUnitReporter) SpecWillRun(specSummary *types.SpecSummary) {
75}
76
77func (reporter *JUnitReporter) BeforeSuiteDidRun(setupSummary *types.SetupSummary) {
78 reporter.handleSetupSummary("BeforeSuite", setupSummary)
79}
80
81func (reporter *JUnitReporter) AfterSuiteDidRun(setupSummary *types.SetupSummary) {
82 reporter.handleSetupSummary("AfterSuite", setupSummary)
83}
84
85func failureMessage(failure types.SpecFailure) string {
86 return fmt.Sprintf("%s\n%s\n%s", failure.ComponentCodeLocation.String(), failure.Message, failure.Location.String())
87}
88
89func (reporter *JUnitReporter) handleSetupSummary(name string, setupSummary *types.SetupSummary) {
90 if setupSummary.State != types.SpecStatePassed {
91 testCase := JUnitTestCase{
92 Name: name,
93 ClassName: reporter.testSuiteName,
94 }
95
96 testCase.FailureMessage = &JUnitFailureMessage{
97 Type: reporter.failureTypeForState(setupSummary.State),
98 Message: failureMessage(setupSummary.Failure),
99 }
100 testCase.SystemOut = setupSummary.CapturedOutput
101 testCase.Time = setupSummary.RunTime.Seconds()
102 reporter.suite.TestCases = append(reporter.suite.TestCases, testCase)
103 }
104}
105
106func (reporter *JUnitReporter) SpecDidComplete(specSummary *types.SpecSummary) {
107 testCase := JUnitTestCase{
108 Name: strings.Join(specSummary.ComponentTexts[1:], " "),
109 ClassName: reporter.testSuiteName,
110 }
111 if reporter.ReporterConfig.ReportPassed && specSummary.State == types.SpecStatePassed {
112 testCase.SystemOut = specSummary.CapturedOutput
113 }
114 if specSummary.State == types.SpecStateFailed || specSummary.State == types.SpecStateTimedOut || specSummary.State == types.SpecStatePanicked {
115 testCase.FailureMessage = &JUnitFailureMessage{
116 Type: reporter.failureTypeForState(specSummary.State),
117 Message: failureMessage(specSummary.Failure),
118 }
119 if specSummary.State == types.SpecStatePanicked {
120 testCase.FailureMessage.Message += fmt.Sprintf("\n\nPanic: %s\n\nFull stack:\n%s",
121 specSummary.Failure.ForwardedPanic,
122 specSummary.Failure.Location.FullStackTrace)
123 }
124 testCase.SystemOut = specSummary.CapturedOutput
125 }
126 if specSummary.State == types.SpecStateSkipped || specSummary.State == types.SpecStatePending {
127 testCase.Skipped = &JUnitSkipped{}
128 if specSummary.Failure.Message != "" {
129 testCase.Skipped.Message = failureMessage(specSummary.Failure)
130 }
131 }
132 testCase.Time = specSummary.RunTime.Seconds()
133 reporter.suite.TestCases = append(reporter.suite.TestCases, testCase)
134}
135
136func (reporter *JUnitReporter) SpecSuiteDidEnd(summary *types.SuiteSummary) {
137 reporter.suite.Tests = summary.NumberOfSpecsThatWillBeRun
138 reporter.suite.Time = math.Trunc(summary.RunTime.Seconds()*1000) / 1000
139 reporter.suite.Failures = summary.NumberOfFailedSpecs
140 reporter.suite.Errors = 0
141 if reporter.ReporterConfig.ReportFile != "" {
142 reporter.filename = reporter.ReporterConfig.ReportFile
143 fmt.Printf("\nJUnit path was configured: %s\n", reporter.filename)
144 }
145 filePath, _ := filepath.Abs(reporter.filename)
146 dirPath := filepath.Dir(filePath)
147 err := os.MkdirAll(dirPath, os.ModePerm)
148 if err != nil {
149 fmt.Printf("\nFailed to create JUnit directory: %s\n\t%s", filePath, err.Error())
150 }
151 file, err := os.Create(filePath)
152 if err != nil {
153 fmt.Fprintf(os.Stderr, "Failed to create JUnit report file: %s\n\t%s", filePath, err.Error())
154 }
155 defer file.Close()
156 file.WriteString(xml.Header)
157 encoder := xml.NewEncoder(file)
158 encoder.Indent(" ", " ")
159 err = encoder.Encode(reporter.suite)
160 if err == nil {
161 fmt.Fprintf(os.Stdout, "\nJUnit report was created: %s\n", filePath)
162 } else {
163 fmt.Fprintf(os.Stderr,"\nFailed to generate JUnit report data:\n\t%s", err.Error())
164 }
165}
166
167func (reporter *JUnitReporter) failureTypeForState(state types.SpecState) string {
168 switch state {
169 case types.SpecStateFailed:
170 return "Failure"
171 case types.SpecStateTimedOut:
172 return "Timeout"
173 case types.SpecStatePanicked:
174 return "Panic"
175 default:
176 return ""
177 }
178}