github.com/cloudfoundry-attic/garden-linux@v0.333.2-candidate/container_daemon/unix_socket/roundtrip_linux_test.go (about) 1 package unix_socket_test 2 3 import ( 4 "encoding/json" 5 "errors" 6 "io/ioutil" 7 "os" 8 "path" 9 "sync" 10 11 "github.com/cloudfoundry-incubator/garden-linux/container_daemon" 12 "github.com/cloudfoundry-incubator/garden-linux/container_daemon/fake_connection_handler" 13 "github.com/cloudfoundry-incubator/garden-linux/container_daemon/unix_socket" 14 . "github.com/onsi/ginkgo" 15 . "github.com/onsi/gomega" 16 17 "fmt" 18 "net" 19 ) 20 21 var _ = Describe("Unix socket", func() { 22 var ( 23 listener *unix_socket.Listener 24 connector *unix_socket.Connector 25 connectionHandler *fake_connection_handler.FakeConnectionHandler 26 socketPath string 27 sentPid int 28 sentError error 29 sentErrorMutex sync.Mutex 30 ) 31 32 BeforeEach(func() { 33 tmpDir, err := ioutil.TempDir("", "") 34 Expect(err).ToNot(HaveOccurred()) 35 socketPath = path.Join(tmpDir, "the_socket_file.sock") 36 37 sentErrorMutex.Lock() 38 defer sentErrorMutex.Unlock() 39 sentError = nil 40 sentPid = 0 41 connectionHandler = &fake_connection_handler.FakeConnectionHandler{} 42 }) 43 44 JustBeforeEach(func() { 45 connector = &unix_socket.Connector{ 46 SocketPath: socketPath, 47 } 48 }) 49 50 Describe("Listener creation", func() { 51 Context("when listener is created by socket path", func() { 52 Context("when file does not exist", func() { 53 Context("when there is no permission to create the file", func() { 54 It("returns an error", func() { 55 socketPath := "/proc/a_socket.sock" 56 _, err := unix_socket.NewListenerFromPath(socketPath) 57 Expect(err).To(HaveOccurred()) 58 }) 59 }) 60 61 Context("when there is permission to create the file", func() { 62 It("creates the listener", func() { 63 socketPath := fmt.Sprintf("/tmp/a_socket-%d.sock", GinkgoParallelNode()) 64 65 listener, err := unix_socket.NewListenerFromPath(socketPath) 66 Expect(err).ToNot(HaveOccurred()) 67 68 Expect(listener.Close()).To(Succeed()) 69 }) 70 }) 71 }) 72 73 Context("when the file does exist", func() { 74 It("returns an error", func() { 75 socketFile, err := ioutil.TempFile("", "") 76 Expect(err).ToNot(HaveOccurred()) 77 78 _, err = unix_socket.NewListenerFromPath(socketFile.Name()) 79 Expect(err).To(HaveOccurred()) 80 81 socketFile.Close() 82 }) 83 }) 84 }) 85 86 Context("when listener is created by socket file", func() { 87 Context("when the file does exist", func() { 88 Context("when the file is not a socket file", func() { 89 It("returns an error", func() { 90 socketFile, err := ioutil.TempFile("", "") 91 Expect(err).ToNot(HaveOccurred()) 92 93 _, err = unix_socket.NewListenerFromPath(socketFile.Name()) 94 Expect(err).To(HaveOccurred()) 95 96 socketFile.Close() 97 }) 98 }) 99 100 Context("when the file is a socket file", func() { 101 It("creates the listener", func() { 102 socketPath := fmt.Sprintf("/tmp/a_socket-%d.sock", GinkgoParallelNode()) 103 socketListener, err := net.Listen("unix", socketPath) 104 Expect(err).ToNot(HaveOccurred()) 105 106 socketFile, err := socketListener.(*net.UnixListener).File() 107 Expect(err).ToNot(HaveOccurred()) 108 109 listener, err := unix_socket.NewListenerFromFile(socketFile) 110 Expect(err).ToNot(HaveOccurred()) 111 112 Expect(socketFile.Close()).To(Succeed()) 113 Expect(listener.Close()).To(Succeed()) 114 }) 115 }) 116 }) 117 }) 118 }) 119 120 Describe("Connect", func() { 121 Context("when the server is not running", func() { 122 It("fails to connect", func() { 123 _, err := connector.Connect(nil) 124 Expect(err).To(MatchError(ContainSubstring("unix_socket: connect to server socket"))) 125 }) 126 }) 127 128 Context("when the server is running", func() { 129 var recvMsg *container_daemon.RequestMessage 130 var sentFiles []*os.File 131 var stubDone chan bool 132 var sentMsg *container_daemon.RequestMessage 133 134 JustBeforeEach(func() { 135 var err error 136 listener, err = unix_socket.NewListenerFromPath(socketPath) 137 Expect(err).NotTo(HaveOccurred()) 138 139 f1r, f1w, err := os.Pipe() 140 Expect(err).ToNot(HaveOccurred()) 141 f2r, f2w, err := os.Pipe() 142 Expect(err).ToNot(HaveOccurred()) 143 sentFiles = []*os.File{f1r, f2w} 144 145 sentPid = 123 146 147 stubDone = make(chan bool, 1) 148 149 sentFilesCp := []container_daemon.StreamingFile{f1w, f2r} 150 sentErrorMutex.Lock() 151 defer sentErrorMutex.Unlock() 152 sentErrorCp := sentError 153 sentPidCp := sentPid 154 connectionHandler.HandleStub = func(decoder *json.Decoder) (*container_daemon.ResponseMessage, error) { 155 defer GinkgoRecover() 156 err := decoder.Decode(&recvMsg) 157 Expect(err).ToNot(HaveOccurred()) 158 stubDone <- true 159 160 resp := &container_daemon.ResponseMessage{ 161 Files: sentFilesCp, 162 Pid: sentPidCp, 163 } 164 if sentErrorCp != nil { 165 resp.ErrMessage = sentErrorCp.Error() 166 } 167 return resp, sentErrorCp 168 } 169 170 go listener.Listen(connectionHandler) 171 }) 172 173 AfterEach(func() { 174 if listener != nil { 175 Expect(listener.Close()).To(Succeed()) 176 } 177 }) 178 179 BeforeEach(func() { 180 data := map[string]string{"fruit": "apple"} 181 jsonData, err := json.Marshal(&data) 182 Expect(err).ToNot(HaveOccurred()) 183 184 sentMsg = &container_daemon.RequestMessage{ 185 Type: container_daemon.ProcessRequest, 186 Data: jsonData, 187 } 188 }) 189 190 It("calls the handler with the sent message", func() { 191 _, err := connector.Connect(sentMsg) 192 Expect(err).ToNot(HaveOccurred()) 193 194 Eventually(stubDone).Should(Receive()) 195 Expect(recvMsg).To(Equal(sentMsg)) 196 }) 197 198 It("gets back the stream the handler provided", func() { 199 resp, err := connector.Connect(sentMsg) 200 Expect(err).ToNot(HaveOccurred()) 201 202 Expect(stubDone).To(Receive()) 203 Expect(resp.Files).To(HaveLen(2)) 204 205 _, err = resp.Files[0].Write([]byte("potato potato")) 206 Expect(err).NotTo(HaveOccurred()) 207 err = resp.Files[0].Close() 208 Expect(err).NotTo(HaveOccurred()) 209 sentFiles[0].Seek(0, 0) 210 Expect(ioutil.ReadAll(sentFiles[0])).Should(Equal([]byte("potato potato"))) 211 212 _, err = sentFiles[1].Write([]byte("brocoli brocoli")) 213 Expect(err).NotTo(HaveOccurred()) 214 err = sentFiles[1].Close() 215 Expect(err).NotTo(HaveOccurred()) 216 Expect(ioutil.ReadAll(resp.Files[1])).Should(Equal([]byte("brocoli brocoli"))) 217 }) 218 219 It("gets back the pid the handler provided", func() { 220 resp, err := connector.Connect(sentMsg) 221 Expect(err).ToNot(HaveOccurred()) 222 Eventually(stubDone).Should(Receive()) 223 Expect(resp.Pid).To(Equal(sentPid)) 224 }) 225 226 Context("when the handler fails", func() { 227 BeforeEach(func() { 228 sentErrorMutex.Lock() 229 defer sentErrorMutex.Unlock() 230 sentError = errors.New("no cake") 231 }) 232 233 It("sends back the error from the handler", func() { 234 _, err := connector.Connect(sentMsg) 235 Expect(err).To(MatchError("no cake")) 236 }) 237 }) 238 }) 239 }) 240 })