github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/juju/user/logincontroller_test.go (about) 1 // Copyright 2018 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package user_test 5 6 import ( 7 "bytes" 8 "fmt" 9 "net/http" 10 "net/http/httptest" 11 "os" 12 "strings" 13 14 "github.com/juju/cmd" 15 "github.com/juju/errors" 16 jc "github.com/juju/testing/checkers" 17 gc "gopkg.in/check.v1" 18 "gopkg.in/juju/names.v2" 19 20 "github.com/juju/juju/api" 21 "github.com/juju/juju/cmd/juju/user" 22 "github.com/juju/juju/cmd/modelcmd" 23 "github.com/juju/juju/jujuclient" 24 "github.com/juju/juju/testing" 25 ) 26 27 func (s *LoginCommandSuite) TestLoginFromDirectory(c *gc.C) { 28 dirSrv := serveDirectory(map[string]string{ 29 "bighost": "bighost.jujucharms.com:443", 30 }) 31 defer dirSrv.Close() 32 os.Setenv("JUJU_DIRECTORY", dirSrv.URL) 33 s.apiConnection.authTag = names.NewUserTag("bob@external") 34 s.apiConnection.controllerAccess = "login" 35 stdout, stderr, code := s.run(c, "bighost") 36 c.Check(stderr, gc.Equals, ` 37 Welcome, bob@external. You are now logged into "bighost". 38 `[1:]+user.NoModelsMessage) 39 c.Check(stdout, gc.Equals, "") 40 c.Assert(code, gc.Equals, 0) 41 42 // The controller and account details should be recorded with 43 // the specified controller name and user 44 // name from the auth tag. 45 46 controller, err := s.store.ControllerByName("bighost") 47 c.Assert(err, jc.ErrorIsNil) 48 c.Assert(controller, jc.DeepEquals, &jujuclient.ControllerDetails{ 49 ControllerUUID: mockControllerUUID, 50 APIEndpoints: []string{"bighost.jujucharms.com:443"}, 51 }) 52 account, err := s.store.AccountDetails("bighost") 53 c.Assert(err, jc.ErrorIsNil) 54 c.Assert(account, jc.DeepEquals, &jujuclient.AccountDetails{ 55 User: "bob@external", 56 LastKnownAccess: "login", 57 }) 58 59 // Test that we can run the same command again and it works. 60 stdout, stderr, code = s.run(c, "bighost") 61 c.Check(code, gc.Equals, 0) 62 c.Check(stdout, gc.Equals, "") 63 c.Check(stderr, gc.Equals, "") 64 } 65 66 func (s *LoginCommandSuite) TestLoginPublicDNSName(c *gc.C) { 67 s.apiConnection.authTag = names.NewUserTag("bob@external") 68 s.apiConnection.controllerAccess = "login" 69 stdout, stderr, code := s.run(c, "0.1.2.3") 70 c.Check(stderr, gc.Equals, ` 71 Welcome, bob@external. You are now logged into "0.1.2.3". 72 `[1:]+user.NoModelsMessage) 73 c.Check(stdout, gc.Equals, "") 74 c.Assert(code, gc.Equals, 0) 75 76 // The controller and account details should be recorded with 77 // the specified controller name and user 78 // name from the auth tag. 79 controller, err := s.store.ControllerByName("0.1.2.3") 80 c.Assert(err, jc.ErrorIsNil) 81 c.Assert(controller, jc.DeepEquals, &jujuclient.ControllerDetails{ 82 ControllerUUID: mockControllerUUID, 83 APIEndpoints: []string{"0.1.2.3:443"}, 84 }) 85 account, err := s.store.AccountDetails("0.1.2.3") 86 c.Assert(err, jc.ErrorIsNil) 87 c.Assert(account, jc.DeepEquals, &jujuclient.AccountDetails{ 88 User: "bob@external", 89 LastKnownAccess: "login", 90 }) 91 } 92 93 func (s *LoginCommandSuite) TestRegisterPublicDNSNameWithPort(c *gc.C) { 94 s.apiConnection.authTag = names.NewUserTag("bob@external") 95 s.apiConnection.controllerAccess = "login" 96 stdout, stderr, code := s.run(c, "0.1.2.3:5678") 97 c.Check(stdout, gc.Equals, "") 98 c.Check(stderr, gc.Equals, "ERROR cannot use \"0.1.2.3:5678\" as a controller name - use -c option to choose a different one\n") 99 c.Check(code, gc.Equals, 1) 100 } 101 102 func (s *LoginCommandSuite) TestRegisterPublicDNSNameWithPortAndControllerFlag(c *gc.C) { 103 s.apiConnection.authTag = names.NewUserTag("bob@external") 104 s.apiConnection.controllerAccess = "login" 105 stdout, stderr, code := s.run(c, "-c", "foo", "0.1.2.3:5678") 106 c.Check(stdout, gc.Equals, "") 107 c.Check(stderr, gc.Equals, ` 108 Welcome, bob@external. You are now logged into "foo". 109 `[1:]+user.NoModelsMessage) 110 c.Check(stdout, gc.Equals, "") 111 c.Assert(code, gc.Equals, 0) 112 113 // The controller and account details should be recorded with 114 // the specified controller name and user 115 // name from the auth tag. 116 controller, err := s.store.ControllerByName("foo") 117 c.Assert(err, jc.ErrorIsNil) 118 c.Assert(controller, jc.DeepEquals, &jujuclient.ControllerDetails{ 119 ControllerUUID: mockControllerUUID, 120 APIEndpoints: []string{"0.1.2.3:5678"}, 121 }) 122 } 123 124 func (s *LoginCommandSuite) TestRegisterPublicAPIOpenError(c *gc.C) { 125 srv := serveDirectory(map[string]string{"bighost": "https://0.1.2.3/directory"}) 126 defer srv.Close() 127 os.Setenv("JUJU_DIRECTORY", srv.URL) 128 *user.APIOpen = func(c *modelcmd.CommandBase, info *api.Info, opts api.DialOpts) (api.Connection, error) { 129 return nil, errors.New("open failed") 130 } 131 stdout, stderr, code := s.run(c, "bighost") 132 c.Check(stdout, gc.Equals, "") 133 c.Check(stderr, gc.Matches, `ERROR cannot log into "bighost": open failed\n`) 134 c.Check(code, gc.Equals, 1) 135 } 136 137 func (s *LoginCommandSuite) TestRegisterPublicControllerMismatch(c *gc.C) { 138 srv := serveDirectory(map[string]string{"bighost": "https://0.1.2.3/directory"}) 139 defer srv.Close() 140 os.Setenv("JUJU_DIRECTORY", srv.URL) 141 s.store.Controllers["other"] = jujuclient.ControllerDetails{ 142 APIEndpoints: []string{"0.1.2.3:123"}, 143 CACert: testing.CACert, 144 ControllerUUID: "00000000-1111-2222-3333-444444444444", 145 } 146 stdout, stderr, code := s.run(c, "-c", "other", "bighost") 147 c.Check(stdout, gc.Equals, "") 148 c.Check(stderr, gc.Matches, ` 149 ERROR controller at "bighost" does not match existing controller. 150 Please choose a different controller name with the -c option, or 151 use "juju unregister other" to remove the existing controller\. 152 `[1:]) 153 c.Check(code, gc.Equals, 1) 154 } 155 156 func (s *LoginCommandSuite) run(c *gc.C, args ...string) (stdout, stderr string, errCode int) { 157 var stdoutBuf, stderrBuf bytes.Buffer 158 ctxt := &cmd.Context{ 159 Dir: c.MkDir(), 160 Stdin: strings.NewReader(""), 161 Stdout: &stdoutBuf, 162 Stderr: &stderrBuf, 163 } 164 exitCode := cmd.Main(user.NewLoginCommand(), ctxt, args) 165 return stdoutBuf.String(), stderrBuf.String(), exitCode 166 } 167 168 // loginMockAPIConnection implements just enough of the api.Connection interface 169 // to satisfy the methods used by the login command. 170 type loginMockAPI struct { 171 // This will be nil - it's just there to satisfy the api.Connection 172 // interface methods not explicitly defined by loginMockAPIConnection. 173 api.Connection 174 175 // controllerTag is returned by ControllerTag. 176 controllerTag names.ControllerTag 177 178 // authTag is returned by AuthTag. 179 authTag names.Tag 180 181 // controllerAccess is returned by ControllerAccess. 182 controllerAccess string 183 } 184 185 func (*loginMockAPI) Close() error { 186 return nil 187 } 188 189 func (m *loginMockAPI) ControllerTag() names.ControllerTag { 190 return m.controllerTag 191 } 192 193 func (m *loginMockAPI) AuthTag() names.Tag { 194 return m.authTag 195 } 196 197 func (m *loginMockAPI) ControllerAccess() string { 198 return m.controllerAccess 199 } 200 201 const mockControllerUUID = "df136476-12e9-11e4-8a70-b2227cce2b54" 202 203 func serveDirectory(dir map[string]string) *httptest.Server { 204 return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { 205 name := strings.TrimPrefix(req.URL.Path, "/v1/controller/") 206 if name == req.URL.Path || dir[name] == "" { 207 http.NotFound(w, req) 208 return 209 } 210 w.Header().Set("Content-Type", "application/json") 211 fmt.Fprintf(w, `{"host":%q}`, dir[name]) 212 })) 213 }