gitlab_ci_yaml_processor_spec.rb 45.8 KB
Newer Older
1 2
require 'spec_helper'

Valery Sizov's avatar
Valery Sizov committed
3
module Ci
Douwe Maan's avatar
Douwe Maan committed
4
  describe GitlabCiYamlProcessor, lib: true do
5
    let(:path) { 'path' }
6

Valery Sizov's avatar
Valery Sizov committed
7 8 9 10 11 12 13 14 15
    describe "#builds_for_ref" do
      let(:type) { 'test' }

      it "returns builds if no branch specified" do
        config = YAML.dump({
          before_script: ["pwd"],
          rspec: { script: "rspec" }
        })

16
        config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
17 18 19 20

        expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref(type, "master").first).to eq({
          stage: "test",
21
          stage_idx: 1,
Valery Sizov's avatar
Valery Sizov committed
22 23 24
          except: nil,
          name: :rspec,
          only: nil,
Kamil Trzcinski's avatar
Kamil Trzcinski committed
25 26
          commands: "pwd\nrspec",
          tag_list: [],
Valery Sizov's avatar
Valery Sizov committed
27
          options: {},
Kamil Trzcinski's avatar
Kamil Trzcinski committed
28
          allow_failure: false,
29 30
          when: "on_success",
          environment: nil,
Valery Sizov's avatar
Valery Sizov committed
31 32
        })
      end
33

34 35 36 37 38 39
      describe :only do
        it "does not return builds if only has another branch" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", only: ["deploy"] }
                             })
Valery Sizov's avatar
Valery Sizov committed
40

41
          config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
42

43 44
          expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
        end
Valery Sizov's avatar
Valery Sizov committed
45

46 47 48 49 50
        it "does not return builds if only has regexp with another branch" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", only: ["/^deploy$/"] }
                             })
Valery Sizov's avatar
Valery Sizov committed
51

52
          config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
53

54 55
          expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
        end
Valery Sizov's avatar
Valery Sizov committed
56

57 58 59 60 61
        it "returns builds if only has specified this branch" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", only: ["master"] }
                             })
Valery Sizov's avatar
Valery Sizov committed
62

63
          config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
64

65 66
          expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
        end
Valery Sizov's avatar
Valery Sizov committed
67

68 69 70 71 72
        it "returns builds if only has a list of branches including specified" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["master", "deploy"] }
                             })
Valery Sizov's avatar
Valery Sizov committed
73

74
          config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
75

76 77
          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
        end
Valery Sizov's avatar
Valery Sizov committed
78

79 80 81 82 83
        it "returns builds if only has a branches keyword specified" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["branches"] }
                             })
Valery Sizov's avatar
Valery Sizov committed
84

