diff options
Diffstat (limited to 'spec/lib/gitlab/ci/config')
-rw-r--r-- | spec/lib/gitlab/ci/config/external/file/artifact_spec.rb | 5 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/file/base_spec.rb | 40 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/file/component_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb | 13 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/processor_spec.rb | 2 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/external/rules_spec.rb | 40 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb | 144 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/yaml/loader_spec.rb | 165 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/config/yaml_spec.rb | 172 |
9 files changed, 79 insertions, 504 deletions
diff --git a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb index 1f4586bd5a9..c7f18f0d01a 100644 --- a/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/artifact_spec.rb @@ -41,6 +41,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact, feature_category: : it 'sets the expected error' do expect(valid?).to be_falsy expect(external_file.errors).to contain_exactly(expected_error) + expect(external_file.content).to eq(nil) end end @@ -139,7 +140,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact, feature_category: : before do allow_next_instance_of(Gitlab::Ci::ArtifactFileReader) do |reader| - allow(reader).to receive(:read).and_return('') + allow(reader).to receive(:read).and_return(nil) end end @@ -165,8 +166,8 @@ RSpec.describe Gitlab::Ci::Config::External::File::Artifact, feature_category: : } expect(context).to receive(:mutate).with(expected_attrs).and_call_original - expect(valid?).to be_truthy external_file.content + expect(valid?).to be_truthy end end end diff --git a/spec/lib/gitlab/ci/config/external/file/base_spec.rb b/spec/lib/gitlab/ci/config/external/file/base_spec.rb index 1c5918f77ca..d6dd75f4b10 100644 --- a/spec/lib/gitlab/ci/config/external/file/base_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/base_spec.rb @@ -106,7 +106,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe it 'is not a valid file' do expect(valid?).to be_falsy expect(file.error_message) - .to eq('`some/file/xxxxxxxxxxxxxxxx.yml`: content does not have a valid YAML syntax') + .to eq('`some/file/xxxxxxxxxxxxxxxx.yml`: Invalid configuration format') end end @@ -128,31 +128,6 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe end end - context 'when interpolation is disabled but there is a spec header' do - before do - stub_feature_flags(ci_includable_files_interpolation: false) - end - - let(:location) { 'some-location.yml' } - - let(:content) do - <<~YAML - spec: - include: - website: - --- - run: - script: deploy $[[ inputs.website ]] - YAML - end - - it 'returns an error saying that interpolation is disabled' do - expect(valid?).to be_falsy - expect(file.errors) - .to include('`some-location.yml`: can not evaluate included file because interpolation is disabled') - end - end - context 'when interpolation was unsuccessful' do let(:location) { 'some-location.yml' } @@ -275,4 +250,17 @@ RSpec.describe Gitlab::Ci::Config::External::File::Base, feature_category: :pipe it { is_expected.to eq([{ location: location, content: content }, nil, 'HEAD'].hash) } end end + + describe '#load_and_validate_expanded_hash!' do + let(:location) { 'some/file/config.yml' } + let(:logger) { instance_double(::Gitlab::Ci::Pipeline::Logger, :instrument) } + let(:context_params) { { sha: 'HEAD', variables: variables, project: project, logger: logger } } + + it 'includes instrumentation for loading and expanding the content' do + expect(logger).to receive(:instrument).once.ordered.with(:config_file_fetch_content_hash).and_yield + expect(logger).to receive(:instrument).once.ordered.with(:config_file_expand_content_includes).and_yield + + file.load_and_validate_expanded_hash! + end + end end diff --git a/spec/lib/gitlab/ci/config/external/file/component_spec.rb b/spec/lib/gitlab/ci/config/external/file/component_spec.rb index fe811bce9fe..7e3406413d0 100644 --- a/spec/lib/gitlab/ci/config/external/file/component_spec.rb +++ b/spec/lib/gitlab/ci/config/external/file/component_spec.rb @@ -121,7 +121,7 @@ RSpec.describe Gitlab::Ci::Config::External::File::Component, feature_category: it 'is invalid' do expect(subject).to be_falsy - expect(external_resource.error_message).to match(/does not have a valid YAML syntax/) + expect(external_resource.error_message).to match(/Invalid configuration format/) end end end diff --git a/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb b/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb index 4da3e7e51a7..1a2a6c5beeb 100644 --- a/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb +++ b/spec/lib/gitlab/ci/config/external/mapper/filter_spec.rb @@ -29,18 +29,5 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper::Filter, feature_category: : [{ local: 'config/.gitlab-ci.yml', rules: [{ if: '$VARIABLE1' }] }] ) end - - context 'when FF `ci_support_include_rules_when_never` is disabled' do - before do - stub_feature_flags(ci_support_include_rules_when_never: false) - end - - it 'filters locations according to rules ignoring when:' do - is_expected.to eq( - [{ local: 'config/.gitlab-ci.yml', rules: [{ if: '$VARIABLE1' }] }, - { remote: 'https://testing.com/.gitlab-ci.yml', rules: [{ if: '$VARIABLE1', when: 'never' }] }] - ) - end - end end end diff --git a/spec/lib/gitlab/ci/config/external/processor_spec.rb b/spec/lib/gitlab/ci/config/external/processor_spec.rb index 74afb3b1e97..935b6989dd7 100644 --- a/spec/lib/gitlab/ci/config/external/processor_spec.rb +++ b/spec/lib/gitlab/ci/config/external/processor_spec.rb @@ -221,7 +221,7 @@ RSpec.describe Gitlab::Ci::Config::External::Processor, feature_category: :pipel it 'raises an error' do expect { processor.perform }.to raise_error( described_class::IncludeError, - '`lib/gitlab/ci/templates/template.yml`: content does not have a valid YAML syntax' + '`lib/gitlab/ci/templates/template.yml`: Invalid configuration format' ) end end diff --git a/spec/lib/gitlab/ci/config/external/rules_spec.rb b/spec/lib/gitlab/ci/config/external/rules_spec.rb index 1ba5caa1d4b..25b7998ef5e 100644 --- a/spec/lib/gitlab/ci/config/external/rules_spec.rb +++ b/spec/lib/gitlab/ci/config/external/rules_spec.rb @@ -3,8 +3,7 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_composition do - # Remove `project` property when FF `ci_support_include_rules_when_never` is removed - let(:context) { double(variables_hash: {}, project: nil) } + let(:context) { double(variables_hash: {}) } let(:rule_hashes) { [{ if: '$MY_VAR == "hello"' }] } subject(:rules) { described_class.new(rule_hashes) } @@ -19,11 +18,6 @@ RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_ end shared_examples 'when there is a rule with if' do |rule_matched_result = true, rule_not_matched_result = false| - # Remove this `before` block when FF `ci_support_include_rules_when_never` is removed - before do - allow(context).to receive(:project).and_return(nil) - end - context 'when the rule matches' do let(:context) { double(variables_hash: { 'MY_VAR' => 'hello' }) } @@ -70,28 +64,12 @@ RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_ let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'never' }] } it_behaves_like 'when there is a rule with if', false, false - - context 'when FF `ci_support_include_rules_when_never` is disabled' do - before do - stub_feature_flags(ci_support_include_rules_when_never: false) - end - - it_behaves_like 'when there is a rule with if' - end end context 'with when: always' do let(:rule_hashes) { [{ if: '$MY_VAR == "hello"', when: 'always' }] } it_behaves_like 'when there is a rule with if' - - context 'when FF `ci_support_include_rules_when_never` is disabled' do - before do - stub_feature_flags(ci_support_include_rules_when_never: false) - end - - it_behaves_like 'when there is a rule with if' - end end context 'with when: <invalid string>' do @@ -115,28 +93,12 @@ RSpec.describe Gitlab::Ci::Config::External::Rules, feature_category: :pipeline_ let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'never' }] } it_behaves_like 'when there is a rule with exists', false, false - - context 'when FF `ci_support_include_rules_when_never` is disabled' do - before do - stub_feature_flags(ci_support_include_rules_when_never: false) - end - - it_behaves_like 'when there is a rule with exists' - end end context 'with when: always' do let(:rule_hashes) { [{ exists: 'Dockerfile', when: 'always' }] } it_behaves_like 'when there is a rule with exists' - - context 'when FF `ci_support_include_rules_when_never` is disabled' do - before do - stub_feature_flags(ci_support_include_rules_when_never: false) - end - - it_behaves_like 'when there is a rule with exists' - end end context 'with when: <invalid string>' do diff --git a/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb b/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb index 726ed6d95a0..888756a3eb1 100644 --- a/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb +++ b/spec/lib/gitlab/ci/config/yaml/interpolator_spec.rb @@ -5,10 +5,10 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeline_composition do let_it_be(:project) { create(:project) } - let(:ctx) { instance_double(Gitlab::Ci::Config::External::Context, project: project, user: build(:user, id: 1234)) } + let(:current_user) { build(:user, id: 1234) } let(:result) { ::Gitlab::Ci::Config::Yaml::Result.new(config: [header, content]) } - subject { described_class.new(result, arguments, ctx) } + subject { described_class.new(result, arguments, current_user: current_user) } context 'when input data is valid' do let(:header) do @@ -39,7 +39,7 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli end context 'when config has a syntax error' do - let(:result) { ::Gitlab::Ci::Config::Yaml::Result.new(error: ArgumentError.new) } + let(:result) { ::Gitlab::Ci::Config::Yaml::Result.new(error: 'Invalid configuration format') } let(:arguments) do { website: 'gitlab.com' } @@ -50,7 +50,7 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli expect(subject).not_to be_valid expect(subject.error_message).to eq subject.errors.first - expect(subject.errors).to include 'content does not have a valid YAML syntax' + expect(subject.errors).to include 'Invalid configuration format' end end @@ -142,28 +142,6 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli end describe '#to_hash' do - context 'when interpolation is disabled' do - before do - stub_feature_flags(ci_includable_files_interpolation: false) - end - - let(:header) do - { spec: { inputs: { website: nil } } } - end - - let(:content) do - { test: 'deploy $[[ inputs.website ]]' } - end - - let(:arguments) { {} } - - it 'returns an empty hash' do - subject.interpolate! - - expect(subject.to_hash).to be_empty - end - end - context 'when interpolation is not used' do let(:result) do ::Gitlab::Ci::Config::Yaml::Result.new(config: content) @@ -202,118 +180,4 @@ RSpec.describe Gitlab::Ci::Config::Yaml::Interpolator, feature_category: :pipeli end end end - - describe '#ready?' do - let(:header) do - { spec: { inputs: { website: nil } } } - end - - let(:content) do - { test: 'deploy $[[ inputs.website ]]' } - end - - let(:arguments) do - { website: 'gitlab.com' } - end - - it 'returns false if interpolation has not been done yet' do - expect(subject).not_to be_ready - end - - it 'returns true if interpolation has been performed' do - subject.interpolate! - - expect(subject).to be_ready - end - - context 'when interpolation can not be performed' do - let(:result) do - ::Gitlab::Ci::Config::Yaml::Result.new(error: ArgumentError.new) - end - - it 'returns true if interpolator has preliminary errors' do - expect(subject).to be_ready - end - - it 'returns true if interpolation has been attempted' do - subject.interpolate! - - expect(subject).to be_ready - end - end - end - - describe '#interpolate?' do - let(:header) do - { spec: { inputs: { website: nil } } } - end - - let(:content) do - { test: 'deploy $[[ inputs.something.abc ]] $[[ inputs.cde ]] $[[ efg ]]' } - end - - let(:arguments) do - { website: 'gitlab.com' } - end - - context 'when interpolation can be performed' do - it 'will perform interpolation' do - expect(subject.interpolate?).to eq true - end - end - - context 'when interpolation is disabled' do - before do - stub_feature_flags(ci_includable_files_interpolation: false) - end - - it 'will not perform interpolation' do - expect(subject.interpolate?).to eq false - end - end - - context 'when an interpolation header is missing' do - let(:header) { nil } - - it 'will not perform interpolation' do - expect(subject.interpolate?).to eq false - end - end - - context 'when interpolator has preliminary errors' do - let(:result) do - ::Gitlab::Ci::Config::Yaml::Result.new(error: ArgumentError.new) - end - - it 'will not perform interpolation' do - expect(subject.interpolate?).to eq false - end - end - end - - describe '#has_header?' do - let(:content) do - { test: 'deploy $[[ inputs.something.abc ]] $[[ inputs.cde ]] $[[ efg ]]' } - end - - let(:arguments) do - { website: 'gitlab.com' } - end - - context 'when header is an empty hash' do - let(:header) { {} } - - it 'does not have a header available' do - expect(subject).not_to have_header - end - end - - context 'when header is not specified' do - let(:header) { nil } - - it 'does not have a header available' do - expect(subject).not_to have_header - end - end - end end diff --git a/spec/lib/gitlab/ci/config/yaml/loader_spec.rb b/spec/lib/gitlab/ci/config/yaml/loader_spec.rb index 1e417bcd8af..4e6151677e6 100644 --- a/spec/lib/gitlab/ci/config/yaml/loader_spec.rb +++ b/spec/lib/gitlab/ci/config/yaml/loader_spec.rb @@ -2,151 +2,58 @@ require 'spec_helper' -RSpec.describe Gitlab::Ci::Config::Yaml::Loader, feature_category: :pipeline_composition do - describe '#to_result' do +RSpec.describe ::Gitlab::Ci::Config::Yaml::Loader, feature_category: :pipeline_composition do + describe '#load' do let_it_be(:project) { create(:project) } - subject(:result) { described_class.new(yaml, project: project).to_result } - - context 'when syntax is invalid' do - let(:yaml) { 'some: invalid: syntax' } - - it 'returns an invalid result object' do - expect(result).not_to be_valid - expect(result.error).to be_a ::Gitlab::Config::Loader::FormatError - end + let(:inputs) { { test_input: 'hello test' } } + + let(:yaml) do + <<~YAML + --- + spec: + inputs: + test_input: + --- + test_job: + script: + - echo "$[[ inputs.test_input ]]" + YAML end - context 'when the first document is a header' do - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - spec: - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result.header).to eq({ spec: nil }) - expect(result.content).to eq({ b: 2 }) - end - end - end + subject(:result) { described_class.new(yaml, inputs: inputs, current_user: project.creator).load } - context 'when first document is empty' do - let(:yaml) do - <<~YAML - --- - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end - end - - context 'when first document is an empty hash' do - let(:yaml) do - <<~YAML - {} - --- - b: 2 - YAML - end + it 'loads and interpolates CI config YAML' do + expected_config = { test_job: { script: ['echo "hello test"'] } } - it 'returns second document as a content' do - expect(result).not_to have_header - expect(result.content).to eq({ b: 2 }) - end + expect(result).to be_valid + expect(result.content).to eq(expected_config) end - context 'when first an array' do - let(:yaml) do - <<~YAML - --- - - a - - b - --- - b: 2 - YAML - end + it 'allows the use of YAML reference tags' do + expect(Psych).to receive(:add_tag).once.with( + ::Gitlab::Ci::Config::Yaml::Tags::Reference.tag, + ::Gitlab::Ci::Config::Yaml::Tags::Reference + ) - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end + result end - context 'when the first document is not a header' do - let(:yaml) do - <<~YAML - a: 1 - --- - b: 2 - YAML - end - - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - b: 2 - YAML - end + context 'when there is an error loading the YAML' do + let(:yaml) { 'invalid...yaml' } - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + it 'returns an error result' do + expect(result).not_to be_valid + expect(result.error).to eq('Invalid configuration format') end end - context 'when the first document is not a header and second document is empty' do - let(:yaml) do - <<~YAML - a: 1 - --- - YAML - end - - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - YAML - end + context 'when there is an error interpolating the YAML' do + let(:inputs) { {} } - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + it 'returns an error result' do + expect(result).not_to be_valid + expect(result.error).to eq('`test_input` input: required value has not been provided') end end end diff --git a/spec/lib/gitlab/ci/config/yaml_spec.rb b/spec/lib/gitlab/ci/config/yaml_spec.rb index 3576dd481c6..27d93d555f1 100644 --- a/spec/lib/gitlab/ci/config/yaml_spec.rb +++ b/spec/lib/gitlab/ci/config/yaml_spec.rb @@ -3,18 +3,20 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_composition do - describe '.load!' do - it 'loads a YAML file' do - yaml = <<~YAML - image: 'image:1.0' - texts: - nested_key: 'value1' - more_text: - more_nested_key: 'value2' - YAML + let(:yaml) do + <<~YAML + image: 'image:1.0' + texts: + nested_key: 'value1' + more_text: + more_nested_key: 'value2' + YAML + end - config = described_class.load!(yaml) + describe '.load!' do + subject(:config) { described_class.load!(yaml) } + it 'loads a YAML file' do expect(config).to eq({ image: 'image:1.0', texts: { @@ -30,156 +32,20 @@ RSpec.describe Gitlab::Ci::Config::Yaml, feature_category: :pipeline_composition let(:yaml) { 'some: invalid: syntax' } it 'raises an error' do - expect { described_class.load!(yaml) } + expect { config } .to raise_error ::Gitlab::Config::Loader::FormatError, /mapping values are not allowed in this context/ end end - end - - describe '.load_result!' do - let_it_be(:project) { create(:project) } - - subject(:result) { described_class.load_result!(yaml, project: project) } - - context 'when syntax is invalid' do - let(:yaml) { 'some: invalid: syntax' } - - it 'returns an invalid result object' do - expect(result).not_to be_valid - expect(result.error).to be_a ::Gitlab::Config::Loader::FormatError - end - end - - context 'when the first document is a header' do - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - spec: - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result.header).to eq({ spec: nil }) - expect(result.content).to eq({ b: 2 }) - end - end - end - - context 'when first document is empty' do - let(:yaml) do - <<~YAML - --- - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end - end - - context 'when first document is an empty hash' do - let(:yaml) do - <<~YAML - {} - --- - b: 2 - YAML - end - it 'returns second document as a content' do - expect(result).not_to have_header - expect(result.content).to eq({ b: 2 }) - end - end + context 'when given a user' do + let(:user) { instance_double(User) } - context 'when first an array' do - let(:yaml) do - <<~YAML - --- - - a - - b - --- - b: 2 - YAML - end - - it 'considers the first document as header and the second as content' do - expect(result).not_to have_header - end - end - - context 'when the first document is not a header' do - let(:yaml) do - <<~YAML - a: 1 - --- - b: 2 - YAML - end - - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - b: 2 - YAML - end - - it 'considers the first document as content for backwards compatibility' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end - end - end - - context 'when the first document is not a header and second document is empty' do - let(:yaml) do - <<~YAML - a: 1 - --- - YAML - end - - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + subject(:config) { described_class.load!(yaml, current_user: user) } - context 'with explicit document start marker' do - let(:yaml) do - <<~YAML - --- - a: 1 - --- - YAML - end + it 'passes it to Loader' do + expect(::Gitlab::Ci::Config::Yaml::Loader).to receive(:new).with(yaml, current_user: user).and_call_original - it 'considers the first document as content' do - expect(result).to be_valid - expect(result.error).to be_nil - expect(result).not_to have_header - expect(result.content).to eq({ a: 1 }) - end + config end end end |