github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/api/state_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package api_test 5 6 import ( 7 stdtesting "testing" 8 9 jc "github.com/juju/testing/checkers" 10 gc "gopkg.in/check.v1" 11 "gopkg.in/juju/names.v2" 12 "gopkg.in/macaroon.v1" 13 14 "github.com/juju/juju/api" 15 "github.com/juju/juju/api/modelmanager" 16 "github.com/juju/juju/api/usermanager" 17 jujutesting "github.com/juju/juju/juju/testing" 18 "github.com/juju/juju/network" 19 coretesting "github.com/juju/juju/testing" 20 ) 21 22 func TestAll(t *stdtesting.T) { 23 coretesting.MgoTestPackage(t) 24 } 25 26 type stateSuite struct { 27 jujutesting.JujuConnSuite 28 } 29 30 var _ = gc.Suite(&stateSuite{}) 31 32 type slideSuite struct { 33 coretesting.BaseSuite 34 } 35 36 var _ = gc.Suite(&slideSuite{}) 37 38 func (s *stateSuite) TestCloseMultipleOk(c *gc.C) { 39 c.Assert(s.APIState.Close(), gc.IsNil) 40 c.Assert(s.APIState.Close(), gc.IsNil) 41 c.Assert(s.APIState.Close(), gc.IsNil) 42 } 43 44 // OpenAPIWithoutLogin connects to the API and returns an api.State without 45 // actually calling st.Login already. The returned strings are the "tag" and 46 // "password" that we would have used to login. 47 func (s *stateSuite) OpenAPIWithoutLogin(c *gc.C) (api.Connection, names.Tag, string) { 48 info := s.APIInfo(c) 49 tag := info.Tag 50 password := info.Password 51 info.Tag = nil 52 info.Password = "" 53 info.Macaroons = nil 54 info.SkipLogin = true 55 apistate, err := api.Open(info, api.DialOpts{}) 56 c.Assert(err, jc.ErrorIsNil) 57 return apistate, tag, password 58 } 59 60 func (s *stateSuite) TestAPIHostPortsAlwaysIncludesTheConnection(c *gc.C) { 61 hostportslist := s.APIState.APIHostPorts() 62 c.Check(hostportslist, gc.HasLen, 1) 63 serverhostports := hostportslist[0] 64 c.Check(serverhostports, gc.HasLen, 1) 65 // the other addresses, but always see this one as well. 66 info := s.APIInfo(c) 67 // We intentionally set this to invalid values 68 badServer := network.NewHostPorts(1234, "0.1.2.3") 69 badServer[0].Scope = network.ScopeMachineLocal 70 s.State.SetAPIHostPorts([][]network.HostPort{badServer}) 71 apistate, err := api.Open(info, api.DialOpts{}) 72 c.Assert(err, jc.ErrorIsNil) 73 defer apistate.Close() 74 hostports := apistate.APIHostPorts() 75 c.Check(hostports, gc.DeepEquals, [][]network.HostPort{ 76 serverhostports, 77 badServer, 78 }) 79 } 80 81 func (s *stateSuite) TestTags(c *gc.C) { 82 model, err := s.State.Model() 83 c.Assert(err, jc.ErrorIsNil) 84 apistate, tag, password := s.OpenAPIWithoutLogin(c) 85 defer apistate.Close() 86 // Even though we haven't called Login, the model tag should 87 // still be set. 88 modelTag, ok := apistate.ModelTag() 89 c.Check(ok, jc.IsTrue) 90 c.Check(modelTag, gc.Equals, model.ModelTag()) 91 err = apistate.Login(tag, password, "", nil) 92 c.Assert(err, jc.ErrorIsNil) 93 // Now that we've logged in, ModelTag should still be the same. 94 modelTag, ok = apistate.ModelTag() 95 c.Check(ok, jc.IsTrue) 96 c.Check(modelTag, gc.Equals, model.ModelTag()) 97 controllerTag := apistate.ControllerTag() 98 c.Check(controllerTag, gc.Equals, coretesting.ControllerTag) 99 } 100 101 func (s *stateSuite) TestLoginSetsModelAccess(c *gc.C) { 102 // The default user has admin access. 103 c.Assert(s.APIState.ModelAccess(), gc.Equals, "admin") 104 105 manager := usermanager.NewClient(s.OpenControllerAPI(c)) 106 defer manager.Close() 107 usertag, _, err := manager.AddUser("ro", "ro", "ro-password") 108 c.Assert(err, jc.ErrorIsNil) 109 mmanager := modelmanager.NewClient(s.OpenControllerAPI(c)) 110 defer mmanager.Close() 111 modeltag, ok := s.APIState.ModelTag() 112 c.Assert(ok, jc.IsTrue) 113 err = mmanager.GrantModel(usertag.Canonical(), "read", modeltag.Id()) 114 c.Assert(err, jc.ErrorIsNil) 115 conn := s.OpenAPIAs(c, usertag, "ro-password") 116 c.Assert(conn.ModelAccess(), gc.Equals, "read") 117 } 118 119 func (s *stateSuite) TestLoginSetsControllerAccess(c *gc.C) { 120 // The default user has admin access. 121 c.Assert(s.APIState.ControllerAccess(), gc.Equals, "superuser") 122 123 manager := usermanager.NewClient(s.OpenControllerAPI(c)) 124 defer manager.Close() 125 usertag, _, err := manager.AddUser("ro", "ro", "ro-password") 126 c.Assert(err, jc.ErrorIsNil) 127 mmanager := modelmanager.NewClient(s.OpenControllerAPI(c)) 128 defer mmanager.Close() 129 modeltag, ok := s.APIState.ModelTag() 130 c.Assert(ok, jc.IsTrue) 131 err = mmanager.GrantModel(usertag.Canonical(), "read", modeltag.Id()) 132 c.Assert(err, jc.ErrorIsNil) 133 conn := s.OpenAPIAs(c, usertag, "ro-password") 134 c.Assert(conn.ControllerAccess(), gc.Equals, "login") 135 } 136 137 func (s *stateSuite) TestLoginMacaroonInvalidId(c *gc.C) { 138 apistate, tag, _ := s.OpenAPIWithoutLogin(c) 139 defer apistate.Close() 140 mac, err := macaroon.New([]byte("root-key"), "id", "juju") 141 c.Assert(err, jc.ErrorIsNil) 142 err = apistate.Login(tag, "", "", []macaroon.Slice{{mac}}) 143 c.Assert(err, gc.ErrorMatches, "interaction required but not possible") 144 } 145 146 func (s *stateSuite) TestLoginTracksFacadeVersions(c *gc.C) { 147 apistate, tag, password := s.OpenAPIWithoutLogin(c) 148 defer apistate.Close() 149 // We haven't called Login yet, so the Facade Versions should be empty 150 c.Check(apistate.AllFacadeVersions(), gc.HasLen, 0) 151 err := apistate.Login(tag, password, "", nil) 152 c.Assert(err, jc.ErrorIsNil) 153 // Now that we've logged in, AllFacadeVersions should be updated. 154 allVersions := apistate.AllFacadeVersions() 155 c.Check(allVersions, gc.Not(gc.HasLen), 0) 156 // For sanity checking, ensure that we have a v2 of the Client facade 157 c.Assert(allVersions["Client"], gc.Not(gc.HasLen), 0) 158 c.Check(allVersions["Client"][0], gc.Equals, 1) 159 } 160 161 func (s *stateSuite) TestAllFacadeVersionsSafeFromMutation(c *gc.C) { 162 allVersions := s.APIState.AllFacadeVersions() 163 clients := allVersions["Client"] 164 origClients := make([]int, len(clients)) 165 copy(origClients, clients) 166 // Mutating the dict should not affect the cached versions 167 allVersions["Client"] = append(allVersions["Client"], 2597) 168 newVersions := s.APIState.AllFacadeVersions() 169 newClientVers := newVersions["Client"] 170 c.Check(newClientVers, gc.DeepEquals, origClients) 171 c.Check(newClientVers[len(newClientVers)-1], gc.Not(gc.Equals), 2597) 172 } 173 174 func (s *stateSuite) TestBestFacadeVersion(c *gc.C) { 175 c.Check(s.APIState.BestFacadeVersion("Client"), gc.Equals, 1) 176 } 177 178 func (s *stateSuite) TestAPIHostPortsMovesConnectedValueFirst(c *gc.C) { 179 hostportslist := s.APIState.APIHostPorts() 180 c.Check(hostportslist, gc.HasLen, 1) 181 serverhostports := hostportslist[0] 182 c.Check(serverhostports, gc.HasLen, 1) 183 goodAddress := serverhostports[0] 184 // the other addresses, but always see this one as well. 185 info := s.APIInfo(c) 186 // We intentionally set this to invalid values 187 badValue := network.HostPort{ 188 Address: network.Address{ 189 Value: "0.1.2.3", 190 Type: network.IPv4Address, 191 Scope: network.ScopeMachineLocal, 192 }, 193 Port: 1234, 194 } 195 badServer := []network.HostPort{badValue} 196 extraAddress := network.HostPort{ 197 Address: network.Address{ 198 Value: "0.1.2.4", 199 Type: network.IPv4Address, 200 Scope: network.ScopeMachineLocal, 201 }, 202 Port: 5678, 203 } 204 extraAddress2 := network.HostPort{ 205 Address: network.Address{ 206 Value: "0.1.2.1", 207 Type: network.IPv4Address, 208 Scope: network.ScopeMachineLocal, 209 }, 210 Port: 9012, 211 } 212 serverExtra := []network.HostPort{ 213 extraAddress, goodAddress, extraAddress2, 214 } 215 current := [][]network.HostPort{badServer, serverExtra} 216 s.State.SetAPIHostPorts(current) 217 apistate, err := api.Open(info, api.DialOpts{}) 218 c.Assert(err, jc.ErrorIsNil) 219 defer apistate.Close() 220 hostports := apistate.APIHostPorts() 221 // We should have rotate the server we connected to as the first item, 222 // and the address of that server as the first address 223 sortedServer := []network.HostPort{ 224 goodAddress, extraAddress, extraAddress2, 225 } 226 expected := [][]network.HostPort{sortedServer, badServer} 227 c.Check(hostports, gc.DeepEquals, expected) 228 } 229 230 var exampleHostPorts = []network.HostPort{{ 231 Address: network.NewAddress("0.1.2.3"), 232 Port: 1234, 233 }, { 234 Address: network.NewAddress("0.1.2.4"), 235 Port: 5678, 236 }, { 237 Address: network.NewAddress("0.1.2.1"), 238 Port: 9012, 239 }, { 240 Address: network.NewAddress("0.1.9.1"), 241 Port: 8888, 242 }} 243 244 func (s *slideSuite) TestSlideToFrontNoOp(c *gc.C) { 245 servers := [][]network.HostPort{ 246 {exampleHostPorts[0]}, 247 {exampleHostPorts[1]}, 248 } 249 // order should not have changed 250 expected := [][]network.HostPort{ 251 {exampleHostPorts[0]}, 252 {exampleHostPorts[1]}, 253 } 254 api.SlideAddressToFront(servers, 0, 0) 255 c.Check(servers, gc.DeepEquals, expected) 256 } 257 258 func (s *slideSuite) TestSlideToFrontAddress(c *gc.C) { 259 servers := [][]network.HostPort{ 260 {exampleHostPorts[0], exampleHostPorts[1], exampleHostPorts[2]}, 261 {exampleHostPorts[3]}, 262 } 263 // server order should not change, but ports should be switched 264 expected := [][]network.HostPort{ 265 {exampleHostPorts[1], exampleHostPorts[0], exampleHostPorts[2]}, 266 {exampleHostPorts[3]}, 267 } 268 api.SlideAddressToFront(servers, 0, 1) 269 c.Check(servers, gc.DeepEquals, expected) 270 } 271 272 func (s *slideSuite) TestSlideToFrontServer(c *gc.C) { 273 servers := [][]network.HostPort{ 274 {exampleHostPorts[0], exampleHostPorts[1]}, 275 {exampleHostPorts[2]}, 276 {exampleHostPorts[3]}, 277 } 278 // server 1 should be slid to the front 279 expected := [][]network.HostPort{ 280 {exampleHostPorts[2]}, 281 {exampleHostPorts[0], exampleHostPorts[1]}, 282 {exampleHostPorts[3]}, 283 } 284 api.SlideAddressToFront(servers, 1, 0) 285 c.Check(servers, gc.DeepEquals, expected) 286 } 287 288 func (s *slideSuite) TestSlideToFrontBoth(c *gc.C) { 289 servers := [][]network.HostPort{ 290 {exampleHostPorts[0]}, 291 {exampleHostPorts[1], exampleHostPorts[2]}, 292 {exampleHostPorts[3]}, 293 } 294 // server 1 should be slid to the front 295 expected := [][]network.HostPort{ 296 {exampleHostPorts[2], exampleHostPorts[1]}, 297 {exampleHostPorts[0]}, 298 {exampleHostPorts[3]}, 299 } 300 api.SlideAddressToFront(servers, 1, 1) 301 c.Check(servers, gc.DeepEquals, expected) 302 }