@@ -23,6 +23,16 @@ type TestEvent struct {
2323 Output string
2424}
2525
26+ const (
27+ ActionBuildOutput = "build-output"
28+ ActionBuildFail = "build-fail"
29+ ActionOutput = "output"
30+ ActionRun = "run"
31+ ActionPass = "pass"
32+ ActionFail = "fail"
33+ ActionSkip = "skip"
34+ )
35+
2636var buildOutput []string
2737
2838func ParseTestResults (r io.Reader , verbose bool , env * ctrf.Environment ) (* ctrf.Report , error ) {
@@ -33,6 +43,8 @@ func ParseTestResults(r io.Reader, verbose bool, env *ctrf.Environment) (*ctrf.R
3343 report .Results .Summary .Start = time .Now ().UnixNano () / int64 (time .Millisecond )
3444
3545 testStartTimes := make (map [string ]int64 )
46+ extraMap := make (map [string ]any )
47+ report .Results .Extra = extraMap
3648
3749 for {
3850 var event TestEvent
@@ -44,56 +56,49 @@ func ParseTestResults(r io.Reader, verbose bool, env *ctrf.Environment) (*ctrf.R
4456 testEvents = append (testEvents , event )
4557
4658 if verbose {
47- if event .Action == "build-output" || event .Action == "output" {
59+ if event .Action == ActionBuildOutput || event .Action == ActionOutput {
4860 fmt .Print (event .Output )
4961 }
5062 }
5163 }
5264
5365 for i , event := range testEvents {
66+ // If we see any test failures, mark an overall failure in the Extra fields
67+ if event .Action == ActionFail {
68+ extraMap ["FailedBuild" ] = true
69+ }
5470
55- if event .Action == "build-output" || event .Action == "build-fail" || event .Action == "fail" {
56- if report .Results .Extra == nil {
57- report .Results .Extra = make (map [string ]any )
58- }
59- extraMap , ok := report .Results .Extra .(map [string ]any )
60- if ! ok {
61- return nil , fmt .Errorf ("expected a map, but got %T instead" , report .Results .Extra )
62- }
63-
64- if event .Action == "fail" {
65- if _ , ok := extraMap ["FailedBuild" ]; ! ok {
66- extraMap ["FailedBuild" ] = true
67- }
68- }
69-
70- if event .Action == "build-output" {
71- if _ , ok := extraMap ["buildOutput" ]; ! ok {
72- extraMap ["buildOutput" ] = []TestEvent {}
73- }
74- buildOutputEvents := extraMap ["buildOutput" ].([]TestEvent )
75- extraMap ["buildOutput" ] = append (buildOutputEvents , event )
76- buildOutput = append (buildOutput , event .Output )
77- continue
71+ // Capture all build output as extras
72+ if event .Action == ActionBuildOutput {
73+ if _ , ok := extraMap ["buildOutput" ]; ! ok {
74+ extraMap ["buildOutput" ] = []TestEvent {}
7875 }
76+ buildOutputEvents := extraMap ["buildOutput" ].([]TestEvent )
77+ extraMap ["buildOutput" ] = append (buildOutputEvents , event )
78+ buildOutput = append (buildOutput , event .Output )
79+ continue
80+ }
7981
80- if event .Action == "build-fail" {
81- if _ , ok := extraMap ["buildFail" ]; ! ok {
82- extraMap ["buildFail" ] = []TestEvent {}
83- }
84- buildFailEvents := extraMap ["buildFail" ].([]TestEvent )
85- extraMap ["buildFail" ] = append (buildFailEvents , event )
86- break
82+ // Mark if we see a build failure in the extras field
83+ if event .Action == ActionBuildFail {
84+ if _ , ok := extraMap ["buildFail" ]; ! ok {
85+ extraMap ["buildFail" ] = []TestEvent {}
8786 }
87+ buildFailEvents := extraMap ["buildFail" ].([]TestEvent )
88+ extraMap ["buildFail" ] = append (buildFailEvents , event )
89+ break
8890 }
8991
90- if event .Action == "output" {
92+ if event .Action == ActionOutput {
9193 buildOutput = append (buildOutput , event .Output )
9294 }
9395
96+ // From this point, we only care about events associated with an actual test
9497 if event .Test == "" {
9598 continue
9699 }
100+
101+ // Parse timestamp data from the event
97102 eventTime , err := parseTimeString (event .Time )
98103 if err != nil {
99104 fmt .Fprintf (os .Stderr , "error parsing test event start time '%s' : %v\n " , event .Time , err )
@@ -107,14 +112,14 @@ func ParseTestResults(r io.Reader, verbose bool, env *ctrf.Environment) (*ctrf.R
107112
108113 // If this is a "run" event, record the start time of the test. We'll look this up later when
109114 // we process the "pass"/"fail"/"skip" event for the test to create the TestResult
110- if event .Action == "run" {
115+ if event .Action == ActionRun {
111116 testStartTimes [testNameKey (event .Package , event .Test )] = eventTime
112117 }
113118 }
114119
115120 // From this point on, we only deal with pass, fail, and skip events, which indicate that the
116121 // test has completed, and we can create/update a TestResult for it.
117- if event .Action == "pass" || event .Action == "fail" || event .Action == "skip" {
122+ if event .Action == ActionPass || event .Action == ActionFail || event .Action == ActionSkip {
118123 // Look up the start time, and use this event's time as the endTime, to mark the start/stop times
119124 // for the test result. Duration we get from the event.Elapsed field, which better takes into
120125 // account parallel tests, setup/teardown time, etc...
@@ -127,7 +132,7 @@ func ParseTestResults(r io.Reader, verbose bool, env *ctrf.Environment) (*ctrf.R
127132 // Determine the message for this test result. We only include messages on failures though,
128133 // per the CTRF spec, so if this is not a failure, we pass an empty string for the message.
129134 message := ""
130- if event .Action == "fail" {
135+ if event .Action == ActionFail {
131136 message = getMessagesForTest (testEvents , i , event .Package , event .Test , startTime )
132137 }
133138
@@ -158,7 +163,7 @@ func ParseTestResults(r io.Reader, verbose bool, env *ctrf.Environment) (*ctrf.R
158163 return report , nil
159164}
160165
161- // addResult adds a new test result to the report, filling out all the relevant details
166+ // addResult adds a new test result to the report, filling out all the relevant details.
162167func addResult (report * ctrf.Report , result * ctrf.TestResult ) {
163168 // Update the overall test count in the Summary
164169 report .Results .Summary .Tests ++
@@ -171,59 +176,63 @@ func addResult(report *ctrf.Report, result *ctrf.TestResult) {
171176 report .Results .Summary .Failed ++
172177 case ctrf .TestSkipped :
173178 report .Results .Summary .Skipped ++
179+ case ctrf .TestPending :
180+ report .Results .Summary .Pending ++
181+ default :
182+ report .Results .Summary .Other ++
174183 }
175184
176185 // Append the result to the report's results
177186 report .Results .Tests = append (report .Results .Tests , result )
178187}
179188
180- func updateResult (report * ctrf.Report , existing , new * ctrf.TestResult ) {
189+ func updateResult (report * ctrf.Report , oldResult , newResult * ctrf.TestResult ) {
181190 // If the existing result does not have a retries field, initialize it, and move the
182191 // results to the first RetryAttempts object
183- if existing .RetryAttempts == nil {
184- existing .Retries = 1
185- existing .RetryAttempts = append (existing .RetryAttempts , ctrf.RetryAttempt {
192+ if oldResult .RetryAttempts == nil {
193+ oldResult .Retries = 1
194+ oldResult .RetryAttempts = append (oldResult .RetryAttempts , ctrf.RetryAttempt {
186195 Attempt : 1 ,
187- Status : existing .Status ,
188- Message : existing .Message ,
189- Duration : existing .Duration ,
190- Start : existing .Start ,
191- Stop : existing .Stop ,
196+ Status : oldResult .Status ,
197+ Message : oldResult .Message ,
198+ Duration : oldResult .Duration ,
199+ Start : oldResult .Start ,
200+ Stop : oldResult .Stop ,
192201 })
193202 }
194203
195204 // If this is a pass after a failure, mark the test as flaky, not failed,
196205 // and update the summary counts accordingly
197- if existing .Status == ctrf .TestFailed && new .Status == ctrf .TestPassed {
198- existing .Flaky = true
206+ if oldResult .Status == ctrf .TestFailed && newResult .Status == ctrf .TestPassed {
207+ oldResult .Flaky = true
199208 report .Results .Summary .Flaky ++
200209 report .Results .Summary .Failed --
201210 }
202211
203212 // Update the overall test status to match that of the new result
204- existing .Status = new .Status
213+ oldResult .Status = newResult .Status
205214
206215 // Clear out the top-level message on the overall result, since the messages are in the retries
207- existing .Message = ""
216+ oldResult .Message = ""
208217
209218 // Update the times of the overall test result
210- existing .Duration += new .Duration
211- if new .Stop > existing .Stop {
212- existing .Stop = new .Stop
219+ oldResult .Duration += newResult .Duration
220+ if newResult .Stop > oldResult .Stop {
221+ oldResult .Stop = newResult .Stop
213222 }
214- if new .Start < existing .Start {
215- existing .Start = new .Start
223+ if newResult .Start < oldResult .Start {
224+ oldResult .Start = newResult .Start
216225 }
217226
218227 // Now add the new attempt to the retries
219- existing .Retries ++
220- existing .RetryAttempts = append (existing .RetryAttempts , ctrf.RetryAttempt {
221- Attempt : existing .Retries ,
222- Status : new .Status ,
223- Message : new .Message ,
224- Duration : new .Duration ,
225- Start : new .Start ,
226- Stop : new .Stop ,
228+ oldResult .Retries ++
229+ oldResult .RetryAttempts = append (oldResult .RetryAttempts , ctrf.RetryAttempt {
230+ Attempt : oldResult .Retries ,
231+ Status : newResult .Status ,
232+ Message : newResult .Message ,
233+ Duration : newResult .Duration ,
234+ Start : newResult .Start ,
235+ Stop : newResult .Stop ,
227236 })
228237}
229238
@@ -234,11 +243,11 @@ func testNameKey(suite, name string) string {
234243
235244func actionToTestResult (action string ) ctrf.TestStatus {
236245 switch action {
237- case "pass" :
246+ case ActionPass :
238247 return ctrf .TestPassed
239- case "fail" :
248+ case ActionFail :
240249 return ctrf .TestFailed
241- case "skip" :
250+ case ActionSkip :
242251 return ctrf .TestSkipped
243252 default :
244253 return ctrf .TestOther
@@ -310,7 +319,7 @@ func getMessagesForTest(testEvents []TestEvent, index int, packageName, testName
310319 }
311320 }
312321
313- if testEvents [i ].Action == "output" {
322+ if testEvents [i ].Action == ActionOutput {
314323 messages = append (messages , testEvents [i ].Output )
315324 }
316325 }
0 commit comments