github.com/onsi/ginkgo@v1.16.6-0.20211118180735-4e1925ba4c95/internal/output_interceptor_test.go (about)

     1  package internal_test
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"os/exec"
     7  	"runtime"
     8  
     9  	. "github.com/onsi/ginkgo"
    10  	. "github.com/onsi/gomega"
    11  	"github.com/onsi/gomega/gbytes"
    12  
    13  	"github.com/onsi/ginkgo/internal"
    14  )
    15  
    16  var _ = Describe("OutputInterceptor", func() {
    17  	var interceptor internal.OutputInterceptor
    18  
    19  	sharedInterceptorTests := func() {
    20  		It("intercepts output", func() {
    21  			for i := 0; i < 2048; i++ { //we loop here to stress test and make sure we aren't leaking any file descriptors
    22  				interceptor.StartInterceptingOutput()
    23  				fmt.Println("hi stdout")
    24  				fmt.Fprintln(os.Stderr, "hi stderr")
    25  				output := interceptor.StopInterceptingAndReturnOutput()
    26  				Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
    27  			}
    28  		})
    29  
    30  		It("can forward intercepted output to a buffer", func() {
    31  			buffer := gbytes.NewBuffer()
    32  			interceptor.StartInterceptingOutputAndForwardTo(buffer)
    33  			fmt.Println("hi stdout")
    34  			fmt.Fprintln(os.Stderr, "hi stderr")
    35  			output := interceptor.StopInterceptingAndReturnOutput()
    36  			Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
    37  			Ω(buffer).Should(gbytes.Say("hi stdout\nhi stderr\n"))
    38  		})
    39  
    40  		It("is stable across multiple shutdowns", func() {
    41  			numRoutines := runtime.NumGoroutine()
    42  			for i := 0; i < 2048; i++ { //we loop here to stress test and make sure we aren't leaking any file descriptors
    43  				interceptor.StartInterceptingOutput()
    44  				fmt.Println("hi stdout")
    45  				fmt.Fprintln(os.Stderr, "hi stderr")
    46  				output := interceptor.StopInterceptingAndReturnOutput()
    47  				Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
    48  				interceptor.Shutdown()
    49  			}
    50  			Eventually(runtime.NumGoroutine).Should(BeNumerically("~", numRoutines, 10))
    51  		})
    52  
    53  		It("can bail out if stdout and stderr are tied up by an external process", func() {
    54  			// See GitHub issue #851: https://github.com/onsi/ginkgo/issues/851
    55  			interceptor.StartInterceptingOutput()
    56  			cmd := exec.Command("sleep", "60")
    57  			//by threading stdout and stderr through, the sleep process will hold them open and prevent the interceptor from stopping:
    58  			cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
    59  			Ω(cmd.Start()).Should(Succeed())
    60  			fmt.Println("hi stdout")
    61  			fmt.Fprintln(os.Stderr, "hi stderr")
    62  
    63  			// we try to stop here and see that we bail out eventually:
    64  			outputChan := make(chan string)
    65  			go func() {
    66  				outputChan <- interceptor.StopInterceptingAndReturnOutput()
    67  			}()
    68  			var output string
    69  			Eventually(outputChan, internal.BAILOUT_TIME*2).Should(Receive(&output))
    70  			Ω(output).Should(Equal(internal.BAILOUT_MESSAGE))
    71  
    72  			//subsequent attempts should be fine
    73  			interceptor.StartInterceptingOutput()
    74  			fmt.Println("hi stdout, again")
    75  			fmt.Fprintln(os.Stderr, "hi stderr, again")
    76  			output = interceptor.StopInterceptingAndReturnOutput()
    77  			Ω(output).Should(Equal("hi stdout, again\nhi stderr, again\n"))
    78  
    79  			cmd.Process.Kill()
    80  
    81  			interceptor.StartInterceptingOutput()
    82  			fmt.Println("hi stdout, once more")
    83  			fmt.Fprintln(os.Stderr, "hi stderr, once more")
    84  			output = interceptor.StopInterceptingAndReturnOutput()
    85  			Ω(output).Should(Equal("hi stdout, once more\nhi stderr, once more\n"))
    86  		})
    87  
    88  		It("doesn't get stuck if it's paused and resumed before starting an external process that attaches to stdout/stderr", func() {
    89  			// See GitHub issue #851: https://github.com/onsi/ginkgo/issues/851
    90  			interceptor.StartInterceptingOutput()
    91  			interceptor.PauseIntercepting()
    92  			cmd := exec.Command("sleep", "60")
    93  			//by threading stdout and stderr through, the sleep process will hold them open and prevent the interceptor from stopping:
    94  			cmd.Stdout, cmd.Stderr = os.Stdout, os.Stderr
    95  			Ω(cmd.Start()).Should(Succeed())
    96  
    97  			interceptor.ResumeIntercepting()
    98  			fmt.Println("hi stdout")
    99  			fmt.Fprintln(os.Stderr, "hi stderr")
   100  			output := interceptor.StopInterceptingAndReturnOutput()
   101  
   102  			Ω(output).Should(Equal("hi stdout\nhi stderr\n"))
   103  			Ω(output).ShouldNot(ContainSubstring(internal.BAILOUT_MESSAGE))
   104  			cmd.Process.Kill()
   105  		})
   106  
   107  		It("can start/stop/pause/resume correctly", func() {
   108  			interceptor.StartInterceptingOutput()
   109  			fmt.Fprint(os.Stdout, "O-A")
   110  			fmt.Fprint(os.Stderr, "E-A")
   111  			interceptor.PauseIntercepting()
   112  			fmt.Fprint(os.Stdout, "O-B")
   113  			fmt.Fprint(os.Stderr, "E-B")
   114  			interceptor.ResumeIntercepting()
   115  			fmt.Fprint(os.Stdout, "O-C")
   116  			fmt.Fprint(os.Stderr, "E-C")
   117  			interceptor.ResumeIntercepting() //noop
   118  			fmt.Fprint(os.Stdout, "O-D")
   119  			fmt.Fprint(os.Stderr, "E-D")
   120  			interceptor.PauseIntercepting()
   121  			fmt.Fprint(os.Stdout, "O-E")
   122  			fmt.Fprint(os.Stderr, "E-E")
   123  			interceptor.PauseIntercepting() //noop
   124  			fmt.Fprint(os.Stdout, "O-F")
   125  			fmt.Fprint(os.Stderr, "E-F")
   126  			interceptor.ResumeIntercepting()
   127  			fmt.Fprint(os.Stdout, "O-G")
   128  			fmt.Fprint(os.Stderr, "E-G")
   129  			interceptor.StartInterceptingOutput() //noop
   130  			fmt.Fprint(os.Stdout, "O-H")
   131  			fmt.Fprint(os.Stderr, "E-H")
   132  			interceptor.PauseIntercepting()
   133  			output := interceptor.StopInterceptingAndReturnOutput()
   134  			Ω(output).Should(Equal("O-AE-AO-CE-CO-DE-DO-GE-GO-HE-H"))
   135  		})
   136  	}
   137  
   138  	Context("the OutputInterceptor for this OS", func() {
   139  		BeforeEach(func() {
   140  			interceptor = internal.NewOutputInterceptor()
   141  			DeferCleanup(interceptor.Shutdown)
   142  		})
   143  		sharedInterceptorTests()
   144  	})
   145  
   146  	Context("the OSGlobalReassigningOutputInterceptor used on windows", func() {
   147  		BeforeEach(func() {
   148  			interceptor = internal.NewOSGlobalReassigningOutputInterceptor()
   149  			DeferCleanup(interceptor.Shutdown)
   150  		})
   151  
   152  		sharedInterceptorTests()
   153  	})
   154  
   155  })