85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
        end

        it "does not return builds if only has a tags keyword" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["tags"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
        end

101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
        it "returns builds if only has a triggers keyword specified and a trigger is provided" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["triggers"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(1)
        end

        it "does not return builds if only has a triggers keyword specified and no trigger is provided" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["triggers"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
        end

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
        it "returns builds if only has current repository path" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["branches@path"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
        end

        it "does not return builds if only has different repository path" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, only: ["branches@fork"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
        end

        it "returns build only for specified type" do
          config = YAML.dump({
                               before_script: ["pwd"],
Kamil Trzcinski's avatar
Kamil Trzcinski committed
148
                               rspec: { script: "rspec", type: "test", only: ["master", "deploy"] },
149 150 151
                               staging: { script: "deploy", type: "deploy", only: ["master", "deploy"] },
                               production: { script: "deploy", type: "deploy", only: ["master@path", "deploy"] },
                             })
Valery Sizov's avatar
Valery Sizov committed
152

Kamil Trzcinski's avatar
Kamil Trzcinski committed
153
          config_processor = GitlabCiYamlProcessor.new(config, 'fork')
Valery Sizov's avatar
Valery Sizov committed
154

155
          expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2)
Kamil Trzcinski's avatar
Kamil Trzcinski committed
156 157
          expect(config_processor.builds_for_stage_and_ref("test", "deploy").size).to eq(1)
          expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(1)
158
        end
159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187

        context 'for invalid value' do
          let(:config) { { rspec: { script: "rspec", type: "test", only: only } } }
          let(:processor) { GitlabCiYamlProcessor.new(YAML.dump(config)) }

          shared_examples 'raises an error' do
            it do
              expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, 'rspec job: only parameter should be an array of strings or regexps')
            end
          end

          context 'when it is integer' do
            let(:only) { 1 }

            it_behaves_like 'raises an error'
          end

          context 'when it is an array of integers' do
            let(:only) { [1, 1] }

            it_behaves_like 'raises an error'
          end

          context 'when it is invalid regex' do
            let(:only) { ["/*invalid/"] }

            it_behaves_like 'raises an error'
          end
        end
Valery Sizov's avatar
Valery Sizov committed
188 189
      end

190 191 192 193 194 195
      describe :except do
        it "returns builds if except has another branch" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", except: ["deploy"] }
                             })
Valery Sizov's avatar
Valery Sizov committed
196

197
          config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
198

199 200 201 202 203 204 205 206 207 208 209 210 211
          expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
        end

        it "returns builds if except has regexp with another branch" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", except: ["/^deploy$/"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(1)
        end
Valery Sizov's avatar
Valery Sizov committed
212

213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
        it "does not return builds if except has specified this branch" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", except: ["master"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "master").size).to eq(0)
        end

        it "does not return builds if except has a list of branches including specified" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["master", "deploy"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
        end

        it "does not return builds if except has a branches keyword specified" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["branches"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
        end

        it "returns builds if except has a tags keyword" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["tags"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
        end

257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
        it "does not return builds if except has a triggers keyword specified and a trigger is provided" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["triggers"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy", false, true).size).to eq(0)
        end

        it "returns builds if except has a triggers keyword specified and no trigger is provided" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["triggers"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
        end

279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
        it "does not return builds if except has current repository path" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["branches@path"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(0)
        end

        it "returns builds if except has different repository path" do
          config = YAML.dump({
                               before_script: ["pwd"],
                               rspec: { script: "rspec", type: type, except: ["branches@fork"] }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)

          expect(config_processor.builds_for_stage_and_ref(type, "deploy").size).to eq(1)
        end

        it "returns build except specified type" do
          config = YAML.dump({
                               before_script: ["pwd"],
Kamil Trzcinski's avatar
Kamil Trzcinski committed
304 305 306
                               rspec: { script: "rspec", type: "test", except: ["master", "deploy", "test@fork"] },
                               staging: { script: "deploy", type: "deploy", except: ["master"] },
                               production: { script: "deploy", type: "deploy", except: ["master@fork"] },
307 308
                             })

Kamil Trzcinski's avatar
Kamil Trzcinski committed
309
          config_processor = GitlabCiYamlProcessor.new(config, 'fork')
310

Kamil Trzcinski's avatar
Kamil Trzcinski committed
311 312 313
          expect(config_processor.builds_for_stage_and_ref("deploy", "deploy").size).to eq(2)
          expect(config_processor.builds_for_stage_and_ref("test", "test").size).to eq(0)
          expect(config_processor.builds_for_stage_and_ref("deploy", "master").size).to eq(0)
314 315
        end

316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
        context 'for invalid value' do
          let(:config) { { rspec: { script: "rspec", except: except } } }
          let(:processor) { GitlabCiYamlProcessor.new(YAML.dump(config)) }

          shared_examples 'raises an error' do
            it do
              expect { processor }.to raise_error(GitlabCiYamlProcessor::ValidationError, 'rspec job: except parameter should be an array of strings or regexps')
            end
          end

          context 'when it is integer' do
            let(:except) { 1 }

            it_behaves_like 'raises an error'
          end

          context 'when it is an array of integers' do
            let(:except) { [1, 1] }

            it_behaves_like 'raises an error'
          end

          context 'when it is invalid regex' do
            let(:except) { ["/*invalid/"] }

            it_behaves_like 'raises an error'
          end
        end
      end
345
    end
346

347 348 349
    describe "Scripts handling" do
      let(:config_data) { YAML.dump(config) }
      let(:config_processor) { GitlabCiYamlProcessor.new(config_data, path) }
350

351
      subject { config_processor.builds_for_stage_and_ref("test", "master").first }
352

353 354
      describe "before_script" do
        context "in global context" do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
355
          let(:config) do
356 357 358 359
            {
              before_script: ["global script"],
              test: { script: ["script"] }
            }
Kamil Trzcinski's avatar
Kamil Trzcinski committed
360
          end
361

362 363 364 365
          it "return commands with scripts concencaced" do
            expect(subject[:commands]).to eq("global script\nscript")
          end
        end
366

367
        context "overwritten in local context" do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
368
          let(:config) do
369 370 371 372
            {
              before_script: ["global script"],
              test: { before_script: ["local script"], script: ["script"] }
            }
Kamil Trzcinski's avatar
Kamil Trzcinski committed
373
          end
374 375 376 377 378 379 380 381

          it "return commands with scripts concencaced" do
            expect(subject[:commands]).to eq("local script\nscript")
          end
        end
      end

      describe "script" do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
382
        let(:config) do
383 384 385
          {
            test: { script: ["script"] }
          }
Kamil Trzcinski's avatar
Kamil Trzcinski committed
386
        end
387 388 389 390 391 392

        it "return commands with scripts concencaced" do
          expect(subject[:commands]).to eq("script")
        end
      end

393
      describe "after_script" do
394
        context "in global context" do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
395
          let(:config) do
396
            {
397
              after_script: ["after_script"],
398 399
              test: { script: ["script"] }
            }
Kamil Trzcinski's avatar
Kamil Trzcinski committed
400
          end
401

402 403
          it "return after_script in options" do
            expect(subject[:options][:after_script]).to eq(["after_script"])
404 405
          end
        end
406 407

        context "overwritten in local context" do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
408
          let(:config) do
409
            {
410 411
              after_script: ["local after_script"],
              test: { after_script: ["local after_script"], script: ["script"] }
412
            }
Kamil Trzcinski's avatar
Kamil Trzcinski committed
413
          end
414

415 416
          it "return after_script in options" do
            expect(subject[:options][:after_script]).to eq(["local after_script"])
417 418
          end
        end
419 420
      end
    end
421

Valery Sizov's avatar
Valery Sizov committed
422 423 424 425 426 427 428 429 430
    describe "Image and service handling" do
      it "returns image and service when defined" do
        config = YAML.dump({
                             image: "ruby:2.1",
                             services: ["mysql"],
                             before_script: ["pwd"],
                             rspec: { script: "rspec" }
                           })

431
        config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
432 433 434 435 436

        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
          except: nil,
          stage: "test",
437
          stage_idx: 1,
Valery Sizov's avatar
Valery Sizov committed
438 439
          name: :rspec,
          only: nil,
Kamil Trzcinski's avatar
Kamil Trzcinski committed
440 441
          commands: "pwd\nrspec",
          tag_list: [],
Valery Sizov's avatar
Valery Sizov committed
442 443 444 445
          options: {
            image: "ruby:2.1",
            services: ["mysql"]
          },
446
          allow_failure: false,
447 448
          when: "on_success",
          environment: nil,
Valery Sizov's avatar
Valery Sizov committed
449 450 451 452 453 454 455 456 457 458 459
        })
      end

      it "returns image and service when overridden for job" do
        config = YAML.dump({
                             image:         "ruby:2.1",
                             services:      ["mysql"],
                             before_script: ["pwd"],
                             rspec:         { image: "ruby:2.5", services: ["postgresql"], script: "rspec" }
                           })

460
        config_processor = GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
461 462 463 464 465

        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
          except: nil,
          stage: "test",
466
          stage_idx: 1,
Valery Sizov's avatar
Valery Sizov committed
467 468
          name: :rspec,
          only: nil,
Kamil Trzcinski's avatar
Kamil Trzcinski committed
469 470
          commands: "pwd\nrspec",
          tag_list: [],
Valery Sizov's avatar
Valery Sizov committed
471 472 473 474
          options: {
            image: "ruby:2.5",
            services: ["postgresql"]
          },
475
          allow_failure: false,
476 477
          when: "on_success",
          environment: nil,
Valery Sizov's avatar
Valery Sizov committed
478 479
        })
      end
480 481
    end

482
    describe 'Variables' do
483
      context 'when global variables are defined' do
484
        it 'returns global variables' do
485
          variables = {
486 487
            VAR1: 'value1',
            VAR2: 'value2',
488
          }
Valery Sizov's avatar
Valery Sizov committed
489

490
          config = YAML.dump({
491 492 493 494
            variables: variables,
            before_script: ['pwd'],
            rspec: { script: 'rspec' }
          })
Valery Sizov's avatar
Valery Sizov committed
495

496
          config_processor = GitlabCiYamlProcessor.new(config, path)
497

498
          expect(config_processor.global_variables).to eq(variables)
499 500 501 502
        end
      end

      context 'when job variables are defined' do
503 504
        context 'when syntax is correct' do
          it 'returns job variables' do
505
            variables = {
506 507 508 509
              KEY1: 'value1',
              SOME_KEY_2: 'value2'
            }

510
            config = YAML.dump(
511 512 513 514 515 516 517 518 519 520 521
              { before_script: ['pwd'],
                rspec: {
                  variables: variables,
                  script: 'rspec' }
              })

            config_processor = GitlabCiYamlProcessor.new(config, path)

            expect(config_processor.job_variables(:rspec)).to eq variables
          end
        end
522

523
        context 'when syntax is incorrect' do
524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539
          context 'when variables defined but invalid' do
            it 'raises error' do
              variables = [:KEY1, 'value1', :KEY2, 'value2']

              config =  YAML.dump(
                { before_script: ['pwd'],
                  rspec: {
                    variables: variables,
                    script: 'rspec' }
                })

              expect { GitlabCiYamlProcessor.new(config, path) }
                .to raise_error(GitlabCiYamlProcessor::ValidationError,
                                 /job: variables should be a map/)
            end
          end
540

541 542 543 544 545 546 547 548 549 550 551 552
          context 'when variables key defined but value not specified' do
            it 'returns empty array' do
              config =  YAML.dump(
                { before_script: ['pwd'],
                  rspec: {
                    variables: nil,
                    script: 'rspec' }
                })

              config_processor = GitlabCiYamlProcessor.new(config, path)

              ##
553 554
              # When variables config is empty, we assume this is a valid
              # configuration, see issue #18775
555 556 557 558
              #
              expect(config_processor.job_variables(:rspec))
                .to be_an_instance_of(Array).and be_empty
            end
559
          end
560
        end
Valery Sizov's avatar
Valery Sizov committed
561
      end
562 563 564 565

      context 'when job variables are not defined' do
        it 'returns empty array' do
          config = YAML.dump({
566 567 568
            before_script: ['pwd'],
            rspec: { script: 'rspec' }
          })
569 570

          config_processor = GitlabCiYamlProcessor.new(config, path)
571

572 573
          expect(config_processor.job_variables(:rspec)).to eq []
        end
Valery Sizov's avatar
Valery Sizov committed
574
      end
575 576
    end

577 578 579 580 581 582 583
    describe "When" do
      %w(on_success on_failure always).each do |when_state|
        it "returns #{when_state} when defined" do
          config = YAML.dump({
                               rspec: { script: "rspec", when: when_state }
                             })

584
          config_processor = GitlabCiYamlProcessor.new(config, path)
Kamil Trzcinski's avatar
Kamil Trzcinski committed
585

586 587 588 589 590 591 592
          builds = config_processor.builds_for_stage_and_ref("test", "master")
          expect(builds.size).to eq(1)
          expect(builds.first[:when]).to eq(when_state)
        end
      end
    end

593 594 595 596 597 598 599 600 601
    describe 'cache' do
      context 'when cache definition has unknown keys' do
        it 'raises relevant validation error' do
          config = YAML.dump(
            { cache: { untracked: true, invalid: 'key' },
              rspec: { script: 'rspec' } })

          expect { GitlabCiYamlProcessor.new(config) }.to raise_error(
            GitlabCiYamlProcessor::ValidationError,
602
            'cache config contains unknown keys: invalid'
603 604 605 606
          )
        end
      end

607 608
      it "returns cache when defined globally" do
        config = YAML.dump({
609
                             cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
610 611 612 613 614 615 616 617 618 619 620
                             rspec: {
                               script: "rspec"
                             }
                           })

        config_processor = GitlabCiYamlProcessor.new(config)

        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
          paths: ["logs/", "binaries/"],
          untracked: true,
621
          key: 'key',
622 623 624 625 626 627
        )
      end

      it "returns cache when defined in a job" do
        config = YAML.dump({
                             rspec: {
628
                               cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'key' },
629 630 631 632 633 634 635 636 637 638
                               script: "rspec"
                             }
                           })

        config_processor = GitlabCiYamlProcessor.new(config)

        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
          paths: ["logs/", "binaries/"],
          untracked: true,
639
          key: 'key',
640 641 642 643 644
        )
      end

      it "overwrite cache when defined for a job and globally" do
        config = YAML.dump({
645
                             cache: { paths: ["logs/", "binaries/"], untracked: true, key: 'global' },
646 647
                             rspec: {
                               script: "rspec",
648
                               cache: { paths: ["test/"], untracked: false, key: 'local' },
649 650 651 652 653 654 655 656 657
                             }
                           })

        config_processor = GitlabCiYamlProcessor.new(config)

        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref("test", "master").first[:options][:cache]).to eq(
          paths: ["test/"],
          untracked: false,
658
          key: 'local',
659 660 661 662
        )
      end
    end

