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  })