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