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 }