diff options
Diffstat (limited to 'spec/lib/gitlab/ci/config/entry')
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/job_spec.rb | 88 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/processable_spec.rb | 86 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb | 188 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb | 94 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/product/variables_spec.rb | 88 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/entry/service_spec.rb | 1 |
6 files changed, 516 insertions, 29 deletions
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index 180c52ee1ab..ca02eaee0a0 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -30,7 +30,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do %i[before_script script stage type after_script cache image services only except rules needs variables artifacts environment coverage retry interruptible timeout release tags - inherit] + inherit parallel] end it { is_expected.to include(*result) } @@ -73,6 +73,45 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do it { is_expected.to be_falsey } end + + context 'when config does not contain script' do + let(:name) { :build } + + let(:config) do + { before_script: "cd ${PROJ_DIR} " } + end + + it { is_expected.to be_truthy } + end + + context 'when using the default job without script' do + let(:name) { :default } + let(:config) do + { before_script: "cd ${PROJ_DIR} " } + end + + it { is_expected.to be_falsey } + end + + context 'when using the default job with script' do + let(:name) { :default } + let(:config) do + { + before_script: "cd ${PROJ_DIR} ", + script: "ls" + } + end + + it { is_expected.to be_truthy } + end + + context 'there are no shared keys between jobs and bridges' do + subject(:shared_values) do + described_class::ALLOWED_KEYS & Gitlab::Ci::Config::Entry::Bridge::ALLOWED_KEYS + end + + it { is_expected.to be_empty } + end end describe 'validations' do @@ -202,56 +241,47 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do context 'when parallel value is not correct' do context 'when it is not a numeric value' do - let(:config) { { parallel: true } } + let(:config) { { script: 'echo', parallel: true } } it 'returns error about invalid type' do expect(entry).not_to be_valid - expect(entry.errors).to include 'job parallel is not a number' + expect(entry.errors).to include 'parallel should be an integer or a hash' end end context 'when it is lower than two' do - let(:config) { { parallel: 1 } } + let(:config) { { script: 'echo', parallel: 1 } } it 'returns error about value too low' do expect(entry).not_to be_valid expect(entry.errors) - .to include 'job parallel must be greater than or equal to 2' + .to include 'parallel config must be greater than or equal to 2' end end - context 'when it is bigger than 50' do - let(:config) { { parallel: 51 } } + context 'when it is an empty hash' do + let(:config) { { script: 'echo', parallel: {} } } - it 'returns error about value too high' do + it 'returns error about missing matrix' do expect(entry).not_to be_valid expect(entry.errors) - .to include 'job parallel must be less than or equal to 50' + .to include 'parallel config missing required keys: matrix' end end + end - context 'when it is not an integer' do - let(:config) { { parallel: 1.5 } } - - it 'returns error about wrong value' do - expect(entry).not_to be_valid - expect(entry.errors).to include 'job parallel must be an integer' - end + context 'when it uses both "when:" and "rules:"' do + let(:config) do + { + script: 'echo', + when: 'on_failure', + rules: [{ if: '$VARIABLE', when: 'on_success' }] + } end - context 'when it uses both "when:" and "rules:"' do - let(:config) do - { - script: 'echo', - when: 'on_failure', - rules: [{ if: '$VARIABLE', when: 'on_success' }] - } - end - - it 'returns an error about when: being combined with rules' do - expect(entry).not_to be_valid - expect(entry.errors).to include 'job config key may not be used with `rules`: when' - end + it 'returns an error about when: being combined with rules' do + expect(entry).not_to be_valid + expect(entry.errors).to include 'job config key may not be used with `rules`: when' end end diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb index fdf6008f89f..ac8dd2a3267 100644 --- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb @@ -230,6 +230,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do end end + shared_examples 'has no warnings' do + it 'does not raise the warning' do + expect(entry.warnings).to be_empty + end + end + context 'when workflow rules is used' do let(:workflow) { double('workflow', 'has_rules?' => true) } @@ -254,6 +260,86 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do end end + context 'when workflow rules is not used' do + let(:workflow) { double('workflow', 'has_rules?' => false) } + let(:feature_flag_value) { true } + + before do + stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: feature_flag_value) + entry.compose!(deps) + end + + context 'when rules are valid' do + let(:config) do + { + script: 'ls', + rules: [ + { if: '$CI_COMMIT_BRANCH', when: 'on_success' }, + last_rule + ] + } + end + + context 'when last rule contains only `when`' do + let(:last_rule) { { when: when_value } } + + context 'and its value is not `never`' do + let(:when_value) { 'on_success' } + + it 'raises a warning' do + expect(entry.warnings).to contain_exactly(/may allow multiple pipelines/) + end + + context 'when feature flag is disabled' do + let(:feature_flag_value) { false } + + it_behaves_like 'has no warnings' + end + end + + context 'and its value is `never`' do + let(:when_value) { 'never' } + + it_behaves_like 'has no warnings' + end + end + + context 'when last rule does not contain only `when`' do + let(:last_rule) { { if: '$CI_MERGE_REQUEST_ID', when: 'always' } } + + it_behaves_like 'has no warnings' + end + end + + context 'when rules are invalid' do + let(:config) { { script: 'ls', rules: { when: 'always' } } } + + it_behaves_like 'has no warnings' + end + end + + context 'when workflow rules is used' do + let(:workflow) { double('workflow', 'has_rules?' => true) } + + before do + entry.compose!(deps) + end + + context 'when last rule contains only `when' do + let(:config) do + { + script: 'ls', + rules: [ + { if: '$CI_COMMIT_BRANCH', when: 'on_success' }, + { when: 'always' } + ] + } + end + + it_behaves_like 'has no warnings' + end + end + context 'with inheritance' do context 'of variables' do let(:config) do diff --git a/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb new file mode 100644 index 00000000000..39697884e3b --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/product/matrix_spec.rb @@ -0,0 +1,188 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_dependency 'active_model' + +RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do + subject(:matrix) { described_class.new(config) } + + describe 'validations' do + before do + matrix.compose! + end + + context 'when entry config value is correct' do + let(:config) do + [ + { 'VAR_1' => [1, 2, 3], 'VAR_2' => [4, 5, 6] }, + { 'VAR_3' => %w[a b], 'VAR_4' => %w[c d] } + ] + end + + describe '#valid?' do + it { is_expected.to be_valid } + end + end + + context 'when entry config generates too many jobs' do + let(:config) do + [ + { + 'VAR_1' => (1..10).to_a, + 'VAR_2' => (11..20).to_a + } + ] + end + + describe '#valid?' do + it { is_expected.not_to be_valid } + end + + describe '#errors' do + it 'returns error about too many jobs' do + expect(matrix.errors) + .to include('matrix config generates too many jobs (maximum is 50)') + end + end + end + + context 'when entry config has only one variable' do + let(:config) do + [ + { + 'VAR_1' => %w[test] + } + ] + end + + describe '#valid?' do + it { is_expected.not_to be_valid } + end + + describe '#errors' do + it 'returns error about too many jobs' do + expect(matrix.errors) + .to include('variables config requires at least 2 items') + end + end + + describe '#value' do + before do + matrix.compose! + end + + it 'returns the value without raising an error' do + expect(matrix.value).to eq([{ 'VAR_1' => ['test'] }]) + end + end + end + + context 'when config value has wrong type' do + let(:config) { {} } + + describe '#valid?' do + it { is_expected.not_to be_valid } + end + + describe '#errors' do + it 'returns error about incorrect type' do + expect(matrix.errors) + .to include('matrix config should be an array of hashes') + end + end + end + end + + describe '.compose!' do + context 'when valid job entries composed' do + let(:config) do + [ + { PROVIDER: 'aws', STACK: %w[monitoring app1 app2] }, + { STACK: %w[monitoring backup app], PROVIDER: 'ovh' }, + { PROVIDER: 'gcp', STACK: %w[data processing], ARGS: 'normal' }, + { PROVIDER: 'vultr', STACK: 'data', ARGS: 'store' } + ] + end + + before do + matrix.compose! + end + + describe '#value' do + it 'returns key value' do + expect(matrix.value).to match( + [ + { 'PROVIDER' => %w[aws], 'STACK' => %w[monitoring app1 app2] }, + { 'PROVIDER' => %w[ovh], 'STACK' => %w[monitoring backup app] }, + { 'ARGS' => %w[normal], 'PROVIDER' => %w[gcp], 'STACK' => %w[data processing] }, + { 'ARGS' => %w[store], 'PROVIDER' => %w[vultr], 'STACK' => %w[data] } + ] + ) + end + end + + describe '#descendants' do + it 'creates valid descendant nodes' do + expect(matrix.descendants.count).to eq(config.size) + expect(matrix.descendants) + .to all(be_an_instance_of(::Gitlab::Ci::Config::Entry::Product::Variables)) + end + end + end + + context 'with empty config' do + let(:config) { [] } + + before do + matrix.compose! + end + + describe '#value' do + it 'returns empty value' do + expect(matrix.value).to eq([]) + end + end + end + end + + describe '#number_of_generated_jobs' do + before do + matrix.compose! + end + + subject { matrix.number_of_generated_jobs } + + context 'with empty config' do + let(:config) { [] } + + it { is_expected.to be_zero } + end + + context 'with only one variable' do + let(:config) do + [{ 'VAR_1' => (1..10).to_a }] + end + + it { is_expected.to eq(10) } + end + + context 'with two variables' do + let(:config) do + [{ 'VAR_1' => (1..10).to_a, 'VAR_2' => (1..5).to_a }] + end + + it { is_expected.to eq(50) } + end + + context 'with two sets of variables' do + let(:config) do + [ + { 'VAR_1' => (1..10).to_a, 'VAR_2' => (1..5).to_a }, + { 'VAR_3' => (1..2).to_a, 'VAR_4' => (1..3).to_a } + ] + end + + it { is_expected.to eq(56) } + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb b/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb new file mode 100644 index 00000000000..bc09e20d748 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/product/parallel_spec.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_dependency 'active_model' + +RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Parallel do + subject(:parallel) { described_class.new(config) } + + context 'with invalid config' do + shared_examples 'invalid config' do |error_message| + describe '#valid?' do + it { is_expected.not_to be_valid } + end + + describe '#errors' do + it 'returns error about invalid type' do + expect(parallel.errors).to match(a_collection_including(error_message)) + end + end + end + + context 'when it is not a numeric value' do + let(:config) { true } + + it_behaves_like 'invalid config', /should be an integer or a hash/ + end + + context 'when it is lower than two' do + let(:config) { 1 } + + it_behaves_like 'invalid config', /must be greater than or equal to 2/ + end + + context 'when it is bigger than 50' do + let(:config) { 51 } + + it_behaves_like 'invalid config', /must be less than or equal to 50/ + end + + context 'when it is not an integer' do + let(:config) { 1.5 } + + it_behaves_like 'invalid config', /must be an integer/ + end + + context 'with empty hash config' do + let(:config) { {} } + + it_behaves_like 'invalid config', /matrix builds config missing required keys: matrix/ + end + end + + context 'with numeric config' do + context 'when job is specified' do + let(:config) { 2 } + + describe '#valid?' do + it { is_expected.to be_valid } + end + + describe '#value' do + it 'returns job needs configuration' do + expect(parallel.value).to match(number: config) + end + end + end + end + + context 'with matrix builds config' do + context 'when matrix is specified' do + let(:config) do + { + matrix: [ + { PROVIDER: 'aws', STACK: %w[monitoring app1 app2] }, + { PROVIDER: 'gcp', STACK: %w[data processing] } + ] + } + end + + describe '#valid?' do + it { is_expected.to be_valid } + end + + describe '#value' do + it 'returns job needs configuration' do + expect(parallel.value).to match(matrix: [ + { PROVIDER: 'aws', STACK: %w[monitoring app1 app2] }, + { PROVIDER: 'gcp', STACK: %w[data processing] } + ]) + end + end + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb b/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb new file mode 100644 index 00000000000..230b001d620 --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/product/variables_spec.rb @@ -0,0 +1,88 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_dependency 'active_model' + +RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do + let(:entry) { described_class.new(config) } + + describe 'validations' do + context 'when entry config value is correct' do + let(:config) do + { + 'VARIABLE_1' => 1, + 'VARIABLE_2' => 'value 2', + 'VARIABLE_3' => :value_3, + :VARIABLE_4 => 'value 4', + 5 => ['value 5'], + 'VARIABLE_6' => ['value 6'] + } + end + + describe '#value' do + it 'returns hash with key value strings' do + expect(entry.value).to match({ + 'VARIABLE_1' => ['1'], + 'VARIABLE_2' => ['value 2'], + 'VARIABLE_3' => ['value_3'], + 'VARIABLE_4' => ['value 4'], + '5' => ['value 5'], + 'VARIABLE_6' => ['value 6'] + }) + end + end + + describe '#errors' do + it 'does not append errors' do + expect(entry.errors).to be_empty + end + end + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + end + + context 'when entry value is not correct' do + shared_examples 'invalid variables' do |message| + describe '#errors' do + it 'saves errors' do + expect(entry.errors).to include(message) + end + end + + describe '#valid?' do + it 'is not valid' do + expect(entry).not_to be_valid + end + end + end + + context 'with array' do + let(:config) { [:VAR, 'test'] } + + it_behaves_like 'invalid variables', /should be a hash of key value pairs/ + end + + context 'with empty array' do + let(:config) { { VAR: 'test', VAR2: [] } } + + it_behaves_like 'invalid variables', /should be a hash of key value pairs/ + end + + context 'with nested array' do + let(:config) { { VAR: 'test', VAR2: [1, [2]] } } + + it_behaves_like 'invalid variables', /should be a hash of key value pairs/ + end + + context 'with only one variable' do + let(:config) { { VAR: 'test' } } + + it_behaves_like 'invalid variables', /variables config requires at least 2 items/ + end + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb index 9fbc14c19b9..ec137ef2ae4 100644 --- a/spec/lib/gitlab/ci/config/entry/service_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb @@ -95,6 +95,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do let(:config) do { name: 'postgresql:9.5', alias: 'db', command: %w(cmd run), entrypoint: %w(/bin/sh run), ports: ports } end + let(:entry) { described_class.new(config, { with_image_ports: image_ports }) } let(:image_ports) { false } |