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  }