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