func (s *GardenServer) streamInput(decoder *json.Decoder, in *io.PipeWriter, process garden.Process, connCloseCh chan struct{}) { for { var payload transport.ProcessPayload err := decoder.Decode(&payload) if err != nil { close(connCloseCh) in.CloseWithError(errors.New("Connection closed")) return } switch { case payload.TTY != nil: process.SetTTY(*payload.TTY) case payload.Source != nil: if payload.Data == nil { in.Close() return } else { _, err := in.Write([]byte(*payload.Data)) if err != nil { return } } case payload.Signal != nil: s.logger.Info("stream-input-process-signal", lager.Data{"payload": payload}) switch *payload.Signal { case garden.SignalKill: err = process.Signal(garden.SignalKill) if err != nil { s.logger.Error("stream-input-process-signal-kill-failed", err, lager.Data{"payload": payload}) } case garden.SignalTerminate: err = process.Signal(garden.SignalTerminate) if err != nil { s.logger.Error("stream-input-process-signal-terminate-failed", err, lager.Data{"payload": payload}) } default: s.logger.Error("stream-input-unknown-process-payload-signal", nil, lager.Data{"payload": payload}) in.Close() return } default: s.logger.Error("stream-input-unknown-process-payload", nil, lager.Data{"payload": payload}) in.Close() return } } }
Stderr: GinkgoWriter, }, nil, signaller) Expect(err).NotTo(HaveOccurred()) Eventually(stdout).Should(gbytes.Say("pid")) }) AfterEach(func() { if cmd.ProcessState != nil && !cmd.ProcessState.Exited() { cmd.Process.Signal(os.Kill) } }) Context("when the signaller is an LinkSignaller", func() { It("sends a kill message on the extra file descriptor", func(done Done) { Expect(process.Signal(garden.SignalKill)).To(Succeed()) Eventually(stdout).Should(gbytes.Say("Received: killed")) close(done) }, 2.0) It("kills the process with a terminate signal", func(done Done) { Expect(process.Signal(garden.SignalTerminate)).To(Succeed()) Eventually(stdout).Should(gbytes.Say("Received: terminated")) close(done) }, 2.0) Context("when an unsupported signal is sent", func() { AfterEach(func() { Expect(process.Signal(garden.SignalKill)).To(Succeed()) })
Stdout: io.MultiWriter(stdout, GinkgoWriter), Stderr: GinkgoWriter, }, nil) Expect(err).NotTo(HaveOccurred()) Eventually(stdout).Should(gbytes.Say("trapping")) }) AfterEach(func() { if cmd.ProcessState != nil && !cmd.ProcessState.Exited() { cmd.Process.Signal(os.Kill) } }) It("kill the process", func(done Done) { Expect(process.Signal(garden.SignalKill)).To(Succeed()) Expect(cmd.Wait()).NotTo(Succeed()) close(done) }, 2.0) It("kills the process with a terminate signal", func(done Done) { Expect(process.Signal(garden.SignalTerminate)).To(Succeed()) Eventually(stdout).Should(gbytes.Say("terminated")) Expect(cmd.Wait()).NotTo(Succeed()) close(done) }, 2.0) })
}) }) Describe("Signal", func() { BeforeEach(func() { errs := make(chan error, 1) errs <- io.EOF close(errs) fakeProcess.SignalStub = func(garden.Signal) error { return <-errs } }) It("reattaches on use of closed connection", func() { Ω(process.Signal(garden.SignalTerminate)).Should(Succeed()) Ω(fakeProcess.SignalArgsForCall(0)).Should(Equal(garden.SignalTerminate)) Ω(innerConnection.AttachCallCount()).Should(Equal(2)) handle, processID, calledProcessIO := innerConnection.AttachArgsForCall(1) Ω(handle).Should(Equal("la-contineur")) Ω(processID).Should(Equal(uint32(6))) Ω(calledProcessIO).Should(Equal(processIO)) }) }) Describe("SetTTY", func() { BeforeEach(func() { errs := make(chan error, 1) errs <- io.EOF close(errs)