Description
I recently began using go-junit-report
and noticed that all the testsuite
timestamp
tags were the same for a given report, even though my tests are taking several minutes to run.
Some tools, such as DataDog CI Test Integration use these timestamps to calculate the total time for all tests.
I took a closer look at the code and can see that there's already functionality in place to use time.Now
for each testsuite
, e.g. here and here. However, CreatePackage
is called within a loop that runs after all lines are read. This means that the timestamp represents the current time while generating the report, not the time the test result became available.
I've played around and was able to pretty quickly get a working solution. I was wondering if you'd consider accepting a pull request for this change? It passes existing tests at least, and seems to work as desired when run against my tests. If you are interested in this change, I can do some additional validation and look into expanding tests.
diff --git a/parser/gotest/gotest.go b/parser/gotest/gotest.go
index 2f38282..6d4a09a 100644
--- a/parser/gotest/gotest.go
+++ b/parser/gotest/gotest.go
@@ -8,6 +8,7 @@ import (
"regexp"
"strconv"
"strings"
+ "sync"
"time"
"github.com/jstemmer/go-junit-report/v2/gtr"
@@ -136,6 +137,17 @@ func (p *Parser) Parse(r io.Reader) (gtr.Report, error) {
func (p *Parser) parse(r reader.LineReader) (gtr.Report, error) {
p.events = nil
+
+ var (
+ finalReport gtr.Report
+ events = make(chan Event)
+ waitOnReport sync.WaitGroup
+ )
+ waitOnReport.Add(1)
+ go func() {
+ finalReport = p.report(events)
+ waitOnReport.Add(-1)
+ }()
for {
line, metadata, err := r.ReadLine()
if err == io.EOF {
@@ -162,21 +174,24 @@ func (p *Parser) parse(r reader.LineReader) (gtr.Report, error) {
for _, ev := range evs {
ev.applyMetadata(metadata)
- p.events = append(p.events, ev)
+ events <- ev
}
}
- return p.report(p.events), nil
+ close(events)
+ waitOnReport.Wait()
+
+ return finalReport, nil
}
// report generates a gtr.Report from the given list of events.
-func (p *Parser) report(events []Event) gtr.Report {
+func (p *Parser) report(events <-chan Event) gtr.Report {
rb := newReportBuilder()
rb.packageName = p.packageName
rb.subtestMode = p.subtestMode
if p.timestampFunc != nil {
rb.timestampFunc = p.timestampFunc
}
- for _, ev := range events {
+ for ev := range events {
rb.ProcessEvent(ev)
}
return rb.Build()
By using a channel we can call ProcessEvent
at about the same time the test is finished. An alternative approach would be to evaluate a timestamp function in *Parser.summary
and add a time.Time
to the Event
.
Thanks for making and maintaining a great tool!