github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/apiserver/common/tools_test.go (about) 1 // Copyright 2013 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common_test 5 6 import ( 7 "fmt" 8 9 "github.com/juju/errors" 10 "github.com/juju/names" 11 jc "github.com/juju/testing/checkers" 12 gc "gopkg.in/check.v1" 13 14 "github.com/juju/juju/apiserver/common" 15 "github.com/juju/juju/apiserver/params" 16 apiservertesting "github.com/juju/juju/apiserver/testing" 17 "github.com/juju/juju/environs" 18 "github.com/juju/juju/juju/testing" 19 "github.com/juju/juju/network" 20 "github.com/juju/juju/state" 21 "github.com/juju/juju/state/toolstorage" 22 coretools "github.com/juju/juju/tools" 23 "github.com/juju/juju/version" 24 ) 25 26 type toolsSuite struct { 27 testing.JujuConnSuite 28 machine0 *state.Machine 29 } 30 31 var _ = gc.Suite(&toolsSuite{}) 32 33 func (s *toolsSuite) SetUpTest(c *gc.C) { 34 s.JujuConnSuite.SetUpTest(c) 35 var err error 36 s.machine0, err = s.State.AddMachine("series", state.JobHostUnits) 37 c.Assert(err, jc.ErrorIsNil) 38 s.AddDefaultToolsToState(c) 39 } 40 41 func (s *toolsSuite) TestTools(c *gc.C) { 42 getCanRead := func() (common.AuthFunc, error) { 43 return func(tag names.Tag) bool { 44 return tag == names.NewMachineTag("0") || tag == names.NewMachineTag("42") 45 }, nil 46 } 47 tg := common.NewToolsGetter(s.State, s.State, s.State, sprintfURLGetter("tools:%s"), getCanRead) 48 c.Assert(tg, gc.NotNil) 49 50 err := s.machine0.SetAgentVersion(version.Current) 51 c.Assert(err, jc.ErrorIsNil) 52 53 args := params.Entities{ 54 Entities: []params.Entity{ 55 {Tag: "machine-0"}, 56 {Tag: "machine-1"}, 57 {Tag: "machine-42"}, 58 }} 59 result, err := tg.Tools(args) 60 c.Assert(err, jc.ErrorIsNil) 61 c.Assert(result.Results, gc.HasLen, 3) 62 c.Assert(result.Results[0].Error, gc.IsNil) 63 c.Assert(result.Results[0].Tools, gc.NotNil) 64 c.Assert(result.Results[0].Tools.Version, gc.DeepEquals, version.Current) 65 c.Assert(result.Results[0].Tools.URL, gc.Equals, "tools:"+version.Current.String()) 66 c.Assert(result.Results[0].DisableSSLHostnameVerification, jc.IsTrue) 67 c.Assert(result.Results[1].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 68 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.NotFoundError("machine 42")) 69 } 70 71 func (s *toolsSuite) TestToolsError(c *gc.C) { 72 getCanRead := func() (common.AuthFunc, error) { 73 return nil, fmt.Errorf("splat") 74 } 75 tg := common.NewToolsGetter(s.State, s.State, s.State, sprintfURLGetter("%s"), getCanRead) 76 args := params.Entities{ 77 Entities: []params.Entity{{Tag: "machine-42"}}, 78 } 79 result, err := tg.Tools(args) 80 c.Assert(err, gc.ErrorMatches, "splat") 81 c.Assert(result.Results, gc.HasLen, 1) 82 } 83 84 func (s *toolsSuite) TestSetTools(c *gc.C) { 85 getCanWrite := func() (common.AuthFunc, error) { 86 return func(tag names.Tag) bool { 87 return tag == names.NewMachineTag("0") || tag == names.NewMachineTag("42") 88 }, nil 89 } 90 ts := common.NewToolsSetter(s.State, getCanWrite) 91 c.Assert(ts, gc.NotNil) 92 93 err := s.machine0.SetAgentVersion(version.Current) 94 c.Assert(err, jc.ErrorIsNil) 95 96 args := params.EntitiesVersion{ 97 AgentTools: []params.EntityVersion{{ 98 Tag: "machine-0", 99 Tools: ¶ms.Version{ 100 Version: version.Current, 101 }, 102 }, { 103 Tag: "machine-1", 104 Tools: ¶ms.Version{ 105 Version: version.Current, 106 }, 107 }, { 108 Tag: "machine-42", 109 Tools: ¶ms.Version{ 110 Version: version.Current, 111 }, 112 }}, 113 } 114 result, err := ts.SetTools(args) 115 c.Assert(err, jc.ErrorIsNil) 116 c.Assert(result.Results, gc.HasLen, 3) 117 c.Assert(result.Results[0].Error, gc.IsNil) 118 agentTools, err := s.machine0.AgentTools() 119 c.Assert(err, jc.ErrorIsNil) 120 c.Assert(agentTools.Version, gc.DeepEquals, version.Current) 121 c.Assert(result.Results[1].Error, gc.DeepEquals, apiservertesting.ErrUnauthorized) 122 c.Assert(result.Results[2].Error, gc.DeepEquals, apiservertesting.NotFoundError("machine 42")) 123 } 124 125 func (s *toolsSuite) TestToolsSetError(c *gc.C) { 126 getCanWrite := func() (common.AuthFunc, error) { 127 return nil, fmt.Errorf("splat") 128 } 129 ts := common.NewToolsSetter(s.State, getCanWrite) 130 args := params.EntitiesVersion{ 131 AgentTools: []params.EntityVersion{{ 132 Tag: "machine-42", 133 Tools: ¶ms.Version{ 134 Version: version.Current, 135 }, 136 }}, 137 } 138 result, err := ts.SetTools(args) 139 c.Assert(err, gc.ErrorMatches, "splat") 140 c.Assert(result.Results, gc.HasLen, 1) 141 } 142 143 func (s *toolsSuite) TestFindTools(c *gc.C) { 144 envtoolsList := coretools.List{ 145 &coretools.Tools{ 146 Version: version.MustParseBinary("123.456.0-win81-alpha"), 147 Size: 2048, 148 SHA256: "badf00d", 149 }, 150 &coretools.Tools{ 151 Version: version.MustParseBinary("123.456.1-win81-alpha"), 152 }, 153 } 154 storageMetadata := []toolstorage.Metadata{{ 155 Version: version.MustParseBinary("123.456.0-win81-alpha"), 156 Size: 1024, 157 SHA256: "feedface", 158 }} 159 160 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (coretools.List, error) { 161 c.Assert(major, gc.Equals, 123) 162 c.Assert(minor, gc.Equals, 456) 163 c.Assert(filter.Series, gc.Equals, "win81") 164 c.Assert(filter.Arch, gc.Equals, "alpha") 165 return envtoolsList, nil 166 }) 167 toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{metadata: storageMetadata}, sprintfURLGetter("tools:%s")) 168 result, err := toolsFinder.FindTools(params.FindToolsParams{ 169 MajorVersion: 123, 170 MinorVersion: 456, 171 Series: "win81", 172 Arch: "alpha", 173 }) 174 c.Assert(err, jc.ErrorIsNil) 175 c.Assert(result.Error, gc.IsNil) 176 c.Assert(result.List, gc.DeepEquals, coretools.List{ 177 &coretools.Tools{ 178 Version: storageMetadata[0].Version, 179 Size: storageMetadata[0].Size, 180 SHA256: storageMetadata[0].SHA256, 181 URL: "tools:" + storageMetadata[0].Version.String(), 182 }, 183 envtoolsList[1], 184 }) 185 } 186 187 func (s *toolsSuite) TestFindToolsNotFound(c *gc.C) { 188 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (list coretools.List, err error) { 189 return nil, errors.NotFoundf("tools") 190 }) 191 toolsFinder := common.NewToolsFinder(s.State, s.State, sprintfURLGetter("%s")) 192 result, err := toolsFinder.FindTools(params.FindToolsParams{}) 193 c.Assert(err, jc.ErrorIsNil) 194 c.Assert(result.Error, jc.Satisfies, params.IsCodeNotFound) 195 } 196 197 func (s *toolsSuite) TestFindToolsExactInStorage(c *gc.C) { 198 mockToolsStorage := &mockToolsStorage{ 199 metadata: []toolstorage.Metadata{{Version: version.Current}}, 200 } 201 s.testFindToolsExact(c, mockToolsStorage, true) 202 } 203 204 func (s *toolsSuite) TestFindToolsExactNotInStorage(c *gc.C) { 205 mockToolsStorage := &mockToolsStorage{} 206 s.testFindToolsExact(c, mockToolsStorage, false) 207 } 208 209 func (s *toolsSuite) testFindToolsExact(c *gc.C, t common.ToolsStorageGetter, inStorage bool) { 210 var called bool 211 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (list coretools.List, err error) { 212 called = true 213 c.Assert(filter.Number, gc.Equals, version.Current.Number) 214 c.Assert(filter.Series, gc.Equals, version.Current.Series) 215 c.Assert(filter.Arch, gc.Equals, version.Current.Arch) 216 return nil, errors.NotFoundf("tools") 217 }) 218 toolsFinder := common.NewToolsFinder(s.State, t, sprintfURLGetter("tools:%s")) 219 result, err := toolsFinder.FindTools(params.FindToolsParams{ 220 Number: version.Current.Number, 221 MajorVersion: -1, 222 MinorVersion: -1, 223 Series: version.Current.Series, 224 Arch: version.Current.Arch, 225 }) 226 c.Assert(err, jc.ErrorIsNil) 227 if inStorage { 228 c.Assert(result.Error, gc.IsNil) 229 c.Assert(called, jc.IsFalse) 230 } else { 231 c.Assert(result.Error, gc.ErrorMatches, "tools not found") 232 c.Assert(called, jc.IsTrue) 233 } 234 } 235 236 func (s *toolsSuite) TestFindToolsToolsStorageError(c *gc.C) { 237 var called bool 238 s.PatchValue(common.EnvtoolsFindTools, func(e environs.Environ, major, minor int, filter coretools.Filter) (list coretools.List, err error) { 239 called = true 240 return nil, errors.NotFoundf("tools") 241 }) 242 toolsFinder := common.NewToolsFinder(s.State, &mockToolsStorage{ 243 err: errors.New("AllMetadata failed"), 244 }, sprintfURLGetter("tools:%s")) 245 result, err := toolsFinder.FindTools(params.FindToolsParams{ 246 MajorVersion: 1, 247 MinorVersion: -1, 248 }) 249 c.Assert(err, jc.ErrorIsNil) 250 // ToolsStorage errors always cause FindTools to bail. Only 251 // if AllMetadata succeeds but returns nothing that matches 252 // do we continue on to searching simplestreams. 253 c.Assert(result.Error, gc.ErrorMatches, "AllMetadata failed") 254 c.Assert(called, jc.IsFalse) 255 } 256 257 func (s *toolsSuite) TestToolsURLGetterNoAPIHostPorts(c *gc.C) { 258 g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{}) 259 _, err := g.ToolsURL(version.Current) 260 c.Assert(err, gc.ErrorMatches, "no API host ports") 261 } 262 263 func (s *toolsSuite) TestToolsURLGetterAPIHostPortsError(c *gc.C) { 264 g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{err: errors.New("oh noes")}) 265 _, err := g.ToolsURL(version.Current) 266 c.Assert(err, gc.ErrorMatches, "oh noes") 267 } 268 269 func (s *toolsSuite) TestToolsURLGetter(c *gc.C) { 270 g := common.NewToolsURLGetter("my-uuid", mockAPIHostPortsGetter{ 271 hostPorts: [][]network.HostPort{ 272 network.NewHostPorts(1234, "0.1.2.3"), 273 }, 274 }) 275 url, err := g.ToolsURL(version.Current) 276 c.Assert(err, jc.ErrorIsNil) 277 c.Assert(url, gc.Equals, "https://0.1.2.3:1234/environment/my-uuid/tools/"+version.Current.String()) 278 } 279 280 type sprintfURLGetter string 281 282 func (s sprintfURLGetter) ToolsURL(v version.Binary) (string, error) { 283 return fmt.Sprintf(string(s), v), nil 284 } 285 286 type mockAPIHostPortsGetter struct { 287 hostPorts [][]network.HostPort 288 err error 289 } 290 291 func (g mockAPIHostPortsGetter) APIHostPorts() ([][]network.HostPort, error) { 292 return g.hostPorts, g.err 293 } 294 295 type mockToolsStorage struct { 296 toolstorage.Storage 297 metadata []toolstorage.Metadata 298 err error 299 } 300 301 func (s *mockToolsStorage) ToolsStorage() (toolstorage.StorageCloser, error) { 302 return s, nil 303 } 304 305 func (s *mockToolsStorage) Close() error { 306 return nil 307 } 308 309 func (s *mockToolsStorage) AllMetadata() ([]toolstorage.Metadata, error) { 310 return s.metadata, s.err 311 }