Skip to content

TestSuite Timestamps Report All Constant #147

Closed
@cameron-dunn-sublime

Description

@cameron-dunn-sublime

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!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions