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

     1  package internal_integration_test
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	"github.com/onsi/ginkgo/internal/interrupt_handler"
     9  	. "github.com/onsi/ginkgo/internal/test_helpers"
    10  	"github.com/onsi/ginkgo/types"
    11  	. "github.com/onsi/gomega"
    12  )
    13  
    14  const SKIP_DUE_TO_EARLIER_FAILURE = "Spec skipped because an earlier spec in an ordered container failed"
    15  const SKIP_DUE_TO_BEFORE_ALL_SKIP = "Spec skipped because Skip() was called in BeforeAll"
    16  
    17  var DC = func(label string, callback ...func()) func() {
    18  	return func() {
    19  		DeferCleanup(rt.T(label, callback...))
    20  	}
    21  }
    22  
    23  var FlakeyFailer = func(n int) func() {
    24  	i := 0
    25  	return func() {
    26  		i += 1
    27  		if i <= n {
    28  			F("fail")
    29  		}
    30  	}
    31  }
    32  
    33  var FlakeyFailerWithCleanup = func(n int, cleanupLabel string) func() {
    34  	i := 0
    35  	return func() {
    36  		i += 1
    37  		DeferCleanup(rt.T(cleanupLabel + "-pre"))
    38  		if i <= n {
    39  			F("fail")
    40  		}
    41  		DeferCleanup(rt.T(cleanupLabel + "-post"))
    42  	}
    43  }
    44  
    45  var _ = DescribeTable("Ordered Containers",
    46  	func(expectedSuccess bool, fixture func(), runs []string, args ...interface{}) {
    47  		success, _ := RunFixture(CurrentSpecReport().LeafNodeText, fixture)
    48  		Ω(success).Should(Equal(expectedSuccess))
    49  		Ω(rt).Should(HaveTracked(runs...))
    50  		specs := Reports{}
    51  		for i := 0; i < len(args); i += 1 {
    52  			switch v := args[i].(type) {
    53  			case string:
    54  				specs = append(specs, reporter.Did.Find(v))
    55  			case OmegaMatcher:
    56  				Ω(specs).ShouldNot(BeEmpty(), "Got a matcher but expected a spec to look up")
    57  				for _, spec := range specs {
    58  					Ω(spec).Should(v, "Spec that failed: %s", spec.LeafNodeText)
    59  				}
    60  				specs = Reports{}
    61  			default:
    62  				Fail(fmt.Sprintf("Unexpected type %T", args[i]))
    63  			}
    64  		}
    65  		Ω(specs).Should(BeEmpty(), "Trailing spec - missing a matcher")
    66  	},
    67  	// basic ordering
    68  	Entry("simply happy path", true, func() {
    69  		Context("container", Ordered, func() {
    70  			It("A", rt.T("A"))
    71  			It("B", rt.T("B"))
    72  			It("C", rt.T("C"))
    73  		})
    74  	}, []string{"A", "B", "C"},
    75  		"A", "B", "C", HavePassed(),
    76  	),
    77  	Entry("when a spec fails", false, func() {
    78  		Context("outer container", func() {
    79  			Context("container", Ordered, func() {
    80  				It("A", rt.T("A"))
    81  				It("B", rt.T("B"))
    82  				It("C", rt.T("C", func() { F("fail") }))
    83  				It("D", rt.T("D"))
    84  				It("E", rt.T("E"))
    85  			})
    86  			Context("container", Ordered, func() {
    87  				It("F", FlakeAttempts(3), rt.T("F", FlakeyFailer(2)))
    88  				It("G", rt.T("G"))
    89  			})
    90  		})
    91  	}, []string{"A", "B", "C", "F", "F", "F", "G"},
    92  		"A", "B", HavePassed(),
    93  		"C", HaveFailed(),
    94  		"D", "E", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
    95  		"F", HavePassed(NumAttempts(3)),
    96  		"G", HavePassed(NumAttempts(1)),
    97  	),
    98  	// BeforeAll and AfterAll - happy paths
    99  	Entry("BeforeAll and AfterAll Happy Path", true, func() {
   100  		BeforeEach(rt.T("BE1"))
   101  		JustBeforeEach(rt.T("JBE1"))
   102  		AfterEach(rt.T("AE1"))
   103  		Context("container", Ordered, func() {
   104  			BeforeEach(rt.T("BE2"))
   105  			JustBeforeEach(rt.T("JBE2"))
   106  			BeforeAll(rt.T("BA1"))
   107  			BeforeEach(rt.T("BE3"))
   108  			JustBeforeEach(rt.T("JBE3"))
   109  			BeforeAll(rt.T("BA2"))
   110  			BeforeEach(rt.T("BE4"))
   111  			It("A", rt.T("A"))
   112  			It("B", rt.T("B"))
   113  			It("C", rt.T("C"))
   114  			JustAfterEach(rt.T("JAE1"))
   115  			AfterEach(rt.T("AE2"))
   116  			AfterAll(rt.T("AA1"))
   117  			AfterEach(rt.T("AE3"))
   118  			JustAfterEach(rt.T("JAE2"))
   119  			AfterAll(rt.T("AA2"))
   120  			AfterEach(rt.T("AE4"))
   121  			JustAfterEach(rt.T("JAE3"))
   122  		})
   123  		JustAfterEach(rt.T("JAE4"))
   124  		AfterEach(rt.T("AE5"))
   125  		BeforeEach(rt.T("BE5"))
   126  		JustBeforeEach(rt.T("JBE4"))
   127  	}, []string{
   128  		"BE1", "BE5",
   129  		"BA1", "BA2", "BE2", "BE3", "BE4",
   130  		"JBE1", "JBE4", "JBE2", "JBE3",
   131  		"A",
   132  		"JAE1", "JAE2", "JAE3", "JAE4",
   133  		"AE2", "AE3", "AE4",
   134  		"AE1", "AE5",
   135  		"BE1", "BE5",
   136  		"BE2", "BE3", "BE4",
   137  		"JBE1", "JBE4", "JBE2", "JBE3",
   138  		"B",
   139  		"JAE1", "JAE2", "JAE3", "JAE4",
   140  		"AE2", "AE3", "AE4",
   141  		"AE1", "AE5",
   142  		"BE1", "BE5",
   143  		"BE2", "BE3", "BE4",
   144  		"JBE1", "JBE4", "JBE2", "JBE3",
   145  		"C",
   146  		"JAE1", "JAE2", "JAE3", "JAE4",
   147  		"AE2", "AE3", "AE4", "AA1", "AA2",
   148  		"AE1", "AE5",
   149  	}),
   150  	Entry("when there is only one spec", true, func() {
   151  		Context("container", Ordered, func() {
   152  			BeforeEach(rt.T("BE"))
   153  			BeforeAll(rt.T("BA"))
   154  			It("A", rt.T("A"))
   155  			AfterAll(rt.T("AA"))
   156  			AfterEach(rt.T("AE"))
   157  		})
   158  	}, []string{
   159  		"BA", "BE", "A", "AE", "AA",
   160  	}),
   161  	Entry("when there are focused specs", true, func() {
   162  		Context("container", Ordered, func() {
   163  			BeforeEach(rt.T("BE"))
   164  			BeforeAll(rt.T("BA"))
   165  			It("A", rt.T("A"))
   166  			FIt("B", rt.T("B"))
   167  			FIt("C", rt.T("C"))
   168  			It("D", rt.T("D"))
   169  			AfterAll(rt.T("AA"))
   170  			AfterEach(rt.T("AE"))
   171  		})
   172  	}, []string{
   173  		"BA", "BE", "B", "AE", "BE", "C", "AE", "AA",
   174  	},
   175  		"B", "C", HavePassed(),
   176  		"A", "D", HaveBeenSkipped(),
   177  	),
   178  	Entry("when there is nothing to run", true, func() {
   179  		Context("container", Ordered, func() {
   180  			BeforeEach(rt.T("BE"))
   181  			BeforeAll(rt.T("BA"))
   182  			PIt("A", rt.T("A"))
   183  			PIt("B", rt.T("B"))
   184  			PIt("C", rt.T("C"))
   185  			AfterAll(rt.T("AA"))
   186  			AfterEach(rt.T("AE"))
   187  		})
   188  	}, []string{}, "A", "B", "C", BePending()),
   189  	// BeforeAll and AfterAll - when skips are called
   190  	Entry("when a skip occurs in a BeforeAll, it skips the entire group", true, func() {
   191  		Context("container", Ordered, func() {
   192  			BeforeAll(rt.T("BA", func() { DeferCleanup(rt.T("DC")); Skip("skip") }))
   193  			It("A", FlakeAttempts(3), rt.T("A"))
   194  			It("B", rt.T("B"))
   195  			It("C", rt.T("C"))
   196  			AfterAll(rt.T("AA"))
   197  		})
   198  	}, []string{"BA", "AA", "DC"},
   199  		"A", HaveBeenSkippedWithMessage("skip", NumAttempts(1)),
   200  		"B", "C", HaveBeenSkippedWithMessage(SKIP_DUE_TO_BEFORE_ALL_SKIP),
   201  	),
   202  	Entry("when a skip occurs in a test", true, func() {
   203  		Context("container", Ordered, func() {
   204  			BeforeAll(rt.T("BA"))
   205  			It("A", rt.T("A"))
   206  			It("B", rt.T("B", func() { Skip("skip") }))
   207  			It("C", rt.T("C"))
   208  			AfterAll(rt.T("AA"))
   209  		})
   210  	}, []string{"BA", "A", "B", "C", "AA"},
   211  		"A", "C", HavePassed(),
   212  		"B", HaveBeenSkippedWithMessage("skip"),
   213  	),
   214  	Entry("when a skip occurs in the last test", true, func() {
   215  		Context("container", Ordered, func() {
   216  			BeforeAll(rt.T("BA"))
   217  			It("A", rt.T("A"))
   218  			It("B", rt.T("B"))
   219  			It("C", rt.T("C", func() { Skip("skip") }))
   220  			AfterAll(rt.T("AA"))
   221  		})
   222  	}, []string{"BA", "A", "B", "C", "AA"},
   223  		"A", "B", HavePassed(),
   224  		"C", HaveBeenSkippedWithMessage("skip"),
   225  	),
   226  	// BeforeAll and AfterAll - when failures, panics, interrupts, and aborts happen
   227  	Entry("when a failure occurs prior to the BeforeAll, it doesn't run the Alls", false, func() {
   228  		BeforeEach(rt.T("BE-outer", func() { F("fail") }))
   229  		Context("container", Ordered, func() {
   230  			BeforeEach(rt.T("BE"))
   231  			BeforeAll(rt.T("BA"))
   232  			It("A", rt.T("A"))
   233  			AfterAll(rt.T("AA"))
   234  			AfterEach(rt.T("AE"))
   235  		})
   236  		AfterEach(rt.T("AE-outer"))
   237  	}, []string{
   238  		"BE-outer", "AE-outer",
   239  	}, "A", HaveFailed(types.FailureNodeAtTopLevel, FailureNodeType(types.NodeTypeBeforeEach), "fail")),
   240  	Entry("when a failure occurs in a spec, it runs the AfterAll and skips subsequent specs", false, func() {
   241  		BeforeEach(rt.T("BE-outer"))
   242  		Context("container", Ordered, func() {
   243  			BeforeEach(rt.T("BE"))
   244  			BeforeAll(rt.T("BA"))
   245  			It("A", rt.T("A", func() { F("fail") }))
   246  			It("B", rt.T("B"))
   247  			AfterAll(rt.T("AA"))
   248  			AfterEach(rt.T("AE"))
   249  		})
   250  		AfterEach(rt.T("AE-outer"))
   251  	}, []string{"BE-outer", "BA", "BE", "A", "AE", "AA", "AE-outer"},
   252  		"A", HaveFailed(types.FailureNodeIsLeafNode, FailureNodeType(types.NodeTypeIt), "fail"),
   253  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   254  	),
   255  	Entry("when a failure occurs in a BeforeAll", false, func() {
   256  		BeforeEach(rt.T("BE-outer"))
   257  		Context("container", Ordered, func() {
   258  			BeforeEach(rt.T("BE"))
   259  			BeforeAll(rt.T("BA", func() { F("fail") }))
   260  			It("A", rt.T("A"))
   261  			It("B", rt.T("B"))
   262  			AfterAll(rt.T("AA"))
   263  			AfterEach(rt.T("AE"))
   264  		})
   265  		AfterEach(rt.T("AE-outer"))
   266  	}, []string{"BE-outer", "BA", "AE", "AA", "AE-outer"},
   267  		"A", HaveFailed(types.FailureNodeInContainer, FailureNodeType(types.NodeTypeBeforeAll), "fail"),
   268  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   269  	),
   270  	Entry("when a failure occurs in an AfterAll", false, func() {
   271  		BeforeEach(rt.T("BE-outer"))
   272  		Context("container", Ordered, func() {
   273  			BeforeEach(rt.T("BE"))
   274  			BeforeAll(rt.T("BA"))
   275  			It("A", rt.T("A"))
   276  			It("B", rt.T("B"))
   277  			AfterAll(rt.T("AA", func() { F("fail") }))
   278  			AfterEach(rt.T("AE"))
   279  		})
   280  		AfterEach(rt.T("AE-outer"))
   281  	}, []string{
   282  		"BE-outer", "BA", "BE", "A", "AE", "AE-outer",
   283  		"BE-outer", "BE", "B", "AE", "AA", "AE-outer",
   284  	}, "A", HavePassed(),
   285  		"B", HaveFailed(types.FailureNodeInContainer, FailureNodeType(types.NodeTypeAfterAll), "fail"),
   286  	),
   287  	Entry("when a panic occurs in a BeforeAll", false, func() {
   288  		BeforeEach(rt.T("BE-outer"))
   289  		Context("container", Ordered, func() {
   290  			BeforeEach(rt.T("BE"))
   291  			BeforeAll(rt.T("BA", func() { panic("boom") }))
   292  			It("A", rt.T("A"))
   293  			It("B", rt.T("B"))
   294  			AfterAll(rt.T("AA"))
   295  			AfterEach(rt.T("AE"))
   296  		})
   297  		AfterEach(rt.T("AE-outer"))
   298  	}, []string{"BE-outer", "BA", "AE", "AA", "AE-outer"},
   299  		"A", HavePanicked(types.FailureNodeInContainer, FailureNodeType(types.NodeTypeBeforeAll), "boom"),
   300  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   301  	),
   302  	Entry("when a panic occurs in an AfterAll", false, func() {
   303  		BeforeEach(rt.T("BE-outer"))
   304  		Context("container", Ordered, func() {
   305  			BeforeEach(rt.T("BE"))
   306  			BeforeAll(rt.T("BA"))
   307  			It("A", rt.T("A"))
   308  			It("B", rt.T("B"))
   309  			AfterAll(rt.T("AA", func() { panic("boom") }))
   310  			AfterEach(rt.T("AE"))
   311  		})
   312  		AfterEach(rt.T("AE-outer"))
   313  	}, []string{
   314  		"BE-outer", "BA", "BE", "A", "AE", "AE-outer",
   315  		"BE-outer", "BE", "B", "AE", "AA", "AE-outer",
   316  	}, "A", HavePassed(),
   317  		"B", HavePanicked(types.FailureNodeInContainer, FailureNodeType(types.NodeTypeAfterAll), "boom"),
   318  	),
   319  	Entry("when a failure occurs in an AfterEach, it runs the AfterAll", false, func() {
   320  		BeforeEach(rt.T("BE-outer"))
   321  		Context("container", Ordered, func() {
   322  			BeforeEach(rt.T("BE"))
   323  			BeforeAll(rt.T("BA"))
   324  			It("A", rt.T("A"))
   325  			It("B", rt.T("B"))
   326  			AfterAll(rt.T("AA"))
   327  			AfterEach(rt.T("AE", func() { F("fail") }))
   328  		})
   329  		AfterEach(rt.T("AE-outer"))
   330  	}, []string{"BE-outer", "BA", "BE", "A", "AE", "AE-outer", "AA"},
   331  		"A", HaveFailed(types.FailureNodeInContainer, FailureNodeType(types.NodeTypeAfterEach), "fail"),
   332  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   333  	),
   334  	Entry("when a failure occurs in a DeferCleanup, it runs the AfterAll", false, func() {
   335  		BeforeEach(rt.T("BE-outer"))
   336  		Context("container", Ordered, func() {
   337  			BeforeEach(rt.T("BE"))
   338  			BeforeAll(rt.T("BA"))
   339  			It("A", rt.T("A", func() {
   340  				DeferCleanup(func() {
   341  					rt.Run("cleanup")
   342  					Fail("fail")
   343  				})
   344  			}))
   345  			It("B", rt.T("B"))
   346  			AfterAll(rt.T("AA"))
   347  			AfterEach(rt.T("AE"))
   348  		})
   349  		AfterEach(rt.T("AE-outer"))
   350  	}, []string{"BE-outer", "BA", "BE", "A", "AE", "AE-outer", "cleanup", "AA"},
   351  		"A", HaveFailed(types.FailureNodeInContainer, FailureNodeType(types.NodeTypeCleanupAfterEach), "fail"),
   352  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   353  	),
   354  	Entry("when an interruption occurs, run the AfterAll and skip subsequent specs", false, func() {
   355  		BeforeEach(rt.T("BE-outer"))
   356  		Context("container", Ordered, FlakeAttempts(4), func() {
   357  			BeforeEach(rt.T("BE"))
   358  			BeforeAll(rt.T("BA"))
   359  			It("A", rt.T("A", func() {
   360  				interruptHandler.Interrupt(interrupt_handler.InterruptCauseSignal)
   361  				time.Sleep(time.Minute)
   362  			}))
   363  			It("B", rt.T("B"))
   364  			AfterAll(rt.T("AA"))
   365  			AfterEach(rt.T("AE"))
   366  		})
   367  		AfterEach(rt.T("AE-outer"))
   368  	}, []string{"BE-outer", "BA", "BE", "A", "AE", "AA", "AE-outer"},
   369  		"A", HaveBeenInterrupted(interrupt_handler.InterruptCauseSignal),
   370  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   371  	),
   372  	Entry("when an interruption occurs in a BeforeAll, run the AfterAll and skip subsequent specs", false, func() {
   373  		BeforeEach(rt.T("BE-outer"))
   374  		Context("container", Ordered, FlakeAttempts(4), func() {
   375  			BeforeEach(rt.T("BE"))
   376  			BeforeAll(rt.T("BA", func() {
   377  				DeferCleanup(rt.T("DC-BA"))
   378  				interruptHandler.Interrupt(interrupt_handler.InterruptCauseSignal)
   379  				time.Sleep(time.Minute)
   380  			}))
   381  			It("A", rt.T("A"))
   382  			It("B", rt.T("B"))
   383  			AfterAll(rt.T("AA"))
   384  			AfterEach(rt.T("AE"))
   385  		})
   386  		AfterEach(rt.T("AE-outer"))
   387  	}, []string{"BE-outer", "BA", "AE", "AA", "AE-outer", "DC-BA"},
   388  		"A", HaveBeenInterrupted(interrupt_handler.InterruptCauseSignal),
   389  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   390  	),
   391  	Entry("when an interruption occurs in an AfterAll, run any remaining cleanup", false, func() {
   392  		BeforeEach(rt.T("BE-outer"))
   393  		Context("container", Ordered, FlakeAttempts(4), func() {
   394  			BeforeEach(rt.T("BE"))
   395  			BeforeAll(rt.T("BA", DC("DC-BA")))
   396  			It("A", rt.T("A"))
   397  			It("B", rt.T("B"))
   398  			AfterAll(rt.T("AA", func() {
   399  				DeferCleanup(rt.T("DC-AA"))
   400  				interruptHandler.Interrupt(interrupt_handler.InterruptCauseSignal)
   401  				time.Sleep(time.Minute)
   402  			}))
   403  			AfterEach(rt.T("AE"))
   404  		})
   405  		AfterEach(rt.T("AE-outer"))
   406  	}, []string{
   407  		"BE-outer", "BA", "BE", "A", "AE", "AE-outer",
   408  		"BE-outer", "BE", "B", "AE", "AA", "AE-outer",
   409  		"DC-AA", "DC-BA",
   410  	},
   411  		"A", HavePassed(),
   412  		"B", HaveBeenInterrupted(interrupt_handler.InterruptCauseSignal),
   413  	),
   414  	Entry("when an abort occurs, run the AfterAll and skip subsequent specs", false, func() {
   415  		BeforeEach(rt.T("BE-outer"))
   416  		Context("container", Ordered, FlakeAttempts(4), func() {
   417  			BeforeEach(rt.T("BE"))
   418  			BeforeAll(rt.T("BA"))
   419  			It("A", rt.T("A", func() {
   420  				Abort("abort!")
   421  			}))
   422  			It("B", rt.T("B"))
   423  			AfterAll(rt.T("AA"))
   424  			AfterEach(rt.T("AE"))
   425  		})
   426  		AfterEach(rt.T("AE-outer"))
   427  	}, []string{"BE-outer", "BA", "BE", "A", "AE", "AA", "AE-outer"},
   428  		"A", HaveAborted("abort!"),
   429  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   430  	),
   431  	Entry("when an abort occurs in a BeforeAll, run the AfterAll and skip subsequent specs", false, func() {
   432  		BeforeEach(rt.T("BE-outer"))
   433  		Context("container", Ordered, FlakeAttempts(4), func() {
   434  			BeforeEach(rt.T("BE"))
   435  			BeforeAll(rt.T("BA", func() {
   436  				DeferCleanup(rt.T("DC-BA"))
   437  				Abort("abort!")
   438  			}))
   439  			It("A", rt.T("A"))
   440  			It("B", rt.T("B"))
   441  			AfterAll(rt.T("AA"))
   442  			AfterEach(rt.T("AE"))
   443  		})
   444  		AfterEach(rt.T("AE-outer"))
   445  	}, []string{"BE-outer", "BA", "AE", "AA", "AE-outer", "DC-BA"},
   446  		"A", HaveAborted("abort!"),
   447  		"B", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   448  	),
   449  	Entry("when an abort occurs in an AfterAll, run any remaining cleanup", false, func() {
   450  		BeforeEach(rt.T("BE-outer"))
   451  		Context("container", Ordered, FlakeAttempts(4), func() {
   452  			BeforeEach(rt.T("BE"))
   453  			BeforeAll(rt.T("BA", DC("DC-BA")))
   454  			It("A", rt.T("A"))
   455  			It("B", rt.T("B"))
   456  			AfterAll(rt.T("AA", func() {
   457  				DeferCleanup(rt.T("DC-AA"))
   458  				Abort("abort!")
   459  			}))
   460  			AfterEach(rt.T("AE"))
   461  		})
   462  		AfterEach(rt.T("AE-outer"))
   463  	}, []string{
   464  		"BE-outer", "BA", "BE", "A", "AE", "AE-outer",
   465  		"BE-outer", "BE", "B", "AE", "AA", "AE-outer",
   466  		"DC-AA", "DC-BA",
   467  	},
   468  		"A", HavePassed(),
   469  		"B", HaveAborted("abort!"),
   470  	),
   471  	//here be dragons: the interplay between BeforeAll/AfterAll and FlakeAttempts
   472  	Entry("when the first spec is flaky, it runs the BeforeAll just once", true, func() {
   473  		Context("container", Ordered, FlakeAttempts(4), func() {
   474  			BeforeAll(rt.T("BA"))
   475  			It("A", rt.T("A", FlakeyFailer(2)))
   476  			It("B", rt.T("B"))
   477  			It("C", rt.T("C"))
   478  			AfterAll(rt.T("AA"))
   479  		})
   480  	}, []string{"BA", "A", "A", "A", "B", "C", "AA"},
   481  		"A", HavePassed(NumAttempts(3)),
   482  		"B", "C", HavePassed(NumAttempts(1)),
   483  	),
   484  	Entry("when a spec is flaky and never succeeds, it runs the AfterAll (just once) when the spec ultimately fails", false, func() {
   485  		Context("container", Ordered, FlakeAttempts(4), func() {
   486  			BeforeAll(rt.T("BA"))
   487  			It("A", rt.T("A"))
   488  			It("B", rt.T("B", FlakeyFailer(4)))
   489  			It("C", rt.T("C"))
   490  			AfterAll(rt.T("AA"))
   491  		})
   492  	}, []string{"BA", "A", "B", "B", "B", "B", "AA"},
   493  		"A", HavePassed(),
   494  		"B", HaveFailed("fail", NumAttempts(4)),
   495  		"C", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   496  	),
   497  	Entry("when the last spec is flaky, it runs the AFterAll just once", true, func() {
   498  		Context("container", Ordered, FlakeAttempts(4), func() {
   499  			BeforeAll(rt.T("BA"))
   500  			It("A", rt.T("A"))
   501  			It("B", rt.T("B"))
   502  			It("C", rt.T("C", FlakeyFailer(2)))
   503  			AfterAll(rt.T("AA"))
   504  		})
   505  	}, []string{"BA", "A", "B", "C", "C", "C", "AA"},
   506  		"A", "B", HavePassed(NumAttempts(1)),
   507  		"C", HavePassed(NumAttempts(3)),
   508  	),
   509  	Entry("When the BeforeAll is flaky", true, func() {
   510  		Context("container", Ordered, FlakeAttempts(5), func() {
   511  			BeforeAll(rt.T("BA", FlakeyFailerWithCleanup(2, "DC-BA")))
   512  			It("A", rt.T("A", FlakeyFailer(2)))
   513  			It("B", rt.T("B"))
   514  			It("C", rt.T("C"))
   515  			AfterAll(rt.T("AA"))
   516  		})
   517  	}, []string{
   518  		"BA", "AA", "DC-BA-pre",
   519  		"BA", "AA", "DC-BA-pre",
   520  		"BA", "A", "A", "A",
   521  		"B", "C",
   522  		"AA", "DC-BA-post", "DC-BA-pre",
   523  	},
   524  		"A", HavePassed(NumAttempts(5)),
   525  		"B", "C", HavePassed(),
   526  	),
   527  	Entry("When the AFterAll is flaky", true, func() {
   528  		Context("container", Ordered, FlakeAttempts(4), func() {
   529  			BeforeAll(rt.T("BA", DC("DC-BA")))
   530  			It("A", rt.T("A"))
   531  			It("B", rt.T("B"))
   532  			It("C", rt.T("C"))
   533  			AfterAll(rt.T("AA", FlakeyFailerWithCleanup(2, "DC-AA")))
   534  		})
   535  	}, []string{
   536  		"BA", "A", "B", "C", "AA", "DC-AA-pre",
   537  		"C", "AA", "DC-AA-pre",
   538  		"C", "AA", "DC-AA-post", "DC-AA-pre", "DC-BA",
   539  	},
   540  		"A", "B", HavePassed(),
   541  		"C", HavePassed(NumAttempts(3)),
   542  	),
   543  
   544  	//Let's enter the dragons nest!
   545  	Entry("happy-path for nested containers", true, func() {
   546  		BeforeEach(rt.T("BE-L0"))
   547  		Context("container", Ordered, func() {
   548  			BeforeAll(rt.T("BA-1-L1", DC("DC-BA-L1")))
   549  			BeforeAll(rt.T("BA-2-L1"))
   550  			BeforeEach(rt.T("BE-L1"))
   551  			It("A", rt.T("A"))
   552  			It("B", rt.T("B"))
   553  			Context("inner", func() {
   554  				BeforeAll(rt.T("BA-1-L2", DC("DC-BA-L2")))
   555  				BeforeAll(rt.T("BA-2-L2"))
   556  				BeforeEach(rt.T("BE-L2"))
   557  				It("C", rt.T("C"))
   558  				It("D", rt.T("D"))
   559  				AfterEach(rt.T("AE-L2"))
   560  				AfterAll(rt.T("AA-1-L2", DC("DC-AA-L2")))
   561  				AfterAll(rt.T("AA-2-L2"))
   562  			})
   563  			It("E", rt.T("E"))
   564  			AfterEach(rt.T("AE-L1"))
   565  			AfterAll(rt.T("AA-1-L1", DC("DC-AA-L1")))
   566  			AfterAll(rt.T("AA-2-L1"))
   567  		})
   568  		AfterEach(rt.T("AE-L0"))
   569  	}, []string{
   570  		"BE-L0", "BA-1-L1", "BA-2-L1", "BE-L1", "A", "AE-L1", "AE-L0",
   571  		"BE-L0", "BE-L1", "B", "AE-L1", "AE-L0",
   572  		"BE-L0", "BE-L1", "BA-1-L2", "BA-2-L2", "BE-L2", "C", "AE-L2", "AE-L1", "AE-L0",
   573  		"BE-L0", "BE-L1", "BE-L2", "D", "AE-L2", "AA-1-L2", "AA-2-L2", "AE-L1", "AE-L0", "DC-AA-L2", "DC-BA-L2",
   574  		"BE-L0", "BE-L1", "E", "AE-L1", "AA-1-L1", "AA-2-L1", "AE-L0", "DC-AA-L1", "DC-BA-L1",
   575  	}),
   576  	Entry("happy-path where last spec is in nested container", true, func() {
   577  		BeforeEach(rt.T("BE-L0"))
   578  		Context("container", Ordered, func() {
   579  			BeforeAll(rt.T("BA-1-L1", DC("DC-BA-L1")))
   580  			BeforeAll(rt.T("BA-2-L1"))
   581  			BeforeEach(rt.T("BE-L1"))
   582  			It("A", rt.T("A"))
   583  			It("B", rt.T("B"))
   584  			Context("inner", func() {
   585  				BeforeAll(rt.T("BA-1-L2", DC("DC-BA-L2")))
   586  				BeforeAll(rt.T("BA-2-L2"))
   587  				BeforeEach(rt.T("BE-L2"))
   588  				It("C", rt.T("C"))
   589  				It("D", rt.T("D"))
   590  				AfterEach(rt.T("AE-L2"))
   591  				AfterAll(rt.T("AA-1-L2", DC("DC-AA-L2")))
   592  				AfterAll(rt.T("AA-2-L2"))
   593  			})
   594  			AfterEach(rt.T("AE-L1"))
   595  			AfterAll(rt.T("AA-1-L1", DC("DC-AA-L1")))
   596  			AfterAll(rt.T("AA-2-L1"))
   597  		})
   598  		AfterEach(rt.T("AE-L0"))
   599  	}, []string{
   600  		"BE-L0", "BA-1-L1", "BA-2-L1", "BE-L1", "A", "AE-L1", "AE-L0",
   601  		"BE-L0", "BE-L1", "B", "AE-L1", "AE-L0",
   602  		"BE-L0", "BE-L1", "BA-1-L2", "BA-2-L2", "BE-L2", "C", "AE-L2", "AE-L1", "AE-L0",
   603  		"BE-L0", "BE-L1", "BE-L2", "D", "AE-L2", "AA-1-L2", "AA-2-L2", "AE-L1", "AA-1-L1", "AA-2-L1", "AE-L0", "DC-AA-L1", "DC-AA-L2", "DC-BA-L2", "DC-BA-L1",
   604  	}),
   605  	Entry("when an outer spec is skipped", true, func() {
   606  		Context("container", Ordered, func() {
   607  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   608  			It("A", rt.T("A", func() { Skip("skip") }))
   609  			It("B", rt.T("B"))
   610  			Context("inner", func() {
   611  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   612  				It("C", rt.T("C"))
   613  				It("D", rt.T("D"))
   614  				AfterAll(rt.T("AA-I"))
   615  			})
   616  			It("E", rt.T("E"))
   617  			AfterAll(rt.T("AA-O"))
   618  		})
   619  	}, []string{"BA-O", "A", "B", "BA-I", "C", "D", "AA-I", "DC-I", "E", "AA-O", "DC-O"},
   620  		"A", HaveBeenSkippedWithMessage("skip"),
   621  		"B", "C", "D", "E", HavePassed(),
   622  	),
   623  	Entry("when an inner spec is skipped", true, func() {
   624  		Context("container", Ordered, func() {
   625  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   626  			It("A", rt.T("A"))
   627  			It("B", rt.T("B"))
   628  			Context("inner", func() {
   629  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   630  				It("C", rt.T("C", func() { Skip("skip") }))
   631  				It("D", rt.T("D"))
   632  				AfterAll(rt.T("AA-I"))
   633  			})
   634  			It("E", rt.T("E"))
   635  			AfterAll(rt.T("AA-O"))
   636  		})
   637  	}, []string{"BA-O", "A", "B", "BA-I", "C", "D", "AA-I", "DC-I", "E", "AA-O", "DC-O"},
   638  		"C", HaveBeenSkippedWithMessage("skip"),
   639  		"A", "B", "D", "E", HavePassed(),
   640  	),
   641  	Entry("when an outer BeforeAll is skipped", true, func() {
   642  		Context("container", Ordered, func() {
   643  			BeforeAll(rt.T("BA-O", func() { DeferCleanup(rt.T("DC-O")); Skip("skip") }))
   644  			It("A", rt.T("A"))
   645  			It("B", rt.T("B"))
   646  			Context("inner", func() {
   647  				BeforeAll(rt.T("BA-I"))
   648  				It("C", rt.T("C"))
   649  				It("D", rt.T("D"))
   650  				AfterAll(rt.T("AA-I"))
   651  			})
   652  			It("E", rt.T("E"))
   653  			AfterAll(rt.T("AA-O"))
   654  		})
   655  	}, []string{"BA-O", "AA-O", "DC-O"},
   656  		"A", HaveBeenSkippedWithMessage("skip"),
   657  		"B", "C", "D", "E", HaveBeenSkippedWithMessage(SKIP_DUE_TO_BEFORE_ALL_SKIP),
   658  	),
   659  	Entry("when an inner BeforeAll is skipped", true, func() {
   660  		Context("container", Ordered, func() {
   661  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   662  			It("A", rt.T("A"))
   663  			It("B", rt.T("B"))
   664  			Context("inner", func() {
   665  				BeforeAll(rt.T("BA-I", func() { DeferCleanup(rt.T("DC-I")); Skip("skip") }))
   666  				It("C", rt.T("C"))
   667  				It("D", rt.T("D"))
   668  				AfterAll(rt.T("AA-I"))
   669  			})
   670  			It("E", rt.T("E"))
   671  			AfterAll(rt.T("AA-O"))
   672  		})
   673  	}, []string{"BA-O", "A", "B", "BA-I", "AA-I", "DC-I", "E", "AA-O", "DC-O"},
   674  		"A", "B", "E", HavePassed(),
   675  		"C", HaveBeenSkippedWithMessage("skip"),
   676  		"D", HaveBeenSkippedWithMessage(SKIP_DUE_TO_BEFORE_ALL_SKIP),
   677  	),
   678  	Entry("when the last spec is marked as pending", true, func() {
   679  		Context("container", Ordered, func() {
   680  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   681  			FIt("A", rt.T("A"))
   682  			FIt("B", rt.T("B"))
   683  			FContext("inner", func() {
   684  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   685  				It("C", rt.T("C"))
   686  				PIt("D", rt.T("D"))
   687  				AfterAll(rt.T("AA-I"))
   688  			})
   689  			FIt("E", rt.T("E"))
   690  			It("F", rt.T("F"))
   691  			AfterAll(rt.T("AA-O"))
   692  		})
   693  	}, []string{"BA-O", "A", "B", "BA-I", "C", "AA-I", "DC-I", "E", "AA-O", "DC-O"},
   694  		"A", "B", "C", "E", HavePassed(),
   695  		"D", BePending(), "F", HaveBeenSkipped(),
   696  	),
   697  	Entry("when an outer spec fails", false, func() {
   698  		Context("container", Ordered, func() {
   699  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   700  			It("A", rt.T("A"))
   701  			It("B", rt.T("B", func() { F("fail") }))
   702  			Context("inner", func() {
   703  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   704  				It("C", rt.T("C"))
   705  				It("D", rt.T("D"))
   706  				AfterAll(rt.T("AA-I"))
   707  			})
   708  			It("E", rt.T("E"))
   709  			AfterAll(rt.T("AA-O"))
   710  		})
   711  	}, []string{"BA-O", "A", "B", "AA-O", "DC-O"},
   712  		"A", HavePassed(), "B", HaveFailed("fail"),
   713  		"C", "D", "E", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   714  	),
   715  	Entry("when an inner spec fails", false, func() {
   716  		Context("container", Ordered, func() {
   717  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   718  			It("A", rt.T("A"))
   719  			It("B", rt.T("B"))
   720  			Context("inner", func() {
   721  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   722  				It("C", rt.T("C", func() { F("fail") }))
   723  				It("D", rt.T("D"))
   724  				AfterAll(rt.T("AA-I"))
   725  			})
   726  			It("E", rt.T("E"))
   727  			AfterAll(rt.T("AA-O"))
   728  		})
   729  	}, []string{"BA-O", "A", "B", "BA-I", "C", "AA-I", "AA-O", "DC-I", "DC-O"},
   730  		"A", HavePassed(), "B", HavePassed(), "C", HaveFailed("fail"),
   731  		"D", "E", HaveBeenSkippedWithMessage(SKIP_DUE_TO_EARLIER_FAILURE),
   732  	),
   733  	Entry("when flakey, and an outer BeforeAll flakes", true, func() {
   734  		i := 0
   735  		Context("container", Ordered, FlakeAttempts(4), func() {
   736  			BeforeAll(rt.T("BA-O", func() {
   737  				i += 1
   738  				DeferCleanup(rt.T("DC-O"))
   739  				if i < 3 {
   740  					F("fail")
   741  				}
   742  			}))
   743  			It("A", rt.T("A"))
   744  			It("B", rt.T("B"))
   745  			Context("inner", func() {
   746  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   747  				It("C", rt.T("C"))
   748  				It("D", rt.T("D"))
   749  				AfterAll(rt.T("AA-I"))
   750  			})
   751  			It("E", rt.T("E"))
   752  			AfterAll(rt.T("AA-O"))
   753  		})
   754  	}, []string{
   755  		"BA-O", "AA-O", "DC-O",
   756  		"BA-O", "AA-O", "DC-O",
   757  		"BA-O", "A", "B", "BA-I", "C", "D", "AA-I", "DC-I", "E", "AA-O", "DC-O"},
   758  		"A", HavePassed(NumAttempts(3)),
   759  		"B", "C", "D", "E", HavePassed(),
   760  	),
   761  	Entry("when flakey, and an inner BeforeAll flakes", true, func() {
   762  		i := 0
   763  		Context("container", Ordered, FlakeAttempts(4), func() {
   764  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   765  			It("A", rt.T("A"))
   766  			It("B", rt.T("B"))
   767  			Context("inner", func() {
   768  				BeforeAll(rt.T("BA-I", func() {
   769  					i += 1
   770  					DeferCleanup(rt.T("DC-I"))
   771  					if i < 3 {
   772  						F("fail")
   773  					}
   774  				}))
   775  				It("C", rt.T("C"))
   776  				It("D", rt.T("D"))
   777  				AfterAll(rt.T("AA-I"))
   778  			})
   779  			It("E", rt.T("E"))
   780  			AfterAll(rt.T("AA-O"))
   781  		})
   782  	}, []string{
   783  		"BA-O", "A", "B",
   784  		"BA-I", "AA-I", "DC-I",
   785  		"BA-I", "AA-I", "DC-I",
   786  		"BA-I", "C", "D", "AA-I", "DC-I", "E", "AA-O", "DC-O"},
   787  		"A", "B", "D", "E", HavePassed(),
   788  		"C", HavePassed(NumAttempts(3)),
   789  	),
   790  	Entry("when specs are flakey", true, func() {
   791  		Context("container", Ordered, FlakeAttempts(4), func() {
   792  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   793  			It("A", rt.T("A", FlakeyFailer(2)))
   794  			It("B", rt.T("B", FlakeyFailer(2)))
   795  			Context("inner", func() {
   796  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   797  				It("C", rt.T("C", FlakeyFailer(2)))
   798  				It("D", rt.T("D", FlakeyFailer(2)))
   799  				AfterAll(rt.T("AA-I"))
   800  			})
   801  			It("E", rt.T("E", FlakeyFailer(2)))
   802  			AfterAll(rt.T("AA-O"))
   803  		})
   804  	}, []string{
   805  		"BA-O", "A", "A", "A",
   806  		"B", "B", "B",
   807  		"BA-I", "C", "C", "C",
   808  		"D", "D", "D", "AA-I", "DC-I",
   809  		"E", "E", "E", "AA-O", "DC-O",
   810  	},
   811  		"A", "B", "C", "D", "E", HavePassed(NumAttempts(3)),
   812  	),
   813  	Entry("when AfterAlls are flakey", true, func() {
   814  		Context("container", Ordered, FlakeAttempts(4), func() {
   815  			BeforeAll(rt.T("BA-O", DC("DC-O")))
   816  			It("A", rt.T("A"))
   817  			It("B", rt.T("B"))
   818  			Context("inner", func() {
   819  				BeforeAll(rt.T("BA-I", DC("DC-I")))
   820  				It("C", rt.T("C"))
   821  				It("D", rt.T("D"))
   822  				AfterAll(rt.T("AA-I", FlakeyFailer(2)))
   823  			})
   824  			It("E", rt.T("E"))
   825  			AfterAll(rt.T("AA-O", FlakeyFailer(2)))
   826  		})
   827  	}, []string{
   828  		"BA-O", "A", "B", "BA-I", "C",
   829  		"D", "AA-I", "D", "AA-I", "D", "AA-I", "DC-I",
   830  		"E", "AA-O", "E", "AA-O", "E", "AA-O", "DC-O",
   831  	},
   832  		"A", "B", "C", "D", "E", HavePassed(),
   833  	),
   834  	//this behavior is a bit weird, but it's such an edge case that we're going to leave it
   835  	//unless an issue gets opened
   836  	Entry("when DeferCleanups are flakey", true, func() {
   837  		Context("container", Ordered, FlakeAttempts(4), func() {
   838  			BeforeAll(rt.T("BA-O", DC("DC-O", FlakeyFailer(2))))
   839  			It("A", rt.T("A"))
   840  			It("B", rt.T("B"))
   841  			Context("inner", func() {
   842  				BeforeAll(rt.T("BA-I", DC("DC-I", FlakeyFailer(2))))
   843  				It("C", rt.T("C"))
   844  				It("D", rt.T("D"))
   845  				AfterAll(rt.T("AA-I"))
   846  			})
   847  			It("E", rt.T("E"))
   848  			AfterAll(rt.T("AA-O"))
   849  		})
   850  	}, []string{
   851  		"BA-O", "A", "B", "BA-I", "C", "D", "AA-I", "DC-I", "D", "AA-I",
   852  		"E", "AA-O", "DC-O", "E", "AA-O",
   853  	},
   854  		"A", "B", "C", "D", "E", HavePassed(),
   855  	),
   856  )