663 664 665 666 667 668
    describe "Artifacts" do
      it "returns artifacts when defined" do
        config = YAML.dump({
                             image:         "ruby:2.1",
                             services:      ["mysql"],
                             before_script: ["pwd"],
669
                             rspec:         {
670 671 672 673 674 675
                               artifacts: {
                                 paths: ["logs/", "binaries/"],
                                 untracked: true,
                                 name: "custom_name",
                                 expire_in: "7d"
                               },
676 677
                               script: "rspec"
                             }
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
                           })

        config_processor = GitlabCiYamlProcessor.new(config)

        expect(config_processor.builds_for_stage_and_ref("test", "master").size).to eq(1)
        expect(config_processor.builds_for_stage_and_ref("test", "master").first).to eq({
          except: nil,
          stage: "test",
          stage_idx: 1,
          name: :rspec,
          only: nil,
          commands: "pwd\nrspec",
          tag_list: [],
          options: {
            image: "ruby:2.1",
            services: ["mysql"],
694
            artifacts: {
695
              name: "custom_name",
696
              paths: ["logs/", "binaries/"],
697 698
              untracked: true,
              expire_in: "7d"
699
            }
700 701
          },
          when: "on_success",
702 703
          allow_failure: false,
          environment: nil,
704 705
        })
      end
