github.com/onsi/gomega@v1.32.0/gexec/session_test.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package gexec_test 5 6 import ( 7 "io" 8 "os/exec" 9 "syscall" 10 "time" 11 12 . "github.com/onsi/gomega/gbytes" 13 . "github.com/onsi/gomega/gexec" 14 15 . "github.com/onsi/ginkgo/v2" 16 . "github.com/onsi/gomega" 17 ) 18 19 var _ = Describe("Session", func() { 20 Context("firefly binary", func() { 21 var fireflyPath string 22 var command *exec.Cmd 23 var session *Session 24 25 var outWriter, errWriter io.Writer 26 27 BeforeEach(func() { 28 outWriter = nil 29 errWriter = nil 30 31 var err error 32 fireflyPath, err = Build("./_fixture/firefly") 33 Expect(err).ShouldNot(HaveOccurred()) 34 35 }) 36 37 JustBeforeEach(func() { 38 command = exec.Command(fireflyPath) 39 var err error 40 session, err = Start(command, outWriter, errWriter) 41 Expect(err).ShouldNot(HaveOccurred()) 42 }) 43 44 Context("running a command", func() { 45 It("should start the process", func() { 46 Expect(command.Process).ShouldNot(BeNil()) 47 }) 48 49 It("should wrap the process's stdout and stderr with gbytes buffers", func() { 50 Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) 51 Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) 52 defer session.Out.CancelDetects() 53 54 select { 55 case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"): 56 Eventually(session).Should(Exit(0)) 57 case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."): 58 Eventually(session).Should(Exit(1)) 59 case <-session.Out.Detect("My work's illegal, but at least it's honest."): 60 Eventually(session).Should(Exit(2)) 61 case <-time.After(5 * time.Second): 62 Fail("timed out waiting for detection") 63 } 64 }) 65 66 It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() { 67 Eventually(session).Should(Say("We've done the impossible, and that makes us mighty")) 68 Eventually(session).Should(Exit()) 69 }) 70 }) 71 72 Describe("providing the exit code", func() { 73 It("should provide the app's exit code", func() { 74 Expect(session.ExitCode()).Should(Equal(-1)) 75 76 Eventually(session).Should(Exit()) 77 Expect(session.ExitCode()).Should(BeNumerically(">=", 0)) 78 Expect(session.ExitCode()).Should(BeNumerically("<", 3)) 79 }) 80 }) 81 82 Describe("wait", func() { 83 It("should wait till the command exits", func() { 84 Expect(session.ExitCode()).Should(Equal(-1)) 85 Expect(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) 86 Expect(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) 87 }) 88 }) 89 90 Describe("exited", func() { 91 It("should close when the command exits", func() { 92 Eventually(session.Exited).Should(BeClosed()) 93 Expect(session.ExitCode()).ShouldNot(Equal(-1)) 94 }) 95 }) 96 97 Describe("kill", func() { 98 It("should kill the command", func() { 99 session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 100 Expect(err).ShouldNot(HaveOccurred()) 101 102 session.Kill() 103 Eventually(session).Should(Exit(128 + 9)) 104 }) 105 }) 106 107 Describe("interrupt", func() { 108 It("should interrupt the command", func() { 109 session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 110 Expect(err).ShouldNot(HaveOccurred()) 111 112 session.Interrupt() 113 Eventually(session).Should(Exit(128 + 2)) 114 }) 115 }) 116 117 Describe("terminate", func() { 118 It("should terminate the command", func() { 119 session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 120 Expect(err).ShouldNot(HaveOccurred()) 121 122 session.Terminate() 123 Eventually(session).Should(Exit(128 + 15)) 124 }) 125 }) 126 127 Describe("signal", func() { 128 It("should send the signal to the command", func() { 129 session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 130 Expect(err).ShouldNot(HaveOccurred()) 131 132 session.Signal(syscall.SIGABRT) 133 Eventually(session).WithTimeout(5 * time.Second).Should(Exit(128 + 6)) 134 }) 135 136 It("should ignore sending a signal if the command did not start", func() { 137 session, err := Start(exec.Command("notexisting"), GinkgoWriter, GinkgoWriter) 138 Expect(err).To(HaveOccurred()) 139 140 Expect(func() { session.Signal(syscall.SIGUSR1) }).NotTo(Panic()) 141 }) 142 }) 143 144 Context("tracking sessions", func() { 145 BeforeEach(func() { 146 KillAndWait() 147 }) 148 149 Describe("kill", func() { 150 It("should kill all the started sessions", func() { 151 session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 152 Expect(err).ShouldNot(HaveOccurred()) 153 154 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 155 Expect(err).ShouldNot(HaveOccurred()) 156 157 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 158 Expect(err).ShouldNot(HaveOccurred()) 159 160 Kill() 161 162 Eventually(session1).Should(Exit(128 + 9)) 163 Eventually(session2).Should(Exit(128 + 9)) 164 Eventually(session3).Should(Exit(128 + 9)) 165 }) 166 167 It("should not track unstarted sessions", func() { 168 _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter) 169 Expect(err).Should(HaveOccurred()) 170 171 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 172 Expect(err).ShouldNot(HaveOccurred()) 173 174 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 175 Expect(err).ShouldNot(HaveOccurred()) 176 177 Kill() 178 179 Eventually(session2).Should(Exit(128 + 9)) 180 Eventually(session3).Should(Exit(128 + 9)) 181 }) 182 183 }) 184 185 Describe("killAndWait", func() { 186 It("should kill all the started sessions and wait for them to finish", func() { 187 session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 188 Expect(err).ShouldNot(HaveOccurred()) 189 190 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 191 Expect(err).ShouldNot(HaveOccurred()) 192 193 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 194 Expect(err).ShouldNot(HaveOccurred()) 195 196 KillAndWait() 197 Expect(session1).Should(Exit(128+9), "Should have exited") 198 Expect(session2).Should(Exit(128+9), "Should have exited") 199 Expect(session3).Should(Exit(128+9), "Should have exited") 200 }) 201 }) 202 203 Describe("terminate", func() { 204 It("should terminate all the started sessions", func() { 205 session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 206 Expect(err).ShouldNot(HaveOccurred()) 207 208 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 209 Expect(err).ShouldNot(HaveOccurred()) 210 211 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 212 Expect(err).ShouldNot(HaveOccurred()) 213 214 Terminate() 215 216 Eventually(session1).Should(Exit(128 + 15)) 217 Eventually(session2).Should(Exit(128 + 15)) 218 Eventually(session3).Should(Exit(128 + 15)) 219 }) 220 }) 221 222 Describe("terminateAndWait", func() { 223 It("should terminate all the started sessions, and wait for them to exit", func() { 224 session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 225 Expect(err).ShouldNot(HaveOccurred()) 226 227 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 228 Expect(err).ShouldNot(HaveOccurred()) 229 230 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 231 Expect(err).ShouldNot(HaveOccurred()) 232 233 TerminateAndWait() 234 235 Expect(session1).Should(Exit(128+15), "Should have exited") 236 Expect(session2).Should(Exit(128+15), "Should have exited") 237 Expect(session3).Should(Exit(128+15), "Should have exited") 238 }) 239 }) 240 241 Describe("signal", func() { 242 It("should signal all the started sessions", func() { 243 session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 244 Expect(err).ShouldNot(HaveOccurred()) 245 246 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 247 Expect(err).ShouldNot(HaveOccurred()) 248 249 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 250 Expect(err).ShouldNot(HaveOccurred()) 251 252 Signal(syscall.SIGABRT) 253 254 Eventually(session1).WithTimeout(5 * time.Second).Should(Exit(128 + 6)) 255 Eventually(session2).WithTimeout(5 * time.Second).Should(Exit(128 + 6)) 256 Eventually(session3).WithTimeout(5 * time.Second).Should(Exit(128 + 6)) 257 }) 258 }) 259 260 Describe("interrupt", func() { 261 It("should interrupt all the started sessions, and not wait", func() { 262 session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 263 Expect(err).ShouldNot(HaveOccurred()) 264 265 session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 266 Expect(err).ShouldNot(HaveOccurred()) 267 268 session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) 269 Expect(err).ShouldNot(HaveOccurred()) 270 271 Interrupt() 272 273 Eventually(session1).Should(Exit(128 + 2)) 274 Eventually(session2).Should(Exit(128 + 2)) 275 Eventually(session3).Should(Exit(128 + 2)) 276 }) 277 }) 278 }) 279 280 When("the command exits", func() { 281 It("should close the buffers", func() { 282 Eventually(session).Should(Exit()) 283 284 Expect(session.Out.Closed()).Should(BeTrue()) 285 Expect(session.Err.Closed()).Should(BeTrue()) 286 287 Expect(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) 288 }) 289 290 var So = It 291 292 So("this means that eventually should short circuit", func() { 293 t := time.Now() 294 failures := InterceptGomegaFailures(func() { 295 Eventually(session).Should(Say("blah blah blah blah blah")) 296 }) 297 Expect(time.Since(t)).Should(BeNumerically("<", time.Second)) 298 Expect(failures).Should(HaveLen(1)) 299 }) 300 }) 301 302 When("wrapping out and err", func() { 303 var ( 304 outWriterBuffer, errWriterBuffer *Buffer 305 ) 306 307 BeforeEach(func() { 308 outWriterBuffer = NewBuffer() 309 outWriter = outWriterBuffer 310 errWriterBuffer = NewBuffer() 311 errWriter = errWriterBuffer 312 }) 313 314 It("should route to both the provided writers and the gbytes buffers", func() { 315 Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) 316 Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) 317 318 Expect(outWriterBuffer.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) 319 Expect(errWriterBuffer.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) 320 321 Eventually(session).Should(Exit()) 322 323 Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents())) 324 Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents())) 325 }) 326 327 When("discarding the output of the command", func() { 328 BeforeEach(func() { 329 outWriter = io.Discard 330 errWriter = io.Discard 331 }) 332 333 It("executes succesfuly", func() { 334 Eventually(session).Should(Exit()) 335 }) 336 }) 337 }) 338 }) 339 340 Context("firefly tests", func() { 341 var fireflyTestPath string 342 var command *exec.Cmd 343 var session *Session 344 345 var outWriter, errWriter io.Writer 346 347 BeforeEach(func() { 348 outWriter = nil 349 errWriter = nil 350 351 var err error 352 fireflyTestPath, err = CompileTest("./_fixture/firefly") 353 Expect(err).ShouldNot(HaveOccurred()) 354 }) 355 356 JustBeforeEach(func() { 357 command = exec.Command(fireflyTestPath) 358 var err error 359 session, err = Start(command, outWriter, errWriter) 360 Expect(err).ShouldNot(HaveOccurred()) 361 }) 362 363 When("wrapping out and err", func() { 364 var ( 365 outWriterBuffer, errWriterBuffer *Buffer 366 ) 367 368 BeforeEach(func() { 369 outWriterBuffer = NewBuffer() 370 outWriter = outWriterBuffer 371 errWriterBuffer = NewBuffer() 372 errWriter = errWriterBuffer 373 }) 374 375 It("should route to both the provided writers and the gbytes buffers", func() { 376 Eventually(session.Out).Should(Say("PASS")) 377 Eventually(session.Err).Should(Say("")) 378 379 Expect(outWriterBuffer.Contents()).Should(ContainSubstring("PASS")) 380 Expect(errWriterBuffer.Contents()).Should(BeEmpty()) 381 382 Eventually(session).Should(Exit()) 383 384 Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents())) 385 Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents())) 386 }) 387 388 When("discarding the output of the command", func() { 389 BeforeEach(func() { 390 outWriter = io.Discard 391 errWriter = io.Discard 392 }) 393 394 It("executes succesfuly", func() { 395 Eventually(session).Should(Exit()) 396 }) 397 }) 398 }) 399 }) 400 401 Describe("when the command fails to start", func() { 402 It("should return an error", func() { 403 _, err := Start(exec.Command("agklsjdfas"), nil, nil) 404 Expect(err).Should(HaveOccurred()) 405 }) 406 }) 407 })