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