github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/containerizer/system/process_reaper_linux_test.go (about) 1 package system_test 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "syscall" 8 9 "github.com/cloudfoundry-incubator/garden-linux/containerizer/system" 10 "github.com/pivotal-golang/lager" 11 12 . "github.com/onsi/ginkgo" 13 . "github.com/onsi/gomega" 14 "github.com/onsi/gomega/gbytes" 15 ) 16 17 var _ = Describe("ProcessReaper", func() { 18 var reaper *system.ProcessReaper 19 var waitFunc system.Wait4Func 20 21 BeforeEach(func() { 22 waitFunc = syscall.Wait4 23 }) 24 25 JustBeforeEach(func() { 26 logger := lager.NewLogger("process_reaper_test_logger") 27 logger.RegisterSink(lager.NewWriterSink(GinkgoWriter, lager.ERROR)) 28 reaper = system.StartReaper(logger, waitFunc) 29 }) 30 31 AfterEach(func() { 32 reaper.Stop() 33 }) 34 35 It("waits for a process to return and returns its exit status", func() { 36 cmd := exec.Command("sh", "-c", "exit 3") 37 Expect(reaper.Start(cmd)).To(Succeed()) 38 39 Expect(reaper.Wait(cmd)).To(Equal(byte(3))) 40 }) 41 42 It("waits for multiple processes", func() { 43 cmd1 := exec.Command("sh", "-c", "exit 3") 44 cmd2 := exec.Command("sh", "-c", "exit 33") 45 46 Expect(reaper.Start(cmd1)).To(Succeed()) 47 Expect(reaper.Start(cmd2)).To(Succeed()) 48 49 Expect(reaper.Wait(cmd1)).To(Equal(byte(3))) 50 Expect(reaper.Wait(cmd2)).To(Equal(byte(33))) 51 }) 52 53 Context("when there are grandchildren processes", func() { 54 It("waits for a process to return and returns its exit status", func() { 55 cmd := exec.Command("sh", "-c", "sleep 1; exit 3") 56 Expect(reaper.Start(cmd)).To(Succeed()) 57 Expect(reaper.Wait(cmd)).To(Equal(byte(3))) 58 }) 59 60 It("the child process can receive SIGCHLD when a grandchild terminates", func() { 61 stdout := gbytes.NewBuffer() 62 trap := exec.Command("sh", "-c", "trap 'echo caught SIGCHLD' CHLD; (ls / >/dev/null 2/&1); exit 0") 63 trap.Stdout = stdout 64 65 Expect(reaper.Start(trap)).To(Succeed()) 66 Expect(reaper.Wait(trap)).To(Equal(byte(0))) 67 Eventually(stdout).Should(gbytes.Say("caught SIGCHLD\n")) 68 }) 69 }) 70 71 It("returns correct exit statuses of short-lived processes", func(done Done) { 72 for i := 0; i < 100; i++ { 73 cmd := exec.Command("sh", "-c", "exit 42") 74 Expect(reaper.Start(cmd)).To(Succeed()) 75 76 cmd2 := exec.Command("sh", "-c", "exit 43") 77 Expect(reaper.Start(cmd2)).To(Succeed()) 78 79 cmd3 := exec.Command("sh", "-c", "exit 44") 80 Expect(reaper.Start(cmd3)).To(Succeed()) 81 82 exitStatus := reaper.Wait(cmd3) 83 Expect(exitStatus).To(Equal(byte(44))) 84 85 exitStatus = reaper.Wait(cmd2) 86 Expect(exitStatus).To(Equal(byte(43))) 87 88 exitStatus = reaper.Wait(cmd) 89 Expect(exitStatus).To(Equal(byte(42))) 90 } 91 close(done) 92 }, 90.0) 93 94 It("reaps processes when they terminate in close succession", func(done Done) { 95 for i := 0; i < 100; i++ { 96 cmd := exec.Command("sh", "-c", `while true; do sleep 1; done`) 97 Expect(reaper.Start(cmd)).To(Succeed()) 98 99 kill := exec.Command("kill", "-9", fmt.Sprintf("%d", cmd.Process.Pid)) 100 Expect(reaper.Start(kill)).To(Succeed()) 101 102 exitStatus := reaper.Wait(kill) 103 Expect(exitStatus).To(Equal(byte(0))) 104 105 exitStatus = reaper.Wait(cmd) 106 Expect(exitStatus).To(Equal(byte(255))) 107 } 108 close(done) 109 }, 90.0) 110 111 Context("when a container reuses a waited-for pid", func() { 112 var nextPid chan int 113 var waited chan bool 114 115 BeforeEach(func() { 116 nextPid = make(chan int, 100) 117 waited = make(chan bool) 118 waitFunc = func(pid int, wstatu *syscall.WaitStatus, options int, rusage *syscall.Rusage) (int, error) { 119 waited <- true 120 return <-nextPid, nil 121 } 122 }) 123 124 It("does not deadlock", func(done Done) { 125 cmd := exec.Command("sh", "-c", `while true; do sleep 1; done`) 126 Expect(reaper.Start(cmd)).To(Succeed()) 127 128 thePid := cmd.Process.Pid 129 130 nextPid <- thePid 131 nextPid <- 0 132 syscall.Kill(os.Getpid(), syscall.SIGCHLD) 133 Eventually(waited).Should(Receive()) 134 Eventually(waited).Should(Receive()) 135 136 nextPid <- thePid 137 nextPid <- thePid 138 nextPid <- 0 139 syscall.Kill(os.Getpid(), syscall.SIGCHLD) 140 141 Eventually(waited).Should(Receive()) 142 Eventually(waited).Should(Receive()) 143 Eventually(waited).Should(Receive()) 144 close(done) 145 }) 146 }) 147 })