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