github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/environment/jenv_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package environment_test 5 6 import ( 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "runtime" 11 12 gitjujutesting "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/yaml.v1" 16 17 "github.com/juju/juju/cmd/envcmd" 18 "github.com/juju/juju/cmd/juju/environment" 19 "github.com/juju/juju/environs/configstore" 20 "github.com/juju/juju/juju/osenv" 21 "github.com/juju/juju/testing" 22 ) 23 24 type jenvSuite struct { 25 testing.FakeJujuHomeSuite 26 } 27 28 var _ = gc.Suite(&jenvSuite{}) 29 30 var jenvInitErrorsTests = []struct { 31 about string 32 args []string 33 err string 34 }{{ 35 about: "no args", 36 err: "no jenv file provided", 37 }, { 38 about: "invalid env name", 39 args: []string{"path/to/jenv", "invalid/name"}, 40 err: `invalid environment name "invalid/name"`, 41 }, { 42 about: "too many args", 43 args: []string{"path/to/jenv", "env-name", "unexpected"}, 44 err: `unrecognized args: \["unexpected"\]`, 45 }} 46 47 func (*jenvSuite) TestInitErrors(c *gc.C) { 48 for i, test := range jenvInitErrorsTests { 49 c.Logf("test %d: %s", i, test.about) 50 51 jenvCmd := &environment.JenvCommand{} 52 err := testing.InitCommand(jenvCmd, test.args) 53 c.Assert(err, gc.ErrorMatches, test.err) 54 } 55 } 56 57 func (*jenvSuite) TestJenvFileNotFound(c *gc.C) { 58 jenvCmd := &environment.JenvCommand{} 59 ctx, err := testing.RunCommand(c, jenvCmd, "/no/such/file.jenv") 60 c.Assert(err, gc.ErrorMatches, `jenv file "/no/such/file.jenv" not found`) 61 c.Assert(testing.Stdout(ctx), gc.Equals, "") 62 } 63 64 func (*jenvSuite) TestJenvFileDirectory(c *gc.C) { 65 jenvCmd := &environment.JenvCommand{} 66 ctx, err := testing.RunCommand(c, jenvCmd, c.MkDir()) 67 68 // The error is different on some platforms 69 c.Assert(err, gc.ErrorMatches, "cannot read the provided jenv file .*: (is a directory|The handle is invalid.)") 70 c.Assert(testing.Stdout(ctx), gc.Equals, "") 71 } 72 73 func (*jenvSuite) TestJenvFileNotReadable(c *gc.C) { 74 if runtime.GOOS == "windows" { 75 c.Skip("Cannot test on windows because it uses chmod") 76 } 77 // Create a read-only jenv file. 78 f := openJenvFile(c, nil) 79 defer f.Close() 80 err := f.Chmod(0) 81 c.Assert(err, jc.ErrorIsNil) 82 83 // Run the command. 84 jenvCmd := &environment.JenvCommand{} 85 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 86 c.Assert(err, gc.ErrorMatches, "cannot read the provided jenv file .* permission denied") 87 c.Assert(testing.Stdout(ctx), gc.Equals, "") 88 } 89 90 var jenvFileContentErrorsTests = []struct { 91 about string 92 contents []byte 93 err string 94 }{{ 95 about: "empty", 96 err: "invalid jenv file .*: missing required fields in jenv data: User, Password, EnvironUUID, StateServers, CACert", 97 }, { 98 about: "invalid YAML", 99 contents: []byte(":"), 100 err: "invalid jenv file .*: cannot unmarshal jenv data: YAML error: .*", 101 }, { 102 about: "missing field", 103 contents: makeJenvContents("myuser", "mypasswd", "env-uuid", "", "1.2.3.4:17070"), 104 err: "invalid jenv file .*: missing required fields in jenv data: CACert", 105 }} 106 107 func (*jenvSuite) TestJenvFileContentErrors(c *gc.C) { 108 for i, test := range jenvFileContentErrorsTests { 109 c.Logf("test %d: %s", i, test.about) 110 111 // Create the jenv file with the contents provided by the test. 112 f := openJenvFile(c, test.contents) 113 defer f.Close() 114 115 jenvCmd := &environment.JenvCommand{} 116 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 117 c.Assert(err, gc.ErrorMatches, test.err) 118 c.Assert(testing.Stdout(ctx), gc.Equals, "") 119 } 120 } 121 122 func (*jenvSuite) TestConfigStoreError(c *gc.C) { 123 if runtime.GOOS == "windows" { 124 c.Skip("Cannot test on windows because it uses chmod") 125 } 126 // Create a jenv file. 127 f := openJenvFile(c, nil) 128 defer f.Close() 129 130 // Remove Juju home read permissions. 131 home := gitjujutesting.HomePath(".juju") 132 err := os.Chmod(home, 0) 133 c.Assert(err, jc.ErrorIsNil) 134 defer os.Chmod(home, 0700) 135 136 jenvCmd := &environment.JenvCommand{} 137 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 138 c.Assert(err, gc.ErrorMatches, "cannot get config store: .*: permission denied") 139 c.Assert(testing.Stdout(ctx), gc.Equals, "") 140 } 141 142 func (*jenvSuite) TestWriteError(c *gc.C) { 143 if runtime.GOOS == "windows" { 144 c.Skip("Cannot test on windows because it uses chmod") 145 } 146 // Create a jenv file. 147 f := openJenvFile(c, makeValidJenvContents()) 148 defer f.Close() 149 150 // Create the environments dir without write permissions. 151 envsDir := gitjujutesting.HomePath(".juju", "environments") 152 err := os.Mkdir(envsDir, 0500) 153 c.Assert(err, jc.ErrorIsNil) 154 155 jenvCmd := &environment.JenvCommand{} 156 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 157 c.Assert(err, gc.ErrorMatches, "cannot write the jenv file: cannot write info: .*: permission denied") 158 c.Assert(testing.Stdout(ctx), gc.Equals, "") 159 } 160 161 func (*jenvSuite) TestSwitchErrorJujuEnvSet(c *gc.C) { 162 // Create a jenv file. 163 f := openJenvFile(c, makeValidJenvContents()) 164 defer f.Close() 165 166 // Override the default Juju environment with the environment variable. 167 err := os.Setenv(osenv.JujuEnvEnvKey, "ec2") 168 c.Assert(err, jc.ErrorIsNil) 169 170 jenvCmd := &environment.JenvCommand{} 171 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 172 c.Assert(err, gc.ErrorMatches, `cannot switch to the new environment "testing": cannot switch when JUJU_ENV is overriding the environment \(set to "ec2"\)`) 173 c.Assert(testing.Stdout(ctx), gc.Equals, "") 174 } 175 176 func (*jenvSuite) TestSwitchErrorEnvironmentsNotReadable(c *gc.C) { 177 if runtime.GOOS == "windows" { 178 c.Skip("Cannot test on windows because it uses chmod") 179 } 180 // Create a jenv file. 181 f := openJenvFile(c, makeValidJenvContents()) 182 defer f.Close() 183 184 // Remove write permissions to the environments.yaml file. 185 envPath := gitjujutesting.HomePath(".juju", "environments.yaml") 186 err := os.Chmod(envPath, 0200) 187 c.Assert(err, jc.ErrorIsNil) 188 189 jenvCmd := &environment.JenvCommand{} 190 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 191 c.Assert(err, gc.ErrorMatches, `cannot switch to the new environment "testing": cannot get the default environment: .*: permission denied`) 192 c.Assert(testing.Stdout(ctx), gc.Equals, "") 193 } 194 195 func (*jenvSuite) TestSwitchErrorCannotWriteCurrentEnvironment(c *gc.C) { 196 if runtime.GOOS == "windows" { 197 c.Skip("Cannot test on windows because it uses chmod") 198 } 199 // Create a jenv file. 200 f := openJenvFile(c, makeValidJenvContents()) 201 defer f.Close() 202 203 // Create the current environment file without write permissions. 204 currentEnvPath := gitjujutesting.HomePath(".juju", envcmd.CurrentEnvironmentFilename) 205 currentEnvFile, err := os.Create(currentEnvPath) 206 c.Assert(err, jc.ErrorIsNil) 207 defer currentEnvFile.Close() 208 err = currentEnvFile.Chmod(0500) 209 c.Assert(err, jc.ErrorIsNil) 210 211 jenvCmd := &environment.JenvCommand{} 212 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 213 c.Assert(err, gc.ErrorMatches, `cannot switch to the new environment "testing": unable to write to the environment file: .*: permission denied`) 214 c.Assert(testing.Stdout(ctx), gc.Equals, "") 215 } 216 217 func (*jenvSuite) TestSuccess(c *gc.C) { 218 // Create a jenv file. 219 contents := makeJenvContents("who", "Secret!", "env-UUID", testing.CACert, "1.2.3.4:17070") 220 f := openJenvFile(c, contents) 221 defer f.Close() 222 223 // Import the newly created jenv file. 224 jenvCmd := &environment.JenvCommand{} 225 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 226 c.Assert(err, jc.ErrorIsNil) 227 228 // The jenv file has been properly imported. 229 assertJenvContents(c, contents, "testing") 230 231 // The default environment is now the newly imported one, and the output 232 // reflects the change. 233 currEnv, err := envcmd.ReadCurrentEnvironment() 234 c.Assert(err, jc.ErrorIsNil) 235 c.Assert(currEnv, gc.Equals, "testing") 236 c.Assert(testing.Stdout(ctx), gc.Equals, "erewhemos -> testing\n") 237 238 // Trying to import the jenv with the same name a second time raises an 239 // error. 240 jenvCmd = &environment.JenvCommand{} 241 ctx, err = testing.RunCommand(c, jenvCmd, f.Name()) 242 c.Assert(err, gc.ErrorMatches, `an environment named "testing" already exists: you can provide a second parameter to rename the environment`) 243 244 // Overriding the environment name solves the problem. 245 jenvCmd = &environment.JenvCommand{} 246 ctx, err = testing.RunCommand(c, jenvCmd, f.Name(), "another") 247 c.Assert(err, jc.ErrorIsNil) 248 assertJenvContents(c, contents, "another") 249 250 currEnv, err = envcmd.ReadCurrentEnvironment() 251 c.Assert(err, jc.ErrorIsNil) 252 c.Assert(currEnv, gc.Equals, "another") 253 c.Assert(testing.Stdout(ctx), gc.Equals, "testing -> another\n") 254 } 255 256 func (*jenvSuite) TestSuccessCustomEnvironmentName(c *gc.C) { 257 // Create a jenv file. 258 contents := makeValidJenvContents() 259 f := openJenvFile(c, contents) 260 defer f.Close() 261 262 // Import the newly created jenv file with a customized name. 263 jenvCmd := &environment.JenvCommand{} 264 ctx, err := testing.RunCommand(c, jenvCmd, f.Name(), "my-env") 265 c.Assert(err, jc.ErrorIsNil) 266 267 // The jenv file has been properly imported. 268 assertJenvContents(c, contents, "my-env") 269 270 // The default environment is now the newly imported one, and the output 271 // reflects the change. 272 currEnv, err := envcmd.ReadCurrentEnvironment() 273 c.Assert(err, jc.ErrorIsNil) 274 c.Assert(currEnv, gc.Equals, "my-env") 275 c.Assert(testing.Stdout(ctx), gc.Equals, "erewhemos -> my-env\n") 276 } 277 278 func (*jenvSuite) TestSuccessNoJujuEnvironments(c *gc.C) { 279 // Create a jenv file. 280 contents := makeValidJenvContents() 281 f := openJenvFile(c, contents) 282 defer f.Close() 283 284 // Remove the Juju environments.yaml file. 285 envPath := gitjujutesting.HomePath(".juju", "environments.yaml") 286 err := os.Remove(envPath) 287 c.Assert(err, jc.ErrorIsNil) 288 289 // Importing a jenv does not require having environments already defined. 290 jenvCmd := &environment.JenvCommand{} 291 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 292 c.Assert(err, jc.ErrorIsNil) 293 assertJenvContents(c, contents, "testing") 294 c.Assert(testing.Stdout(ctx), gc.Equals, "-> testing\n") 295 } 296 297 // openJenvFile creates and returns a jenv file with the given contents. 298 // Callers are responsible of closing the file. 299 func openJenvFile(c *gc.C, contents []byte) *os.File { 300 path := filepath.Join(c.MkDir(), "testing.jenv") 301 f, err := os.Create(path) 302 c.Assert(err, jc.ErrorIsNil) 303 _, err = f.Write(contents) 304 c.Assert(err, jc.ErrorIsNil) 305 return f 306 } 307 308 // makeJenvContents returns a YAML encoded environment info data. 309 func makeJenvContents(user, password, environUUID, caCert string, stateServers ...string) []byte { 310 b, err := yaml.Marshal(configstore.EnvironInfoData{ 311 User: user, 312 Password: password, 313 EnvironUUID: environUUID, 314 CACert: caCert, 315 StateServers: stateServers, 316 }) 317 if err != nil { 318 panic(err) 319 } 320 return b 321 } 322 323 // makeValidJenvContents returns valid jenv file YAML encoded contents. 324 func makeValidJenvContents() []byte { 325 return makeJenvContents( 326 "myuser", "mypasswd", "env-uuid", testing.CACert, 327 "1.2.3.4:17070", "example.com:17070") 328 } 329 330 // assertJenvContents checks that the jenv file corresponding to the given 331 // envName is correctly present in the Juju Home and has the given contents. 332 func assertJenvContents(c *gc.C, contents []byte, envName string) { 333 path := gitjujutesting.HomePath(".juju", "environments", envName+".jenv") 334 // Ensure the jenv file has been created. 335 c.Assert(path, jc.IsNonEmptyFile) 336 337 // Retrieve the jenv file contents. 338 b, err := ioutil.ReadFile(path) 339 c.Assert(err, jc.ErrorIsNil) 340 341 // Ensure the jenv file reflects the source contents. 342 var data map[string]interface{} 343 err = yaml.Unmarshal(contents, &data) 344 c.Assert(err, jc.ErrorIsNil) 345 c.Assert(string(b), jc.YAMLEquals, data) 346 }