github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/util/manifestparser/application_test.go (about)

     1  package manifestparser_test
     2  
     3  import (
     4  	. "code.cloudfoundry.org/cli/util/manifestparser"
     5  	"gopkg.in/yaml.v2"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  )
    10  
    11  var _ = Describe("Application", func() {
    12  	Describe("Unmarshal", func() {
    13  		var (
    14  			emptyMap    map[string]interface{}
    15  			rawYAML     []byte
    16  			application Application
    17  			executeErr  error
    18  		)
    19  
    20  		BeforeEach(func() {
    21  			emptyMap = make(map[string]interface{})
    22  		})
    23  
    24  		JustBeforeEach(func() {
    25  			application = Application{}
    26  			executeErr = yaml.Unmarshal(rawYAML, &application)
    27  		})
    28  
    29  		Context("when a name is provided", func() {
    30  			BeforeEach(func() {
    31  				rawYAML = []byte(`---
    32  name: spark
    33  `)
    34  			})
    35  
    36  			It("unmarshals the name", func() {
    37  				Expect(executeErr).ToNot(HaveOccurred())
    38  				Expect(application.Name).To(Equal("spark"))
    39  			})
    40  		})
    41  
    42  		When("a disk quota is provided", func() {
    43  			When("it has a hyphen (`disk-quota`)", func() {
    44  				BeforeEach(func() {
    45  					rawYAML = []byte(`---
    46  disk-quota: 5G
    47  `)
    48  				})
    49  
    50  				It("unmarshals the disk quota", func() {
    51  					Expect(executeErr).ToNot(HaveOccurred())
    52  					Expect(application.DiskQuota).To(Equal("5G"))
    53  				})
    54  			})
    55  			When("it has an underscore (`disk_quota`)", func() {
    56  				BeforeEach(func() {
    57  					rawYAML = []byte(`---
    58  disk_quota: 5G
    59  `)
    60  				})
    61  
    62  				It("unmarshals the disk quota because we maintain backwards-compatibility with the old style", func() {
    63  					Expect(executeErr).ToNot(HaveOccurred())
    64  					Expect(application.DiskQuota).To(Equal("5G"))
    65  				})
    66  				It("doesn't leave a second version of `disk_quota` in the remaining manifest fields", func() {
    67  					Expect(application.RemainingManifestFields["disk_quota"]).To(BeNil())
    68  				})
    69  			})
    70  			When("it has an underscore but it isn't a string", func() {
    71  				BeforeEach(func() {
    72  					rawYAML = []byte(`---
    73  disk_quota: [1]
    74  `)
    75  				})
    76  
    77  				It("returns an error", func() {
    78  					Expect(executeErr).To(MatchError("`disk_quota` must be a string"))
    79  				})
    80  			})
    81  			When("both underscore and hyphen versions are present", func() {
    82  				BeforeEach(func() {
    83  					rawYAML = []byte(`---
    84  disk_quota: 5G
    85  disk-quota: 6G
    86  `)
    87  				})
    88  
    89  				It("returns an error", func() {
    90  					Expect(executeErr).To(MatchError("cannot define both `disk_quota` and `disk-quota`"))
    91  				})
    92  			})
    93  		})
    94  
    95  		Context("when default-route is provided", func() {
    96  			BeforeEach(func() {
    97  				rawYAML = []byte(`---
    98  default-route: true
    99  `)
   100  			})
   101  
   102  			It("unmarshals the name", func() {
   103  				Expect(executeErr).ToNot(HaveOccurred())
   104  				Expect(application.DefaultRoute).To(BeTrue())
   105  			})
   106  		})
   107  
   108  		Context("when a path is provided", func() {
   109  			BeforeEach(func() {
   110  				rawYAML = []byte(`---
   111  path: /my/path
   112  `)
   113  			})
   114  
   115  			It("unmarshals the path", func() {
   116  				Expect(executeErr).ToNot(HaveOccurred())
   117  				Expect(application.Path).To(Equal("/my/path"))
   118  			})
   119  		})
   120  
   121  		Context("when a docker map is provided", func() {
   122  			BeforeEach(func() {
   123  				rawYAML = []byte(`---
   124  docker:
   125    image: some-image
   126    username: some-username
   127  `)
   128  			})
   129  
   130  			It("unmarshals the docker properties", func() {
   131  				Expect(executeErr).ToNot(HaveOccurred())
   132  				Expect(application.Docker.Image).To(Equal("some-image"))
   133  				Expect(application.Docker.Username).To(Equal("some-username"))
   134  			})
   135  		})
   136  
   137  		Context("when no-route is provided", func() {
   138  			BeforeEach(func() {
   139  				rawYAML = []byte(`---
   140  no-route: true
   141  `)
   142  			})
   143  
   144  			It("unmarshals the no-route property", func() {
   145  				Expect(executeErr).ToNot(HaveOccurred())
   146  				Expect(application.NoRoute).To(BeTrue())
   147  			})
   148  		})
   149  
   150  		Context("when random-route is provided", func() {
   151  			BeforeEach(func() {
   152  				rawYAML = []byte(`---
   153  random-route: true
   154  `)
   155  			})
   156  
   157  			It("unmarshals the random-route property", func() {
   158  				Expect(executeErr).ToNot(HaveOccurred())
   159  				Expect(application.RandomRoute).To(BeTrue())
   160  			})
   161  		})
   162  
   163  		Context("when buildpacks is provided", func() {
   164  			BeforeEach(func() {
   165  				rawYAML = []byte(`---
   166  buildpacks:
   167  - ruby_buildpack
   168  - java_buildpack
   169  `)
   170  			})
   171  
   172  			It("unmarshals the buildpacks property", func() {
   173  				Expect(executeErr).ToNot(HaveOccurred())
   174  				Expect(application.RemainingManifestFields["buildpacks"]).To(ConsistOf("ruby_buildpack", "java_buildpack"))
   175  			})
   176  		})
   177  
   178  		Context("when stack is provided", func() {
   179  			BeforeEach(func() {
   180  				rawYAML = []byte(`---
   181  stack: cflinuxfs3
   182  `)
   183  			})
   184  
   185  			It("unmarshals the stack property", func() {
   186  				Expect(executeErr).ToNot(HaveOccurred())
   187  				Expect(application.Stack).To(Equal("cflinuxfs3"))
   188  			})
   189  		})
   190  
   191  		Context("when an unknown field is provided", func() {
   192  			BeforeEach(func() {
   193  				rawYAML = []byte(`---
   194  unknown-key: 2
   195  `)
   196  			})
   197  
   198  			It("unmarshals the unknown field to a map", func() {
   199  				Expect(executeErr).ToNot(HaveOccurred())
   200  
   201  				mapVal, ok := application.RemainingManifestFields["unknown-key"]
   202  				Expect(ok).To(BeTrue())
   203  
   204  				mapValAsInt, ok := mapVal.(int)
   205  				Expect(ok).To(BeTrue())
   206  
   207  				Expect(mapValAsInt).To(Equal(2))
   208  			})
   209  		})
   210  
   211  		Context("when Processes are provided", func() {
   212  			BeforeEach(func() {
   213  				rawYAML = []byte(`---
   214  processes: []
   215  `)
   216  			})
   217  
   218  			It("unmarshals the processes property", func() {
   219  				Expect(executeErr).ToNot(HaveOccurred())
   220  				Expect(application.Processes).To(Equal([]Process{}))
   221  			})
   222  		})
   223  
   224  		Context("process-level configuration", func() {
   225  			Context("the Type command is always provided", func() {
   226  				BeforeEach(func() {
   227  					rawYAML = []byte(`---
   228  processes:
   229  - type: web
   230  `)
   231  				})
   232  
   233  				It("unmarshals the processes property with the type", func() {
   234  					Expect(executeErr).ToNot(HaveOccurred())
   235  					Expect(application.Processes).To(Equal([]Process{
   236  						{Type: "web", RemainingManifestFields: emptyMap},
   237  					}))
   238  				})
   239  			})
   240  
   241  			Context("when the start command is provided", func() {
   242  				BeforeEach(func() {
   243  					rawYAML = []byte(`---
   244  processes:
   245  - command: /bin/python
   246  `)
   247  				})
   248  
   249  				It("unmarshals the processes property with the start command", func() {
   250  					Expect(executeErr).ToNot(HaveOccurred())
   251  					Expect(application.Processes[0].RemainingManifestFields["command"]).To(Equal("/bin/python"))
   252  				})
   253  			})
   254  
   255  			Context("when a disk quota is provided", func() {
   256  				BeforeEach(func() {
   257  					rawYAML = []byte(`---
   258  processes:
   259  - disk_quota: 5GB
   260  `)
   261  				})
   262  
   263  				It("unmarshals the processes property with the disk quota", func() {
   264  					Expect(executeErr).ToNot(HaveOccurred())
   265  					Expect(application.Processes).To(Equal([]Process{
   266  						{DiskQuota: "5GB", RemainingManifestFields: emptyMap},
   267  					}))
   268  				})
   269  			})
   270  
   271  			Context("when a health check endpoint is provided", func() {
   272  				BeforeEach(func() {
   273  					rawYAML = []byte(`---
   274  processes:
   275  - health-check-http-endpoint: https://localhost
   276  `)
   277  				})
   278  
   279  				It("unmarshals the processes property with the health check endpoint", func() {
   280  					Expect(executeErr).ToNot(HaveOccurred())
   281  					Expect(application.Processes).To(Equal([]Process{
   282  						{HealthCheckEndpoint: "https://localhost", RemainingManifestFields: emptyMap},
   283  					}))
   284  				})
   285  			})
   286  
   287  			Context("when a health check timeout is provided", func() {
   288  				BeforeEach(func() {
   289  					rawYAML = []byte(`---
   290  processes:
   291  - timeout: 42
   292  `)
   293  				})
   294  
   295  				It("unmarshals the processes property with the health check endpoint", func() {
   296  					Expect(executeErr).ToNot(HaveOccurred())
   297  					Expect(application.Processes).To(Equal([]Process{
   298  						{HealthCheckTimeout: 42, RemainingManifestFields: emptyMap},
   299  					}))
   300  				})
   301  			})
   302  
   303  			Context("when a health check type is provided", func() {
   304  				BeforeEach(func() {
   305  					rawYAML = []byte(`---
   306  processes:
   307  - health-check-type: http
   308  `)
   309  				})
   310  
   311  				It("unmarshals the processes property with the health check type", func() {
   312  					Expect(executeErr).ToNot(HaveOccurred())
   313  					Expect(application.Processes).To(Equal([]Process{
   314  						{HealthCheckType: "http", RemainingManifestFields: emptyMap},
   315  					}))
   316  				})
   317  			})
   318  
   319  			Context("when a memory limit is provided", func() {
   320  				BeforeEach(func() {
   321  					rawYAML = []byte(`---
   322  processes:
   323  - memory: 512M
   324  `)
   325  				})
   326  
   327  				It("unmarshals the processes property with the memory limit", func() {
   328  					Expect(executeErr).ToNot(HaveOccurred())
   329  					Expect(application.Processes).To(Equal([]Process{
   330  						{Memory: "512M", RemainingManifestFields: emptyMap},
   331  					}))
   332  				})
   333  			})
   334  
   335  			Context("when instances are provided", func() {
   336  				BeforeEach(func() {
   337  					rawYAML = []byte(`---
   338  processes:
   339  - instances: 4
   340  `)
   341  				})
   342  
   343  				It("unmarshals the processes property with instances", func() {
   344  					a := 4
   345  					Expect(executeErr).ToNot(HaveOccurred())
   346  					Expect(application.Processes).To(Equal([]Process{
   347  						{Instances: &a, RemainingManifestFields: emptyMap},
   348  					}))
   349  				})
   350  			})
   351  
   352  			Context("when a log rate limit is provided", func() {
   353  				BeforeEach(func() {
   354  					rawYAML = []byte(`---
   355  processes:
   356  - log-rate-limit-per-second: 512M
   357  `)
   358  				})
   359  
   360  				It("unmarshals the processes property with the log rate limit", func() {
   361  					Expect(executeErr).ToNot(HaveOccurred())
   362  					Expect(application.Processes).To(Equal([]Process{
   363  						{LogRateLimit: "512M", RemainingManifestFields: emptyMap},
   364  					}))
   365  				})
   366  			})
   367  
   368  			Context("when an unknown field is provided", func() {
   369  				BeforeEach(func() {
   370  					rawYAML = []byte(`---
   371  processes:
   372  - unknown-key: 2
   373  `)
   374  				})
   375  
   376  				It("unmarshals the unknown field to a map", func() {
   377  					Expect(executeErr).ToNot(HaveOccurred())
   378  
   379  					mapVal, ok := application.Processes[0].RemainingManifestFields["unknown-key"]
   380  					Expect(ok).To(BeTrue())
   381  
   382  					mapValAsInt, ok := mapVal.(int)
   383  					Expect(ok).To(BeTrue())
   384  
   385  					Expect(mapValAsInt).To(Equal(2))
   386  				})
   387  			})
   388  		})
   389  
   390  		Context("marshalling & unmarshalling fields with special-cased empty values", func() {
   391  			BeforeEach(func() {
   392  				rawYAML = []byte(`---
   393  name: ""
   394  command: null
   395  buildpacks: []
   396  processes:
   397  - type: web
   398    command: null
   399  `)
   400  			})
   401  
   402  			It("preserves the values as-written", func() {
   403  				Expect(executeErr).NotTo(HaveOccurred())
   404  
   405  				remarshalledYaml, err := yaml.Marshal(&application)
   406  				Expect(err).NotTo(HaveOccurred())
   407  
   408  				Expect(remarshalledYaml).To(MatchYAML(rawYAML))
   409  			})
   410  		})
   411  
   412  		Context("when a log rate limit is provided", func() {
   413  			BeforeEach(func() {
   414  				rawYAML = []byte(`---
   415  log-rate-limit-per-second: 5K
   416  `)
   417  			})
   418  
   419  			It("unmarshals the log rate limit", func() {
   420  				Expect(executeErr).ToNot(HaveOccurred())
   421  				Expect(application.LogRateLimit).To(Equal("5K"))
   422  			})
   423  		})
   424  	})
   425  
   426  	Describe("SetStartCommand", func() {
   427  		var (
   428  			app     Application
   429  			command string
   430  		)
   431  
   432  		BeforeEach(func() {
   433  			app = Application{}
   434  			command = "./start.sh"
   435  		})
   436  
   437  		JustBeforeEach(func() {
   438  			app.SetStartCommand(command)
   439  		})
   440  
   441  		When("the remaining fields map exists", func() {
   442  			BeforeEach(func() {
   443  				app.RemainingManifestFields = map[string]interface{}{}
   444  			})
   445  
   446  			It("sets the start command in the map", func() {
   447  				Expect(app.RemainingManifestFields["command"]).To(Equal("./start.sh"))
   448  			})
   449  
   450  			When("the command is nil", func() {
   451  				BeforeEach(func() {
   452  					command = ""
   453  				})
   454  
   455  				It("sets the start command to nil in the map", func() {
   456  					Expect(app.RemainingManifestFields["command"]).To(BeNil())
   457  				})
   458  			})
   459  		})
   460  
   461  		When("the remaining fields map does not exist", func() {
   462  			It("sets the start command in the map", func() {
   463  				Expect(app.RemainingManifestFields["command"]).To(Equal("./start.sh"))
   464  			})
   465  		})
   466  	})
   467  
   468  	Describe("SetBuildpacks", func() {
   469  		var (
   470  			app        Application
   471  			buildpacks []string
   472  		)
   473  
   474  		BeforeEach(func() {
   475  			app = Application{}
   476  			buildpacks = []string{"bp1", "bp2"}
   477  		})
   478  
   479  		JustBeforeEach(func() {
   480  			app.SetBuildpacks(buildpacks)
   481  		})
   482  
   483  		When("the remaining fields map exists", func() {
   484  			BeforeEach(func() {
   485  				app.RemainingManifestFields = map[string]interface{}{}
   486  			})
   487  
   488  			It("sets the buildpacks in the map", func() {
   489  				Expect(app.RemainingManifestFields["buildpacks"]).To(ConsistOf("bp1", "bp2"))
   490  			})
   491  
   492  			When("buildpacks is empty", func() {
   493  				BeforeEach(func() {
   494  					buildpacks = []string{}
   495  				})
   496  
   497  				It("sets the buildpacks to empty in the map", func() {
   498  					Expect(app.RemainingManifestFields["buildpacks"]).To(BeEmpty())
   499  				})
   500  			})
   501  		})
   502  
   503  		When("the remaining fields map does not exist", func() {
   504  			It("sets the buildpacks in the map", func() {
   505  				Expect(app.RemainingManifestFields["buildpacks"]).To(ConsistOf("bp1", "bp2"))
   506  			})
   507  		})
   508  	})
   509  
   510  	Describe("HasBuildpacks", func() {
   511  		var (
   512  			app        Application
   513  			buildpacks []string
   514  		)
   515  
   516  		When("the app has buildpacks", func() {
   517  			BeforeEach(func() {
   518  				buildpacks = []string{"bp1", "bp2"}
   519  				app = Application{RemainingManifestFields: map[string]interface{}{"buildpacks": buildpacks}}
   520  			})
   521  
   522  			It("returns true", func() {
   523  				Expect(app.HasBuildpacks()).To(BeTrue())
   524  			})
   525  		})
   526  
   527  		When("the app does not have buildpacks", func() {
   528  			BeforeEach(func() {
   529  				app = Application{}
   530  			})
   531  
   532  			It("returns false", func() {
   533  				Expect(app.HasBuildpacks()).To(BeFalse())
   534  			})
   535  		})
   536  	})
   537  })