github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/cmd/juju/cloud/detectcredentials_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package cloud_test 5 6 import ( 7 "fmt" 8 "io" 9 "regexp" 10 "strings" 11 12 "github.com/juju/cmd" 13 "github.com/juju/errors" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 17 jujucloud "github.com/juju/juju/cloud" 18 "github.com/juju/juju/cmd/juju/cloud" 19 "github.com/juju/juju/environs" 20 "github.com/juju/juju/jujuclient/jujuclienttesting" 21 "github.com/juju/juju/testing" 22 ) 23 24 type detectCredentialsSuite struct { 25 store *jujuclienttesting.MemStore 26 aCredential jujucloud.CloudCredential 27 } 28 29 var _ = gc.Suite(&detectCredentialsSuite{}) 30 31 type mockProvider struct { 32 environs.EnvironProvider 33 detectedCreds *jujucloud.CloudCredential 34 credSchemas *map[jujucloud.AuthType]jujucloud.CredentialSchema 35 } 36 37 func (p *mockProvider) DetectCredentials() (*jujucloud.CloudCredential, error) { 38 if len(p.detectedCreds.AuthCredentials) == 0 { 39 return nil, errors.NotFoundf("credentials") 40 } 41 return p.detectedCreds, nil 42 } 43 44 func (p *mockProvider) CredentialSchemas() map[jujucloud.AuthType]jujucloud.CredentialSchema { 45 if p.credSchemas == nil { 46 return map[jujucloud.AuthType]jujucloud.CredentialSchema{ 47 jujucloud.AccessKeyAuthType: { 48 { 49 "access-key", jujucloud.CredentialAttr{}, 50 }, { 51 "secret-key", jujucloud.CredentialAttr{Hidden: true}, 52 }, 53 }, 54 jujucloud.UserPassAuthType: { 55 { 56 "username", jujucloud.CredentialAttr{}, 57 }, { 58 "password", jujucloud.CredentialAttr{Hidden: true}, 59 }, { 60 "application-password", jujucloud.CredentialAttr{Hidden: true}, 61 }, 62 }, 63 jujucloud.OAuth2AuthType: { 64 { 65 "client-id", jujucloud.CredentialAttr{}, 66 }, { 67 "client-email", jujucloud.CredentialAttr{}, 68 }, { 69 "private-key", jujucloud.CredentialAttr{Hidden: true}, 70 }, { 71 "project-id", jujucloud.CredentialAttr{}, 72 }, 73 }, 74 } 75 } 76 return *p.credSchemas 77 } 78 79 func (p *mockProvider) FinalizeCredential( 80 ctx environs.FinalizeCredentialContext, 81 args environs.FinalizeCredentialParams, 82 ) (*jujucloud.Credential, error) { 83 if args.Credential.AuthType() == "interactive" { 84 fmt.Fprintln(ctx.GetStderr(), "generating userpass credential") 85 out := jujucloud.NewCredential(jujucloud.UserPassAuthType, map[string]string{ 86 "username": args.Credential.Attributes()["username"], 87 "password": args.CloudEndpoint, 88 "application-password": args.CloudIdentityEndpoint, 89 }) 90 return &out, nil 91 } 92 return &args.Credential, nil 93 } 94 95 func (s *detectCredentialsSuite) SetUpSuite(c *gc.C) { 96 environs.RegisterProvider("mock-provider", &mockProvider{detectedCreds: &s.aCredential}) 97 } 98 99 func (s *detectCredentialsSuite) SetUpTest(c *gc.C) { 100 s.store = jujuclienttesting.NewMemStore() 101 s.aCredential = jujucloud.CloudCredential{} 102 } 103 104 func (s *detectCredentialsSuite) run(c *gc.C, stdin io.Reader, clouds map[string]jujucloud.Cloud) (*cmd.Context, error) { 105 registeredProvidersFunc := func() []string { 106 return []string{"mock-provider"} 107 } 108 allCloudsFunc := func() (map[string]jujucloud.Cloud, error) { 109 return clouds, nil 110 } 111 cloudByNameFunc := func(cloudName string) (*jujucloud.Cloud, error) { 112 if cloud, ok := clouds[cloudName]; ok { 113 return &cloud, nil 114 } 115 return nil, errors.NotFoundf("cloud %s", cloudName) 116 } 117 command := cloud.NewDetectCredentialsCommandForTest(s.store, registeredProvidersFunc, allCloudsFunc, cloudByNameFunc) 118 err := testing.InitCommand(command, nil) 119 c.Assert(err, jc.ErrorIsNil) 120 ctx := testing.Context(c) 121 ctx.Stdin = stdin 122 return ctx, command.Run(ctx) 123 } 124 125 func (s *detectCredentialsSuite) credentialWithLabel(authType jujucloud.AuthType, label string) jujucloud.Credential { 126 cred := jujucloud.NewCredential(authType, nil) 127 cred.Label = label 128 return cred 129 } 130 131 func (s *detectCredentialsSuite) assertDetectCredential(c *gc.C, cloudName, expectedRegion, errText string) { 132 s.aCredential = jujucloud.CloudCredential{ 133 DefaultRegion: "default region", 134 AuthCredentials: map[string]jujucloud.Credential{ 135 "test": s.credentialWithLabel(jujucloud.AccessKeyAuthType, "credential")}, 136 } 137 clouds := map[string]jujucloud.Cloud{ 138 "test-cloud": { 139 Type: "mock-provider", 140 }, 141 "another-cloud": { 142 Type: "another-provider", 143 }, 144 } 145 146 stdin := strings.NewReader(fmt.Sprintf("1\n%s\nQ\n", cloudName)) 147 ctx, err := s.run(c, stdin, clouds) 148 c.Assert(err, jc.ErrorIsNil) 149 if errText == "" { 150 if expectedRegion != "" { 151 s.aCredential.DefaultRegion = expectedRegion 152 } 153 c.Assert(s.store.Credentials["test-cloud"], jc.DeepEquals, s.aCredential) 154 } else { 155 output := strings.Replace(testing.Stderr(ctx), "\n", "", -1) 156 c.Assert(output, gc.Matches, ".*"+regexp.QuoteMeta(errText)+".*") 157 } 158 } 159 160 func (s *detectCredentialsSuite) TestDetectNewCredential(c *gc.C) { 161 s.assertDetectCredential(c, "test-cloud", "", "") 162 } 163 164 func (s *detectCredentialsSuite) TestDetectCredentialOverwrites(c *gc.C) { 165 s.store.Credentials = map[string]jujucloud.CloudCredential{ 166 "test-cloud": { 167 AuthCredentials: map[string]jujucloud.Credential{ 168 "test": jujucloud.NewCredential(jujucloud.AccessKeyAuthType, nil), 169 }, 170 }, 171 } 172 s.assertDetectCredential(c, "test-cloud", "", "") 173 } 174 175 func (s *detectCredentialsSuite) TestDetectCredentialKeepsExistingRegion(c *gc.C) { 176 s.store.Credentials = map[string]jujucloud.CloudCredential{ 177 "test-cloud": { 178 DefaultRegion: "west", 179 AuthCredentials: map[string]jujucloud.Credential{ 180 "test": jujucloud.NewCredential(jujucloud.AccessKeyAuthType, nil), 181 }, 182 }, 183 } 184 s.assertDetectCredential(c, "test-cloud", "west", "") 185 } 186 187 func (s *detectCredentialsSuite) TestDetectCredentialDefaultCloud(c *gc.C) { 188 s.assertDetectCredential(c, "", "", "") 189 } 190 191 func (s *detectCredentialsSuite) TestDetectCredentialUnknownCloud(c *gc.C) { 192 s.assertDetectCredential(c, "foo", "", "cloud foo not valid") 193 } 194 195 func (s *detectCredentialsSuite) TestDetectCredentialInvalidCloud(c *gc.C) { 196 s.assertDetectCredential(c, "another-cloud", "", "chosen credentials not compatible with a another-provider cloud") 197 } 198 199 func (s *detectCredentialsSuite) TestNewDetectCredentialNoneFound(c *gc.C) { 200 stdin := strings.NewReader("") 201 ctx, err := s.run(c, stdin, nil) 202 c.Assert(err, jc.ErrorIsNil) 203 output := strings.Replace(testing.Stderr(ctx), "\n", "", -1) 204 c.Assert(output, gc.Matches, ".*No cloud credentials found.*") 205 c.Assert(s.store.Credentials, gc.HasLen, 0) 206 } 207 208 func (s *detectCredentialsSuite) TestDetectCredentialInvalidChoice(c *gc.C) { 209 s.aCredential = jujucloud.CloudCredential{ 210 DefaultRegion: "detected region", 211 AuthCredentials: map[string]jujucloud.Credential{ 212 "test": s.credentialWithLabel(jujucloud.AccessKeyAuthType, "credential 1"), 213 "another": s.credentialWithLabel(jujucloud.AccessKeyAuthType, "credential 2")}, 214 } 215 216 stdin := strings.NewReader("3\nQ\n") 217 ctx, err := s.run(c, stdin, nil) 218 c.Assert(err, jc.ErrorIsNil) 219 output := strings.Replace(testing.Stderr(ctx), "\n", "", -1) 220 c.Assert(output, gc.Matches, ".*Invalid choice, enter a number between 1 and 2.*") 221 c.Assert(s.store.Credentials, gc.HasLen, 0) 222 }