github.com/saucelabs/saucectl@v0.175.1/internal/report/junit/junit.go (about)

     1  package junit
     2  
     3  import (
     4  	"encoding/xml"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"sync"
     9  
    10  	"github.com/rs/zerolog/log"
    11  	"github.com/saucelabs/saucectl/internal/junit"
    12  	"github.com/saucelabs/saucectl/internal/report"
    13  )
    14  
    15  // Reporter is a junit implementation for report.Reporter.
    16  type Reporter struct {
    17  	TestResults []report.TestResult
    18  	Filename    string
    19  	lock        sync.Mutex
    20  }
    21  
    22  // Add adds the test result to the summary.
    23  func (r *Reporter) Add(t report.TestResult) {
    24  	r.lock.Lock()
    25  	defer r.lock.Unlock()
    26  	r.TestResults = append(r.TestResults, t)
    27  }
    28  
    29  // Render renders out a test summary junit report to the destination of Reporter.Filename.
    30  func (r *Reporter) Render() {
    31  	r.lock.Lock()
    32  	defer r.lock.Unlock()
    33  
    34  	tt := junit.TestSuites{}
    35  	for _, v := range r.TestResults {
    36  		t := junit.TestSuite{
    37  			Name: v.Name,
    38  			Time: strconv.Itoa(int(v.Duration.Seconds())),
    39  		}
    40  		t.Properties = append(t.Properties, extractProperties(v)...)
    41  
    42  		var allTestSuites []junit.TestSuites
    43  		for _, attempt := range v.Attempts {
    44  			allTestSuites = append(allTestSuites, attempt.TestSuites)
    45  		}
    46  
    47  		combinedReports := junit.MergeReports(allTestSuites...)
    48  		for _, ts := range combinedReports.TestSuites {
    49  			t.TestCases = append(t.TestCases, ts.TestCases...)
    50  		}
    51  
    52  		tt.TestSuites = append(tt.TestSuites, t)
    53  	}
    54  
    55  	tt.Compute()
    56  
    57  	b, err := xml.MarshalIndent(tt, "", "  ")
    58  	if err != nil {
    59  		log.Err(err).Msg("Failed to create junit report.")
    60  		return
    61  	}
    62  
    63  	f, err := os.Create(r.Filename)
    64  	if err != nil {
    65  		log.Err(err).Msg("Failed to render junit report.")
    66  		return
    67  	}
    68  	defer f.Close()
    69  
    70  	if _, err = f.Write(b); err != nil {
    71  		log.Err(err).Msg("Failed to render junit report.")
    72  		return
    73  	}
    74  	_, _ = fmt.Fprint(f, "\n")
    75  }
    76  
    77  func extractProperties(r report.TestResult) []junit.Property {
    78  	props := []junit.Property{
    79  		{
    80  			Name:  "url",
    81  			Value: r.URL,
    82  		},
    83  		{
    84  			Name:  "browser",
    85  			Value: r.Browser,
    86  		},
    87  		{
    88  			Name:  "device",
    89  			Value: r.DeviceName,
    90  		},
    91  		{
    92  			Name:  "platform",
    93  			Value: r.Platform,
    94  		},
    95  	}
    96  
    97  	var filtered []junit.Property
    98  	for _, p := range props {
    99  		// we don't want to display properties with empty values
   100  		if p.Value == "" {
   101  			continue
   102  		}
   103  
   104  		filtered = append(filtered, p)
   105  	}
   106  
   107  	return filtered
   108  }
   109  
   110  // Reset resets the reporter to its initial state. This action will delete all test results.
   111  func (r *Reporter) Reset() {
   112  	r.lock.Lock()
   113  	defer r.lock.Unlock()
   114  	r.TestResults = make([]report.TestResult, 0)
   115  }
   116  
   117  // ArtifactRequirements returns a list of artifact types are this reporter requires to create a proper report.
   118  func (r *Reporter) ArtifactRequirements() []report.ArtifactType {
   119  	return []report.ArtifactType{report.JUnitArtifact}
   120  }