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

     1  package internal_test
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	"github.com/onsi/ginkgo/internal"
     9  	"github.com/onsi/ginkgo/internal/interrupt_handler"
    10  	"github.com/onsi/ginkgo/internal/parallel_support"
    11  	. "github.com/onsi/ginkgo/internal/test_helpers"
    12  	"github.com/onsi/ginkgo/types"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  var _ = Describe("Suite", func() {
    17  	It("is heavily integration tested over in internal_integration", func() {
    18  	})
    19  
    20  	var suite *internal.Suite
    21  	var failer *internal.Failer
    22  	var reporter *FakeReporter
    23  	var writer *internal.Writer
    24  	var outputInterceptor *FakeOutputInterceptor
    25  	var interruptHandler *interrupt_handler.InterruptHandler
    26  	var conf types.SuiteConfig
    27  	var rt *RunTracker
    28  	var client parallel_support.Client
    29  
    30  	BeforeEach(func() {
    31  		failer = internal.NewFailer()
    32  		reporter = &FakeReporter{}
    33  		writer = internal.NewWriter(io.Discard)
    34  		outputInterceptor = NewFakeOutputInterceptor()
    35  		client = nil
    36  		interruptHandler = interrupt_handler.NewInterruptHandler(0, client)
    37  		DeferCleanup(interruptHandler.Stop)
    38  		conf = types.SuiteConfig{
    39  			ParallelTotal:   1,
    40  			ParallelProcess: 1,
    41  		}
    42  		rt = NewRunTracker()
    43  		suite = internal.NewSuite()
    44  	})
    45  
    46  	Describe("Constructing Trees", func() {
    47  		Describe("PhaseBuildTopLevel vs PhaseBuildTree", func() {
    48  			var err1, err2, err3 error
    49  			BeforeEach(func() {
    50  				err1 = suite.PushNode(N(ntCon, "a top-level container", func() {
    51  					rt.Run("traversing outer")
    52  					err2 = suite.PushNode(N(ntCon, "a nested container", func() {
    53  						rt.Run("traversing nested")
    54  						err3 = suite.PushNode(N(ntIt, "an it", rt.T("running it")))
    55  					}))
    56  				}))
    57  			})
    58  
    59  			It("only traverses top-level containers when told to BuildTree", func() {
    60  				fmt.Fprintln(GinkgoWriter, "HELLO!")
    61  				Ω(rt).Should(HaveTrackedNothing())
    62  				Ω(suite.BuildTree()).Should(Succeed())
    63  				Ω(rt).Should(HaveTracked("traversing outer", "traversing nested"))
    64  
    65  				rt.Reset()
    66  				suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
    67  				Ω(rt).Should(HaveTracked("running it"))
    68  
    69  				Ω(err1).ShouldNot(HaveOccurred())
    70  				Ω(err2).ShouldNot(HaveOccurred())
    71  				Ω(err3).ShouldNot(HaveOccurred())
    72  			})
    73  		})
    74  
    75  		Context("when pushing nodes during PhaseRun", func() {
    76  			var pushNodeErrDuringRun error
    77  
    78  			BeforeEach(func() {
    79  				err := suite.PushNode(N(ntCon, "a top-level container", func() {
    80  					suite.PushNode(N(ntIt, "an it", func() {
    81  						rt.Run("in it")
    82  						pushNodeErrDuringRun = suite.PushNode(N(ntIt, "oops - illegal operation", cl, rt.T("illegal")))
    83  					}))
    84  				}))
    85  
    86  				Ω(err).ShouldNot(HaveOccurred())
    87  				Ω(suite.BuildTree()).Should(Succeed())
    88  			})
    89  
    90  			It("errors", func() {
    91  				suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
    92  				Ω(pushNodeErrDuringRun).Should(HaveOccurred())
    93  				Ω(rt).Should(HaveTracked("in it"))
    94  			})
    95  
    96  		})
    97  
    98  		Context("when the user attemps to fail during PhaseBuildTree", func() {
    99  			BeforeEach(func() {
   100  				suite.PushNode(N(ntCon, "a top-level container", func() {
   101  					failer.Fail("boom", cl)
   102  					panic("simulate ginkgo panic")
   103  				}))
   104  			})
   105  
   106  			It("errors", func() {
   107  				err := suite.BuildTree()
   108  				Ω(err.Error()).Should(ContainSubstring(cl.String()))
   109  				Ω(err.Error()).Should(ContainSubstring("simulate ginkgo panic"))
   110  			})
   111  		})
   112  
   113  		Context("when the user panics during PhaseBuildTree", func() {
   114  			BeforeEach(func() {
   115  				suite.PushNode(N(ntCon, "a top-level container", func() {
   116  					panic("boom")
   117  				}))
   118  			})
   119  
   120  			It("errors", func() {
   121  				err := suite.BuildTree()
   122  				Ω(err).Should(HaveOccurred())
   123  				Ω(err.Error()).Should(ContainSubstring("boom"))
   124  			})
   125  		})
   126  
   127  		Describe("Suite Nodes", func() {
   128  			Context("when pushing suite nodes at the top level", func() {
   129  				BeforeEach(func() {
   130  					err := suite.PushNode(N(types.NodeTypeBeforeSuite))
   131  					Ω(err).ShouldNot(HaveOccurred())
   132  
   133  					err = suite.PushNode(N(types.NodeTypeAfterSuite))
   134  					Ω(err).ShouldNot(HaveOccurred())
   135  				})
   136  
   137  				Context("when pushing more than one BeforeSuite node", func() {
   138  					It("errors", func() {
   139  						err := suite.PushNode(N(types.NodeTypeBeforeSuite))
   140  						Ω(err).Should(HaveOccurred())
   141  
   142  						err = suite.PushNode(N(types.NodeTypeSynchronizedBeforeSuite))
   143  						Ω(err).Should(HaveOccurred())
   144  					})
   145  				})
   146  
   147  				Context("when pushing more than one AfterSuite node", func() {
   148  					It("errors", func() {
   149  						err := suite.PushNode(N(types.NodeTypeAfterSuite))
   150  						Ω(err).Should(HaveOccurred())
   151  
   152  						err = suite.PushNode(N(types.NodeTypeSynchronizedAfterSuite))
   153  						Ω(err).Should(HaveOccurred())
   154  					})
   155  				})
   156  			})
   157  
   158  			Context("when pushing a serial node in an ordered container", func() {
   159  				Context("when the outer-most ordered container is marked serial", func() {
   160  					It("succeeds", func() {
   161  						var errors = make([]error, 3)
   162  						errors[0] = suite.PushNode(N(ntCon, "top-level-container", Ordered, Serial, func() {
   163  							errors[1] = suite.PushNode(N(ntCon, "inner-container", func() {
   164  								errors[2] = suite.PushNode(N(ntIt, "it", Serial, func() {}))
   165  							}))
   166  						}))
   167  						Ω(errors[0]).ShouldNot(HaveOccurred())
   168  						Ω(suite.BuildTree()).Should(Succeed())
   169  						Ω(errors[1]).ShouldNot(HaveOccurred())
   170  						Ω(errors[2]).ShouldNot(HaveOccurred())
   171  					})
   172  				})
   173  
   174  				Context("when the outer-most ordered container is not marked serial", func() {
   175  					It("errors", func() {
   176  						var errors = make([]error, 3)
   177  						errors[0] = suite.PushNode(N(ntCon, "top-level-container", Ordered, func() {
   178  							errors[1] = suite.PushNode(N(ntCon, "inner-container", func() {
   179  								errors[2] = suite.PushNode(N(ntIt, "it", Serial, cl, func() {}))
   180  							}))
   181  						}))
   182  						Ω(errors[0]).ShouldNot(HaveOccurred())
   183  						Ω(suite.BuildTree()).Should(Succeed())
   184  						Ω(errors[1]).ShouldNot(HaveOccurred())
   185  						Ω(errors[2]).Should(MatchError(types.GinkgoErrors.InvalidSerialNodeInNonSerialOrderedContainer(cl, ntIt)))
   186  					})
   187  				})
   188  			})
   189  
   190  			Context("when pushing BeforeAll and AfterAll nodes", func() {
   191  				Context("in an ordered container", func() {
   192  					It("succeeds", func() {
   193  						var errors = make([]error, 3)
   194  						errors[0] = suite.PushNode(N(ntCon, "top-level-container", Ordered, func() {
   195  							errors[1] = suite.PushNode(N(types.NodeTypeBeforeAll, func() {}))
   196  							errors[2] = suite.PushNode(N(types.NodeTypeAfterAll, func() {}))
   197  						}))
   198  						Ω(errors[0]).ShouldNot(HaveOccurred())
   199  						Ω(suite.BuildTree()).Should(Succeed())
   200  						Ω(errors[1]).ShouldNot(HaveOccurred())
   201  						Ω(errors[2]).ShouldNot(HaveOccurred())
   202  					})
   203  				})
   204  
   205  				Context("anywhere else", func() {
   206  					It("errors", func() {
   207  						var errors = make([]error, 3)
   208  						errors[0] = suite.PushNode(N(ntCon, "top-level-container", func() {
   209  							errors[1] = suite.PushNode(N(types.NodeTypeBeforeAll, cl, func() {}))
   210  							errors[2] = suite.PushNode(N(types.NodeTypeAfterAll, cl, func() {}))
   211  						}))
   212  						Ω(errors[0]).ShouldNot(HaveOccurred())
   213  						Ω(suite.BuildTree()).Should(Succeed())
   214  						Ω(errors[1]).Should(MatchError(types.GinkgoErrors.SetupNodeNotInOrderedContainer(cl, types.NodeTypeBeforeAll)))
   215  						Ω(errors[2]).Should(MatchError(types.GinkgoErrors.SetupNodeNotInOrderedContainer(cl, types.NodeTypeAfterAll)))
   216  					})
   217  				})
   218  			})
   219  
   220  			Context("when pushing a suite node during PhaseBuildTree", func() {
   221  				It("errors", func() {
   222  					var pushSuiteNodeErr error
   223  					err := suite.PushNode(N(ntCon, "top-level-container", func() {
   224  						pushSuiteNodeErr = suite.PushNode(N(types.NodeTypeBeforeSuite, cl))
   225  					}))
   226  
   227  					Ω(err).ShouldNot(HaveOccurred())
   228  					Ω(suite.BuildTree()).Should(Succeed())
   229  					Ω(pushSuiteNodeErr).Should(HaveOccurred())
   230  				})
   231  			})
   232  
   233  			Context("when pushing a suite node during PhaseRun", func() {
   234  				It("errors", func() {
   235  					var pushSuiteNodeErr error
   236  					err := suite.PushNode(N(ntIt, "top-level it", func() {
   237  						pushSuiteNodeErr = suite.PushNode(N(types.NodeTypeBeforeSuite, cl))
   238  					}))
   239  
   240  					Ω(err).ShouldNot(HaveOccurred())
   241  					Ω(suite.BuildTree()).Should(Succeed())
   242  					suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
   243  					Ω(pushSuiteNodeErr).Should(HaveOccurred())
   244  				})
   245  			})
   246  		})
   247  
   248  		Describe("Cleanup Nodes", func() {
   249  			Context("when pushing a cleanup node during PhaseTopLevel", func() {
   250  				It("errors", func() {
   251  					err := suite.PushNode(N(types.NodeTypeCleanupInvalid, cl))
   252  					Ω(err).Should(MatchError(types.GinkgoErrors.PushingCleanupNodeDuringTreeConstruction(cl)))
   253  				})
   254  			})
   255  
   256  			Context("when pushing a cleanup node during PhaseBuildTree", func() {
   257  				It("errors", func() {
   258  					var errors = make([]error, 2)
   259  					errors[0] = suite.PushNode(N(ntCon, "container", func() {
   260  						errors[1] = suite.PushNode(N(types.NodeTypeCleanupInvalid, cl))
   261  					}))
   262  					Ω(errors[0]).ShouldNot(HaveOccurred())
   263  					Ω(suite.BuildTree()).Should(Succeed())
   264  					Ω(errors[1]).Should(MatchError(types.GinkgoErrors.PushingCleanupNodeDuringTreeConstruction(cl)))
   265  				})
   266  			})
   267  
   268  			Context("when pushing a cleanup node in a ReportBeforeEach node", func() {
   269  				It("errors", func() {
   270  					var errors = make([]error, 4)
   271  					reportBeforeEachNode, _ := internal.NewReportBeforeEachNode(func(_ types.SpecReport) {
   272  						errors[3] = suite.PushNode(N(types.NodeTypeCleanupInvalid, cl))
   273  					}, types.NewCodeLocation(0))
   274  
   275  					errors[0] = suite.PushNode(N(ntCon, "container", func() {
   276  						errors[1] = suite.PushNode(reportBeforeEachNode)
   277  						errors[2] = suite.PushNode(N(ntIt, "test"))
   278  					}))
   279  					Ω(errors[0]).ShouldNot(HaveOccurred())
   280  
   281  					Ω(suite.BuildTree()).Should(Succeed())
   282  					Ω(errors[1]).ShouldNot(HaveOccurred())
   283  					Ω(errors[2]).ShouldNot(HaveOccurred())
   284  
   285  					suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
   286  					Ω(errors[3]).Should(MatchError(types.GinkgoErrors.PushingCleanupInReportingNode(cl, types.NodeTypeReportBeforeEach)))
   287  				})
   288  			})
   289  
   290  			Context("when pushing a cleanup node in a ReportAfterEach node", func() {
   291  				It("errors", func() {
   292  					var errors = make([]error, 4)
   293  					reportAfterEachNode, _ := internal.NewReportAfterEachNode(func(_ types.SpecReport) {
   294  						errors[3] = suite.PushNode(N(types.NodeTypeCleanupInvalid, cl))
   295  					}, types.NewCodeLocation(0))
   296  
   297  					errors[0] = suite.PushNode(N(ntCon, "container", func() {
   298  						errors[1] = suite.PushNode(N(ntIt, "test"))
   299  						errors[2] = suite.PushNode(reportAfterEachNode)
   300  					}))
   301  					Ω(errors[0]).ShouldNot(HaveOccurred())
   302  
   303  					Ω(suite.BuildTree()).Should(Succeed())
   304  					Ω(errors[1]).ShouldNot(HaveOccurred())
   305  					Ω(errors[2]).ShouldNot(HaveOccurred())
   306  
   307  					suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
   308  					Ω(errors[3]).Should(MatchError(types.GinkgoErrors.PushingCleanupInReportingNode(cl, types.NodeTypeReportAfterEach)))
   309  				})
   310  			})
   311  
   312  			Context("when pushing a cleanup node in a ReportAfterSuite node", func() {
   313  				It("errors", func() {
   314  					var errors = make([]error, 4)
   315  					reportAfterSuiteNode, _ := internal.NewReportAfterSuiteNode("report", func(_ types.Report) {
   316  						errors[3] = suite.PushNode(N(types.NodeTypeCleanupInvalid, cl))
   317  					}, types.NewCodeLocation(0))
   318  
   319  					errors[0] = suite.PushNode(N(ntCon, "container", func() {
   320  						errors[2] = suite.PushNode(N(ntIt, "test"))
   321  					}))
   322  					errors[1] = suite.PushNode(reportAfterSuiteNode)
   323  					Ω(errors[0]).ShouldNot(HaveOccurred())
   324  					Ω(errors[1]).ShouldNot(HaveOccurred())
   325  
   326  					Ω(suite.BuildTree()).Should(Succeed())
   327  					Ω(errors[2]).ShouldNot(HaveOccurred())
   328  
   329  					suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
   330  					Ω(errors[3]).Should(MatchError(types.GinkgoErrors.PushingCleanupInReportingNode(cl, types.NodeTypeReportAfterSuite)))
   331  				})
   332  			})
   333  
   334  			Context("when pushing a cleanup node within a cleanup node", func() {
   335  				It("errors", func() {
   336  					var errors = make([]error, 3)
   337  					errors[0] = suite.PushNode(N(ntIt, "It", func() {
   338  						cleanupNode, _ := internal.NewCleanupNode(nil, types.NewCustomCodeLocation("outerCleanup"), func() {
   339  							innerCleanupNode, _ := internal.NewCleanupNode(nil, cl, func() {})
   340  							errors[2] = suite.PushNode(innerCleanupNode)
   341  						})
   342  						errors[1] = suite.PushNode(cleanupNode)
   343  					}))
   344  					Ω(errors[0]).ShouldNot(HaveOccurred())
   345  					Ω(suite.BuildTree()).Should(Succeed())
   346  					suite.Run("suite", Labels{}, "/path/to/suite", failer, reporter, writer, outputInterceptor, interruptHandler, client, conf)
   347  					Ω(errors[1]).ShouldNot(HaveOccurred())
   348  					Ω(errors[2]).Should(MatchError(types.GinkgoErrors.PushingCleanupInCleanupNode(cl)))
   349  				})
   350  			})
   351  		})
   352  
   353  		Describe("ReportEntries", func() {
   354  			Context("when adding a report entry outside of the run phase", func() {
   355  				It("errors", func() {
   356  					entry, err := internal.NewReportEntry("name", cl)
   357  					Ω(err).ShouldNot(HaveOccurred())
   358  					err = suite.AddReportEntry(entry)
   359  					Ω(err).Should(MatchError(types.GinkgoErrors.AddReportEntryNotDuringRunPhase(cl)))
   360  					suite.BuildTree()
   361  					err = suite.AddReportEntry(entry)
   362  					Ω(err).Should(MatchError(types.GinkgoErrors.AddReportEntryNotDuringRunPhase(cl)))
   363  				})
   364  			})
   365  		})
   366  	})
   367  })