session_test.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. // +build !windows
  2. package gexec_test
  3. import (
  4. "io"
  5. "io/ioutil"
  6. "os/exec"
  7. "syscall"
  8. "time"
  9. . "github.com/onsi/gomega/gbytes"
  10. . "github.com/onsi/gomega/gexec"
  11. . "github.com/onsi/ginkgo"
  12. . "github.com/onsi/gomega"
  13. )
  14. var _ = Describe("Session", func() {
  15. var command *exec.Cmd
  16. var session *Session
  17. var outWriter, errWriter io.Writer
  18. BeforeEach(func() {
  19. outWriter = nil
  20. errWriter = nil
  21. })
  22. JustBeforeEach(func() {
  23. command = exec.Command(fireflyPath)
  24. var err error
  25. session, err = Start(command, outWriter, errWriter)
  26. Expect(err).ShouldNot(HaveOccurred())
  27. })
  28. Context("running a command", func() {
  29. It("should start the process", func() {
  30. Expect(command.Process).ShouldNot(BeNil())
  31. })
  32. It("should wrap the process's stdout and stderr with gbytes buffers", func(done Done) {
  33. Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty"))
  34. Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!"))
  35. defer session.Out.CancelDetects()
  36. select {
  37. case <-session.Out.Detect("Can we maybe vote on the whole murdering people issue"):
  38. Eventually(session).Should(Exit(0))
  39. case <-session.Out.Detect("I swear by my pretty floral bonnet, I will end you."):
  40. Eventually(session).Should(Exit(1))
  41. case <-session.Out.Detect("My work's illegal, but at least it's honest."):
  42. Eventually(session).Should(Exit(2))
  43. }
  44. close(done)
  45. })
  46. It("should satisfy the gbytes.BufferProvider interface, passing Stdout", func() {
  47. Eventually(session).Should(Say("We've done the impossible, and that makes us mighty"))
  48. Eventually(session).Should(Exit())
  49. })
  50. })
  51. Describe("providing the exit code", func() {
  52. It("should provide the app's exit code", func() {
  53. Expect(session.ExitCode()).Should(Equal(-1))
  54. Eventually(session).Should(Exit())
  55. Expect(session.ExitCode()).Should(BeNumerically(">=", 0))
  56. Expect(session.ExitCode()).Should(BeNumerically("<", 3))
  57. })
  58. })
  59. Describe("wait", func() {
  60. It("should wait till the command exits", func() {
  61. Expect(session.ExitCode()).Should(Equal(-1))
  62. Expect(session.Wait().ExitCode()).Should(BeNumerically(">=", 0))
  63. Expect(session.Wait().ExitCode()).Should(BeNumerically("<", 3))
  64. })
  65. })
  66. Describe("exited", func() {
  67. It("should close when the command exits", func() {
  68. Eventually(session.Exited).Should(BeClosed())
  69. Expect(session.ExitCode()).ShouldNot(Equal(-1))
  70. })
  71. })
  72. Describe("kill", func() {
  73. It("should kill the command", func() {
  74. session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  75. Expect(err).ShouldNot(HaveOccurred())
  76. session.Kill()
  77. Eventually(session).Should(Exit(128 + 9))
  78. })
  79. })
  80. Describe("interrupt", func() {
  81. It("should interrupt the command", func() {
  82. session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  83. Expect(err).ShouldNot(HaveOccurred())
  84. session.Interrupt()
  85. Eventually(session).Should(Exit(128 + 2))
  86. })
  87. })
  88. Describe("terminate", func() {
  89. It("should terminate the command", func() {
  90. session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  91. Expect(err).ShouldNot(HaveOccurred())
  92. session.Terminate()
  93. Eventually(session).Should(Exit(128 + 15))
  94. })
  95. })
  96. Describe("signal", func() {
  97. It("should send the signal to the command", func() {
  98. session, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  99. Expect(err).ShouldNot(HaveOccurred())
  100. session.Signal(syscall.SIGABRT)
  101. Eventually(session).Should(Exit(128 + 6))
  102. })
  103. It("should ignore sending a signal if the command did not start", func() {
  104. session, err := Start(exec.Command("notexisting"), GinkgoWriter, GinkgoWriter)
  105. Expect(err).To(HaveOccurred())
  106. Expect(func() { session.Signal(syscall.SIGUSR1) }).NotTo(Panic())
  107. })
  108. })
  109. Context("tracking sessions", func() {
  110. BeforeEach(func() {
  111. KillAndWait()
  112. })
  113. Describe("kill", func() {
  114. It("should kill all the started sessions", func() {
  115. session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  116. Expect(err).ShouldNot(HaveOccurred())
  117. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  118. Expect(err).ShouldNot(HaveOccurred())
  119. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  120. Expect(err).ShouldNot(HaveOccurred())
  121. Kill()
  122. Eventually(session1).Should(Exit(128 + 9))
  123. Eventually(session2).Should(Exit(128 + 9))
  124. Eventually(session3).Should(Exit(128 + 9))
  125. })
  126. It("should not track unstarted sessions", func() {
  127. _, err := Start(exec.Command("does not exist", "10000000"), GinkgoWriter, GinkgoWriter)
  128. Expect(err).Should(HaveOccurred())
  129. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  130. Expect(err).ShouldNot(HaveOccurred())
  131. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  132. Expect(err).ShouldNot(HaveOccurred())
  133. Kill()
  134. Eventually(session2).Should(Exit(128 + 9))
  135. Eventually(session3).Should(Exit(128 + 9))
  136. })
  137. })
  138. Describe("killAndWait", func() {
  139. It("should kill all the started sessions and wait for them to finish", func() {
  140. session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  141. Expect(err).ShouldNot(HaveOccurred())
  142. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  143. Expect(err).ShouldNot(HaveOccurred())
  144. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  145. Expect(err).ShouldNot(HaveOccurred())
  146. KillAndWait()
  147. Expect(session1).Should(Exit(128+9), "Should have exited")
  148. Expect(session2).Should(Exit(128+9), "Should have exited")
  149. Expect(session3).Should(Exit(128+9), "Should have exited")
  150. })
  151. })
  152. Describe("terminate", func() {
  153. It("should terminate all the started sessions", func() {
  154. session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  155. Expect(err).ShouldNot(HaveOccurred())
  156. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  157. Expect(err).ShouldNot(HaveOccurred())
  158. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  159. Expect(err).ShouldNot(HaveOccurred())
  160. Terminate()
  161. Eventually(session1).Should(Exit(128 + 15))
  162. Eventually(session2).Should(Exit(128 + 15))
  163. Eventually(session3).Should(Exit(128 + 15))
  164. })
  165. })
  166. Describe("terminateAndWait", func() {
  167. It("should terminate all the started sessions, and wait for them to exit", func() {
  168. session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  169. Expect(err).ShouldNot(HaveOccurred())
  170. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  171. Expect(err).ShouldNot(HaveOccurred())
  172. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  173. Expect(err).ShouldNot(HaveOccurred())
  174. TerminateAndWait()
  175. Expect(session1).Should(Exit(128+15), "Should have exited")
  176. Expect(session2).Should(Exit(128+15), "Should have exited")
  177. Expect(session3).Should(Exit(128+15), "Should have exited")
  178. })
  179. })
  180. Describe("signal", func() {
  181. It("should signal all the started sessions", func() {
  182. session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  183. Expect(err).ShouldNot(HaveOccurred())
  184. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  185. Expect(err).ShouldNot(HaveOccurred())
  186. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  187. Expect(err).ShouldNot(HaveOccurred())
  188. Signal(syscall.SIGABRT)
  189. Eventually(session1).Should(Exit(128 + 6))
  190. Eventually(session2).Should(Exit(128 + 6))
  191. Eventually(session3).Should(Exit(128 + 6))
  192. })
  193. })
  194. Describe("interrupt", func() {
  195. It("should interrupt all the started sessions, and not wait", func() {
  196. session1, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  197. Expect(err).ShouldNot(HaveOccurred())
  198. session2, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  199. Expect(err).ShouldNot(HaveOccurred())
  200. session3, err := Start(exec.Command("sleep", "10000000"), GinkgoWriter, GinkgoWriter)
  201. Expect(err).ShouldNot(HaveOccurred())
  202. Interrupt()
  203. Eventually(session1).Should(Exit(128 + 2))
  204. Eventually(session2).Should(Exit(128 + 2))
  205. Eventually(session3).Should(Exit(128 + 2))
  206. })
  207. })
  208. })
  209. Context("when the command exits", func() {
  210. It("should close the buffers", func() {
  211. Eventually(session).Should(Exit())
  212. Expect(session.Out.Closed()).Should(BeTrue())
  213. Expect(session.Err.Closed()).Should(BeTrue())
  214. Expect(session.Out).Should(Say("We've done the impossible, and that makes us mighty"))
  215. })
  216. var So = It
  217. So("this means that eventually should short circuit", func() {
  218. t := time.Now()
  219. failures := InterceptGomegaFailures(func() {
  220. Eventually(session).Should(Say("blah blah blah blah blah"))
  221. })
  222. Expect(time.Since(t)).Should(BeNumerically("<=", 500*time.Millisecond))
  223. Expect(failures).Should(HaveLen(1))
  224. })
  225. })
  226. Context("when wrapping out and err", func() {
  227. var (
  228. outWriterBuffer, errWriterBuffer *Buffer
  229. )
  230. BeforeEach(func() {
  231. outWriterBuffer = NewBuffer()
  232. outWriter = outWriterBuffer
  233. errWriterBuffer = NewBuffer()
  234. errWriter = errWriterBuffer
  235. })
  236. It("should route to both the provided writers and the gbytes buffers", func() {
  237. Eventually(session.Out).Should(Say("We've done the impossible, and that makes us mighty"))
  238. Eventually(session.Err).Should(Say("Ah, curse your sudden but inevitable betrayal!"))
  239. Expect(outWriterBuffer.Contents()).Should(ContainSubstring("We've done the impossible, and that makes us mighty"))
  240. Expect(errWriterBuffer.Contents()).Should(ContainSubstring("Ah, curse your sudden but inevitable betrayal!"))
  241. Eventually(session).Should(Exit())
  242. Expect(outWriterBuffer.Contents()).Should(Equal(session.Out.Contents()))
  243. Expect(errWriterBuffer.Contents()).Should(Equal(session.Err.Contents()))
  244. })
  245. Context("when discarding the output of the command", func() {
  246. BeforeEach(func() {
  247. outWriter = ioutil.Discard
  248. errWriter = ioutil.Discard
  249. })
  250. It("executes succesfuly", func() {
  251. Eventually(session).Should(Exit())
  252. })
  253. })
  254. })
  255. Describe("when the command fails to start", func() {
  256. It("should return an error", func() {
  257. _, err := Start(exec.Command("agklsjdfas"), nil, nil)
  258. Expect(err).Should(HaveOccurred())
  259. })
  260. })
  261. })