github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/provider/joyent/local_test.go (about) 1 // Copyright 2013 Joyent Inc. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package joyent_test 5 6 import ( 7 "bytes" 8 "io/ioutil" 9 "net/http" 10 "net/http/httptest" 11 12 lm "github.com/joyent/gomanta/localservices/manta" 13 lc "github.com/joyent/gosdc/localservices/cloudapi" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 "github.com/juju/juju/constraints" 18 "github.com/juju/juju/environs" 19 "github.com/juju/juju/environs/bootstrap" 20 "github.com/juju/juju/environs/imagemetadata" 21 "github.com/juju/juju/environs/jujutest" 22 "github.com/juju/juju/environs/simplestreams" 23 "github.com/juju/juju/environs/storage" 24 envtesting "github.com/juju/juju/environs/testing" 25 "github.com/juju/juju/environs/tools" 26 "github.com/juju/juju/instance" 27 "github.com/juju/juju/juju/arch" 28 "github.com/juju/juju/juju/testing" 29 "github.com/juju/juju/provider/joyent" 30 coretesting "github.com/juju/juju/testing" 31 ) 32 33 func registerLocalTests() { 34 gc.Suite(&localServerSuite{}) 35 gc.Suite(&localLiveSuite{}) 36 } 37 38 type localCloudAPIServer struct { 39 Server *httptest.Server 40 Mux *http.ServeMux 41 oldHandler http.Handler 42 cloudapi *lc.CloudAPI 43 } 44 45 func (ca *localCloudAPIServer) setupServer(c *gc.C) { 46 // Set up the HTTP server. 47 ca.Server = httptest.NewServer(nil) 48 c.Assert(ca.Server, gc.NotNil) 49 ca.oldHandler = ca.Server.Config.Handler 50 ca.Mux = http.NewServeMux() 51 ca.Server.Config.Handler = ca.Mux 52 53 ca.cloudapi = lc.New(ca.Server.URL, testUser) 54 ca.cloudapi.SetupHTTP(ca.Mux) 55 c.Logf("Started local CloudAPI service at: %v", ca.Server.URL) 56 } 57 58 func (c *localCloudAPIServer) destroyServer() { 59 c.Mux = nil 60 c.Server.Config.Handler = c.oldHandler 61 c.Server.Close() 62 } 63 64 type localMantaServer struct { 65 Server *httptest.Server 66 Mux *http.ServeMux 67 oldHandler http.Handler 68 manta *lm.Manta 69 } 70 71 func (m *localMantaServer) setupServer(c *gc.C) { 72 // Set up the HTTP server. 73 m.Server = httptest.NewServer(nil) 74 c.Assert(m.Server, gc.NotNil) 75 m.oldHandler = m.Server.Config.Handler 76 m.Mux = http.NewServeMux() 77 m.Server.Config.Handler = m.Mux 78 79 m.manta = lm.New(m.Server.URL, testUser) 80 m.manta.SetupHTTP(m.Mux) 81 c.Logf("Started local Manta service at: %v", m.Server.URL) 82 } 83 84 func (m *localMantaServer) destroyServer() { 85 m.Mux = nil 86 m.Server.Config.Handler = m.oldHandler 87 m.Server.Close() 88 } 89 90 type localLiveSuite struct { 91 providerSuite 92 jujutest.LiveTests 93 cSrv *localCloudAPIServer 94 mSrv *localMantaServer 95 } 96 97 func (s *localLiveSuite) SetUpSuite(c *gc.C) { 98 s.providerSuite.SetUpSuite(c) 99 s.cSrv = &localCloudAPIServer{} 100 s.mSrv = &localMantaServer{} 101 s.cSrv.setupServer(c) 102 s.mSrv.setupServer(c) 103 s.AddSuiteCleanup(func(*gc.C) { envtesting.PatchAttemptStrategies(&joyent.ShortAttempt) }) 104 105 s.TestConfig = GetFakeConfig(s.cSrv.Server.URL, s.mSrv.Server.URL) 106 s.TestConfig = s.TestConfig.Merge(coretesting.Attrs{ 107 "image-metadata-url": "test://host", 108 }) 109 s.LiveTests.UploadArches = []string{arch.AMD64} 110 s.LiveTests.SetUpSuite(c) 111 } 112 113 func (s *localLiveSuite) TearDownSuite(c *gc.C) { 114 joyent.UnregisterExternalTestImageMetadata() 115 s.LiveTests.TearDownSuite(c) 116 s.cSrv.destroyServer() 117 s.mSrv.destroyServer() 118 s.providerSuite.TearDownSuite(c) 119 } 120 121 func (s *localLiveSuite) SetUpTest(c *gc.C) { 122 s.providerSuite.SetUpTest(c) 123 creds := joyent.MakeCredentials(c, s.TestConfig) 124 joyent.UseExternalTestImageMetadata(creds) 125 restoreFinishBootstrap := envtesting.DisableFinishBootstrap() 126 s.AddCleanup(func(*gc.C) { restoreFinishBootstrap() }) 127 s.LiveTests.SetUpTest(c) 128 } 129 130 func (s *localLiveSuite) TearDownTest(c *gc.C) { 131 s.LiveTests.TearDownTest(c) 132 s.providerSuite.TearDownTest(c) 133 } 134 135 // localServerSuite contains tests that run against an Joyent service double. 136 // These tests can test things that would be unreasonably slow or expensive 137 // to test on a live Joyent server. The service double is started and stopped for 138 // each test. 139 type localServerSuite struct { 140 providerSuite 141 jujutest.Tests 142 cSrv *localCloudAPIServer 143 mSrv *localMantaServer 144 } 145 146 func (s *localServerSuite) SetUpSuite(c *gc.C) { 147 s.providerSuite.SetUpSuite(c) 148 restoreFinishBootstrap := envtesting.DisableFinishBootstrap() 149 s.AddSuiteCleanup(func(*gc.C) { restoreFinishBootstrap() }) 150 } 151 152 func (s *localServerSuite) SetUpTest(c *gc.C) { 153 s.providerSuite.SetUpTest(c) 154 155 s.cSrv = &localCloudAPIServer{} 156 s.mSrv = &localMantaServer{} 157 s.cSrv.setupServer(c) 158 s.mSrv.setupServer(c) 159 160 s.Tests.ToolsFixture.UploadArches = []string{arch.AMD64} 161 s.Tests.SetUpTest(c) 162 s.TestConfig = GetFakeConfig(s.cSrv.Server.URL, s.mSrv.Server.URL) 163 // Put some fake image metadata in place. 164 creds := joyent.MakeCredentials(c, s.TestConfig) 165 joyent.UseExternalTestImageMetadata(creds) 166 } 167 168 func (s *localServerSuite) TearDownTest(c *gc.C) { 169 joyent.UnregisterExternalTestImageMetadata() 170 s.Tests.TearDownTest(c) 171 s.cSrv.destroyServer() 172 s.mSrv.destroyServer() 173 s.providerSuite.TearDownTest(c) 174 } 175 176 func bootstrapContext(c *gc.C) environs.BootstrapContext { 177 return envtesting.BootstrapContext(c) 178 } 179 180 // If the environment is configured not to require a public IP address for nodes, 181 // bootstrapping and starting an instance should occur without any attempt to 182 // allocate a public address. 183 func (s *localServerSuite) TestStartInstance(c *gc.C) { 184 env := s.Prepare(c) 185 err := bootstrap.Bootstrap(bootstrapContext(c), env, bootstrap.BootstrapParams{}) 186 c.Assert(err, jc.ErrorIsNil) 187 inst, _ := testing.AssertStartInstance(c, env, "100") 188 err = env.StopInstances(inst.Id()) 189 c.Assert(err, jc.ErrorIsNil) 190 } 191 192 func (s *localServerSuite) TestStartInstanceAvailabilityZone(c *gc.C) { 193 env := s.Prepare(c) 194 err := bootstrap.Bootstrap(bootstrapContext(c), env, bootstrap.BootstrapParams{}) 195 c.Assert(err, jc.ErrorIsNil) 196 inst, hwc := testing.AssertStartInstance(c, env, "100") 197 err = env.StopInstances(inst.Id()) 198 c.Assert(err, jc.ErrorIsNil) 199 200 c.Check(hwc.AvailabilityZone, gc.IsNil) 201 } 202 203 func (s *localServerSuite) TestStartInstanceHardwareCharacteristics(c *gc.C) { 204 env := s.Prepare(c) 205 err := bootstrap.Bootstrap(bootstrapContext(c), env, bootstrap.BootstrapParams{}) 206 c.Assert(err, jc.ErrorIsNil) 207 _, hc := testing.AssertStartInstanceWithConstraints(c, env, "100", constraints.MustParse("mem=1024")) 208 c.Check(*hc.Arch, gc.Equals, "amd64") 209 c.Check(*hc.Mem, gc.Equals, uint64(1024)) 210 c.Check(*hc.CpuCores, gc.Equals, uint64(1)) 211 c.Assert(hc.CpuPower, gc.IsNil) 212 } 213 214 var instanceGathering = []struct { 215 ids []instance.Id 216 err error 217 }{ 218 {ids: []instance.Id{"id0"}}, 219 {ids: []instance.Id{"id0", "id0"}}, 220 {ids: []instance.Id{"id0", "id1"}}, 221 {ids: []instance.Id{"id1", "id0"}}, 222 {ids: []instance.Id{"id1", "id0", "id1"}}, 223 { 224 ids: []instance.Id{""}, 225 err: environs.ErrNoInstances, 226 }, 227 { 228 ids: []instance.Id{"", ""}, 229 err: environs.ErrNoInstances, 230 }, 231 { 232 ids: []instance.Id{"", "", ""}, 233 err: environs.ErrNoInstances, 234 }, 235 { 236 ids: []instance.Id{"id0", ""}, 237 err: environs.ErrPartialInstances, 238 }, 239 { 240 ids: []instance.Id{"", "id1"}, 241 err: environs.ErrPartialInstances, 242 }, 243 { 244 ids: []instance.Id{"id0", "id1", ""}, 245 err: environs.ErrPartialInstances, 246 }, 247 { 248 ids: []instance.Id{"id0", "", "id0"}, 249 err: environs.ErrPartialInstances, 250 }, 251 { 252 ids: []instance.Id{"id0", "id0", ""}, 253 err: environs.ErrPartialInstances, 254 }, 255 { 256 ids: []instance.Id{"", "id0", "id1"}, 257 err: environs.ErrPartialInstances, 258 }, 259 } 260 261 func (s *localServerSuite) TestInstanceStatus(c *gc.C) { 262 env := s.Prepare(c) 263 inst, _ := testing.AssertStartInstance(c, env, "100") 264 c.Assert(inst.Status(), gc.Equals, "running") 265 err := env.StopInstances(inst.Id()) 266 c.Assert(err, jc.ErrorIsNil) 267 } 268 269 func (s *localServerSuite) TestInstancesGathering(c *gc.C) { 270 env := s.Prepare(c) 271 inst0, _ := testing.AssertStartInstance(c, env, "100") 272 id0 := inst0.Id() 273 inst1, _ := testing.AssertStartInstance(c, env, "101") 274 id1 := inst1.Id() 275 c.Logf("id0: %s, id1: %s", id0, id1) 276 defer func() { 277 err := env.StopInstances(inst0.Id(), inst1.Id()) 278 c.Assert(err, jc.ErrorIsNil) 279 }() 280 281 for i, test := range instanceGathering { 282 c.Logf("test %d: find %v -> expect len %d, err: %v", i, test.ids, len(test.ids), test.err) 283 ids := make([]instance.Id, len(test.ids)) 284 for j, id := range test.ids { 285 switch id { 286 case "id0": 287 ids[j] = id0 288 case "id1": 289 ids[j] = id1 290 } 291 } 292 insts, err := env.Instances(ids) 293 c.Assert(err, gc.Equals, test.err) 294 if err == environs.ErrNoInstances { 295 c.Assert(insts, gc.HasLen, 0) 296 } else { 297 c.Assert(insts, gc.HasLen, len(test.ids)) 298 } 299 for j, inst := range insts { 300 if ids[j] != "" { 301 c.Assert(inst.Id(), gc.Equals, ids[j]) 302 } else { 303 c.Assert(inst, gc.IsNil) 304 } 305 } 306 } 307 } 308 309 // It should be moved to environs.jujutests.Tests. 310 func (s *localServerSuite) TestBootstrapInstanceUserDataAndState(c *gc.C) { 311 env := s.Prepare(c) 312 err := bootstrap.Bootstrap(bootstrapContext(c), env, bootstrap.BootstrapParams{}) 313 c.Assert(err, jc.ErrorIsNil) 314 315 // check that StateServerInstances returns the id of the bootstrap machine. 316 instanceIds, err := env.StateServerInstances() 317 c.Assert(err, jc.ErrorIsNil) 318 c.Assert(instanceIds, gc.HasLen, 1) 319 320 insts, err := env.AllInstances() 321 c.Assert(err, jc.ErrorIsNil) 322 c.Assert(insts, gc.HasLen, 1) 323 c.Check(instanceIds[0], gc.Equals, insts[0].Id()) 324 325 addresses, err := insts[0].Addresses() 326 c.Assert(err, jc.ErrorIsNil) 327 c.Assert(addresses, gc.HasLen, 2) 328 } 329 330 func (s *localServerSuite) TestGetToolsMetadataSources(c *gc.C) { 331 s.PatchValue(&tools.DefaultBaseURL, "") 332 333 env := s.Prepare(c) 334 sources, err := tools.GetMetadataSources(env) 335 c.Assert(err, jc.ErrorIsNil) 336 c.Assert(sources, gc.HasLen, 0) 337 } 338 339 func (s *localServerSuite) TestFindImageBadDefaultImage(c *gc.C) { 340 env := s.Prepare(c) 341 // An error occurs if no suitable image is found. 342 _, err := joyent.FindInstanceSpec(env, "saucy", "amd64", "mem=4G") 343 c.Assert(err, gc.ErrorMatches, `no "saucy" images in some-region with arches \[amd64\]`) 344 } 345 346 func (s *localServerSuite) TestValidateImageMetadata(c *gc.C) { 347 env := s.Prepare(c) 348 params, err := env.(simplestreams.MetadataValidator).MetadataLookupParams("some-region") 349 c.Assert(err, jc.ErrorIsNil) 350 params.Sources, err = environs.ImageMetadataSources(env) 351 c.Assert(err, jc.ErrorIsNil) 352 params.Series = "raring" 353 image_ids, _, err := imagemetadata.ValidateImageMetadata(params) 354 c.Assert(err, jc.ErrorIsNil) 355 c.Assert(image_ids, gc.DeepEquals, []string{"11223344-0a0a-dd77-33cd-abcd1234e5f6"}) 356 } 357 358 func (s *localServerSuite) TestRemoveAll(c *gc.C) { 359 env := s.Prepare(c).(environs.EnvironStorage) 360 stor := env.Storage() 361 for _, a := range []byte("abcdefghijklmnopqrstuvwxyz") { 362 content := []byte{a} 363 name := string(content) 364 err := stor.Put(name, bytes.NewBuffer(content), 365 int64(len(content))) 366 c.Assert(err, jc.ErrorIsNil) 367 } 368 reader, err := storage.Get(stor, "a") 369 c.Assert(err, jc.ErrorIsNil) 370 allContent, err := ioutil.ReadAll(reader) 371 c.Assert(err, jc.ErrorIsNil) 372 c.Assert(string(allContent), gc.Equals, "a") 373 err = stor.RemoveAll() 374 c.Assert(err, jc.ErrorIsNil) 375 _, err = storage.Get(stor, "a") 376 c.Assert(err, gc.NotNil) 377 } 378 379 func (s *localServerSuite) TestDeleteMoreThan100(c *gc.C) { 380 env := s.Prepare(c).(environs.EnvironStorage) 381 stor := env.Storage() 382 // 6*26 = 156 items 383 for _, a := range []byte("abcdef") { 384 for _, b := range []byte("abcdefghijklmnopqrstuvwxyz") { 385 content := []byte{a, b} 386 name := string(content) 387 err := stor.Put(name, bytes.NewBuffer(content), 388 int64(len(content))) 389 c.Assert(err, jc.ErrorIsNil) 390 } 391 } 392 reader, err := storage.Get(stor, "ab") 393 c.Assert(err, jc.ErrorIsNil) 394 allContent, err := ioutil.ReadAll(reader) 395 c.Assert(err, jc.ErrorIsNil) 396 c.Assert(string(allContent), gc.Equals, "ab") 397 err = stor.RemoveAll() 398 c.Assert(err, jc.ErrorIsNil) 399 _, err = storage.Get(stor, "ab") 400 c.Assert(err, gc.NotNil) 401 } 402 403 func (s *localServerSuite) TestConstraintsValidator(c *gc.C) { 404 env := s.Prepare(c) 405 validator, err := env.ConstraintsValidator() 406 c.Assert(err, jc.ErrorIsNil) 407 cons := constraints.MustParse("arch=amd64 tags=bar cpu-power=10") 408 unsupported, err := validator.Validate(cons) 409 c.Assert(err, jc.ErrorIsNil) 410 c.Assert(unsupported, jc.SameContents, []string{"cpu-power", "tags"}) 411 } 412 413 func (s *localServerSuite) TestConstraintsValidatorVocab(c *gc.C) { 414 env := s.Prepare(c) 415 validator, err := env.ConstraintsValidator() 416 c.Assert(err, jc.ErrorIsNil) 417 cons := constraints.MustParse("arch=ppc64el") 418 _, err = validator.Validate(cons) 419 c.Assert(err, gc.ErrorMatches, "invalid constraint value: arch=ppc64el\nvalid values are:.*") 420 cons = constraints.MustParse("instance-type=foo") 421 _, err = validator.Validate(cons) 422 c.Assert(err, gc.ErrorMatches, "invalid constraint value: instance-type=foo\nvalid values are:.*") 423 }