...

Source file src/github.com/onsi/ginkgo/v2/reporters/junit_report_test.go

Documentation: github.com/onsi/ginkgo/v2/reporters

     1  package reporters_test
     2  
     3  import (
     4  	"encoding/xml"
     5  	"fmt"
     6  	"os"
     7  	"path/filepath"
     8  	"time"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  
    13  	"github.com/onsi/ginkgo/v2/reporters"
    14  	"github.com/onsi/ginkgo/v2/types"
    15  )
    16  
    17  var _ = Describe("JunitReport", func() {
    18  	var report types.Report
    19  
    20  	BeforeEach(func() {
    21  		report = types.Report{
    22  			SuiteDescription: "My Suite",
    23  			SuitePath:        "/path/to/suite",
    24  			PreRunStats:      types.PreRunStats{SpecsThatWillRun: 15, TotalSpecs: 20},
    25  			SuiteConfig:      types.SuiteConfig{RandomSeed: 17, ParallelTotal: 1},
    26  			RunTime:          time.Minute,
    27  			SpecReports: types.SpecReports{
    28  				S(types.NodeTypeIt, Label("cat", "dog"), CLabels(Label("dolphin"), Label("gorilla", "cow")), CTS("A", "B"), CLS(cl0, cl1), "C", cl2, types.SpecStateTimedout, STD("some captured stdout\n"), GW("ginkgowriter\noutput\ncleanup!"), SE(types.SpecEventByStart, "a by step", cl0),
    29  					SE(types.SpecEventNodeStart, types.NodeTypeIt, "C", cl2, TL(0)),
    30  					F("failure\nmessage", cl3, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL("ginkgowriter\n"), AF(types.SpecStatePanicked, cl4, types.FailureNodeIsLeafNode, FailureNodeLocation(cl2), types.NodeTypeIt, TL("ginkgowriter\noutput\n"), ForwardedPanic("the panic!"))),
    31  					SE(types.SpecEventNodeEnd, types.NodeTypeIt, "C", cl2, TL("ginkgowriter\noutput\n"), time.Microsecond*87230),
    32  					RE("a report entry", cl1, TL("ginkgowriter\noutput\n")),
    33  					RE("a hidden report entry", cl1, TL("ginkgowriter\noutput\n"), types.ReportEntryVisibilityNever),
    34  					AF(types.SpecStateFailed, "a subsequent failure", types.FailureNodeInContainer, FailureNodeLocation(cl3), types.NodeTypeAfterEach, 0, TL("ginkgowriter\noutput\ncleanup!")),
    35  				),
    36  				S(types.NodeTypeIt, "A", cl0, STD("some captured stdout\n"), GW("some GinkgoWriter\noutput is interspersed\nhere and there\n"), Label("cat", "owner:frank", "OWNer:bob"),
    37  					SE(types.SpecEventNodeStart, types.NodeTypeIt, "A", cl0),
    38  					PR("my progress report", LeafNodeText("A"), TL("some GinkgoWriter\n")),
    39  					SE(types.SpecEventByStart, "My Step", cl1, TL("some GinkgoWriter\n")),
    40  					RE("my entry", cl1, types.ReportEntryVisibilityFailureOrVerbose, TL("some GinkgoWriter\noutput is interspersed\n")),
    41  					RE("my hidden entry", cl1, types.ReportEntryVisibilityNever, TL("some GinkgoWriter\noutput is interspersed\n")),
    42  					SE(types.SpecEventByEnd, "My Step", cl1, time.Millisecond*200, TL("some GinkgoWriter\noutput is interspersed\n")),
    43  					SE(types.SpecEventNodeEnd, types.NodeTypeIt, "A", cl0, time.Millisecond*300, TL("some GinkgoWriter\noutput is interspersed\nhere and there\n")),
    44  				),
    45  				S(types.NodeTypeIt, "A", cl0, types.SpecStatePending, CLabels(Label("owner:org")), Label("owner:team")),
    46  				S(types.NodeTypeIt, "A", cl0, types.SpecStatePanicked, CLabels(Label("owner:org")), STD("some captured stdout\n"),
    47  					SE(types.SpecEventNodeStart, types.NodeTypeIt, "A", cl0),
    48  					F("failure\nmessage", cl1, types.FailureNodeIsLeafNode, FailureNodeLocation(cl0), types.NodeTypeIt, ForwardedPanic("the panic")),
    49  					SE(types.SpecEventNodeEnd, types.NodeTypeIt, "A", cl0, time.Millisecond*300, TL("some GinkgoWriter\noutput is interspersed\nhere and there\n")),
    50  				),
    51  				S(types.NodeTypeBeforeSuite, "A", cl0, types.SpecStatePassed),
    52  			},
    53  		}
    54  	})
    55  
    56  	Describe("default behavior", func() {
    57  		var generated reporters.JUnitTestSuites
    58  
    59  		BeforeEach(func() {
    60  			fname := fmt.Sprintf("./report-%d", GinkgoParallelProcess())
    61  			Ω(reporters.GenerateJUnitReport(report, fname)).Should(Succeed())
    62  			DeferCleanup(os.Remove, fname)
    63  
    64  			generated = reporters.JUnitTestSuites{}
    65  			f, err := os.Open(fname)
    66  			Ω(err).ShouldNot(HaveOccurred())
    67  			Ω(xml.NewDecoder(f).Decode(&generated)).Should(Succeed())
    68  		})
    69  
    70  		It("generates a Junit report and writes it to disk", func() {
    71  			Ω(generated.Tests).Should(Equal(5))
    72  			Ω(generated.Disabled).Should(Equal(1))
    73  			Ω(generated.Errors).Should(Equal(1))
    74  			Ω(generated.Failures).Should(Equal(1))
    75  			Ω(generated.Time).Should(Equal(60.0))
    76  			Ω(generated.TestSuites).Should(HaveLen(1))
    77  
    78  			suite := generated.TestSuites[0]
    79  			Ω(suite.Name).Should(Equal("My Suite"))
    80  			Ω(suite.Package).Should(Equal("/path/to/suite"))
    81  			Ω(suite.Properties.WithName("SuiteSucceeded")).Should(Equal("false"))
    82  			Ω(suite.Properties.WithName("RandomSeed")).Should(Equal("17"))
    83  
    84  			Ω(suite.Tests).Should(Equal(5))
    85  			Ω(suite.Disabled).Should(Equal(1))
    86  			Ω(suite.Errors).Should(Equal(1))
    87  			Ω(suite.Failures).Should(Equal(1))
    88  			Ω(suite.Time).Should(Equal(60.0))
    89  
    90  			Ω(suite.TestCases).Should(HaveLen(5))
    91  
    92  			failingSpec := suite.TestCases[0]
    93  			Ω(failingSpec.Name).Should(Equal("[It] A B C [dolphin, gorilla, cow, cat, dog]"))
    94  			Ω(failingSpec.Classname).Should(Equal("My Suite"))
    95  			Ω(failingSpec.Status).Should(Equal("timedout"))
    96  			Ω(failingSpec.Skipped).Should(BeNil())
    97  			Ω(failingSpec.Error).Should(BeNil())
    98  			Ω(failingSpec.Owner).Should(Equal(""))
    99  			Ω(failingSpec.Failure.Message).Should(Equal("failure\nmessage"))
   100  			Ω(failingSpec.Failure.Type).Should(Equal("timedout"))
   101  			Ω(failingSpec.Failure.Description).Should(MatchLines(
   102  				"[TIMEDOUT] failure",
   103  				"message",
   104  				spr("In [It] at: cl3.go:103 @ %s", FORMATTED_TIME),
   105  				"",
   106  				"[PANICKED] ",
   107  				spr("In [It] at: cl4.go:144 @ %s", FORMATTED_TIME),
   108  				"",
   109  				"the panic!",
   110  				"",
   111  				"Full Stack Trace",
   112  				"  full-trace",
   113  				"  cl-4",
   114  				"",
   115  				"There were additional failures detected after the initial failure. These are visible in the timeline",
   116  				"",
   117  			))
   118  			Ω(failingSpec.SystemOut).Should(Equal("some captured stdout\n"))
   119  			Ω(failingSpec.SystemErr).Should(MatchLines(
   120  				spr("STEP: a by step - cl0.go:12 @ %s", FORMATTED_TIME),
   121  				spr("> Enter [It] C - cl2.go:80 @ %s", FORMATTED_TIME),
   122  				"ginkgowriter",
   123  				"[TIMEDOUT] failure",
   124  				"message",
   125  				spr("In [It] at: cl3.go:103 @ %s", FORMATTED_TIME),
   126  				"output",
   127  				"[PANICKED] ",
   128  				spr("In [It] at: cl4.go:144 @ %s", FORMATTED_TIME),
   129  				"",
   130  				"the panic!",
   131  				"",
   132  				"Full Stack Trace",
   133  				"  full-trace",
   134  				"  cl-4",
   135  				spr("< Exit [It] C - cl2.go:80 @ %s (87ms)", FORMATTED_TIME),
   136  				spr("a report entry - cl1.go:37 @ %s", FORMATTED_TIME),
   137  				spr("a hidden report entry - cl1.go:37 @ %s", FORMATTED_TIME),
   138  				"cleanup!",
   139  				"[FAILED] a subsequent failure",
   140  				spr("In [AfterEach] at: :0 @ %s", FORMATTED_TIME),
   141  				"",
   142  			))
   143  
   144  			passingSpec := suite.TestCases[1]
   145  			Ω(passingSpec.Name).Should(Equal("[It] A [cat, owner:frank, OWNer:bob]"))
   146  			Ω(passingSpec.Classname).Should(Equal("My Suite"))
   147  			Ω(passingSpec.Status).Should(Equal("passed"))
   148  			Ω(passingSpec.Skipped).Should(BeNil())
   149  			Ω(passingSpec.Error).Should(BeNil())
   150  			Ω(passingSpec.Failure).Should(BeNil())
   151  			Ω(passingSpec.Owner).Should(Equal("bob"))
   152  			Ω(passingSpec.SystemOut).Should(Equal("some captured stdout\n"))
   153  			Ω(passingSpec.SystemErr).Should(MatchLines(
   154  				spr("> Enter [It] A - cl0.go:12 @ %s", FORMATTED_TIME),
   155  				"some GinkgoWriter",
   156  				"my progress report",
   157  				"  A (Spec Runtime: 5s)",
   158  				"    cl0.go:12",
   159  				spr("STEP: My Step - cl1.go:37 @ %s", FORMATTED_TIME),
   160  				"output is interspersed",
   161  				spr("my entry - cl1.go:37 @ %s", FORMATTED_TIME),
   162  				spr("my hidden entry - cl1.go:37 @ %s", FORMATTED_TIME),
   163  				spr("END STEP: My Step - cl1.go:37 @ %s (200ms)", FORMATTED_TIME),
   164  				"here and there",
   165  				spr("< Exit [It] A - cl0.go:12 @ %s (300ms)", FORMATTED_TIME),
   166  				"",
   167  			))
   168  
   169  			pendingSpec := suite.TestCases[2]
   170  			Ω(pendingSpec.Name).Should(Equal("[It] A [owner:org, owner:team]"))
   171  			Ω(pendingSpec.Classname).Should(Equal("My Suite"))
   172  			Ω(pendingSpec.Status).Should(Equal("pending"))
   173  			Ω(pendingSpec.Skipped.Message).Should(Equal("pending"))
   174  			Ω(pendingSpec.Error).Should(BeNil())
   175  			Ω(pendingSpec.Owner).Should(Equal("team"))
   176  			Ω(pendingSpec.Failure).Should(BeNil())
   177  			Ω(pendingSpec.SystemOut).Should(BeEmpty())
   178  			Ω(pendingSpec.SystemErr).Should(BeEmpty())
   179  
   180  			panickedSpec := suite.TestCases[3]
   181  			Ω(panickedSpec.Name).Should(Equal("[It] A [owner:org]"))
   182  			Ω(panickedSpec.Classname).Should(Equal("My Suite"))
   183  			Ω(panickedSpec.Status).Should(Equal("panicked"))
   184  			Ω(panickedSpec.Skipped).Should(BeNil())
   185  			Ω(panickedSpec.Owner).Should(Equal("org"))
   186  			Ω(panickedSpec.Error.Message).Should(Equal("the panic"))
   187  			Ω(panickedSpec.Error.Type).Should(Equal("panicked"))
   188  			Ω(panickedSpec.Error.Description).Should(MatchLines(
   189  				"[PANICKED] failure",
   190  				"message",
   191  				spr("In [It] at: cl1.go:37 @ %s", FORMATTED_TIME),
   192  				"",
   193  				"the panic",
   194  				"",
   195  				"Full Stack Trace",
   196  				"  full-trace",
   197  				"  cl-1",
   198  				"",
   199  			))
   200  			Ω(panickedSpec.Failure).Should(BeNil())
   201  			Ω(panickedSpec.SystemOut).Should(Equal("some captured stdout\n"))
   202  			Ω(panickedSpec.SystemErr).Should(MatchLines(
   203  				spr("> Enter [It] A - cl0.go:12 @ %s", FORMATTED_TIME),
   204  				"[PANICKED] failure",
   205  				"message",
   206  				spr("In [It] at: cl1.go:37 @ %s", FORMATTED_TIME),
   207  				"",
   208  				"the panic",
   209  				"",
   210  				"Full Stack Trace",
   211  				"  full-trace",
   212  				"  cl-1",
   213  				spr("< Exit [It] A - cl0.go:12 @ %s (300ms)", FORMATTED_TIME),
   214  				"",
   215  			))
   216  
   217  			beforeSuiteSpec := suite.TestCases[4]
   218  			Ω(beforeSuiteSpec.Name).Should(Equal("[BeforeSuite] A"))
   219  			Ω(beforeSuiteSpec.Classname).Should(Equal("My Suite"))
   220  			Ω(beforeSuiteSpec.Status).Should(Equal("passed"))
   221  			Ω(beforeSuiteSpec.Skipped).Should(BeNil())
   222  			Ω(beforeSuiteSpec.Error).Should(BeNil())
   223  			Ω(beforeSuiteSpec.Failure).Should(BeNil())
   224  			Ω(beforeSuiteSpec.SystemOut).Should(BeEmpty())
   225  			Ω(beforeSuiteSpec.SystemErr).Should(BeEmpty())
   226  		})
   227  	})
   228  
   229  	Describe("when configured to omit all the omittables", func() {
   230  		var generated reporters.JUnitTestSuites
   231  
   232  		BeforeEach(func() {
   233  			fname := fmt.Sprintf("./report-%d", GinkgoParallelProcess())
   234  			Ω(reporters.GenerateJUnitReportWithConfig(report, fname, reporters.JunitReportConfig{
   235  				OmitTimelinesForSpecState: types.SpecStatePassed,
   236  				OmitFailureMessageAttr:    true,
   237  				OmitCapturedStdOutErr:     true,
   238  				OmitSpecLabels:            true,
   239  				OmitLeafNodeType:          true,
   240  				OmitSuiteSetupNodes:       true,
   241  			})).Should(Succeed())
   242  			DeferCleanup(os.Remove, fname)
   243  
   244  			generated = reporters.JUnitTestSuites{}
   245  			f, err := os.Open(fname)
   246  			Ω(err).ShouldNot(HaveOccurred())
   247  			Ω(xml.NewDecoder(f).Decode(&generated)).Should(Succeed())
   248  		})
   249  
   250  		It("generates a Junit report and writes it to disk", func() {
   251  			Ω(generated.Tests).Should(Equal(4))
   252  			Ω(generated.Disabled).Should(Equal(1))
   253  			Ω(generated.Errors).Should(Equal(1))
   254  			Ω(generated.Failures).Should(Equal(1))
   255  			Ω(generated.Time).Should(Equal(60.0))
   256  			Ω(generated.TestSuites).Should(HaveLen(1))
   257  
   258  			suite := generated.TestSuites[0]
   259  			Ω(suite.Name).Should(Equal("My Suite"))
   260  			Ω(suite.Package).Should(Equal("/path/to/suite"))
   261  			Ω(suite.Properties.WithName("SuiteSucceeded")).Should(Equal("false"))
   262  			Ω(suite.Properties.WithName("RandomSeed")).Should(Equal("17"))
   263  
   264  			Ω(suite.Tests).Should(Equal(4))
   265  			Ω(suite.Disabled).Should(Equal(1))
   266  			Ω(suite.Errors).Should(Equal(1))
   267  			Ω(suite.Failures).Should(Equal(1))
   268  			Ω(suite.Time).Should(Equal(60.0))
   269  
   270  			Ω(suite.TestCases).Should(HaveLen(4))
   271  
   272  			failingSpec := suite.TestCases[0]
   273  			Ω(failingSpec.Name).Should(Equal("A B C"))
   274  			Ω(failingSpec.Classname).Should(Equal("My Suite"))
   275  			Ω(failingSpec.Status).Should(Equal("timedout"))
   276  			Ω(failingSpec.Skipped).Should(BeNil())
   277  			Ω(failingSpec.Error).Should(BeNil())
   278  			Ω(failingSpec.Failure.Message).Should(BeEmpty())
   279  			Ω(failingSpec.Failure.Type).Should(Equal("timedout"))
   280  			Ω(failingSpec.Failure.Description).Should(MatchLines(
   281  				"[TIMEDOUT] failure",
   282  				"message",
   283  				spr("In [It] at: cl3.go:103 @ %s", FORMATTED_TIME),
   284  				"",
   285  				"[PANICKED] ",
   286  				spr("In [It] at: cl4.go:144 @ %s", FORMATTED_TIME),
   287  				"",
   288  				"the panic!",
   289  				"",
   290  				"Full Stack Trace",
   291  				"  full-trace",
   292  				"  cl-4",
   293  				"",
   294  				"There were additional failures detected after the initial failure. These are visible in the timeline",
   295  				"",
   296  			))
   297  			Ω(failingSpec.SystemOut).Should(BeEmpty())
   298  			Ω(failingSpec.SystemErr).Should(MatchLines(
   299  				spr("STEP: a by step - cl0.go:12 @ %s", FORMATTED_TIME),
   300  				spr("> Enter [It] C - cl2.go:80 @ %s", FORMATTED_TIME),
   301  				"ginkgowriter",
   302  				"[TIMEDOUT] failure",
   303  				"message",
   304  				spr("In [It] at: cl3.go:103 @ %s", FORMATTED_TIME),
   305  				"output",
   306  				"[PANICKED] ",
   307  				spr("In [It] at: cl4.go:144 @ %s", FORMATTED_TIME),
   308  				"",
   309  				"the panic!",
   310  				"",
   311  				"Full Stack Trace",
   312  				"  full-trace",
   313  				"  cl-4",
   314  				spr("< Exit [It] C - cl2.go:80 @ %s (87ms)", FORMATTED_TIME),
   315  				spr("a report entry - cl1.go:37 @ %s", FORMATTED_TIME),
   316  				spr("a hidden report entry - cl1.go:37 @ %s", FORMATTED_TIME),
   317  				"cleanup!",
   318  				"[FAILED] a subsequent failure",
   319  				spr("In [AfterEach] at: :0 @ %s", FORMATTED_TIME),
   320  				"",
   321  			))
   322  
   323  			passingSpec := suite.TestCases[1]
   324  			Ω(passingSpec.Name).Should(Equal("A"))
   325  			Ω(passingSpec.Classname).Should(Equal("My Suite"))
   326  			Ω(passingSpec.Status).Should(Equal("passed"))
   327  			Ω(passingSpec.Skipped).Should(BeNil())
   328  			Ω(passingSpec.Error).Should(BeNil())
   329  			Ω(passingSpec.Failure).Should(BeNil())
   330  			Ω(passingSpec.SystemOut).Should(BeEmpty())
   331  			Ω(passingSpec.SystemErr).Should(BeEmpty())
   332  
   333  			pendingSpec := suite.TestCases[2]
   334  			Ω(pendingSpec.Name).Should(Equal("A"))
   335  			Ω(pendingSpec.Classname).Should(Equal("My Suite"))
   336  			Ω(pendingSpec.Status).Should(Equal("pending"))
   337  			Ω(pendingSpec.Skipped.Message).Should(Equal("pending"))
   338  			Ω(pendingSpec.Error).Should(BeNil())
   339  			Ω(pendingSpec.Failure).Should(BeNil())
   340  			Ω(pendingSpec.SystemOut).Should(BeEmpty())
   341  			Ω(pendingSpec.SystemErr).Should(BeEmpty())
   342  
   343  			panickedSpec := suite.TestCases[3]
   344  			Ω(panickedSpec.Name).Should(Equal("A"))
   345  			Ω(panickedSpec.Classname).Should(Equal("My Suite"))
   346  			Ω(panickedSpec.Status).Should(Equal("panicked"))
   347  			Ω(panickedSpec.Skipped).Should(BeNil())
   348  			Ω(panickedSpec.Error.Message).Should(BeEmpty())
   349  			Ω(panickedSpec.Error.Type).Should(Equal("panicked"))
   350  			Ω(panickedSpec.Error.Description).Should(MatchLines(
   351  				"[PANICKED] failure",
   352  				"message",
   353  				spr("In [It] at: cl1.go:37 @ %s", FORMATTED_TIME),
   354  				"",
   355  				"the panic",
   356  				"",
   357  				"Full Stack Trace",
   358  				"  full-trace",
   359  				"  cl-1",
   360  				"",
   361  			))
   362  			Ω(panickedSpec.Failure).Should(BeNil())
   363  			Ω(panickedSpec.SystemOut).Should(BeEmpty())
   364  			Ω(panickedSpec.SystemErr).Should(MatchLines(
   365  				spr("> Enter [It] A - cl0.go:12 @ %s", FORMATTED_TIME),
   366  				"[PANICKED] failure",
   367  				"message",
   368  				spr("In [It] at: cl1.go:37 @ %s", FORMATTED_TIME),
   369  				"",
   370  				"the panic",
   371  				"",
   372  				"Full Stack Trace",
   373  				"  full-trace",
   374  				"  cl-1",
   375  				spr("< Exit [It] A - cl0.go:12 @ %s (300ms)", FORMATTED_TIME),
   376  				"",
   377  			))
   378  		})
   379  	})
   380  
   381  	Describe("when configured to write the report inside a folder", func() {
   382  		var folderPath string
   383  		var filePath string
   384  
   385  		BeforeEach(func() {
   386  			folderPath = filepath.Join(fmt.Sprintf("test_outputs_%d", GinkgoParallelProcess()))
   387  			fileName := fmt.Sprintf("report-%d", GinkgoParallelProcess())
   388  			filePath = filepath.Join(folderPath, fileName)
   389  
   390  			Ω(reporters.GenerateJUnitReport(report, filePath)).Should(Succeed())
   391  			DeferCleanup(os.RemoveAll, folderPath)
   392  		})
   393  
   394  		It("creates the folder and the report file", func() {
   395  			_, err := os.Stat(folderPath)
   396  			Ω(err).Should(Succeed(), "Parent folder should be created")
   397  			_, err = os.Stat(filePath)
   398  			Ω(err).Should(Succeed(), "Report file should be created")
   399  		})
   400  	})
   401  })
   402  

View as plain text