Kamil Trzcinski's avatar
Kamil Trzcinski committed
706

Kamil Trzcinski's avatar
Kamil Trzcinski committed
707
      %w[on_success on_failure always].each do |when_state|
Kamil Trzcinski's avatar
Kamil Trzcinski committed
708 709 710 711 712 713 714 715 716
        it "returns artifacts for when #{when_state}  defined" do
          config = YAML.dump({
                               rspec: {
                                 script: "rspec",
                                 artifacts: { paths: ["logs/", "binaries/"], when: when_state }
                               }
                             })

          config_processor = GitlabCiYamlProcessor.new(config, path)
Kamil Trzcinski's avatar
Kamil Trzcinski committed
717

Kamil Trzcinski's avatar
Kamil Trzcinski committed
718 719 720 721 722
          builds = config_processor.builds_for_stage_and_ref("test", "master")
          expect(builds.size).to eq(1)
          expect(builds.first[:options][:artifacts][:when]).to eq(when_state)
        end
      end
723 724
    end

725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769
    describe '#environment' do
      let(:config) do
        {
          deploy_to_production: { stage: 'deploy', script: 'test', environment: environment }
        }
      end

      let(:processor) { GitlabCiYamlProcessor.new(YAML.dump(config)) }
      let(:builds) { processor.builds_for_stage_and_ref('deploy', 'master') }

      context 'when a production environment is specified' do
        let(:environment) { 'production' }

        it 'does return production' do
          expect(builds.size).to eq(1)
          expect(builds.first[:environment]).to eq(environment)
        end
      end

      context 'when no environment is specified' do
        let(:environment) { nil }

        it 'does return nil environment' do
          expect(builds.size).to eq(1)
          expect(builds.first[:environment]).to be_nil
        end
      end

      context 'is not a string' do
        let(:environment) { 1 }

        it 'raises error' do
          expect { builds }.to raise_error("deploy_to_production job: environment parameter #{Gitlab::Regex.environment_name_regex_message}")
        end
      end

      context 'is not a valid string' do
        let(:environment) { 'production staging' }

        it 'raises error' do
          expect { builds }.to raise_error("deploy_to_production job: environment parameter #{Gitlab::Regex.environment_name_regex_message}")
        end
      end
    end

