github.com/Pankov404/juju@v0.0.0-20150703034450-be266991dceb/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 c.Assert(envcmd.ReadCurrentEnvironment(), gc.Equals, "testing") 234 c.Assert(testing.Stdout(ctx), gc.Equals, "erewhemos -> testing\n") 235 236 // Trying to import the jenv with the same name a second time raises an 237 // error. 238 jenvCmd = &environment.JenvCommand{} 239 ctx, err = testing.RunCommand(c, jenvCmd, f.Name()) 240 c.Assert(err, gc.ErrorMatches, `an environment named "testing" already exists: you can provide a second parameter to rename the environment`) 241 242 // Overriding the environment name solves the problem. 243 jenvCmd = &environment.JenvCommand{} 244 ctx, err = testing.RunCommand(c, jenvCmd, f.Name(), "another") 245 c.Assert(err, jc.ErrorIsNil) 246 assertJenvContents(c, contents, "another") 247 c.Assert(envcmd.ReadCurrentEnvironment(), gc.Equals, "another") 248 c.Assert(testing.Stdout(ctx), gc.Equals, "testing -> another\n") 249 } 250 251 func (*jenvSuite) TestSuccessCustomEnvironmentName(c *gc.C) { 252 // Create a jenv file. 253 contents := makeValidJenvContents() 254 f := openJenvFile(c, contents) 255 defer f.Close() 256 257 // Import the newly created jenv file with a customized name. 258 jenvCmd := &environment.JenvCommand{} 259 ctx, err := testing.RunCommand(c, jenvCmd, f.Name(), "my-env") 260 c.Assert(err, jc.ErrorIsNil) 261 262 // The jenv file has been properly imported. 263 assertJenvContents(c, contents, "my-env") 264 265 // The default environment is now the newly imported one, and the output 266 // reflects the change. 267 c.Assert(envcmd.ReadCurrentEnvironment(), gc.Equals, "my-env") 268 c.Assert(testing.Stdout(ctx), gc.Equals, "erewhemos -> my-env\n") 269 } 270 271 func (*jenvSuite) TestSuccessNoJujuEnvironments(c *gc.C) { 272 // Create a jenv file. 273 contents := makeValidJenvContents() 274 f := openJenvFile(c, contents) 275 defer f.Close() 276 277 // Remove the Juju environments.yaml file. 278 envPath := gitjujutesting.HomePath(".juju", "environments.yaml") 279 err := os.Remove(envPath) 280 c.Assert(err, jc.ErrorIsNil) 281 282 // Importing a jenv does not require having environments already defined. 283 jenvCmd := &environment.JenvCommand{} 284 ctx, err := testing.RunCommand(c, jenvCmd, f.Name()) 285 c.Assert(err, jc.ErrorIsNil) 286 assertJenvContents(c, contents, "testing") 287 c.Assert(testing.Stdout(ctx), gc.Equals, "-> testing\n") 288 } 289 290 // openJenvFile creates and returns a jenv file with the given contents. 291 // Callers are responsible of closing the file. 292 func openJenvFile(c *gc.C, contents []byte) *os.File { 293 path := filepath.Join(c.MkDir(), "testing.jenv") 294 f, err := os.Create(path) 295 c.Assert(err, jc.ErrorIsNil) 296 _, err = f.Write(contents) 297 c.Assert(err, jc.ErrorIsNil) 298 return f 299 } 300 301 // makeJenvContents returns a YAML encoded environment info data. 302 func makeJenvContents(user, password, environUUID, caCert string, stateServers ...string) []byte { 303 b, err := yaml.Marshal(configstore.EnvironInfoData{ 304 User: user, 305 Password: password, 306 EnvironUUID: environUUID, 307 CACert: caCert, 308 StateServers: stateServers, 309 }) 310 if err != nil { 311 panic(err) 312 } 313 return b 314 } 315 316 // makeValidJenvContents returns valid jenv file YAML encoded contents. 317 func makeValidJenvContents() []byte { 318 return makeJenvContents( 319 "myuser", "mypasswd", "env-uuid", testing.CACert, 320 "1.2.3.4:17070", "example.com:17070") 321 } 322 323 // assertJenvContents checks that the jenv file corresponding to the given 324 // envName is correctly present in the Juju Home and has the given contents. 325 func assertJenvContents(c *gc.C, contents []byte, envName string) { 326 path := gitjujutesting.HomePath(".juju", "environments", envName+".jenv") 327 // Ensure the jenv file has been created. 328 c.Assert(path, jc.IsNonEmptyFile) 329 330 // Retrieve the jenv file contents. 331 b, err := ioutil.ReadFile(path) 332 c.Assert(err, jc.ErrorIsNil) 333 334 // Ensure the jenv file reflects the source contents. 335 var data map[string]interface{} 336 err = yaml.Unmarshal(contents, &data) 337 c.Assert(err, jc.ErrorIsNil) 338 c.Assert(string(b), jc.YAMLEquals, data) 339 }