github.com/chenbh/concourse/v6@v6.4.2/atc/task_test.go (about)

     1  package atc_test
     2  
     3  import (
     4  	"github.com/chenbh/concourse/v6/atc"
     5  	. "github.com/chenbh/concourse/v6/atc"
     6  
     7  	. "github.com/onsi/ginkgo"
     8  	. "github.com/onsi/gomega"
     9  )
    10  
    11  var _ = Describe("TaskConfig", func() {
    12  	Describe("validating", func() {
    13  		var (
    14  			invalidConfig TaskConfig
    15  			validConfig   TaskConfig
    16  		)
    17  
    18  		BeforeEach(func() {
    19  			validConfig = TaskConfig{
    20  				Platform: "linux",
    21  				Run: TaskRunConfig{
    22  					Path: "reboot",
    23  				},
    24  			}
    25  
    26  			invalidConfig = validConfig
    27  		})
    28  
    29  		Describe("decode task yaml", func() {
    30  			Context("given a valid task config", func() {
    31  				It("works", func() {
    32  					data := []byte(`
    33  platform: beos
    34  
    35  inputs: []
    36  
    37  run: {path: a/file}
    38  `)
    39  					task, err := NewTaskConfig(data)
    40  					Expect(err).ToNot(HaveOccurred())
    41  					Expect(task.Platform).To(Equal("beos"))
    42  					Expect(task.Run.Path).To(Equal("a/file"))
    43  				})
    44  
    45  				It("converts yaml booleans to strings in params", func() {
    46  					data := []byte(`
    47  platform: beos
    48  
    49  params:
    50    testParam: true
    51  
    52  run: {path: a/file}
    53  `)
    54  					config, err := NewTaskConfig(data)
    55  					Expect(err).ToNot(HaveOccurred())
    56  					Expect(config.Params["testParam"]).To(Equal("true"))
    57  				})
    58  
    59  				It("converts yaml ints to the correct string in params", func() {
    60  					data := []byte(`
    61  platform: beos
    62  
    63  params:
    64    testParam: 1059262
    65  
    66  run: {path: a/file}
    67  `)
    68  					config, err := NewTaskConfig(data)
    69  					Expect(err).ToNot(HaveOccurred())
    70  					Expect(config.Params["testParam"]).To(Equal("1059262"))
    71  				})
    72  
    73  				It("converts large yaml ints to the correct string in params", func() {
    74  					data := []byte(`
    75  platform: beos
    76  
    77  params:
    78    testParam: 18446744073709551615
    79  
    80  run: {path: a/file}
    81  `)
    82  					config, err := NewTaskConfig(data)
    83  					Expect(err).ToNot(HaveOccurred())
    84  					Expect(config.Params["testParam"]).To(Equal("18446744073709551615"))
    85  				})
    86  
    87  				It("does not preserve unquoted float notation", func() {
    88  					data := []byte(`
    89  platform: beos
    90  
    91  params:
    92    testParam: 1.8446744e+19
    93  
    94  run: {path: a/file}
    95  `)
    96  					config, err := NewTaskConfig(data)
    97  					Expect(err).ToNot(HaveOccurred())
    98  					Expect(config.Params["testParam"]).To(Equal("18446744000000000000"))
    99  				})
   100  
   101  				It("(obviously) preserves quoted float notation", func() {
   102  					data := []byte(`
   103  platform: beos
   104  
   105  params:
   106    testParam: "1.8446744e+19"
   107  
   108  run: {path: a/file}
   109  `)
   110  					config, err := NewTaskConfig(data)
   111  					Expect(err).ToNot(HaveOccurred())
   112  					Expect(config.Params["testParam"]).To(Equal("1.8446744e+19"))
   113  				})
   114  
   115  				It("converts yaml floats to the correct string in params", func() {
   116  					data := []byte(`
   117  platform: beos
   118  
   119  params:
   120    testParam: 1059262.123123123
   121  
   122  run: {path: a/file}
   123  `)
   124  					config, err := NewTaskConfig(data)
   125  					Expect(err).ToNot(HaveOccurred())
   126  					Expect(config.Params["testParam"]).To(Equal("1059262.123123123"))
   127  				})
   128  
   129  				It("converts maps to json in params", func() {
   130  					data := []byte(`
   131  platform: beos
   132  
   133  params:
   134    testParam:
   135      foo: bar
   136  
   137  run: {path: a/file}
   138  `)
   139  					config, err := NewTaskConfig(data)
   140  					Expect(err).ToNot(HaveOccurred())
   141  					Expect(config.Params["testParam"]).To(Equal(`{"foo":"bar"}`))
   142  				})
   143  
   144  				It("converts empty values to empty string in params", func() {
   145  					data := []byte(`
   146  platform: beos
   147  
   148  params:
   149    testParam:
   150  
   151  run: {path: a/file}
   152  `)
   153  					config, err := NewTaskConfig(data)
   154  					Expect(err).ToNot(HaveOccurred())
   155  					Expect(config.Params["testParam"]).To(Equal(""))
   156  				})
   157  			})
   158  
   159  			Context("given a valid task config with numeric params", func() {
   160  				It("works", func() {
   161  					data := []byte(`
   162  platform: beos
   163  
   164  params:
   165    FOO: 1
   166  
   167  run: {path: a/file}
   168  `)
   169  					task, err := NewTaskConfig(data)
   170  					Expect(err).ToNot(HaveOccurred())
   171  					Expect(task.Platform).To(Equal("beos"))
   172  					Expect(task.Params).To(Equal(atc.TaskEnv{"FOO": "1"}))
   173  				})
   174  			})
   175  
   176  			Context("given a valid task config with extra keys", func() {
   177  				It("returns an error", func() {
   178  					data := []byte(`
   179  platform: beos
   180  
   181  intputs: []
   182  
   183  run: {path: a/file}
   184  `)
   185  					_, err := NewTaskConfig(data)
   186  					Expect(err).To(HaveOccurred())
   187  				})
   188  			})
   189  
   190  			Context("given an invalid task config", func() {
   191  				It("errors on validation", func() {
   192  					data := []byte(`
   193  platform: beos
   194  
   195  inputs: ['a/b/c']
   196  outputs: ['a/b/c']
   197  
   198  run: {path: a/file}
   199  `)
   200  					_, err := NewTaskConfig(data)
   201  					Expect(err).To(HaveOccurred())
   202  				})
   203  			})
   204  		})
   205  
   206  		Context("when platform is missing", func() {
   207  			BeforeEach(func() {
   208  				invalidConfig.Platform = ""
   209  			})
   210  
   211  			It("returns an error", func() {
   212  				Expect(invalidConfig.Validate()).To(MatchError(ContainSubstring("missing 'platform'")))
   213  			})
   214  		})
   215  
   216  		Context("when container limits are specified", func() {
   217  			Context("when memory and cpu limits are correctly specified", func() {
   218  				It("successfully parses the limits with memory units", func() {
   219  					data := []byte(`
   220  platform: beos
   221  container_limits: { cpu: 1024, memory: 1KB }
   222  
   223  run: {path: a/file}
   224  `)
   225  					task, err := NewTaskConfig(data)
   226  					Expect(err).ToNot(HaveOccurred())
   227  					cpu := uint64(1024)
   228  					memory := uint64(1024)
   229  					Expect(task.Limits).To(Equal(&ContainerLimits{
   230  						CPU:    &cpu,
   231  						Memory: &memory,
   232  					}))
   233  				})
   234  
   235  				It("successfully parses the limits without memory units", func() {
   236  					data := []byte(`
   237  platform: beos
   238  container_limits: { cpu: 1024, memory: 209715200 }
   239  
   240  run: {path: a/file}
   241  `)
   242  					task, err := NewTaskConfig(data)
   243  					Expect(err).ToNot(HaveOccurred())
   244  					cpu := uint64(1024)
   245  					memory := uint64(209715200)
   246  					Expect(task.Limits).To(Equal(&ContainerLimits{
   247  						CPU:    &cpu,
   248  						Memory: &memory,
   249  					}))
   250  				})
   251  			})
   252  
   253  			Context("when either one of memory or cpu is correctly specified", func() {
   254  				It("parses the provided memory limit without any errors", func() {
   255  					data := []byte(`
   256  platform: beos
   257  container_limits: { memory: 1KB }
   258  
   259  run: {path: a/file}
   260  `)
   261  					task, err := NewTaskConfig(data)
   262  					Expect(err).ToNot(HaveOccurred())
   263  					memory := uint64(1024)
   264  					Expect(task.Limits).To(Equal(&ContainerLimits{
   265  						Memory: &memory,
   266  					}))
   267  				})
   268  
   269  				It("parses the provided cpu limit without any errors", func() {
   270  					data := []byte(`
   271  platform: beos
   272  container_limits: { cpu: 355 }
   273  
   274  run: {path: a/file}
   275  `)
   276  					task, err := NewTaskConfig(data)
   277  					Expect(err).ToNot(HaveOccurred())
   278  					cpu := uint64(355)
   279  					Expect(task.Limits).To(Equal(&ContainerLimits{
   280  						CPU: &cpu,
   281  					}))
   282  				})
   283  			})
   284  
   285  			Context("when invalid memory limit value is provided", func() {
   286  				It("throws an error and does not continue", func() {
   287  					data := []byte(`
   288  platform: beos
   289  container_limits: { cpu: 1024, memory: abc1000kb  }
   290  
   291  run: {path: a/file}
   292  `)
   293  					_, err := NewTaskConfig(data)
   294  					Expect(err).To(MatchError(ContainSubstring("could not parse container memory limit")))
   295  				})
   296  
   297  			})
   298  
   299  			Context("when invalid cpu limit value is provided", func() {
   300  				It("throws an error and does not continue", func() {
   301  					data := []byte(`
   302  platform: beos
   303  container_limits: { cpu: str1ng-cpu-l1mit, memory: 20MB}
   304  
   305  run: {path: a/file}
   306  `)
   307  					_, err := NewTaskConfig(data)
   308  					Expect(err).To(MatchError(ContainSubstring("cpu limit must be an integer")))
   309  				})
   310  			})
   311  		})
   312  
   313  		Context("when the task has inputs", func() {
   314  			BeforeEach(func() {
   315  				validConfig.Inputs = append(validConfig.Inputs, TaskInputConfig{Name: "concourse"})
   316  			})
   317  
   318  			It("is valid", func() {
   319  				Expect(validConfig.Validate()).ToNot(HaveOccurred())
   320  			})
   321  
   322  			Context("when input.name is missing", func() {
   323  				BeforeEach(func() {
   324  					invalidConfig.Inputs = append(invalidConfig.Inputs, TaskInputConfig{Name: "concourse"}, TaskInputConfig{Name: ""})
   325  				})
   326  
   327  				It("returns an error", func() {
   328  					Expect(invalidConfig.Validate()).To(MatchError(ContainSubstring("input in position 1 is missing a name")))
   329  				})
   330  			})
   331  
   332  			Context("when input.name is missing multiple times", func() {
   333  				BeforeEach(func() {
   334  					invalidConfig.Inputs = append(
   335  						invalidConfig.Inputs,
   336  						TaskInputConfig{Name: "concourse"},
   337  						TaskInputConfig{Name: ""},
   338  						TaskInputConfig{Name: ""},
   339  					)
   340  				})
   341  
   342  				It("returns an error", func() {
   343  					err := invalidConfig.Validate()
   344  
   345  					Expect(err).To(MatchError(ContainSubstring("input in position 1 is missing a name")))
   346  					Expect(err).To(MatchError(ContainSubstring("input in position 2 is missing a name")))
   347  				})
   348  			})
   349  		})
   350  
   351  		Context("when the task has outputs", func() {
   352  			BeforeEach(func() {
   353  				validConfig.Outputs = append(validConfig.Outputs, TaskOutputConfig{Name: "concourse"})
   354  			})
   355  
   356  			It("is valid", func() {
   357  				Expect(validConfig.Validate()).ToNot(HaveOccurred())
   358  			})
   359  
   360  			Context("when output.name is missing", func() {
   361  				BeforeEach(func() {
   362  					invalidConfig.Outputs = append(invalidConfig.Outputs, TaskOutputConfig{Name: "concourse"}, TaskOutputConfig{Name: ""})
   363  				})
   364  
   365  				It("returns an error", func() {
   366  					Expect(invalidConfig.Validate()).To(MatchError(ContainSubstring("output in position 1 is missing a name")))
   367  				})
   368  			})
   369  
   370  			Context("when output.name is missing multiple times", func() {
   371  				BeforeEach(func() {
   372  					invalidConfig.Outputs = append(
   373  						invalidConfig.Outputs,
   374  						TaskOutputConfig{Name: "concourse"},
   375  						TaskOutputConfig{Name: ""},
   376  						TaskOutputConfig{Name: ""},
   377  					)
   378  				})
   379  
   380  				It("returns an error", func() {
   381  					err := invalidConfig.Validate()
   382  
   383  					Expect(err).To(MatchError(ContainSubstring("output in position 1 is missing a name")))
   384  					Expect(err).To(MatchError(ContainSubstring("output in position 2 is missing a name")))
   385  				})
   386  			})
   387  		})
   388  
   389  		Context("when run is missing", func() {
   390  			BeforeEach(func() {
   391  				invalidConfig.Run.Path = ""
   392  			})
   393  
   394  			It("returns an error", func() {
   395  				Expect(invalidConfig.Validate()).To(MatchError(ContainSubstring("missing path to executable to run")))
   396  			})
   397  		})
   398  
   399  	})
   400  
   401  })