github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/internal_integration/report_after_suite_test.go (about)

     1  package internal_integration_test
     2  
     3  import (
     4  	"time"
     5  
     6  	. "github.com/onsi/ginkgo"
     7  	"github.com/onsi/ginkgo/internal/interrupt_handler"
     8  	. "github.com/onsi/ginkgo/internal/test_helpers"
     9  	"github.com/onsi/ginkgo/types"
    10  	. "github.com/onsi/gomega"
    11  )
    12  
    13  var _ = Describe("Sending reports to ReportAfterSuite procs", func() {
    14  	var failInReportAfterSuiteA, interruptSuiteB bool
    15  	var fixture func()
    16  
    17  	BeforeEach(func() {
    18  		failInReportAfterSuiteA = false
    19  		interruptSuiteB = false
    20  		conf.RandomSeed = 17
    21  		fixture = func() {
    22  			BeforeSuite(rt.T("before-suite", func() {
    23  				outputInterceptor.AppendInterceptedOutput("out-before-suite")
    24  			}))
    25  			Context("container", func() {
    26  				It("A", rt.T("A"))
    27  				It("B", rt.T("B", func() {
    28  					F("fail in B")
    29  				}))
    30  				It("C", rt.T("C"))
    31  				PIt("D", rt.T("D"))
    32  			})
    33  			ReportAfterSuite("Report A", func(report Report) {
    34  				rt.RunWithData("report-A", "report", report)
    35  				writer.Print("gw-report-A")
    36  				outputInterceptor.AppendInterceptedOutput("out-report-A")
    37  				if failInReportAfterSuiteA {
    38  					F("fail in report-A")
    39  				}
    40  			})
    41  			ReportAfterSuite("Report B", func(report Report) {
    42  				if interruptSuiteB {
    43  					interruptHandler.Interrupt(interrupt_handler.InterruptCauseTimeout)
    44  					time.Sleep(100 * time.Millisecond)
    45  				}
    46  				rt.RunWithData("report-B", "report", report, "emitted-interrupt", interruptHandler.EmittedInterruptPlaceholderMessage())
    47  				writer.Print("gw-report-B")
    48  				outputInterceptor.AppendInterceptedOutput("out-report-B")
    49  			})
    50  			AfterSuite(rt.T("after-suite", func() {
    51  				writer.Print("gw-after-suite")
    52  				F("fail in after-suite")
    53  			}))
    54  
    55  		}
    56  	})
    57  
    58  	Context("when running in series", func() {
    59  		BeforeEach(func() {
    60  			conf.ParallelTotal = 1
    61  			conf.ParallelProcess = 1
    62  		})
    63  
    64  		Context("the happy path", func() {
    65  			BeforeEach(func() {
    66  				success, _ := RunFixture("happy-path", fixture)
    67  				Ω(success).Should(BeFalse())
    68  			})
    69  
    70  			It("runs all the functions", func() {
    71  				Ω(rt).Should(HaveTracked(
    72  					"before-suite",
    73  					"A", "B", "C",
    74  					"after-suite",
    75  					"report-A", "report-B",
    76  				))
    77  			})
    78  
    79  			It("reports on the report procs", func() {
    80  				Ω(reporter.Did.Find("Report A")).Should(HavePassed(
    81  					types.NodeTypeReportAfterSuite,
    82  					CapturedGinkgoWriterOutput("gw-report-A"),
    83  					CapturedStdOutput("out-report-A"),
    84  				))
    85  
    86  				Ω(reporter.Did.Find("Report B")).Should(HavePassed(
    87  					types.NodeTypeReportAfterSuite,
    88  					CapturedGinkgoWriterOutput("gw-report-B"),
    89  					CapturedStdOutput("out-report-B"),
    90  				))
    91  			})
    92  
    93  			It("passes the report in to each reporter", func() {
    94  				reportA := rt.DataFor("report-A")["report"].(types.Report)
    95  				reportB := rt.DataFor("report-B")["report"].(types.Report)
    96  
    97  				for _, report := range []types.Report{reportA, reportB} {
    98  					Ω(report.SuiteDescription).Should(Equal("happy-path"))
    99  					Ω(report.SuiteSucceeded).Should(BeFalse())
   100  					Ω(report.SuiteConfig.RandomSeed).Should(Equal(int64(17)))
   101  					reports := Reports(report.SpecReports)
   102  					Ω(reports.FindByLeafNodeType(types.NodeTypeBeforeSuite)).Should(HavePassed(CapturedStdOutput("out-before-suite")))
   103  					Ω(reports.Find("A")).Should(HavePassed())
   104  					Ω(reports.Find("B")).Should(HaveFailed("fail in B"))
   105  					Ω(reports.Find("C")).Should(HavePassed())
   106  					Ω(reports.Find("D")).Should(BePending())
   107  					Ω(reports.FindByLeafNodeType(types.NodeTypeAfterSuite)).Should(HaveFailed("fail in after-suite", CapturedGinkgoWriterOutput("gw-after-suite")))
   108  				}
   109  
   110  				Ω(len(reportB.SpecReports)-len(reportA.SpecReports)).Should(Equal(1), "Report B includes the invocation of ReporteAfterSuite A")
   111  				Ω(Reports(reportB.SpecReports).Find("Report A")).Should(Equal(reporter.Did.Find("Report A")))
   112  			})
   113  		})
   114  
   115  		Context("when a ReportAfterSuite proc fails", func() {
   116  			BeforeEach(func() {
   117  				failInReportAfterSuiteA = true
   118  				success, _ := RunFixture("report-A-fails", fixture)
   119  				Ω(success).Should(BeFalse())
   120  			})
   121  
   122  			It("keeps running subseuqent reporting functions", func() {
   123  				Ω(rt).Should(HaveTracked(
   124  					"before-suite",
   125  					"A", "B", "C",
   126  					"after-suite",
   127  					"report-A", "report-B",
   128  				))
   129  			})
   130  
   131  			It("reports on the faitlure, to Ginkgo's reporter and any subsequent reporters", func() {
   132  				Ω(reporter.Did.Find("Report A")).Should(HaveFailed(
   133  					types.NodeTypeReportAfterSuite,
   134  					"fail in report-A",
   135  					CapturedGinkgoWriterOutput("gw-report-A"),
   136  					CapturedStdOutput("out-report-A"),
   137  				))
   138  
   139  				reportB := rt.DataFor("report-B")["report"].(types.Report)
   140  				Ω(Reports(reportB.SpecReports).Find("Report A")).Should(Equal(reporter.Did.Find("Report A")))
   141  			})
   142  		})
   143  
   144  		Context("when an interrupt is attempted in a ReportAfterSuiteNode", func() {
   145  			BeforeEach(func() {
   146  				interruptSuiteB = true
   147  				success, _ := RunFixture("report-B-interrupted", fixture)
   148  				Ω(success).Should(BeFalse())
   149  			})
   150  
   151  			It("ignores the interrupt and soliders on", func() {
   152  				Ω(rt).Should(HaveTracked(
   153  					"before-suite",
   154  					"A", "B", "C",
   155  					"after-suite",
   156  					"report-A", "report-B",
   157  				))
   158  
   159  				Ω(rt.DataFor("report-B")["report"]).ShouldNot(BeZero())
   160  				Ω(rt.DataFor("report-B")["emitted-interrupt"]).Should(ContainSubstring("The running ReportAfterSuite node is at:\n%s", reporter.Did.Find("Report B").LeafNodeLocation.FileName))
   161  			})
   162  		})
   163  	})
   164  
   165  	Context("when running in parallel", func() {
   166  		var otherNodeReport types.Report
   167  
   168  		BeforeEach(func() {
   169  			SetUpForParallel(2)
   170  
   171  			otherNodeReport = types.Report{
   172  				SpecReports: types.SpecReports{
   173  					types.SpecReport{LeafNodeText: "E", LeafNodeLocation: cl, State: types.SpecStatePassed, LeafNodeType: types.NodeTypeIt},
   174  					types.SpecReport{LeafNodeText: "F", LeafNodeLocation: cl, State: types.SpecStateSkipped, LeafNodeType: types.NodeTypeIt},
   175  				},
   176  			}
   177  		})
   178  
   179  		Context("on proc 1", func() {
   180  			BeforeEach(func() {
   181  				conf.ParallelProcess = 1
   182  			})
   183  
   184  			Context("the happy path", func() {
   185  				BeforeEach(func() {
   186  					// proc 2 has reported back and exited
   187  					client.PostSuiteDidEnd(otherNodeReport)
   188  					close(exitChannels[2])
   189  					success, _ := RunFixture("happy-path", fixture)
   190  					Ω(success).Should(BeFalse())
   191  				})
   192  
   193  				It("runs all the functions", func() {
   194  					Ω(rt).Should(HaveTracked(
   195  						"before-suite",
   196  						"A", "B", "C",
   197  						"after-suite",
   198  						"report-A", "report-B",
   199  					))
   200  				})
   201  
   202  				It("passes the report in to each reporter, including information from other procs", func() {
   203  					reportA := rt.DataFor("report-A")["report"].(types.Report)
   204  					reportB := rt.DataFor("report-B")["report"].(types.Report)
   205  
   206  					for _, report := range []types.Report{reportA, reportB} {
   207  						Ω(report.SuiteDescription).Should(Equal("happy-path"))
   208  						Ω(report.SuiteSucceeded).Should(BeFalse())
   209  						reports := Reports(report.SpecReports)
   210  						Ω(reports.FindByLeafNodeType(types.NodeTypeBeforeSuite)).Should(HavePassed(CapturedStdOutput("out-before-suite")))
   211  						Ω(reports.Find("A")).Should(HavePassed())
   212  						Ω(reports.Find("B")).Should(HaveFailed("fail in B"))
   213  						Ω(reports.Find("C")).Should(HavePassed())
   214  						Ω(reports.Find("D")).Should(BePending())
   215  						Ω(reports.Find("E")).Should(HavePassed())
   216  						Ω(reports.Find("F")).Should(HaveBeenSkipped())
   217  						Ω(reports.FindByLeafNodeType(types.NodeTypeAfterSuite)).Should(HaveFailed("fail in after-suite", CapturedGinkgoWriterOutput("gw-after-suite")))
   218  					}
   219  
   220  					Ω(len(reportB.SpecReports)-len(reportA.SpecReports)).Should(Equal(1), "Report B includes the invocation of ReporteAfterSuite A")
   221  					Ω(Reports(reportB.SpecReports).Find("Report A")).Should(Equal(reporter.Did.Find("Report A")))
   222  				})
   223  			})
   224  
   225  			Describe("waiting for reports from other procs", func() {
   226  				It("blocks until the other procs have finished", func() {
   227  					done := make(chan interface{})
   228  					go func() {
   229  						defer GinkgoRecover()
   230  						success, _ := RunFixture("happy-path", fixture)
   231  						Ω(success).Should(BeFalse())
   232  						close(done)
   233  					}()
   234  					Consistently(done).ShouldNot(BeClosed())
   235  					client.PostSuiteDidEnd(otherNodeReport)
   236  					Consistently(done).ShouldNot(BeClosed())
   237  					close(exitChannels[2])
   238  					Eventually(done).Should(BeClosed())
   239  				})
   240  			})
   241  
   242  			Context("when a non-primary proc disappears before it reports", func() {
   243  				BeforeEach(func() {
   244  					close(exitChannels[2]) //proc 2 disappears before reporting
   245  					success, _ := RunFixture("disappearing-proc-2", fixture)
   246  					Ω(success).Should(BeFalse())
   247  				})
   248  
   249  				It("does not run the ReportAfterSuite procs", func() {
   250  					Ω(rt).Should(HaveTracked(
   251  						"before-suite",
   252  						"A", "B", "C",
   253  						"after-suite",
   254  					))
   255  				})
   256  
   257  				It("reports all the ReportAfterSuite procs as failed", func() {
   258  					Ω(reporter.Did.Find("Report A")).Should(HaveFailed(types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing().Error()))
   259  					Ω(reporter.Did.Find("Report B")).Should(HaveFailed(types.GinkgoErrors.AggregatedReportUnavailableDueToNodeDisappearing().Error()))
   260  				})
   261  			})
   262  		})
   263  
   264  		Context("on a non-primary proc", func() {
   265  			BeforeEach(func() {
   266  				conf.ParallelProcess = 2
   267  				success, _ := RunFixture("happy-path", fixture)
   268  				Ω(success).Should(BeFalse())
   269  			})
   270  
   271  			It("does not run the ReportAfterSuite procs", func() {
   272  				Ω(rt).Should(HaveTracked(
   273  					"before-suite",
   274  					"A", "B", "C",
   275  					"after-suite",
   276  				))
   277  			})
   278  		})
   279  	})
   280  })