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