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  })