github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/environs/jujutest/tests.go (about)

     1  // Copyright 2011, 2012, 2013 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujutest
     5  
     6  import (
     7  	"bytes"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"sort"
    11  
    12  	"github.com/juju/errors"
    13  	jc "github.com/juju/testing/checkers"
    14  	"github.com/juju/utils"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/environs"
    18  	"github.com/juju/juju/environs/bootstrap"
    19  	"github.com/juju/juju/environs/config"
    20  	"github.com/juju/juju/environs/configstore"
    21  	"github.com/juju/juju/environs/storage"
    22  	envtesting "github.com/juju/juju/environs/testing"
    23  	"github.com/juju/juju/instance"
    24  	"github.com/juju/juju/juju/testing"
    25  	coretesting "github.com/juju/juju/testing"
    26  	"github.com/juju/juju/version"
    27  )
    28  
    29  // Tests is a gocheck suite containing tests verifying juju functionality
    30  // against the environment with the given configuration. The
    31  // tests are not designed to be run against a live server - the Environ
    32  // is opened once for each test, and some potentially expensive operations
    33  // may be executed.
    34  type Tests struct {
    35  	TestConfig coretesting.Attrs
    36  	envtesting.ToolsFixture
    37  
    38  	// ConfigStore holds the configuration storage
    39  	// used when preparing the environment.
    40  	// This is initialized by SetUpTest.
    41  	ConfigStore configstore.Storage
    42  }
    43  
    44  // Open opens an instance of the testing environment.
    45  func (t *Tests) Open(c *gc.C) environs.Environ {
    46  	info, err := t.ConfigStore.ReadInfo(t.TestConfig["name"].(string))
    47  	c.Assert(err, jc.ErrorIsNil)
    48  	cfg, err := config.New(config.NoDefaults, info.BootstrapConfig())
    49  	c.Assert(err, jc.ErrorIsNil)
    50  	e, err := environs.New(cfg)
    51  	c.Assert(err, gc.IsNil, gc.Commentf("opening environ %#v", cfg.AllAttrs()))
    52  	c.Assert(e, gc.NotNil)
    53  	return e
    54  }
    55  
    56  // Prepare prepares an instance of the testing environment.
    57  func (t *Tests) Prepare(c *gc.C) environs.Environ {
    58  	cfg, err := config.New(config.NoDefaults, t.TestConfig)
    59  	c.Assert(err, jc.ErrorIsNil)
    60  	e, err := environs.Prepare(cfg, envtesting.BootstrapContext(c), t.ConfigStore)
    61  	c.Assert(err, gc.IsNil, gc.Commentf("preparing environ %#v", t.TestConfig))
    62  	c.Assert(e, gc.NotNil)
    63  	return e
    64  }
    65  
    66  func (t *Tests) SetUpTest(c *gc.C) {
    67  	storageDir := c.MkDir()
    68  	t.DefaultBaseURL = "file://" + storageDir + "/tools"
    69  	t.ToolsFixture.SetUpTest(c)
    70  	t.UploadFakeToolsToDirectory(c, storageDir, "released", "released")
    71  	t.ConfigStore = configstore.NewMem()
    72  }
    73  
    74  func (t *Tests) TearDownTest(c *gc.C) {
    75  	t.ToolsFixture.TearDownTest(c)
    76  }
    77  
    78  func (t *Tests) TestStartStop(c *gc.C) {
    79  	e := t.Prepare(c)
    80  	cfg, err := e.Config().Apply(map[string]interface{}{
    81  		"agent-version": version.Current.Number.String(),
    82  	})
    83  	c.Assert(err, jc.ErrorIsNil)
    84  	err = e.SetConfig(cfg)
    85  	c.Assert(err, jc.ErrorIsNil)
    86  
    87  	insts, err := e.Instances(nil)
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	c.Assert(insts, gc.HasLen, 0)
    90  
    91  	inst0, hc := testing.AssertStartInstance(c, e, "0")
    92  	c.Assert(inst0, gc.NotNil)
    93  	id0 := inst0.Id()
    94  	// Sanity check for hardware characteristics.
    95  	c.Assert(hc.Arch, gc.NotNil)
    96  	c.Assert(hc.Mem, gc.NotNil)
    97  	c.Assert(hc.CpuCores, gc.NotNil)
    98  
    99  	inst1, _ := testing.AssertStartInstance(c, e, "1")
   100  	c.Assert(inst1, gc.NotNil)
   101  	id1 := inst1.Id()
   102  
   103  	insts, err = e.Instances([]instance.Id{id0, id1})
   104  	c.Assert(err, jc.ErrorIsNil)
   105  	c.Assert(insts, gc.HasLen, 2)
   106  	c.Assert(insts[0].Id(), gc.Equals, id0)
   107  	c.Assert(insts[1].Id(), gc.Equals, id1)
   108  
   109  	// order of results is not specified
   110  	insts, err = e.AllInstances()
   111  	c.Assert(err, jc.ErrorIsNil)
   112  	c.Assert(insts, gc.HasLen, 2)
   113  	c.Assert(insts[0].Id(), gc.Not(gc.Equals), insts[1].Id())
   114  
   115  	err = e.StopInstances(inst0.Id())
   116  	c.Assert(err, jc.ErrorIsNil)
   117  
   118  	insts, err = e.Instances([]instance.Id{id0, id1})
   119  	c.Assert(err, gc.Equals, environs.ErrPartialInstances)
   120  	c.Assert(insts[0], gc.IsNil)
   121  	c.Assert(insts[1].Id(), gc.Equals, id1)
   122  
   123  	insts, err = e.AllInstances()
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	c.Assert(insts[0].Id(), gc.Equals, id1)
   126  }
   127  
   128  func (t *Tests) TestBootstrap(c *gc.C) {
   129  	e := t.Prepare(c)
   130  	err := bootstrap.EnsureNotBootstrapped(e)
   131  	c.Assert(err, jc.ErrorIsNil)
   132  	err = bootstrap.Bootstrap(envtesting.BootstrapContext(c), e, bootstrap.BootstrapParams{})
   133  	c.Assert(err, jc.ErrorIsNil)
   134  
   135  	stateServerInstances, err := e.StateServerInstances()
   136  	c.Assert(err, jc.ErrorIsNil)
   137  	c.Assert(stateServerInstances, gc.Not(gc.HasLen), 0)
   138  
   139  	err = bootstrap.EnsureNotBootstrapped(e)
   140  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   141  
   142  	e2 := t.Open(c)
   143  	err = bootstrap.EnsureNotBootstrapped(e2)
   144  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   145  
   146  	stateServerInstances2, err := e2.StateServerInstances()
   147  	c.Assert(err, jc.ErrorIsNil)
   148  	c.Assert(stateServerInstances2, gc.Not(gc.HasLen), 0)
   149  	c.Assert(stateServerInstances2, jc.SameContents, stateServerInstances)
   150  
   151  	err = environs.Destroy(e2, t.ConfigStore)
   152  	c.Assert(err, jc.ErrorIsNil)
   153  
   154  	// Prepare again because Destroy invalidates old environments.
   155  	e3 := t.Prepare(c)
   156  
   157  	err = bootstrap.EnsureNotBootstrapped(e3)
   158  	c.Assert(err, jc.ErrorIsNil)
   159  	err = bootstrap.Bootstrap(envtesting.BootstrapContext(c), e3, bootstrap.BootstrapParams{})
   160  	c.Assert(err, jc.ErrorIsNil)
   161  
   162  	err = bootstrap.EnsureNotBootstrapped(e3)
   163  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   164  
   165  	err = environs.Destroy(e3, t.ConfigStore)
   166  	c.Assert(err, jc.ErrorIsNil)
   167  }
   168  
   169  var noRetry = utils.AttemptStrategy{}
   170  
   171  func (t *Tests) TestPersistence(c *gc.C) {
   172  	env, ok := t.Prepare(c).(environs.EnvironStorage)
   173  	if !ok {
   174  		c.Skip("environment does not implement provider storage")
   175  		return
   176  	}
   177  	stor := env.Storage()
   178  
   179  	names := []string{
   180  		"aa",
   181  		"zzz/aa",
   182  		"zzz/bb",
   183  	}
   184  	for _, name := range names {
   185  		checkFileDoesNotExist(c, stor, name, noRetry)
   186  		checkPutFile(c, stor, name, []byte(name))
   187  	}
   188  	checkList(c, stor, "", names)
   189  	checkList(c, stor, "a", []string{"aa"})
   190  	checkList(c, stor, "zzz/", []string{"zzz/aa", "zzz/bb"})
   191  
   192  	storage2 := t.Open(c).(environs.EnvironStorage).Storage()
   193  	for _, name := range names {
   194  		checkFileHasContents(c, storage2, name, []byte(name), noRetry)
   195  	}
   196  
   197  	// remove the first file and check that the others remain.
   198  	err := storage2.Remove(names[0])
   199  	c.Check(err, jc.ErrorIsNil)
   200  
   201  	// check that it's ok to remove a file twice.
   202  	err = storage2.Remove(names[0])
   203  	c.Check(err, jc.ErrorIsNil)
   204  
   205  	// ... and check it's been removed in the other environment
   206  	checkFileDoesNotExist(c, stor, names[0], noRetry)
   207  
   208  	// ... and that the rest of the files are still around
   209  	checkList(c, storage2, "", names[1:])
   210  
   211  	for _, name := range names[1:] {
   212  		err := storage2.Remove(name)
   213  		c.Assert(err, jc.ErrorIsNil)
   214  	}
   215  
   216  	// check they've all gone
   217  	checkList(c, storage2, "", nil)
   218  }
   219  
   220  func checkList(c *gc.C, stor storage.StorageReader, prefix string, names []string) {
   221  	lnames, err := storage.List(stor, prefix)
   222  	c.Assert(err, jc.ErrorIsNil)
   223  	// TODO(dfc) gocheck should grow an SliceEquals checker.
   224  	expected := copyslice(lnames)
   225  	sort.Strings(expected)
   226  	actual := copyslice(names)
   227  	sort.Strings(actual)
   228  	c.Assert(expected, gc.DeepEquals, actual)
   229  }
   230  
   231  // copyslice returns a copy of the slice
   232  func copyslice(s []string) []string {
   233  	r := make([]string, len(s))
   234  	copy(r, s)
   235  	return r
   236  }
   237  
   238  func checkPutFile(c *gc.C, stor storage.StorageWriter, name string, contents []byte) {
   239  	err := stor.Put(name, bytes.NewBuffer(contents), int64(len(contents)))
   240  	c.Assert(err, jc.ErrorIsNil)
   241  }
   242  
   243  func checkFileDoesNotExist(c *gc.C, stor storage.StorageReader, name string, attempt utils.AttemptStrategy) {
   244  	r, err := storage.GetWithRetry(stor, name, attempt)
   245  	c.Assert(r, gc.IsNil)
   246  	c.Assert(err, jc.Satisfies, errors.IsNotFound)
   247  }
   248  
   249  func checkFileHasContents(c *gc.C, stor storage.StorageReader, name string, contents []byte, attempt utils.AttemptStrategy) {
   250  	r, err := storage.GetWithRetry(stor, name, attempt)
   251  	c.Assert(err, jc.ErrorIsNil)
   252  	c.Check(r, gc.NotNil)
   253  	defer r.Close()
   254  
   255  	data, err := ioutil.ReadAll(r)
   256  	c.Check(err, jc.ErrorIsNil)
   257  	c.Check(data, gc.DeepEquals, contents)
   258  
   259  	url, err := stor.URL(name)
   260  	c.Assert(err, jc.ErrorIsNil)
   261  
   262  	var resp *http.Response
   263  	for a := attempt.Start(); a.Next(); {
   264  		resp, err = utils.GetValidatingHTTPClient().Get(url)
   265  		c.Assert(err, jc.ErrorIsNil)
   266  		if resp.StatusCode != 404 {
   267  			break
   268  		}
   269  		c.Logf("get retrying after earlier get succeeded. *sigh*.")
   270  	}
   271  	c.Assert(err, jc.ErrorIsNil)
   272  	data, err = ioutil.ReadAll(resp.Body)
   273  	c.Assert(err, jc.ErrorIsNil)
   274  	defer resp.Body.Close()
   275  	c.Assert(resp.StatusCode, gc.Equals, 200, gc.Commentf("error response: %s", data))
   276  	c.Check(data, gc.DeepEquals, contents)
   277  }