File: output_interceptor_test.go

package info (click to toggle)
golang-github-onsi-ginkgo-v2 2.15.0-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 4,112 kB
  • sloc: javascript: 59; sh: 14; makefile: 7
file content (155 lines) | stat: -rw-r--r-- 5,441 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package internal_test

import (
	"fmt"
	"os"
	"os/exec"
	"runtime"

	. "github.com/onsi/ginkgo/v2"
	. "github.com/onsi/gomega"
	"github.com/onsi/gomega/gbytes"

	"github.com/onsi/ginkgo/v2/internal"
)

var _ = Describe("OutputInterceptor", func() {
	var interceptor internal.OutputInterceptor

	sharedInterceptorTests := func() {
		It("intercepts output", func() {
			for i := 0; i < 2048; i++ { //we loop here to stress test and make sure we aren't leaking any file descriptors
				interceptor.StartInterceptingOutput()
				fmt.Println("hi stdout")
				fmt.Fprintln(os.Stderr, "hi stderr")
				output := interceptor.StopInterceptingAndReturnOutput()
				Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
			}
		})

		It("can forward intercepted output to a buffer", func() {
			buffer := gbytes.NewBuffer()
			interceptor.StartInterceptingOutputAndForwardTo(buffer)
			fmt.Println("hi stdout")
			fmt.Fprintln(os.Stderr, "hi stderr")
			output := interceptor.StopInterceptingAndReturnOutput()
			Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
			Ω(buffer).Should(gbytes.Say("hi stdout\nhi stderr\n"))
		})

		It("is stable across multiple shutdowns", func() {
			numRoutines := runtime.NumGoroutine()
			for i := 0; i < 2048; i++ { //we loop here to stress test and make sure we aren't leaking any file descriptors
				interceptor.StartInterceptingOutput()
				fmt.Println("hi stdout")
				fmt.Fprintln(os.Stderr, "hi stderr")
				output := interceptor.StopInterceptingAndReturnOutput()
				Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
				interceptor.Shutdown()
			}
			Eventually(runtime.NumGoroutine).Should(BeNumerically("~", numRoutines, 10))
		})

		It("can bail out if stdout and stderr are tied up by an external process", func() {
			// See GitHub issue #851: https://github.com/onsi/ginkgo/issues/851
			interceptor.StartInterceptingOutput()
			cmd := exec.Command("sleep", "60")
			//by threading stdout and stderr through, the sleep process will hold them open and prevent the interceptor from stopping:
			cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
			Ω(cmd.Start()).Should(Succeed())
			fmt.Println("hi stdout")
			fmt.Fprintln(os.Stderr, "hi stderr")

			// we try to stop here and see that we bail out eventually:
			outputChan := make(chan string)
			go func() {
				outputChan <- interceptor.StopInterceptingAndReturnOutput()
			}()
			var output string
			Eventually(outputChan, internal.BAILOUT_TIME*2).Should(Receive(&output))
			Ω(output).Should(Equal(internal.BAILOUT_MESSAGE))

			//subsequent attempts should be fine
			interceptor.StartInterceptingOutput()
			fmt.Println("hi stdout, again")
			fmt.Fprintln(os.Stderr, "hi stderr, again")
			output = interceptor.StopInterceptingAndReturnOutput()
			Ω(output).Should(Equal("hi stdout, again\nhi stderr, again\n"))

			cmd.Process.Kill()

			interceptor.StartInterceptingOutput()
			fmt.Println("hi stdout, once more")
			fmt.Fprintln(os.Stderr, "hi stderr, once more")
			output = interceptor.StopInterceptingAndReturnOutput()
			Ω(output).Should(Equal("hi stdout, once more\nhi stderr, once more\n"))
		})

		It("doesn't get stuck if it's paused and resumed before starting an external process that attaches to stdout/stderr", func() {
			// See GitHub issue #851: https://github.com/onsi/ginkgo/issues/851
			interceptor.StartInterceptingOutput()
			interceptor.PauseIntercepting()
			cmd := exec.Command("sleep", "60")
			//by threading stdout and stderr through, the sleep process will hold them open and prevent the interceptor from stopping:
			cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
			Ω(cmd.Start()).Should(Succeed())

			interceptor.ResumeIntercepting()
			fmt.Println("hi stdout")
			fmt.Fprintln(os.Stderr, "hi stderr")
			output := interceptor.StopInterceptingAndReturnOutput()

			Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
			Ω(output).ShouldNot(ContainSubstring(internal.BAILOUT_MESSAGE))
			cmd.Process.Kill()
		})

		It("can start/stop/pause/resume correctly", func() {
			interceptor.StartInterceptingOutput()
			fmt.Fprint(os.Stdout, "O-A")
			fmt.Fprint(os.Stderr, "E-A")
			interceptor.PauseIntercepting()
			fmt.Fprint(os.Stdout, "O-B")
			fmt.Fprint(os.Stderr, "E-B")
			interceptor.ResumeIntercepting()
			fmt.Fprint(os.Stdout, "O-C")
			fmt.Fprint(os.Stderr, "E-C")
			interceptor.ResumeIntercepting() //noop
			fmt.Fprint(os.Stdout, "O-D")
			fmt.Fprint(os.Stderr, "E-D")
			interceptor.PauseIntercepting()
			fmt.Fprint(os.Stdout, "O-E")
			fmt.Fprint(os.Stderr, "E-E")
			interceptor.PauseIntercepting() //noop
			fmt.Fprint(os.Stdout, "O-F")
			fmt.Fprint(os.Stderr, "E-F")
			interceptor.ResumeIntercepting()
			fmt.Fprint(os.Stdout, "O-G")
			fmt.Fprint(os.Stderr, "E-G")
			interceptor.StartInterceptingOutput() //noop
			fmt.Fprint(os.Stdout, "O-H")
			fmt.Fprint(os.Stderr, "E-H")
			interceptor.PauseIntercepting()
			output := interceptor.StopInterceptingAndReturnOutput()
			Ω(output).Should(Equal("O-AE-AO-CE-CO-DE-DO-GE-GO-HE-H"))
		})
	}

	Context("the OutputInterceptor for this OS", func() {
		BeforeEach(func() {
			interceptor = internal.NewOutputInterceptor()
			DeferCleanup(interceptor.Shutdown)
		})
		sharedInterceptorTests()
	})

	Context("the OSGlobalReassigningOutputInterceptor used on windows", func() {
		BeforeEach(func() {
			interceptor = internal.NewOSGlobalReassigningOutputInterceptor()
			DeferCleanup(interceptor.Shutdown)
		})

		sharedInterceptorTests()
	})

})