github.com/mattyw/juju@v0.0.0-20140610034352-732aecd63861/state/api/apiclient_test.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package api_test 5 6 import ( 7 "fmt" 8 "io" 9 "net" 10 "strconv" 11 12 "github.com/juju/utils/parallel" 13 gc "launchpad.net/gocheck" 14 15 jujutesting "github.com/juju/juju/juju/testing" 16 "github.com/juju/juju/state/api" 17 "github.com/juju/juju/state/api/params" 18 coretesting "github.com/juju/juju/testing" 19 ) 20 21 type apiclientSuite struct { 22 jujutesting.JujuConnSuite 23 } 24 25 var _ = gc.Suite(&apiclientSuite{}) 26 27 type websocketSuite struct { 28 coretesting.BaseSuite 29 } 30 31 var _ = gc.Suite(&websocketSuite{}) 32 33 func (s *apiclientSuite) TestOpenPrefersLocalhostIfPresent(c *gc.C) { 34 // Create a socket that proxies to the API server though our localhost address. 35 info := s.APIInfo(c) 36 serverAddr := info.Addrs[0] 37 server, err := net.Dial("tcp", serverAddr) 38 c.Assert(err, gc.IsNil) 39 defer server.Close() 40 listener, err := net.Listen("tcp", "localhost:0") 41 c.Assert(err, gc.IsNil) 42 defer listener.Close() 43 go func() { 44 for { 45 client, err := listener.Accept() 46 if err != nil { 47 return 48 } 49 go io.Copy(client, server) 50 go io.Copy(server, client) 51 } 52 }() 53 54 // Check that we are using our working address to connect 55 listenerAddress := listener.Addr().String() 56 // listenAddress contains the actual IP address, but APIHostPorts 57 // is going to report localhost, so just find the port 58 _, port, err := net.SplitHostPort(listenerAddress) 59 c.Check(err, gc.IsNil) 60 portNum, err := strconv.Atoi(port) 61 c.Check(err, gc.IsNil) 62 expectedHostPort := fmt.Sprintf("localhost:%d", portNum) 63 info.Addrs = []string{"fakeAddress:1", "fakeAddress:1", expectedHostPort} 64 st, err := api.Open(info, api.DialOpts{}) 65 c.Assert(err, gc.IsNil) 66 defer st.Close() 67 c.Assert(st.Addr(), gc.Equals, expectedHostPort) 68 } 69 70 func (s *apiclientSuite) TestOpenMultiple(c *gc.C) { 71 // Create a socket that proxies to the API server. 72 info := s.APIInfo(c) 73 serverAddr := info.Addrs[0] 74 server, err := net.Dial("tcp", serverAddr) 75 c.Assert(err, gc.IsNil) 76 defer server.Close() 77 listener, err := net.Listen("tcp", "127.0.0.1:0") 78 c.Assert(err, gc.IsNil) 79 defer listener.Close() 80 go func() { 81 for { 82 client, err := listener.Accept() 83 if err != nil { 84 return 85 } 86 go io.Copy(client, server) 87 go io.Copy(server, client) 88 } 89 }() 90 91 // Check that we can use the proxy to connect. 92 proxyAddr := listener.Addr().String() 93 info.Addrs = []string{proxyAddr} 94 st, err := api.Open(info, api.DialOpts{}) 95 c.Assert(err, gc.IsNil) 96 defer st.Close() 97 c.Assert(st.Addr(), gc.Equals, proxyAddr) 98 99 // Now break Addrs[0], and ensure that Addrs[1] 100 // is successfully connected to. 101 info.Addrs = []string{proxyAddr, serverAddr} 102 listener.Close() 103 st, err = api.Open(info, api.DialOpts{}) 104 c.Assert(err, gc.IsNil) 105 defer st.Close() 106 c.Assert(st.Addr(), gc.Equals, serverAddr) 107 } 108 109 func (s *apiclientSuite) TestOpenMultipleError(c *gc.C) { 110 listener, err := net.Listen("tcp", "127.0.0.1:0") 111 c.Assert(err, gc.IsNil) 112 defer listener.Close() 113 go func() { 114 for { 115 client, err := listener.Accept() 116 if err != nil { 117 return 118 } 119 client.Close() 120 } 121 }() 122 info := s.APIInfo(c) 123 addr := listener.Addr().String() 124 info.Addrs = []string{addr, addr, addr} 125 _, err = api.Open(info, api.DialOpts{}) 126 c.Assert(err, gc.ErrorMatches, `unable to connect to "wss://.*/"`) 127 } 128 129 func (s *apiclientSuite) TestOpenPassesEnvironTag(c *gc.C) { 130 info := s.APIInfo(c) 131 env, err := s.State.Environment() 132 c.Assert(err, gc.IsNil) 133 // TODO(jam): 2014-06-05 http://pad.lv/1326802 134 // we want to test this eventually, but for now s.APIInfo uses 135 // conn.StateInfo() which doesn't know about EnvironTag. 136 // c.Check(info.EnvironTag, gc.Equals, env.Tag()) 137 // c.Assert(info.EnvironTag, gc.Not(gc.Equals), "") 138 // We start by ensuring we have an invalid tag, and Open should fail. 139 info.EnvironTag = "environment-bad-tag" 140 _, err = api.Open(info, api.DialOpts{}) 141 c.Check(err, gc.ErrorMatches, `unknown environment: "bad-tag"`) 142 c.Check(params.ErrCode(err), gc.Equals, params.CodeNotFound) 143 // Now set it to the right tag, and we should succeed. 144 info.EnvironTag = env.Tag() 145 st, err := api.Open(info, api.DialOpts{}) 146 c.Assert(err, gc.IsNil) 147 st.Close() 148 // Backwards compatibility, we should succeed if we pass just "" as the 149 // environ tag 150 info.EnvironTag = "" 151 st, err = api.Open(info, api.DialOpts{}) 152 c.Assert(err, gc.IsNil) 153 st.Close() 154 } 155 156 func (s *apiclientSuite) TestDialWebsocketStopped(c *gc.C) { 157 stopped := make(chan struct{}) 158 f := api.NewWebsocketDialer(nil, api.DialOpts{}) 159 close(stopped) 160 result, err := f(stopped) 161 c.Assert(err, gc.Equals, parallel.ErrStopped) 162 c.Assert(result, gc.IsNil) 163 } 164 165 func (*websocketSuite) TestSetUpWebsocketConfig(c *gc.C) { 166 conf, err := api.SetUpWebsocket("0.1.2.3:1234", "", nil) 167 c.Assert(err, gc.IsNil) 168 c.Check(conf.Location.String(), gc.Equals, "wss://0.1.2.3:1234/") 169 c.Check(conf.Origin.String(), gc.Equals, "http://localhost/") 170 } 171 172 func (*websocketSuite) TestSetUpWebsocketConfigHandlesEnvironUUID(c *gc.C) { 173 conf, err := api.SetUpWebsocket("0.1.2.3:1234", "dead-beef-1234", nil) 174 c.Assert(err, gc.IsNil) 175 c.Check(conf.Location.String(), gc.Equals, "wss://0.1.2.3:1234/environment/dead-beef-1234/api") 176 c.Check(conf.Origin.String(), gc.Equals, "http://localhost/") 177 }