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 }