github.com/swisscom/cloudfoundry-cli@v7.1.0+incompatible/cf/configuration/coreconfig/config_repository_test.go (about) 1 package coreconfig_test 2 3 import ( 4 "io/ioutil" 5 "os" 6 "path/filepath" 7 8 "code.cloudfoundry.org/cli/cf/configuration" 9 "code.cloudfoundry.org/cli/cf/configuration/configurationfakes" 10 "code.cloudfoundry.org/cli/cf/configuration/coreconfig" 11 "code.cloudfoundry.org/cli/cf/models" 12 "code.cloudfoundry.org/cli/version" 13 "github.com/blang/semver" 14 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 ) 18 19 var _ = Describe("Configuration Repository", func() { 20 21 const ( 22 AccessTokenForClientUsers = "bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleS0xIiwidHlwIjoiSldUIn0.eyJqdGkiOiI5MTExMzczOTRjYTg0NzQzOGUxZjQyOWY4OTQ2ZGZmMyIsInN1YiI6InBvdGF0by1mYWNlIiwiYXV0aG9yaXRpZXMiOlsicm91dGluZy5yb3V0ZXJfZ3JvdXBzLnJlYWQiLCJjbG91ZF9jb250cm9sbGVyLnJlYWQiLCJwYXNzd29yZC53cml0ZSIsImNsb3VkX2NvbnRyb2xsZXIud3JpdGUiLCJvcGVuaWQiLCJuZXR3b3JrLmFkbWluIiwicm91dGluZy5yb3V0ZXJfZ3JvdXBzLndyaXRlIiwiZG9wcGxlci5maXJlaG9zZSIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiLCJjbG91ZF9jb250cm9sbGVyLmFkbWluIiwidWFhLnVzZXIiXSwic2NvcGUiOlsicm91dGluZy5yb3V0ZXJfZ3JvdXBzLnJlYWQiLCJjbG91ZF9jb250cm9sbGVyLnJlYWQiLCJwYXNzd29yZC53cml0ZSIsImNsb3VkX2NvbnRyb2xsZXIud3JpdGUiLCJvcGVuaWQiLCJuZXR3b3JrLmFkbWluIiwicm91dGluZy5yb3V0ZXJfZ3JvdXBzLndyaXRlIiwiZG9wcGxlci5maXJlaG9zZSIsInNjaW0ud3JpdGUiLCJzY2ltLnJlYWQiLCJjbG91ZF9jb250cm9sbGVyLmFkbWluIiwidWFhLnVzZXIiXSwiY2xpZW50X2lkIjoicG90YXRvLWZhY2UiLCJjaWQiOiJwb3RhdG8tZmFjZSIsImF6cCI6InBvdGF0by1mYWNlIiwiZ3JhbnRfdHlwZSI6ImNsaWVudF9jcmVkZW50aWFscyIsInJldl9zaWciOiJkMjU1NjdjYiIsImlhdCI6MTUxNjg0MTY4MCwiZXhwIjoxNTE2ODQxNzQwLCJpc3MiOiJodHRwczovL3VhYS5ib3NoLWxpdGUuY29tL29hdXRoL3Rva2VuIiwiemlkIjoidWFhIiwiYXVkIjpbImNsb3VkX2NvbnRyb2xsZXIiLCJzY2ltIiwicG90YXRvLWZhY2UiLCJwYXNzd29yZCIsInVhYSIsIm9wZW5pZCIsImRvcHBsZXIiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMiLCJuZXR3b3JrIl19.I2flQSfAhWiCdhyd0414dZ0qmv0W-dPTGvj0pIXnaFPNae7gXSz79MPipTelSxCvdtigX8SoW8O7dWU5zt0O7VRkQX_YYElTHnQeWBfljoFvHhYPRMUv24I3lO6beeujKlYbUxVP5BXoyEdyfiDwzJjoX9lzxriBKdY_BO81oRUjItl7oI1VFhj1A_UwUcDwK2t-c7zDxSmh4P48r77QdqDoAjuweZPUU4PdzRlp99XYdmke52KeG7Xums6hrEJJBSDLbczd_308FAitaQKHgAQH1swLQXqcuD29-eoB4_nTSBwok2H5hoHicHWohSBkMOyFqD4HPb8ta8d_FOi8HA" 23 AccessTokenForHumanUsers = "bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiI3YzZkMDA2MjA2OTI0NmViYWI0ZjBmZjY3NGQ3Zjk4OSIsInN1YiI6Ijk1MTliZTNlLTQ0ZDktNDBkMC1hYjlhLWY0YWNlMTFkZjE1OSIsInNjb3BlIjpbIm9wZW5pZCIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy53cml0ZSIsInNjaW0ucmVhZCIsImNsb3VkX2NvbnRyb2xsZXIuYWRtaW4iLCJ1YWEudXNlciIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy5yZWFkIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwicGFzc3dvcmQud3JpdGUiLCJjbG91ZF9jb250cm9sbGVyLndyaXRlIiwiZG9wcGxlci5maXJlaG9zZSIsInNjaW0ud3JpdGUiXSwiY2xpZW50X2lkIjoiY2YiLCJjaWQiOiJjZiIsImF6cCI6ImNmIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9pZCI6Ijk1MTliZTNlLTQ0ZDktNDBkMC1hYjlhLWY0YWNlMTFkZjE1OSIsIm9yaWdpbiI6InVhYSIsInVzZXJfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsImF1dGhfdGltZSI6MTQ3MzI4NDU3NywicmV2X3NpZyI6IjZiMjdkYTZjIiwiaWF0IjoxNDczMjg0NTc3LCJleHAiOjE0NzMyODUxNzcsImlzcyI6Imh0dHBzOi8vdWFhLmJvc2gtbGl0ZS5jb20vb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsiY2YiLCJvcGVuaWQiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMiLCJzY2ltIiwiY2xvdWRfY29udHJvbGxlciIsInVhYSIsInBhc3N3b3JkIiwiZG9wcGxlciJdfQ.OcH_w9yIKJkEcTZMThIs-qJAHk3G0JwNjG-aomVH9hKye4ciFO6IMQMLKmCBrrAQVc7ST1SZZwq7gv12Dq__6Jp-hai0a2_ADJK-Vc9YXyNZKgYTWIeVNGM1JGdHgFSrBR2Lz7IIrH9HqeN8plrKV5HzU8uI9LL4lyOCjbXJ9cM" 24 InvalidAccessToken = "bearer eyJhbGciOiJSUzI1NiJ9" 25 ) 26 27 var ( 28 config coreconfig.Repository 29 persistor *configurationfakes.FakePersistor 30 ) 31 32 BeforeEach(func() { 33 persistor = new(configurationfakes.FakePersistor) 34 persistor.ExistsReturns(true) 35 config = coreconfig.NewRepositoryFromPersistor(persistor, func(err error) { panic(err) }) 36 }) 37 38 It("is threadsafe", func() { 39 performSaveCh := make(chan struct{}) 40 beginSaveCh := make(chan struct{}) 41 finishSaveCh := make(chan struct{}) 42 finishReadCh := make(chan struct{}) 43 44 persistor.SaveStub = func(configuration.DataInterface) error { 45 close(beginSaveCh) 46 <-performSaveCh 47 close(finishSaveCh) 48 49 return nil 50 } 51 52 go func() { 53 config.SetAPIEndpoint("foo") 54 }() 55 56 <-beginSaveCh 57 58 go func() { 59 config.APIEndpoint() 60 close(finishReadCh) 61 }() 62 63 Consistently(finishSaveCh).ShouldNot(BeClosed()) 64 Consistently(finishReadCh).ShouldNot(BeClosed()) 65 66 performSaveCh <- struct{}{} 67 68 Eventually(finishReadCh).Should(BeClosed()) 69 }) 70 71 It("has acccessor methods for all config fields", func() { 72 config.SetAPIEndpoint("http://api.the-endpoint") 73 Expect(config.APIEndpoint()).To(Equal("http://api.the-endpoint")) 74 75 config.SetAPIVersion("3") 76 Expect(config.APIVersion()).To(Equal("3")) 77 78 config.SetAuthenticationEndpoint("http://auth.the-endpoint") 79 Expect(config.AuthenticationEndpoint()).To(Equal("http://auth.the-endpoint")) 80 81 config.SetUaaEndpoint("http://uaa.the-endpoint") 82 Expect(config.UaaEndpoint()).To(Equal("http://uaa.the-endpoint")) 83 84 config.SetAccessToken("the-token") 85 Expect(config.AccessToken()).To(Equal("the-token")) 86 87 config.SetUAAOAuthClient("cf-oauth-client-id") 88 Expect(config.UAAOAuthClient()).To(Equal("cf-oauth-client-id")) 89 90 config.SetUAAOAuthClientSecret("cf-oauth-client-secret") 91 Expect(config.UAAOAuthClientSecret()).To(Equal("cf-oauth-client-secret")) 92 93 config.SetSSHOAuthClient("oauth-client-id") 94 Expect(config.SSHOAuthClient()).To(Equal("oauth-client-id")) 95 96 config.SetDopplerEndpoint("doppler.the-endpoint") 97 Expect(config.DopplerEndpoint()).To(Equal("doppler.the-endpoint")) 98 99 config.SetLogCacheEndpoint("log-cache.the-endpoint") 100 Expect(config.LogCacheEndpoint()).To(Equal("log-cache.the-endpoint")) 101 102 config.SetRefreshToken("the-token") 103 Expect(config.RefreshToken()).To(Equal("the-token")) 104 105 organization := models.OrganizationFields{Name: "the-org"} 106 config.SetOrganizationFields(organization) 107 Expect(config.OrganizationFields()).To(Equal(organization)) 108 109 space := models.SpaceFields{Name: "the-space"} 110 config.SetSpaceFields(space) 111 Expect(config.SpaceFields()).To(Equal(space)) 112 113 config.SetSSLDisabled(false) 114 Expect(config.IsSSLDisabled()).To(BeFalse()) 115 116 config.SetLocale("en_US") 117 Expect(config.Locale()).To(Equal("en_US")) 118 119 config.SetPluginRepo(models.PluginRepo{Name: "repo", URL: "nowhere.com"}) 120 Expect(config.PluginRepos()[0].Name).To(Equal("repo")) 121 Expect(config.PluginRepos()[0].URL).To(Equal("nowhere.com")) 122 123 s, _ := semver.Make("3.1") 124 Expect(config.IsMinAPIVersion(s)).To(Equal(false)) 125 126 config.SetMinCLIVersion("6.5.0") 127 Expect(config.MinCLIVersion()).To(Equal("6.5.0")) 128 129 config.SetMinRecommendedCLIVersion("6.9.0") 130 Expect(config.MinRecommendedCLIVersion()).To(Equal("6.9.0")) 131 }) 132 133 Describe("APIEndpoint", func() { 134 It("sanitizes the target URL", func() { 135 config.SetAPIEndpoint("http://api.the-endpoint/") 136 Expect(config.APIEndpoint()).To(Equal("http://api.the-endpoint")) 137 }) 138 }) 139 140 Describe("HasAPIEndpoint", func() { 141 Context("when both endpoint and version are set", func() { 142 BeforeEach(func() { 143 config.SetAPIEndpoint("http://example.org") 144 config.SetAPIVersion("42.1.2.3") 145 }) 146 147 It("returns true", func() { 148 Expect(config.HasAPIEndpoint()).To(BeTrue()) 149 }) 150 }) 151 152 Context("when endpoint is not set", func() { 153 BeforeEach(func() { 154 config.SetAPIVersion("42.1.2.3") 155 }) 156 157 It("returns false", func() { 158 Expect(config.HasAPIEndpoint()).To(BeFalse()) 159 }) 160 }) 161 162 Context("when version is not set", func() { 163 BeforeEach(func() { 164 config.SetAPIEndpoint("http://example.org") 165 }) 166 167 It("returns false", func() { 168 Expect(config.HasAPIEndpoint()).To(BeFalse()) 169 }) 170 }) 171 }) 172 173 Describe("UserGUID", func() { 174 Context("with a valid user access token", func() { 175 BeforeEach(func() { 176 config.SetAccessToken(AccessTokenForHumanUsers) 177 }) 178 179 It("returns the guid", func() { 180 Expect(config.UserGUID()).To(Equal("9519be3e-44d9-40d0-ab9a-f4ace11df159")) 181 }) 182 }) 183 184 Context("with a valid client access token", func() { 185 BeforeEach(func() { 186 config.SetAccessToken(AccessTokenForClientUsers) 187 }) 188 189 It("returns an empty string", func() { 190 Expect(config.UserGUID()).To(BeEmpty()) 191 }) 192 }) 193 194 Context("with an invalid access token", func() { 195 BeforeEach(func() { 196 config.SetAccessToken(InvalidAccessToken) 197 }) 198 199 It("returns an empty string", func() { 200 Expect(config.UserGUID()).To(BeEmpty()) 201 }) 202 }) 203 204 Context("with an empty access token", func() { 205 BeforeEach(func() { 206 config.SetAccessToken("") 207 }) 208 209 It("returns an empty string", func() { 210 Expect(config.UserGUID()).To(BeEmpty()) 211 }) 212 }) 213 214 }) 215 216 Describe("Username", func() { 217 Context("with a valid user access token", func() { 218 BeforeEach(func() { 219 config.SetAccessToken(AccessTokenForHumanUsers) 220 }) 221 222 It("returns the username", func() { 223 Expect(config.Username()).To(Equal("admin")) 224 }) 225 }) 226 227 Context("with a valid client access token", func() { 228 BeforeEach(func() { 229 config.SetAccessToken(AccessTokenForClientUsers) 230 }) 231 232 It("returns the client id", func() { 233 Expect(config.Username()).To(Equal("potato-face")) 234 }) 235 }) 236 237 Context("with an invalid access token", func() { 238 BeforeEach(func() { 239 config.SetAccessToken(InvalidAccessToken) 240 }) 241 242 It("returns an empty string", func() { 243 Expect(config.Username()).To(BeEmpty()) 244 }) 245 }) 246 247 Context("with an empty access token", func() { 248 BeforeEach(func() { 249 config.SetAccessToken("") 250 }) 251 252 It("returns an empty string", func() { 253 Expect(config.Username()).To(BeEmpty()) 254 }) 255 }) 256 }) 257 258 Describe("UserEmail", func() { 259 Context("with a valid user access token", func() { 260 BeforeEach(func() { 261 config.SetAccessToken(AccessTokenForHumanUsers) 262 }) 263 264 It("returns the email", func() { 265 Expect(config.UserEmail()).To(Equal("admin")) 266 }) 267 }) 268 269 Context("with a valid client access token", func() { 270 BeforeEach(func() { 271 config.SetAccessToken(AccessTokenForClientUsers) 272 }) 273 274 It("returns an empty string", func() { 275 Expect(config.UserEmail()).To(BeEmpty()) 276 }) 277 }) 278 279 Context("with an invalid access token", func() { 280 BeforeEach(func() { 281 config.SetAccessToken(InvalidAccessToken) 282 }) 283 284 It("returns an empty string", func() { 285 Expect(config.UserEmail()).To(BeEmpty()) 286 }) 287 }) 288 289 Context("with an empty access token", func() { 290 BeforeEach(func() { 291 config.SetAccessToken("") 292 }) 293 294 It("returns an empty string", func() { 295 Expect(config.UserEmail()).To(BeEmpty()) 296 }) 297 }) 298 }) 299 300 Describe("NewRepositoryFromFilepath", func() { 301 var configPath string 302 303 It("returns nil repository if no error handler provided", func() { 304 config = coreconfig.NewRepositoryFromFilepath(configPath, nil) 305 Expect(config).To(BeNil()) 306 }) 307 308 Context("when the configuration file doesn't exist", func() { 309 var tmpDir string 310 311 BeforeEach(func() { 312 var err error 313 tmpDir, err = ioutil.TempDir("", "test-config") 314 if err != nil { 315 Fail("Couldn't create tmp file") 316 } 317 318 configPath = filepath.Join(tmpDir, ".cf", "config.json") 319 }) 320 321 AfterEach(func() { 322 Expect(os.RemoveAll(tmpDir)).ToNot(HaveOccurred()) 323 }) 324 325 It("has sane defaults when there is no config to read", func() { 326 config = coreconfig.NewRepositoryFromFilepath(configPath, func(err error) { 327 panic(err) 328 }) 329 330 Expect(config.APIEndpoint()).To(Equal("")) 331 Expect(config.APIVersion()).To(Equal("")) 332 Expect(config.AuthenticationEndpoint()).To(Equal("")) 333 Expect(config.AccessToken()).To(Equal("")) 334 }) 335 }) 336 337 Context("when the configuration version is older than the current version", func() { 338 BeforeEach(func() { 339 cwd, err := os.Getwd() 340 Expect(err).NotTo(HaveOccurred()) 341 configPath = filepath.Join(cwd, "..", "..", "..", "fixtures", "config", "outdated-config", ".cf", "config.json") 342 }) 343 344 It("returns a new empty config", func() { 345 config = coreconfig.NewRepositoryFromFilepath(configPath, func(err error) { 346 panic(err) 347 }) 348 349 Expect(config.APIEndpoint()).To(Equal("")) 350 }) 351 }) 352 }) 353 354 Describe("IsMinCLIVersion", func() { 355 It("returns true when the actual version is the default version string", func() { 356 Expect(config.IsMinCLIVersion(version.DefaultVersion)).To(BeTrue()) 357 }) 358 359 It("returns true when the MinCLIVersion is empty", func() { 360 config.SetMinCLIVersion("") 361 Expect(config.IsMinCLIVersion("1.2.3")).To(BeTrue()) 362 }) 363 364 It("returns false when the actual version is less than the MinCLIVersion", func() { 365 actualVersion := "1.2.3+abc123" 366 minCLIVersion := "1.2.4" 367 config.SetMinCLIVersion(minCLIVersion) 368 Expect(config.IsMinCLIVersion(actualVersion)).To(BeFalse()) 369 }) 370 371 It("returns true when the actual version is equal to the MinCLIVersion", func() { 372 actualVersion := "1.2.3+abc123" 373 minCLIVersion := "1.2.3" 374 config.SetMinCLIVersion(minCLIVersion) 375 Expect(config.IsMinCLIVersion(actualVersion)).To(BeTrue()) 376 }) 377 378 It("returns true when the actual version is greater than the MinCLIVersion", func() { 379 actualVersion := "1.2.3+abc123" 380 minCLIVersion := "1.2.2" 381 config.SetMinCLIVersion(minCLIVersion) 382 Expect(config.IsMinCLIVersion(actualVersion)).To(BeTrue()) 383 }) 384 }) 385 })