github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/cmd/juju/system/login_test.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package system_test
     5  
     6  import (
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    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/api"
    18  	"github.com/juju/juju/cmd/envcmd"
    19  	"github.com/juju/juju/cmd/juju/system"
    20  	"github.com/juju/juju/environs/configstore"
    21  	"github.com/juju/juju/network"
    22  	"github.com/juju/juju/testing"
    23  )
    24  
    25  type LoginSuite struct {
    26  	testing.FakeJujuHomeSuite
    27  	apiConnection *mockAPIConnection
    28  	openError     error
    29  	store         configstore.Storage
    30  	username      string
    31  }
    32  
    33  var _ = gc.Suite(&LoginSuite{})
    34  
    35  func (s *LoginSuite) SetUpTest(c *gc.C) {
    36  	s.FakeJujuHomeSuite.SetUpTest(c)
    37  	s.store = configstore.NewMem()
    38  	s.PatchValue(&configstore.Default, func() (configstore.Storage, error) {
    39  		return s.store, nil
    40  	})
    41  	s.openError = nil
    42  	s.apiConnection = &mockAPIConnection{
    43  		serverTag: testing.EnvironmentTag,
    44  		addr:      "192.168.2.1:1234",
    45  	}
    46  	s.username = "valid-user"
    47  }
    48  
    49  func (s *LoginSuite) apiOpen(info *api.Info, opts api.DialOpts) (api.Connection, error) {
    50  	if s.openError != nil {
    51  		return nil, s.openError
    52  	}
    53  	s.apiConnection.info = info
    54  	return s.apiConnection, nil
    55  }
    56  
    57  func (s *LoginSuite) getUserManager(conn api.Connection) (system.UserManager, error) {
    58  	return s.apiConnection, nil
    59  }
    60  
    61  func (s *LoginSuite) run(c *gc.C, args ...string) (*cmd.Context, error) {
    62  	command := system.NewLoginCommand(s.apiOpen, s.getUserManager)
    63  	return testing.RunCommand(c, command, args...)
    64  }
    65  
    66  func (s *LoginSuite) runServerFile(c *gc.C, args ...string) (*cmd.Context, error) {
    67  	serverFilePath := filepath.Join(c.MkDir(), "server.yaml")
    68  	content := `
    69  addresses: ["192.168.2.1:1234", "192.168.2.2:1234"]
    70  ca-cert: a-cert
    71  username: ` + s.username + `
    72  password: sekrit
    73  `
    74  	err := ioutil.WriteFile(serverFilePath, []byte(content), 0644)
    75  	c.Assert(err, jc.ErrorIsNil)
    76  	allArgs := []string{"foo", "--server", serverFilePath}
    77  	allArgs = append(allArgs, args...)
    78  	return s.run(c, allArgs...)
    79  }
    80  
    81  func (s *LoginSuite) TestInit(c *gc.C) {
    82  	loginCommand := system.NewLoginCommand(nil, nil)
    83  
    84  	err := testing.InitCommand(loginCommand, []string{})
    85  	c.Assert(err, gc.ErrorMatches, "no name specified")
    86  
    87  	err = testing.InitCommand(loginCommand, []string{"foo"})
    88  	c.Assert(err, jc.ErrorIsNil)
    89  	c.Assert(loginCommand.Name, gc.Equals, "foo")
    90  
    91  	err = testing.InitCommand(loginCommand, []string{"foo", "bar"})
    92  	c.Assert(err, gc.ErrorMatches, `unrecognized args: \["bar"\]`)
    93  }
    94  
    95  func (s *LoginSuite) TestNoSpecifiedServerFile(c *gc.C) {
    96  	_, err := s.run(c, "foo")
    97  	c.Assert(err, gc.ErrorMatches, "no server file specified")
    98  }
    99  
   100  func (s *LoginSuite) TestMissingServerFile(c *gc.C) {
   101  	serverFilePath := filepath.Join(c.MkDir(), "server.yaml")
   102  	_, err := s.run(c, "foo", "--server", serverFilePath)
   103  	c.Assert(errors.Cause(err), jc.Satisfies, os.IsNotExist)
   104  }
   105  
   106  func (s *LoginSuite) TestBadServerFile(c *gc.C) {
   107  	serverFilePath := filepath.Join(c.MkDir(), "server.yaml")
   108  	err := ioutil.WriteFile(serverFilePath, []byte("&^%$#@"), 0644)
   109  	c.Assert(err, jc.ErrorIsNil)
   110  
   111  	_, err = s.run(c, "foo", "--server", serverFilePath)
   112  	c.Assert(err, gc.ErrorMatches, "YAML error: did not find expected alphabetic or numeric character")
   113  }
   114  
   115  func (s *LoginSuite) TestBadUser(c *gc.C) {
   116  	serverFilePath := filepath.Join(c.MkDir(), "server.yaml")
   117  	content := `
   118  username: omg@not@valid
   119  `
   120  	err := ioutil.WriteFile(serverFilePath, []byte(content), 0644)
   121  	c.Assert(err, jc.ErrorIsNil)
   122  
   123  	_, err = s.run(c, "foo", "--server", serverFilePath)
   124  	c.Assert(err, gc.ErrorMatches, `"omg@not@valid" is not a valid username`)
   125  }
   126  
   127  func (s *LoginSuite) TestAPIOpenError(c *gc.C) {
   128  	s.openError = errors.New("open failed")
   129  	_, err := s.runServerFile(c)
   130  	c.Assert(err, gc.ErrorMatches, `open failed`)
   131  }
   132  
   133  func (s *LoginSuite) TestOldServerNoServerUUID(c *gc.C) {
   134  	s.apiConnection.serverTag = names.EnvironTag{}
   135  	_, err := s.runServerFile(c)
   136  	c.Assert(err, gc.ErrorMatches, `juju system too old to support login`)
   137  }
   138  
   139  func (s *LoginSuite) TestWritesConfig(c *gc.C) {
   140  	ctx, err := s.runServerFile(c)
   141  	c.Assert(err, jc.ErrorIsNil)
   142  
   143  	info, err := s.store.ReadInfo("foo")
   144  	c.Assert(err, jc.ErrorIsNil)
   145  	creds := info.APICredentials()
   146  	c.Assert(creds.User, gc.Equals, "valid-user")
   147  	// Make sure that the password was changed, and that the new
   148  	// value was not "sekrit".
   149  	c.Assert(creds.Password, gc.Not(gc.Equals), "sekrit")
   150  	c.Assert(creds.Password, gc.Equals, s.apiConnection.password)
   151  	endpoint := info.APIEndpoint()
   152  	c.Assert(endpoint.CACert, gc.Equals, "a-cert")
   153  	c.Assert(endpoint.EnvironUUID, gc.Equals, "")
   154  	c.Assert(endpoint.ServerUUID, gc.Equals, testing.EnvironmentTag.Id())
   155  	c.Assert(endpoint.Addresses, jc.DeepEquals, []string{"192.168.2.1:1234"})
   156  	c.Assert(endpoint.Hostnames, jc.DeepEquals, []string{"192.168.2.1:1234"})
   157  
   158  	c.Assert(testing.Stderr(ctx), jc.Contains, "cached connection details as system \"foo\"\n")
   159  	c.Assert(testing.Stderr(ctx), jc.Contains, "password updated\n")
   160  }
   161  
   162  func (s *LoginSuite) TestKeepPassword(c *gc.C) {
   163  	_, err := s.runServerFile(c, "--keep-password")
   164  	c.Assert(err, jc.ErrorIsNil)
   165  
   166  	info, err := s.store.ReadInfo("foo")
   167  	c.Assert(err, jc.ErrorIsNil)
   168  	creds := info.APICredentials()
   169  	c.Assert(creds.User, gc.Equals, "valid-user")
   170  	c.Assert(creds.Password, gc.Equals, "sekrit")
   171  }
   172  
   173  func (s *LoginSuite) TestRemoteUsersKeepPassword(c *gc.C) {
   174  	s.username = "user@remote"
   175  	_, err := s.runServerFile(c)
   176  	c.Assert(err, jc.ErrorIsNil)
   177  
   178  	info, err := s.store.ReadInfo("foo")
   179  	c.Assert(err, jc.ErrorIsNil)
   180  	creds := info.APICredentials()
   181  	c.Assert(creds.User, gc.Equals, "user@remote")
   182  	c.Assert(creds.Password, gc.Equals, "sekrit")
   183  }
   184  
   185  func (s *LoginSuite) TestConnectsUsingServerFileInfo(c *gc.C) {
   186  	s.username = "valid-user@local"
   187  	_, err := s.runServerFile(c)
   188  	c.Assert(err, jc.ErrorIsNil)
   189  
   190  	info := s.apiConnection.info
   191  	c.Assert(info.Addrs, jc.DeepEquals, []string{"192.168.2.1:1234", "192.168.2.2:1234"})
   192  	c.Assert(info.CACert, gc.Equals, "a-cert")
   193  	c.Assert(info.EnvironTag.Id(), gc.Equals, "")
   194  	c.Assert(info.Tag.Id(), gc.Equals, "valid-user@local")
   195  	c.Assert(info.Password, gc.Equals, "sekrit")
   196  	c.Assert(info.Nonce, gc.Equals, "")
   197  }
   198  
   199  func (s *LoginSuite) TestWritesCurrentSystem(c *gc.C) {
   200  	_, err := s.runServerFile(c)
   201  	c.Assert(err, jc.ErrorIsNil)
   202  	currentSystem, err := envcmd.ReadCurrentSystem()
   203  	c.Assert(err, jc.ErrorIsNil)
   204  	c.Assert(currentSystem, gc.Equals, "foo")
   205  }
   206  
   207  type mockAPIConnection struct {
   208  	api.Connection
   209  	info         *api.Info
   210  	addr         string
   211  	apiHostPorts [][]network.HostPort
   212  	serverTag    names.EnvironTag
   213  	username     string
   214  	password     string
   215  }
   216  
   217  func (*mockAPIConnection) Close() error {
   218  	return nil
   219  }
   220  
   221  func (m *mockAPIConnection) Addr() string {
   222  	return m.addr
   223  }
   224  
   225  func (m *mockAPIConnection) APIHostPorts() [][]network.HostPort {
   226  	return m.apiHostPorts
   227  }
   228  
   229  func (m *mockAPIConnection) ServerTag() (names.EnvironTag, error) {
   230  	if m.serverTag.Id() == "" {
   231  		return m.serverTag, errors.New("no server tag")
   232  	}
   233  	return m.serverTag, nil
   234  }
   235  
   236  func (m *mockAPIConnection) SetPassword(username, password string) error {
   237  	m.username = username
   238  	m.password = password
   239  	return nil
   240  }