|  | package gexec_test | 
|  |  | 
|  | import ( | 
|  | "os/exec" | 
|  | "syscall" | 
|  | "time" | 
|  |  | 
|  | . "github.com/onsi/gomega/gbytes" | 
|  | . "github.com/onsi/gomega/gexec" | 
|  |  | 
|  | . "github.com/onsi/ginkgo" | 
|  | . "github.com/onsi/gomega" | 
|  | ) | 
|  |  | 
|  | var _ = Describe("Session", func() { | 
|  | var command *exec.Cmd | 
|  | var session *Session | 
|  |  | 
|  | var outWriter, errWriter *Buffer | 
|  |  | 
|  | BeforeEach(func() { | 
|  | outWriter = nil | 
|  | errWriter = nil | 
|  | }) | 
|  |  | 
|  | JustBeforeEach(func() { | 
|  | command = exec.Command(fireflyPath) | 
|  | var err error | 
|  | session, err = Start(command, outWriter, errWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  | }) | 
|  |  | 
|  | Context("running a command", func() { | 
|  | It("should start the process", func() { | 
|  | Ω(command.Process).ShouldNot(BeNil()) | 
|  | }) | 
|  |  | 
|  | It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) { | 
|  | Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) | 
|  | Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) | 
|  | defer session.Out.CancelDetects() | 
|  |  | 
|  | select { | 
|  | case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"): | 
|  | Eventually(session).Should(Exit(0)) | 
|  | case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."): | 
|  | Eventually(session).Should(Exit(1)) | 
|  | case <-session.Out.Detect("My work's illegal, but at least it's honest."): | 
|  | Eventually(session).Should(Exit(2)) | 
|  | } | 
|  |  | 
|  | close(done) | 
|  | }) | 
|  |  | 
|  | It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() { | 
|  | Eventually(session).Should(Say("We've done the impossible, and that makes us mighty")) | 
|  | Eventually(session).Should(Exit()) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("providing the exit code", func() { | 
|  | It("should provide the app's exit code", func() { | 
|  | Ω(session.ExitCode()).Should(Equal(-1)) | 
|  |  | 
|  | Eventually(session).Should(Exit()) | 
|  | Ω(session.ExitCode()).Should(BeNumerically(">=", 0)) | 
|  | Ω(session.ExitCode()).Should(BeNumerically("<", 3)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("wait", func() { | 
|  | It("should wait till the command exits", func() { | 
|  | Ω(session.ExitCode()).Should(Equal(-1)) | 
|  | Ω(session.Wait().ExitCode()).Should(BeNumerically(">=", 0)) | 
|  | Ω(session.Wait().ExitCode()).Should(BeNumerically("<", 3)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("exited", func() { | 
|  | It("should close when the command exits", func() { | 
|  | Eventually(session.Exited).Should(BeClosed()) | 
|  | Ω(session.ExitCode()).ShouldNot(Equal(-1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("kill", func() { | 
|  | It("should kill the command and don't wait for it to exit", func() { | 
|  | session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session.Kill() | 
|  | Ω(session).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | Eventually(session).Should(Exit(128 + 9)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("interrupt", func() { | 
|  | It("should interrupt the command", func() { | 
|  | session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session.Interrupt() | 
|  | Ω(session).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | Eventually(session).Should(Exit(128 + 2)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("terminate", func() { | 
|  | It("should terminate the command", func() { | 
|  | session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session.Terminate() | 
|  | Ω(session).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | Eventually(session).Should(Exit(128 + 15)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("signal", func() { | 
|  | It("should send the signal to the command", func() { | 
|  | session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session.Signal(syscall.SIGABRT) | 
|  | Ω(session).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | Eventually(session).Should(Exit(128 + 6)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("tracking sessions", func() { | 
|  | BeforeEach(func() { | 
|  | KillAndWait() | 
|  | }) | 
|  |  | 
|  | Describe("kill", func() { | 
|  | It("should kill all the started sessions", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Kill() | 
|  |  | 
|  | Eventually(session1).Should(Exit(128 + 9)) | 
|  | Eventually(session2).Should(Exit(128 + 9)) | 
|  | Eventually(session3).Should(Exit(128 + 9)) | 
|  | }) | 
|  |  | 
|  | It("should not wait for exit", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Kill() | 
|  | Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") | 
|  |  | 
|  | Eventually(session1).Should(Exit(128 + 9)) | 
|  | }) | 
|  |  | 
|  | It("should not track unstarted sessions", func() { | 
|  | _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).Should(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Kill() | 
|  |  | 
|  | Eventually(session2).Should(Exit(128 + 9)) | 
|  | Eventually(session3).Should(Exit(128 + 9)) | 
|  | }) | 
|  |  | 
|  | }) | 
|  |  | 
|  | Describe("killAndWait", func() { | 
|  | It("should kill all the started sessions and wait for them to finish", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | KillAndWait() | 
|  | Ω(session1).Should(Exit(128+9), "Should have exited") | 
|  | Ω(session2).Should(Exit(128+9), "Should have exited") | 
|  | Ω(session3).Should(Exit(128+9), "Should have exited") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("terminate", func() { | 
|  | It("should terminate all the started sessions", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Terminate() | 
|  |  | 
|  | Eventually(session1).Should(Exit(128 + 15)) | 
|  | Eventually(session2).Should(Exit(128 + 15)) | 
|  | Eventually(session3).Should(Exit(128 + 15)) | 
|  | }) | 
|  |  | 
|  | It("should not wait for exit", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Terminate() | 
|  |  | 
|  | Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("terminateAndWait", func() { | 
|  | It("should terminate all the started sessions, and wait for them to exit", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | TerminateAndWait() | 
|  |  | 
|  | Ω(session1).Should(Exit(128+15), "Should have exited") | 
|  | Ω(session2).Should(Exit(128+15), "Should have exited") | 
|  | Ω(session3).Should(Exit(128+15), "Should have exited") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("signal", func() { | 
|  | It("should signal all the started sessions", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Signal(syscall.SIGABRT) | 
|  |  | 
|  | Eventually(session1).Should(Exit(128 + 6)) | 
|  | Eventually(session2).Should(Exit(128 + 6)) | 
|  | Eventually(session3).Should(Exit(128 + 6)) | 
|  | }) | 
|  |  | 
|  | It("should not wait", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Signal(syscall.SIGABRT) | 
|  |  | 
|  | Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("interrupt", func() { | 
|  | It("should interrupt all the started sessions, and not wait", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Interrupt() | 
|  |  | 
|  | Eventually(session1).Should(Exit(128 + 2)) | 
|  | Eventually(session2).Should(Exit(128 + 2)) | 
|  | Eventually(session3).Should(Exit(128 + 2)) | 
|  | }) | 
|  |  | 
|  | It("should not wait", func() { | 
|  | session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter) | 
|  | Ω(err).ShouldNot(HaveOccurred()) | 
|  |  | 
|  | Interrupt() | 
|  |  | 
|  | Ω(session1).ShouldNot(Exit(), "Should not exit immediately...") | 
|  | }) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when the command exits", func() { | 
|  | It("should close the buffers", func() { | 
|  | Eventually(session).Should(Exit()) | 
|  |  | 
|  | Ω(session.Out.Closed()).Should(BeTrue()) | 
|  | Ω(session.Err.Closed()).Should(BeTrue()) | 
|  |  | 
|  | Ω(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) | 
|  | }) | 
|  |  | 
|  | var So = It | 
|  |  | 
|  | So("this means that eventually should short circuit", func() { | 
|  | t := time.Now() | 
|  | failures := InterceptGomegaFailures(func() { | 
|  | Eventually(session).Should(Say("blah blah blah blah blah")) | 
|  | }) | 
|  | Ω(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond)) | 
|  | Ω(failures).Should(HaveLen(1)) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Context("when wrapping out and err", func() { | 
|  | BeforeEach(func() { | 
|  | outWriter = NewBuffer() | 
|  | errWriter = NewBuffer() | 
|  | }) | 
|  |  | 
|  | It("should route to both the provided writers and the gbytes buffers", func() { | 
|  | Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty")) | 
|  | Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!")) | 
|  |  | 
|  | Ω(outWriter.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty")) | 
|  | Ω(errWriter.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!")) | 
|  |  | 
|  | Eventually(session).Should(Exit()) | 
|  |  | 
|  | Ω(outWriter.Contents()).Should(Equal(session.Out.Contents())) | 
|  | Ω(errWriter.Contents()).Should(Equal(session.Err.Contents())) | 
|  | }) | 
|  | }) | 
|  |  | 
|  | Describe("when the command fails to start", func() { | 
|  | It("should return an error", func() { | 
|  | _, err := Start(exec.Command("agklsjdfas"), nil, nil) | 
|  | Ω(err).Should(HaveOccurred()) | 
|  | }) | 
|  | }) | 
|  | }) |