github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/internal_integration/cleanup_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 var _ = Describe("Cleanup", func() { 15 C := func(label string) func() { 16 return func() { 17 DeferCleanup(rt.Run, label) 18 } 19 } 20 21 Context("the happy path", func() { 22 BeforeEach(func() { 23 success, _ := RunFixture("cleanup happy path", func() { 24 BeforeSuite(rt.T("BS", C("C-BS"))) 25 AfterSuite(rt.T("AS", C("C-AS"))) 26 27 BeforeEach(rt.T("BE-outer", C("C-BE-outer"))) 28 AfterEach(rt.T("AE-outer", C("C-AE-outer"))) 29 30 Context("non-randomizing container", func() { 31 Context("container", Ordered, func() { 32 JustBeforeEach(rt.T("JBE", C("C-JBE"))) 33 It("A", rt.T("A", C("C-A"))) 34 JustAfterEach(rt.T("JAE", C("C-JAE"))) 35 }) 36 37 Context("ordered container", Ordered, func() { 38 BeforeAll(rt.T("BA", C("C-BA"))) 39 BeforeEach(rt.T("BE-inner", C("C-BE-inner"))) 40 It("B", rt.T("B", C("C-B"))) 41 It("C", rt.T("C", C("C-C"))) 42 It("D", rt.T("D", C("C-D"))) 43 AfterEach(rt.T("AE-inner", C("C-AE-inner"))) 44 AfterAll(rt.T("AA", C("C-AA"))) 45 }) 46 }) 47 }) 48 Ω(success).Should(BeTrue()) 49 }) 50 51 It("runs all the things in the correct order", func() { 52 Ω(rt).Should(HaveTracked( 53 //before suite 54 "BS", 55 56 //container 57 "BE-outer", "JBE", "A", "JAE", "AE-outer", "C-AE-outer", "C-JAE", "C-A", "C-JBE", "C-BE-outer", 58 59 //ordered container 60 "BE-outer", "BA", "BE-inner", "B", "AE-inner", "AE-outer", "C-AE-outer", "C-AE-inner", "C-B", "C-BE-inner", "C-BE-outer", 61 "BE-outer", "BE-inner", "C", "AE-inner", "AE-outer", "C-AE-outer", "C-AE-inner", "C-C", "C-BE-inner", "C-BE-outer", 62 "BE-outer", "BE-inner", "D", "AE-inner", "AA", "AE-outer", "C-AE-outer", "C-AE-inner", "C-D", "C-BE-inner", "C-BE-outer", "C-AA", "C-BA", 63 64 //after suite 65 "AS", 66 "C-AS", "C-BS", 67 )) 68 }) 69 }) 70 71 Context("when cleanup fails", func() { 72 Context("because of a failed assertion", func() { 73 BeforeEach(func() { 74 success, _ := RunFixture("cleanup failure", func() { 75 BeforeEach(rt.T("BE", func() { 76 DeferCleanup(func() { 77 rt.Run("C-BE") 78 F("fail") 79 }) 80 })) 81 82 It("A", rt.T("A", C("C-A"))) 83 }) 84 Ω(success).Should(BeFalse()) 85 }) 86 87 It("reports a failure", func() { 88 Ω(rt).Should(HaveTracked("BE", "A", "C-A", "C-BE")) 89 Ω(reporter.Did.Find("A")).Should(HaveFailed("fail", FailureNodeType(types.NodeTypeCleanupAfterEach), types.FailureNodeAtTopLevel)) 90 }) 91 }) 92 93 Context("because of a returned error", func() { 94 BeforeEach(func() { 95 success, _ := RunFixture("cleanup failure", func() { 96 BeforeEach(rt.T("BE", C("C-BE"))) 97 It("A", rt.T("A", func() { 98 DeferCleanup(func() error { 99 rt.Run("C-A") 100 return fmt.Errorf("fail") 101 }) 102 })) 103 }) 104 Ω(success).Should(BeFalse()) 105 }) 106 107 It("reports a failure", func() { 108 Ω(rt).Should(HaveTracked("BE", "A", "C-A", "C-BE")) 109 Ω(reporter.Did.Find("A")).Should(HaveFailed("DeferCleanup callback returned error: fail", FailureNodeType(types.NodeTypeCleanupAfterEach), types.FailureNodeAtTopLevel)) 110 }) 111 }) 112 113 Context("at the suite level", func() { 114 BeforeEach(func() { 115 success, _ := RunFixture("cleanup failure", func() { 116 BeforeSuite(rt.T("BS", func() { 117 DeferCleanup(func() { 118 rt.Run("C-BS") 119 F("fail") 120 }) 121 })) 122 Context("container", func() { 123 It("A", rt.T("A")) 124 It("B", rt.T("B")) 125 }) 126 }) 127 Ω(success).Should(BeFalse()) 128 }) 129 130 It("marks the suite as failed", func() { 131 Ω(rt).Should(HaveTracked("BS", "A", "B", "C-BS")) 132 Ω(reporter.End).Should(BeASuiteSummary(false, NSpecs(2), NPassed(2))) 133 Ω(reporter.Did.FindByLeafNodeType(types.NodeTypeBeforeSuite)).Should(HavePassed()) 134 Ω(reporter.Did.FindByLeafNodeType(types.NodeTypeCleanupAfterSuite)).Should(HaveFailed("fail", FailureNodeType(types.NodeTypeCleanupAfterSuite))) 135 }) 136 }) 137 138 Context("when cleanup is interrupted", func() { 139 BeforeEach(func() { 140 success, _ := RunFixture("cleanup failure", func() { 141 BeforeEach(rt.T("BE", C("C-BE"))) 142 It("A", rt.T("A", func() { 143 DeferCleanup(func() { 144 rt.Run("C-A") 145 interruptHandler.Interrupt(interrupt_handler.InterruptCauseSignal) 146 time.Sleep(time.Minute) 147 }) 148 })) 149 }) 150 Ω(success).Should(BeFalse()) 151 }) 152 It("runs subsequent cleanups and is marked as interrupted", func() { 153 Ω(rt).Should(HaveTracked("BE", "A", "C-A", "C-BE")) 154 155 Ω(reporter.Did.Find("A")).Should(HaveBeenInterrupted(interrupt_handler.InterruptCauseSignal)) 156 }) 157 }) 158 }) 159 160 Context("edge cases", func() { 161 Context("cleanup is added in a SynchronizedBeforeSuite and SynchronizedAfterSuite", func() { 162 Context("when running in serial", func() { 163 BeforeEach(func() { 164 success, _ := RunFixture("cleanup in synchronized suites", func() { 165 SynchronizedBeforeSuite(func() []byte { 166 rt.Run("BS1") 167 DeferCleanup(rt.Run, "C-BS1") 168 return nil 169 }, func(_ []byte) { 170 rt.Run("BS2") 171 DeferCleanup(rt.Run, "C-BS2") 172 }) 173 174 SynchronizedAfterSuite(func() { 175 rt.Run("AS1") 176 DeferCleanup(rt.Run, "C-AS1") 177 }, func() { 178 rt.Run("AS2") 179 DeferCleanup(rt.Run, "C-AS2") 180 }) 181 Context("ordering", func() { 182 It("A", rt.T("A", C("C-A"))) 183 It("B", rt.T("B", C("C-B"))) 184 }) 185 }) 186 Ω(success).Should(BeTrue()) 187 188 }) 189 It("runs the cleanup at the appropriate time", func() { 190 Ω(rt).Should(HaveTracked("BS1", "BS2", "A", "C-A", "B", "C-B", "AS1", "AS2", "C-AS2", "C-AS1", "C-BS2", "C-BS1")) 191 }) 192 }) 193 194 Context("when running in parallel and there is no SynchronizedAfterSuite", func() { 195 fixture := func() { 196 SynchronizedBeforeSuite(func() []byte { 197 rt.Run("BS1") 198 DeferCleanup(rt.Run, "C-BS1") 199 return nil 200 }, func(_ []byte) { 201 rt.Run("BS2") 202 DeferCleanup(rt.Run, "C-BS2") 203 }) 204 205 Context("ordering", func() { 206 It("A", rt.T("A", C("C-A"))) 207 It("B", rt.T("B", C("C-B"))) 208 }) 209 } 210 211 BeforeEach(func() { 212 SetUpForParallel(2) 213 }) 214 215 Context("as process #1", func() { 216 It("runs the cleanup only _after_ the other processes have finished", func() { 217 done := make(chan interface{}) 218 go func() { 219 defer GinkgoRecover() 220 success, _ := RunFixture("DeferCleanup on SBS in parallel on process 1", fixture) 221 Ω(success).Should(BeTrue()) 222 close(done) 223 }() 224 225 Eventually(rt).Should(HaveTracked("BS1", "BS2", "A", "C-A", "B", "C-B")) 226 Consistently(rt).Should(HaveTracked("BS1", "BS2", "A", "C-A", "B", "C-B")) 227 close(exitChannels[2]) 228 Eventually(rt).Should(HaveTracked("BS1", "BS2", "A", "C-A", "B", "C-B", "C-BS2", "C-BS1")) 229 Eventually(done).Should(BeClosed()) 230 }) 231 }) 232 233 Context("as process #2", func() { 234 BeforeEach(func() { 235 conf.ParallelProcess = 2 236 client.PostSynchronizedBeforeSuiteCompleted(types.SpecStatePassed, []byte("hola hola")) 237 success, _ := RunFixture("DeferCleanup on SBS in parallel on process 2", fixture) 238 Ω(success).Should(BeTrue()) 239 }) 240 241 It("runs the cleanup at the appropriate time", func() { 242 Ω(rt).Should(HaveTracked("BS2", "A", "C-A", "B", "C-B", "C-BS2")) 243 }) 244 }) 245 }) 246 }) 247 248 Context("cleanup is added in an AfterAll that is called because an AfterEach has caused the non-final spec in an ordered group to fail", func() { 249 BeforeEach(func() { 250 success, _ := RunFixture("cleanup in hairy edge case", func() { 251 Context("ordered", Ordered, func() { 252 It("A", rt.T("A", C("C-A"))) 253 It("B", rt.T("B")) 254 AfterEach(rt.T("AE", func() { 255 DeferCleanup(rt.Run, "C-AE") 256 F("fail") 257 })) 258 AfterAll(rt.T("AA", C("C-AA"))) 259 }) 260 }) 261 Ω(success).Should(BeFalse()) 262 }) 263 264 It("notes that a cleanup was registered in the AfterAll and runs it", func() { 265 Ω(rt).Should(HaveTracked("A", "AE", "AA", "C-AE", "C-A", "C-AA")) 266 }) 267 }) 268 }) 269 })