770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785
    describe "Dependencies" do
      let(:config) do
        {
          build1: { stage: 'build', script: 'test' },
          build2: { stage: 'build', script: 'test' },
          test1: { stage: 'test', script: 'test', dependencies: dependencies },
          test2: { stage: 'test', script: 'test' },
          deploy: { stage: 'test', script: 'test' }
        }
      end

      subject { GitlabCiYamlProcessor.new(YAML.dump(config)) }

      context 'no dependencies' do
        let(:dependencies) { }

786
        it { expect { subject }.not_to raise_error }
787 788 789
      end

      context 'dependencies to builds' do
790
        let(:dependencies) { ['build1', 'build2'] }
791

792
        it { expect { subject }.not_to raise_error }
793 794
      end

795 796 797
      context 'dependencies to builds defined as symbols' do
        let(:dependencies) { [:build1, :build2] }

798
        it { expect { subject }.not_to raise_error }
799 800
      end

801
      context 'undefined dependency' do
802
        let(:dependencies) { ['undefined'] }
803 804 805 806 807

        it { expect { subject }.to raise_error(GitlabCiYamlProcessor::ValidationError, 'test1 job: undefined dependency: undefined') }
      end

      context 'dependencies to deploy' do
808
        let(:dependencies) { ['deploy'] }
809 810 811 812 813

        it { expect { subject }.to raise_error(GitlabCiYamlProcessor::ValidationError, 'test1 job: dependency deploy is not defined in prior stages') }
      end
    end

814
    describe "Hidden jobs" do
815 816 817 818
      let(:config_processor) { GitlabCiYamlProcessor.new(config) }
      subject { config_processor.builds_for_stage_and_ref("test", "master") }

      shared_examples 'hidden_job_handling' do
Tomasz Maczukin's avatar
Tomasz Maczukin committed
819
        it "doesn't create jobs that start with dot" do
820 821 822 823 824 825 826 827 828 829 830
          expect(subject.size).to eq(1)
          expect(subject.first).to eq({
            except: nil,
            stage: "test",
            stage_idx: 1,
            name: :normal_job,
            only: nil,
            commands: "test",
            tag_list: [],
            options: {},
            when: "on_success",
831 832
            allow_failure: false,
            environment: nil,
833 834
          })
        end
835 836
      end

Tomasz Maczukin's avatar
Tomasz Maczukin committed
837
      context 'when hidden job have a script definition' do
838 839 840 841 842 843
        let(:config) do
          YAML.dump({
                      '.hidden_job' => { image: 'ruby:2.1', script: 'test' },
                      'normal_job' => { script: 'test' }
                    })
        end
844

845 846
        it_behaves_like 'hidden_job_handling'
      end
847

Tomasz Maczukin's avatar
Tomasz Maczukin committed
848
      context "when hidden job doesn't have a script definition" do
849 850 851 852 853 854 855 856
        let(:config) do
          YAML.dump({
                      '.hidden_job' => { image: 'ruby:2.1' },
                      'normal_job' => { script: 'test' }
                    })
        end

        it_behaves_like 'hidden_job_handling'
857 858 859
      end
    end

