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  }