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  }