github.com/altoros/juju-vmware@v0.0.0-20150312064031-f19ae857ccca/cmd/juju/user/add_test.go (about)

     1  // Copyright 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package user_test
     5  
     6  import (
     7  	"io/ioutil"
     8  	"path/filepath"
     9  	"strings"
    10  
    11  	"github.com/juju/cmd"
    12  	"github.com/juju/errors"
    13  	"github.com/juju/names"
    14  	jc "github.com/juju/testing/checkers"
    15  	gc "gopkg.in/check.v1"
    16  
    17  	"github.com/juju/juju/apiserver/params"
    18  	"github.com/juju/juju/cmd/envcmd"
    19  	"github.com/juju/juju/cmd/juju/user"
    20  	"github.com/juju/juju/testing"
    21  )
    22  
    23  // All of the functionality of the AddUser api call is contained elsewhere.
    24  // This suite provides basic tests for the "user add" command
    25  type UserAddCommandSuite struct {
    26  	BaseSuite
    27  	mockAPI *mockAddUserAPI
    28  }
    29  
    30  var _ = gc.Suite(&UserAddCommandSuite{})
    31  
    32  func (s *UserAddCommandSuite) SetUpTest(c *gc.C) {
    33  	s.BaseSuite.SetUpTest(c)
    34  	s.mockAPI = &mockAddUserAPI{}
    35  	s.PatchValue(user.GetAddUserAPI, func(c *user.AddCommand) (user.AddUserAPI, error) {
    36  		return s.mockAPI, nil
    37  	})
    38  	s.PatchValue(user.GetShareEnvAPI, func(c *user.AddCommand) (user.ShareEnvironmentAPI, error) {
    39  		return s.mockAPI, nil
    40  	})
    41  }
    42  
    43  func newUserAddCommand() cmd.Command {
    44  	return envcmd.Wrap(&user.AddCommand{})
    45  }
    46  
    47  func (s *UserAddCommandSuite) TestInit(c *gc.C) {
    48  	for i, test := range []struct {
    49  		args        []string
    50  		user        string
    51  		displayname string
    52  		outPath     string
    53  		generate    bool
    54  		errorString string
    55  	}{
    56  		{
    57  			errorString: "no username supplied",
    58  		}, {
    59  			args: []string{"foobar"},
    60  			user: "foobar",
    61  		}, {
    62  			args:        []string{"foobar", "Foo Bar"},
    63  			user:        "foobar",
    64  			displayname: "Foo Bar",
    65  		}, {
    66  			args:        []string{"foobar", "Foo Bar", "extra"},
    67  			errorString: `unrecognized args: \["extra"\]`,
    68  		}, {
    69  			args:     []string{"foobar", "--generate"},
    70  			user:     "foobar",
    71  			generate: true,
    72  		}, {
    73  			args:    []string{"foobar", "--output", "somefile"},
    74  			user:    "foobar",
    75  			outPath: "somefile",
    76  		}, {
    77  			args:    []string{"foobar", "-o", "somefile"},
    78  			user:    "foobar",
    79  			outPath: "somefile",
    80  		},
    81  	} {
    82  		c.Logf("test %d", i)
    83  		addUserCmd := &user.AddCommand{}
    84  		err := testing.InitCommand(addUserCmd, test.args)
    85  		if test.errorString == "" {
    86  			c.Check(addUserCmd.User, gc.Equals, test.user)
    87  			c.Check(addUserCmd.DisplayName, gc.Equals, test.displayname)
    88  			c.Check(addUserCmd.OutPath, gc.Equals, test.outPath)
    89  			c.Check(addUserCmd.Generate, gc.Equals, test.generate)
    90  		} else {
    91  			c.Check(err, gc.ErrorMatches, test.errorString)
    92  		}
    93  	}
    94  }
    95  
    96  // serializedCACert adjusts the testing.CACert for the test below.
    97  func serializedCACert() string {
    98  	parts := strings.Split(testing.CACert, "\n")
    99  	for i, part := range parts {
   100  		parts[i] = strings.TrimSpace(part)
   101  	}
   102  	return strings.Join(parts[:len(parts)-1], "\n")
   103  }
   104  
   105  func assertJENVContents(c *gc.C, filename, username, password string) {
   106  	raw, err := ioutil.ReadFile(filename)
   107  	c.Assert(err, jc.ErrorIsNil)
   108  	expected := map[string]interface{}{
   109  		"user":          username,
   110  		"password":      password,
   111  		"state-servers": []interface{}{"127.0.0.1:12345"},
   112  		"ca-cert":       serializedCACert(),
   113  		"environ-uuid":  "env-uuid",
   114  	}
   115  	c.Assert(string(raw), jc.YAMLEquals, expected)
   116  }
   117  
   118  func (s *UserAddCommandSuite) AssertJENVContents(c *gc.C, filename string) {
   119  	assertJENVContents(c, filename, s.mockAPI.username, s.mockAPI.password)
   120  }
   121  
   122  func (s *UserAddCommandSuite) TestAddUserJustUsername(c *gc.C) {
   123  	context, err := testing.RunCommand(c, newUserAddCommand(), "foobar")
   124  	c.Assert(err, jc.ErrorIsNil)
   125  	c.Assert(s.mockAPI.username, gc.Equals, "foobar")
   126  	c.Assert(s.mockAPI.displayname, gc.Equals, "")
   127  	c.Assert(s.mockAPI.password, gc.Equals, "sekrit")
   128  	expected := `
   129  password:
   130  type password again:
   131  user "foobar" added
   132  environment file written to .*foobar.jenv
   133  `[1:]
   134  	c.Assert(testing.Stdout(context), gc.Matches, expected)
   135  	c.Assert(testing.Stderr(context), gc.Equals, "To generate a random strong password, use the --generate flag.\n")
   136  	s.AssertJENVContents(c, context.AbsPath("foobar.jenv"))
   137  }
   138  
   139  func (s *UserAddCommandSuite) TestAddUserUsernameAndDisplayname(c *gc.C) {
   140  	context, err := testing.RunCommand(c, newUserAddCommand(), "foobar", "Foo Bar")
   141  	c.Assert(err, jc.ErrorIsNil)
   142  	c.Assert(s.mockAPI.username, gc.Equals, "foobar")
   143  	c.Assert(s.mockAPI.displayname, gc.Equals, "Foo Bar")
   144  	expected := `user "Foo Bar (foobar)" added`
   145  	c.Assert(testing.Stdout(context), jc.Contains, expected)
   146  	s.AssertJENVContents(c, context.AbsPath("foobar.jenv"))
   147  }
   148  
   149  func (s *UserAddCommandSuite) TestBlockAddUser(c *gc.C) {
   150  	// Block operation
   151  	s.mockAPI.blocked = true
   152  	_, err := testing.RunCommand(c, newUserAddCommand(), "foobar", "Foo Bar")
   153  	c.Assert(err, gc.ErrorMatches, cmd.ErrSilent.Error())
   154  	// msg is logged
   155  	stripped := strings.Replace(c.GetTestLog(), "\n", "", -1)
   156  	c.Check(stripped, gc.Matches, ".*To unblock changes.*")
   157  }
   158  
   159  func (s *UserAddCommandSuite) TestGeneratePassword(c *gc.C) {
   160  	context, err := testing.RunCommand(c, newUserAddCommand(), "foobar", "--generate")
   161  	c.Assert(err, jc.ErrorIsNil)
   162  	c.Assert(s.mockAPI.username, gc.Equals, "foobar")
   163  	c.Assert(s.mockAPI.password, gc.Not(gc.Equals), "sekrit")
   164  	c.Assert(s.mockAPI.password, gc.HasLen, 24)
   165  	expected := `
   166  user "foobar" added
   167  environment file written to .*foobar.jenv
   168  `[1:]
   169  	c.Assert(testing.Stdout(context), gc.Matches, expected)
   170  	c.Assert(testing.Stderr(context), gc.Equals, "")
   171  	s.AssertJENVContents(c, context.AbsPath("foobar.jenv"))
   172  }
   173  
   174  func (s *UserAddCommandSuite) TestAddUserErrorResponse(c *gc.C) {
   175  	s.mockAPI.failMessage = "failed to create user, chaos ensues"
   176  	context, err := testing.RunCommand(c, newUserAddCommand(), "foobar", "--generate")
   177  	c.Assert(err, gc.ErrorMatches, "failed to create user, chaos ensues")
   178  	c.Assert(s.mockAPI.username, gc.Equals, "foobar")
   179  	c.Assert(s.mockAPI.displayname, gc.Equals, "")
   180  	c.Assert(testing.Stdout(context), gc.Equals, "")
   181  }
   182  
   183  func (s *UserAddCommandSuite) TestJenvOutput(c *gc.C) {
   184  	outputName := filepath.Join(c.MkDir(), "output")
   185  	context, err := testing.RunCommand(c, newUserAddCommand(),
   186  		"foobar", "--output", outputName)
   187  	c.Assert(err, jc.ErrorIsNil)
   188  	s.AssertJENVContents(c, context.AbsPath(outputName+".jenv"))
   189  }
   190  
   191  func (s *UserAddCommandSuite) TestJenvOutputWithSuffix(c *gc.C) {
   192  	outputName := filepath.Join(c.MkDir(), "output.jenv")
   193  	context, err := testing.RunCommand(c, newUserAddCommand(),
   194  		"foobar", "--output", outputName)
   195  	c.Assert(err, jc.ErrorIsNil)
   196  	s.AssertJENVContents(c, context.AbsPath(outputName))
   197  }
   198  
   199  type mockAddUserAPI struct {
   200  	failMessage string
   201  	username    string
   202  	displayname string
   203  	password    string
   204  
   205  	shareFailMsg string
   206  	sharedUsers  []names.UserTag
   207  	blocked      bool
   208  }
   209  
   210  func (m *mockAddUserAPI) AddUser(username, displayname, password string) (names.UserTag, error) {
   211  	if m.blocked {
   212  		return names.UserTag{}, &params.Error{
   213  			Code:    params.CodeOperationBlocked,
   214  			Message: "The operation has been blocked.",
   215  		}
   216  	}
   217  
   218  	m.username = username
   219  	m.displayname = displayname
   220  	m.password = password
   221  	if m.failMessage == "" {
   222  		return names.NewLocalUserTag(username), nil
   223  	}
   224  	return names.UserTag{}, errors.New(m.failMessage)
   225  }
   226  
   227  func (m *mockAddUserAPI) ShareEnvironment(users []names.UserTag) error {
   228  	if m.shareFailMsg != "" {
   229  		return errors.New(m.shareFailMsg)
   230  	}
   231  	m.sharedUsers = users
   232  	return nil
   233  }
   234  
   235  func (*mockAddUserAPI) Close() error {
   236  	return nil
   237  }