860
    describe "YAML Alias/Anchor" do
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
      let(:config_processor) { GitlabCiYamlProcessor.new(config) }
      subject { config_processor.builds_for_stage_and_ref("build", "master") }

      shared_examples 'job_templates_handling' do
        it "is correctly supported for jobs" do
          expect(subject.size).to eq(2)
          expect(subject.first).to eq({
            except: nil,
            stage: "build",
            stage_idx: 0,
            name: :job1,
            only: nil,
            commands: "execute-script-for-job",
            tag_list: [],
            options: {},
            when: "on_success",
877 878
            allow_failure: false,
            environment: nil,
879 880 881 882 883 884 885 886 887 888 889
          })
          expect(subject.second).to eq({
            except: nil,
            stage: "build",
            stage_idx: 0,
            name: :job2,
            only: nil,
            commands: "execute-script-for-job",
            tag_list: [],
            options: {},
            when: "on_success",
890 891
            allow_failure: false,
            environment: nil,
892 893 894 895
          })
        end
      end

Tomasz Maczukin's avatar
Tomasz Maczukin committed
896
      context 'when template is a job' do
Tomasz Maczukin's avatar
Tomasz Maczukin committed
897
        let(:config) do
898
          <<EOT
899
job1: &JOBTMPL
900
  stage: build
901 902 903 904
  script: execute-script-for-job

job2: *JOBTMPL
EOT
905
        end
906

907 908
        it_behaves_like 'job_templates_handling'
      end
909

Tomasz Maczukin's avatar
Tomasz Maczukin committed
910
      context 'when template is a hidden job' do
Tomasz Maczukin's avatar
Tomasz Maczukin committed
911
        let(:config) do
912 913 914 915 916 917 918 919 920 921 922 923 924 925
          <<EOT
.template: &JOBTMPL
  stage: build
  script: execute-script-for-job

job1: *JOBTMPL

job2: *JOBTMPL
EOT
        end

        it_behaves_like 'job_templates_handling'
      end

Tomasz Maczukin's avatar
Tomasz Maczukin committed
926
      context 'when job adds its own keys to a template definition' do
Tomasz Maczukin's avatar
Tomasz Maczukin committed
927
        let(:config) do
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
          <<EOT
.template: &JOBTMPL
  stage: build

job1:
  <<: *JOBTMPL
  script: execute-script-for-job

job2:
  <<: *JOBTMPL
  script: execute-script-for-job
EOT
        end

        it_behaves_like 'job_templates_handling'
943 944 945
      end
    end

Valery Sizov's avatar
Valery Sizov committed
946
    describe "Error handling" do
947 948 949 950
      it "fails to parse YAML" do
        expect{GitlabCiYamlProcessor.new("invalid: yaml: test")}.to raise_error(Psych::SyntaxError)
      end

Valery Sizov's avatar
Valery Sizov committed
951
      it "indicates that object is invalid" do
952
        expect{GitlabCiYamlProcessor.new("invalid_yaml")}.to raise_error(GitlabCiYamlProcessor::ValidationError)
Valery Sizov's avatar
Valery Sizov committed
953 954 955 956 957
      end

      it "returns errors if tags parameter is invalid" do
        config = YAML.dump({ rspec: { script: "test", tags: "mysql" } })
        expect do
958
          GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
959 960 961 962 963 964
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: tags parameter should be an array of strings")
      end

      it "returns errors if before_script parameter is invalid" do
        config = YAML.dump({ before_script: "bundle update", rspec: { script: "test" } })
        expect do
965
          GitlabCiYamlProcessor.new(config, path)
966
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "before_script config should be an array of strings")
Valery Sizov's avatar
Valery Sizov committed
967 968
      end

969 970 971 972
      it "returns errors if job before_script parameter is not an array of strings" do
        config = YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } })
        expect do
          GitlabCiYamlProcessor.new(config, path)
973
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array of strings")
974 975
      end

976 977
      it "returns errors if after_script parameter is invalid" do
        config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } })
978 979
        expect do
          GitlabCiYamlProcessor.new(config, path)
980
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "after_script config should be an array of strings")
981 982
      end

983 984
      it "returns errors if job after_script parameter is not an array of strings" do
        config = YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } })
985 986
        expect do
          GitlabCiYamlProcessor.new(config, path)
987
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array of strings")
988 989
      end

Valery Sizov's avatar
Valery Sizov committed
990 991 992
      it "returns errors if image parameter is invalid" do
        config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
        expect do
993
          GitlabCiYamlProcessor.new(config, path)
994
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "image config should be a string")
Valery Sizov's avatar
Valery Sizov committed
995 996
      end

Kamil Trzcinski's avatar
Kamil Trzcinski committed
997 998 999
      it "returns errors if job name is blank" do
        config = YAML.dump({ '' => { script: "test" } })
        expect do
1000
          GitlabCiYamlProcessor.new(config, path)
1001
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:job name can't be blank")
Kamil Trzcinski's avatar
Kamil Trzcinski committed
1002 1003 1004 1005 1006
      end

      it "returns errors if job name is non-string" do
        config = YAML.dump({ 10 => { script: "test" } })
        expect do
