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