launchpad.net/~rogpeppe/juju-core/500-errgo-fix@v0.0.0-20140213181702-000000002356/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, 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 bootstrapContext(c *gc.C) environs.BootstrapContext {
    82  	return envtesting.NewBootstrapContext(coretesting.Context(c))
    83  }
    84  
    85  func (t *Tests) TestStartStop(c *gc.C) {
    86  	e := t.Prepare(c)
    87  	envtesting.UploadFakeTools(c, e.Storage())
    88  	cfg, err := e.Config().Apply(map[string]interface{}{
    89  		"agent-version": version.Current.Number.String(),
    90  	})
    91  	c.Assert(err, gc.IsNil)
    92  	err = e.SetConfig(cfg)
    93  	c.Assert(err, gc.IsNil)
    94  
    95  	insts, err := e.Instances(nil)
    96  	c.Assert(err, gc.IsNil)
    97  	c.Assert(insts, gc.HasLen, 0)
    98  
    99  	inst0, hc := testing.AssertStartInstance(c, e, "0")
   100  	c.Assert(inst0, gc.NotNil)
   101  	id0 := inst0.Id()
   102  	// Sanity check for hardware characteristics.
   103  	c.Assert(hc.Arch, gc.NotNil)
   104  	c.Assert(hc.Mem, gc.NotNil)
   105  	c.Assert(hc.CpuCores, gc.NotNil)
   106  
   107  	inst1, _ := testing.AssertStartInstance(c, e, "1")
   108  	c.Assert(inst1, gc.NotNil)
   109  	id1 := inst1.Id()
   110  
   111  	insts, err = e.Instances([]instance.Id{id0, id1})
   112  	c.Assert(err, gc.IsNil)
   113  	c.Assert(insts, gc.HasLen, 2)
   114  	c.Assert(insts[0].Id(), gc.Equals, id0)
   115  	c.Assert(insts[1].Id(), gc.Equals, id1)
   116  
   117  	// order of results is not specified
   118  	insts, err = e.AllInstances()
   119  	c.Assert(err, gc.IsNil)
   120  	c.Assert(insts, gc.HasLen, 2)
   121  	c.Assert(insts[0].Id(), gc.Not(gc.Equals), insts[1].Id())
   122  
   123  	err = e.StopInstances([]instance.Instance{inst0})
   124  	c.Assert(err, gc.IsNil)
   125  
   126  	insts, err = e.Instances([]instance.Id{id0, id1})
   127  	c.Assert(err, gc.Equals, environs.ErrPartialInstances)
   128  	c.Assert(insts[0], gc.IsNil)
   129  	c.Assert(insts[1].Id(), gc.Equals, id1)
   130  
   131  	insts, err = e.AllInstances()
   132  	c.Assert(err, gc.IsNil)
   133  	c.Assert(insts[0].Id(), gc.Equals, id1)
   134  }
   135  
   136  func (t *Tests) TestBootstrap(c *gc.C) {
   137  	e := t.Prepare(c)
   138  	envtesting.UploadFakeTools(c, e.Storage())
   139  	err := common.EnsureNotBootstrapped(e)
   140  	c.Assert(err, gc.IsNil)
   141  	err = bootstrap.Bootstrap(bootstrapContext(c), e, constraints.Value{})
   142  	c.Assert(err, gc.IsNil)
   143  
   144  	info, apiInfo, err := e.StateInfo()
   145  	c.Check(info.Addrs, gc.Not(gc.HasLen), 0)
   146  	c.Check(apiInfo.Addrs, gc.Not(gc.HasLen), 0)
   147  
   148  	err = common.EnsureNotBootstrapped(e)
   149  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   150  
   151  	e2 := t.Open(c)
   152  	envtesting.UploadFakeTools(c, e2.Storage())
   153  	err = common.EnsureNotBootstrapped(e2)
   154  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   155  
   156  	info2, apiInfo2, err := e2.StateInfo()
   157  	c.Check(info2, gc.DeepEquals, info)
   158  	c.Check(apiInfo2, gc.DeepEquals, apiInfo)
   159  
   160  	err = environs.Destroy(e2, t.ConfigStore)
   161  	c.Assert(err, gc.IsNil)
   162  
   163  	// Prepare again because Destroy invalidates old environments.
   164  	e3 := t.Prepare(c)
   165  	envtesting.UploadFakeTools(c, e3.Storage())
   166  
   167  	err = common.EnsureNotBootstrapped(e3)
   168  	c.Assert(err, gc.IsNil)
   169  	err = bootstrap.Bootstrap(bootstrapContext(c), e3, constraints.Value{})
   170  	c.Assert(err, gc.IsNil)
   171  
   172  	err = common.EnsureNotBootstrapped(e3)
   173  	c.Assert(err, gc.ErrorMatches, "environment is already bootstrapped")
   174  }
   175  
   176  var noRetry = utils.AttemptStrategy{}
   177  
   178  func (t *Tests) TestPersistence(c *gc.C) {
   179  	stor := t.Prepare(c).Storage()
   180  
   181  	names := []string{
   182  		"aa",
   183  		"zzz/aa",
   184  		"zzz/bb",
   185  	}
   186  	for _, name := range names {
   187  		checkFileDoesNotExist(c, stor, name, noRetry)
   188  		checkPutFile(c, stor, name, []byte(name))
   189  	}
   190  	checkList(c, stor, "", names)
   191  	checkList(c, stor, "a", []string{"aa"})
   192  	checkList(c, stor, "zzz/", []string{"zzz/aa", "zzz/bb"})
   193  
   194  	storage2 := t.Open(c).Storage()
   195  	for _, name := range names {
   196  		checkFileHasContents(c, storage2, name, []byte(name), noRetry)
   197  	}
   198  
   199  	// remove the first file and check that the others remain.
   200  	err := storage2.Remove(names[0])
   201  	c.Check(err, gc.IsNil)
   202  
   203  	// check that it's ok to remove a file twice.
   204  	err = storage2.Remove(names[0])
   205  	c.Check(err, gc.IsNil)
   206  
   207  	// ... and check it's been removed in the other environment
   208  	checkFileDoesNotExist(c, stor, names[0], noRetry)
   209  
   210  	// ... and that the rest of the files are still around
   211  	checkList(c, storage2, "", names[1:])
   212  
   213  	for _, name := range names[1:] {
   214  		err := storage2.Remove(name)
   215  		c.Assert(err, gc.IsNil)
   216  	}
   217  
   218  	// check they've all gone
   219  	checkList(c, storage2, "", nil)
   220  }
   221  
   222  func checkList(c *gc.C, stor storage.StorageReader, prefix string, names []string) {
   223  	lnames, err := storage.List(stor, prefix)
   224  	c.Assert(err, gc.IsNil)
   225  	// TODO(dfc) gocheck should grow an SliceEquals checker.
   226  	expected := copyslice(lnames)
   227  	sort.Strings(expected)
   228  	actual := copyslice(names)
   229  	sort.Strings(actual)
   230  	c.Assert(expected, gc.DeepEquals, actual)
   231  }
   232  
   233  // copyslice returns a copy of the slice
   234  func copyslice(s []string) []string {
   235  	r := make([]string, len(s))
   236  	copy(r, s)
   237  	return r
   238  }
   239  
   240  func checkPutFile(c *gc.C, stor storage.StorageWriter, name string, contents []byte) {
   241  	err := stor.Put(name, bytes.NewBuffer(contents), int64(len(contents)))
   242  	c.Assert(err, gc.IsNil)
   243  }
   244  
   245  func checkFileDoesNotExist(c *gc.C, stor storage.StorageReader, name string, attempt utils.AttemptStrategy) {
   246  	r, err := storage.GetWithRetry(stor, name, attempt)
   247  	c.Assert(r, gc.IsNil)
   248  	c.Assert(err, jc.Satisfies, errors.IsNotFoundError)
   249  }
   250  
   251  func checkFileHasContents(c *gc.C, stor storage.StorageReader, name string, contents []byte, attempt utils.AttemptStrategy) {
   252  	r, err := storage.GetWithRetry(stor, name, attempt)
   253  	c.Assert(err, gc.IsNil)
   254  	c.Check(r, gc.NotNil)
   255  	defer r.Close()
   256  
   257  	data, err := ioutil.ReadAll(r)
   258  	c.Check(err, gc.IsNil)
   259  	c.Check(data, gc.DeepEquals, contents)
   260  
   261  	url, err := stor.URL(name)
   262  	c.Assert(err, gc.IsNil)
   263  
   264  	var resp *http.Response
   265  	for a := attempt.Start(); a.Next(); {
   266  		resp, err = http.Get(url)
   267  		c.Assert(err, gc.IsNil)
   268  		if resp.StatusCode != 404 {
   269  			break
   270  		}
   271  		c.Logf("get retrying after earlier get succeeded. *sigh*.")
   272  	}
   273  	c.Assert(err, gc.IsNil)
   274  	data, err = ioutil.ReadAll(resp.Body)
   275  	c.Assert(err, gc.IsNil)
   276  	defer resp.Body.Close()
   277  	c.Assert(resp.StatusCode, gc.Equals, 200, gc.Commentf("error response: %s", data))
   278  	c.Check(data, gc.DeepEquals, contents)
   279  }