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 }