1007
          GitlabCiYamlProcessor.new(config, path)
1008
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:10 name should be a symbol")
Kamil Trzcinski's avatar
Kamil Trzcinski committed
1009 1010
      end

Valery Sizov's avatar
Valery Sizov committed
1011 1012 1013
      it "returns errors if job image parameter is invalid" do
        config = YAML.dump({ rspec: { script: "test", image: ["test"] } })
        expect do
1014
          GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
1015 1016 1017 1018 1019 1020
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: image should be a string")
      end

      it "returns errors if services parameter is not an array" do
        config = YAML.dump({ services: "test", rspec: { script: "test" } })
        expect do
1021
          GitlabCiYamlProcessor.new(config, path)
1022
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be an array of strings")
Valery Sizov's avatar
Valery Sizov committed
1023 1024 1025 1026 1027
      end

      it "returns errors if services parameter is not an array of strings" do
        config = YAML.dump({ services: [10, "test"], rspec: { script: "test" } })
        expect do
1028
          GitlabCiYamlProcessor.new(config, path)
1029
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "services config should be an array of strings")
Valery Sizov's avatar
Valery Sizov committed
1030 1031 1032 1033 1034
      end

      it "returns errors if job services parameter is not an array" do
        config = YAML.dump({ rspec: { script: "test", services: "test" } })
        expect do
1035
          GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
1036 1037 1038 1039 1040 1041
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings")
      end

      it "returns errors if job services parameter is not an array of strings" do
        config = YAML.dump({ rspec: { script: "test", services: [10, "test"] } })
        expect do
1042
          GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
1043 1044 1045
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: services should be an array of strings")
      end

1046
      it "returns error if job configuration is invalid" do
Valery Sizov's avatar
Valery Sizov committed
1047 1048
        config = YAML.dump({ extra: "bundle update" })
        expect do
1049
          GitlabCiYamlProcessor.new(config, path)
1050
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:extra config should be a hash")
Valery Sizov's avatar
Valery Sizov committed
1051 1052 1053 1054 1055
      end

      it "returns errors if there are unknown parameters that are hashes, but doesn't have a script" do
        config = YAML.dump({ extra: { services: "test" } })
        expect do
1056
          GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
1057 1058 1059
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "Unknown parameter: extra")
      end

1060
      it "returns errors if there are no jobs defined" do
Valery Sizov's avatar
Valery Sizov committed
1061 1062
        config = YAML.dump({ before_script: ["bundle update"] })
        expect do
1063
          GitlabCiYamlProcessor.new(config, path)
1064 1065 1066 1067
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs config should contain at least one visible job")
      end

      it "returns errors if there are no visible jobs defined" do
1068
        config = YAML.dump({ before_script: ["bundle update"], '.hidden'.to_sym => { script: 'ls' } })
1069 1070 1071
        expect do
          GitlabCiYamlProcessor.new(config, path)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs config should contain at least one visible job")
Valery Sizov's avatar
Valery Sizov committed
1072 1073 1074 1075 1076
      end

      it "returns errors if job allow_failure parameter is not an boolean" do
        config = YAML.dump({ rspec: { script: "test", allow_failure: "string" } })
        expect do
1077
          GitlabCiYamlProcessor.new(config, path)
Valery Sizov's avatar
Valery Sizov committed
1078 1079 1080 1081
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: allow_failure parameter should be an boolean")
      end

      it "returns errors if job stage is not a string" do
1082
        config = YAML.dump({ rspec: { script: "test", type: 1 } })
Valery Sizov's avatar
Valery Sizov committed
1083
        expect do
1084
          GitlabCiYamlProcessor.new(config, path)
1085
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "jobs:rspec:type config should be a string")
Valery Sizov's avatar
Valery Sizov committed
1086 1087 1088
      end

      it "returns errors if job stage is not a pre-defined stage" do
1089
        config = YAML.dump({ rspec: { script: "test", type: "acceptance" } })
Valery Sizov's avatar
Valery Sizov committed
1090
        expect do
1091
          GitlabCiYamlProcessor.new(config, path)
1092
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test, deploy")
Valery Sizov's avatar
Valery Sizov committed
1093 1094 1095
      end

      it "returns errors if job stage is not a defined stage" do
1096
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", type: "acceptance" } })
Valery Sizov's avatar
Valery Sizov committed
1097
        expect do
1098
          GitlabCiYamlProcessor.new(config, path)
1099
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: stage parameter should be build, test")
Valery Sizov's avatar
Valery Sizov committed
1100 1101 1102
      end

      it "returns errors if stages is not an array" do
1103
        config = YAML.dump({ stages: "test", rspec: { script: "test" } })
Valery Sizov's avatar
Valery Sizov committed
1104
        expect do
1105
          GitlabCiYamlProcessor.new(config, path)
