1
2
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 })
408
View as plain text