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 }