1106
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages config should be an array of strings")
Valery Sizov's avatar
Valery Sizov committed
1107 1108 1109
      end

      it "returns errors if stages is not an array of strings" do
1110
        config = YAML.dump({ stages: [true, "test"], rspec: { script: "test" } })
Valery Sizov's avatar
Valery Sizov committed
1111
        expect do
1112
          GitlabCiYamlProcessor.new(config, path)
1113
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "stages config should be an array of strings")
Valery Sizov's avatar
Valery Sizov committed
1114 1115 1116 1117 1118
      end

      it "returns errors if variables is not a map" do
        config = YAML.dump({ variables: "test", rspec: { script: "test" } })
        expect do
1119
          GitlabCiYamlProcessor.new(config, path)
1120
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables config should be a hash of key value pairs")
Valery Sizov's avatar
Valery Sizov committed
1121 1122
      end

1123
      it "returns errors if variables is not a map of key-value strings" do
Valery Sizov's avatar
Valery Sizov committed
1124 1125
        config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } })
        expect do
1126
          GitlabCiYamlProcessor.new(config, path)
1127
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "variables config should be a hash of key value pairs")
Valery Sizov's avatar
Valery Sizov committed
1128
      end
1129 1130

      it "returns errors if job when is not on_success, on_failure or always" do
Kamil Trzcinski's avatar
Kamil Trzcinski committed
1131
        config = YAML.dump({ rspec: { script: "test", when: 1 } })
1132
        expect do
1133
          GitlabCiYamlProcessor.new(config, path)
1134 1135
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: when parameter should be on_success, on_failure or always")
      end
1136

1137 1138 1139 1140 1141 1142 1143
      it "returns errors if job artifacts:name is not an a string" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { name: 1 } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:name parameter should be a string")
      end

Kamil Trzcinski's avatar
Kamil Trzcinski committed
1144 1145 1146 1147 1148 1149 1150
      it "returns errors if job artifacts:when is not an a predefined value" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { when: 1 } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:when parameter should be on_success, on_failure or always")
      end

1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164
      it "returns errors if job artifacts:expire_in is not an a string" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { expire_in: 1 } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:expire_in parameter should be a duration")
      end

      it "returns errors if job artifacts:expire_in is not an a valid duration" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:expire_in parameter should be a duration")
      end

1165 1166
      it "returns errors if job artifacts:untracked is not an array of strings" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { untracked: "string" } } })
1167 1168
        expect do
          GitlabCiYamlProcessor.new(config)
1169 1170 1171 1172 1173 1174 1175 1176
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:untracked parameter should be an boolean")
      end

      it "returns errors if job artifacts:paths is not an array of strings" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", artifacts: { paths: "string" } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: artifacts:paths parameter should be an array of strings")
1177
      end
1178 1179 1180 1181 1182

      it "returns errors if cache:untracked is not an array of strings" do
        config = YAML.dump({ cache: { untracked: "string" }, rspec: { script: "test" } })
        expect do
          GitlabCiYamlProcessor.new(config)
1183
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "cache:untracked config should be a boolean value")
1184 1185 1186 1187 1188 1189
      end

      it "returns errors if cache:paths is not an array of strings" do
        config = YAML.dump({ cache: { paths: "string" }, rspec: { script: "test" } })
        expect do
          GitlabCiYamlProcessor.new(config)
1190
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "cache:paths config should be an array of strings")
1191 1192
      end

1193 1194 1195 1196
      it "returns errors if cache:key is not a string" do
        config = YAML.dump({ cache: { key: 1 }, rspec: { script: "test" } })
        expect do
          GitlabCiYamlProcessor.new(config)
1197
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "cache:key config should be a string or symbol")
1198 1199 1200 1201 1202 1203 1204 1205 1206
      end

      it "returns errors if job cache:key is not an a string" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { key: 1 } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: cache:key parameter should be a string")
      end

1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219
      it "returns errors if job cache:untracked is not an array of strings" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { untracked: "string" } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: cache:untracked parameter should be an boolean")
      end

      it "returns errors if job cache:paths is not an array of strings" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", cache: { paths: "string" } } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: cache:paths parameter should be an array of strings")
      end
1220 1221 1222 1223 1224 1225 1226

      it "returns errors if job dependencies is not an array of strings" do
        config = YAML.dump({ types: ["build", "test"], rspec: { script: "test", dependencies: "string" } })
        expect do
          GitlabCiYamlProcessor.new(config)
        end.to raise_error(GitlabCiYamlProcessor::ValidationError, "rspec job: dependencies parameter should be an array of strings")
      end
1227
    end
1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239

    describe "Validate configuration templates" do
      templates = Dir.glob("#{Rails.root.join('vendor/gitlab-ci-yml')}/**/*.gitlab-ci.yml")

      templates.each do |file|
        it "does not return errors for #{file}" do
          file = File.read(file)

          expect { GitlabCiYamlProcessor.new(file) }.not_to raise_error
        end
      end
    end
1240 1241
  end
end