Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-09-19 04:45:44 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-09-19 04:45:44 +0300
commit85dc423f7090da0a52c73eb66faf22ddb20efff9 (patch)
tree9160f299afd8c80c038f08e1545be119f5e3f1e1 /spec/lib/gitlab/ci
parent15c2c8c66dbe422588e5411eee7e68f1fa440bb8 (diff)
Add latest changes from gitlab-org/gitlab@13-4-stable-ee
Diffstat (limited to 'spec/lib/gitlab/ci')
-rw-r--r--spec/lib/gitlab/ci/artifact_file_reader_spec.rb11
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb18
-rw-r--r--spec/lib/gitlab/ci/config/entry/jobs_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/config/entry/root_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb21
-rw-r--r--spec/lib/gitlab/ci/config/normalizer_spec.rb26
-rw-r--r--spec/lib/gitlab/ci/config_spec.rb4
-rw-r--r--spec/lib/gitlab/ci/jwt_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/lint_spec.rb251
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb19
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb74
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb39
-rw-r--r--spec/lib/gitlab/ci/pipeline_object_hierarchy_spec.rb111
-rw-r--r--spec/lib/gitlab/ci/reports/test_case_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/reports/test_suite_spec.rb31
-rw-r--r--spec/lib/gitlab/ci/status/bridge/common_spec.rb49
-rw-r--r--spec/lib/gitlab/ci/status/composite_spec.rb51
-rw-r--r--spec/lib/gitlab/ci/templates/templates_spec.rb39
-rw-r--r--spec/lib/gitlab/ci/trace/stream_spec.rb22
-rw-r--r--spec/lib/gitlab/ci/trace_spec.rb23
-rw-r--r--spec/lib/gitlab/ci/yaml_processor_spec.rb806
23 files changed, 968 insertions, 655 deletions
diff --git a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
index e982f0eb015..83a37655ea9 100644
--- a/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
+++ b/spec/lib/gitlab/ci/artifact_file_reader_spec.rb
@@ -18,6 +18,17 @@ RSpec.describe Gitlab::Ci::ArtifactFileReader do
expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
end
+ context 'when FF ci_new_artifact_file_reader is disabled' do
+ before do
+ stub_feature_flags(ci_new_artifact_file_reader: false)
+ end
+
+ it 'returns the content at the path' do
+ is_expected.to be_present
+ expect(YAML.safe_load(subject).keys).to contain_exactly('rspec', 'time', 'custom')
+ end
+ end
+
context 'when path does not exist' do
let(:path) { 'file/does/not/exist.txt' }
let(:expected_error) do
diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb
index ca02eaee0a0..ab760b107f8 100644
--- a/spec/lib/gitlab/ci/config/entry/job_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb
@@ -74,16 +74,6 @@ 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
@@ -104,14 +94,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do
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
diff --git a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
index 8561bd330b7..ac6b589ec6b 100644
--- a/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/jobs_spec.rb
@@ -68,7 +68,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Jobs do
let(:config) { { rspec: nil } }
it 'reports error' do
- expect(entry.errors).to include "jobs config should contain valid jobs"
+ expect(entry.errors).to include 'jobs rspec config should implement a script: or a trigger: keyword'
end
end
diff --git a/spec/lib/gitlab/ci/config/entry/root_spec.rb b/spec/lib/gitlab/ci/config/entry/root_spec.rb
index 140b3c4f55b..252bda6461d 100644
--- a/spec/lib/gitlab/ci/config/entry/root_spec.rb
+++ b/spec/lib/gitlab/ci/config/entry/root_spec.rb
@@ -344,9 +344,9 @@ RSpec.describe Gitlab::Ci::Config::Entry::Root do
end
describe '#errors' do
- it 'reports errors about missing script' do
+ it 'reports errors about missing script or trigger' do
expect(root.errors)
- .to include "root config contains unknown keys: rspec"
+ .to include 'jobs rspec config should implement a script: or a trigger: keyword'
end
end
end
diff --git a/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb b/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb
index bab604c4504..fbf86927bd9 100644
--- a/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb
+++ b/spec/lib/gitlab/ci/config/normalizer/matrix_strategy_spec.rb
@@ -43,7 +43,7 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
expect(subject.map(&:attributes)).to match_array(
[
{
- name: 'test 1/4',
+ name: 'test: [aws, app1]',
instance: 1,
parallel: { total: 4 },
variables: {
@@ -52,7 +52,7 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
}
},
{
- name: 'test 2/4',
+ name: 'test: [aws, app2]',
instance: 2,
parallel: { total: 4 },
variables: {
@@ -61,7 +61,7 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
}
},
{
- name: 'test 3/4',
+ name: 'test: [ovh, app]',
instance: 3,
parallel: { total: 4 },
variables: {
@@ -70,7 +70,7 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
}
},
{
- name: 'test 4/4',
+ name: 'test: [gcp, app]',
instance: 4,
parallel: { total: 4 },
variables: {
@@ -84,18 +84,7 @@ RSpec.describe Gitlab::Ci::Config::Normalizer::MatrixStrategy do
it 'has parallelized name' do
expect(subject.map(&:name)).to match_array(
- ['test 1/4', 'test 2/4', 'test 3/4', 'test 4/4']
- )
- end
-
- it 'has details' do
- expect(subject.map(&:name_with_details)).to match_array(
- [
- 'test (PROVIDER=aws; STACK=app1)',
- 'test (PROVIDER=aws; STACK=app2)',
- 'test (PROVIDER=gcp; STACK=app)',
- 'test (PROVIDER=ovh; STACK=app)'
- ]
+ ['test: [aws, app1]', 'test: [aws, app2]', 'test: [gcp, app]', 'test: [ovh, app]']
)
end
end
diff --git a/spec/lib/gitlab/ci/config/normalizer_spec.rb b/spec/lib/gitlab/ci/config/normalizer_spec.rb
index 949af8cdc4c..4c19657413c 100644
--- a/spec/lib/gitlab/ci/config/normalizer_spec.rb
+++ b/spec/lib/gitlab/ci/config/normalizer_spec.rb
@@ -178,8 +178,8 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
{
matrix: [
{
- VAR_1: [1],
- VAR_2: [2, 3]
+ VAR_1: ['A'],
+ VAR_2: %w[B C]
}
]
}
@@ -187,8 +187,8 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
let(:expanded_job_names) do
[
- 'rspec 1/2',
- 'rspec 2/2'
+ 'rspec: [A, B]',
+ 'rspec: [A, C]'
]
end
@@ -196,21 +196,17 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
is_expected.not_to include(job_name)
end
- it 'has parallelized jobs' do
- is_expected.to include(*expanded_job_names.map(&:to_sym))
- end
-
it 'sets job instance in options' do
expect(subject.values).to all(include(:instance))
end
it 'sets job variables', :aggregate_failures do
expect(subject.values[0]).to match(
- a_hash_including(variables: { VAR_1: 1, VAR_2: 2, USER_VARIABLE: 'user value' })
+ a_hash_including(variables: { VAR_1: 'A', VAR_2: 'B', USER_VARIABLE: 'user value' })
)
expect(subject.values[1]).to match(
- a_hash_including(variables: { VAR_1: 1, VAR_2: 3, USER_VARIABLE: 'user value' })
+ a_hash_including(variables: { VAR_1: 'A', VAR_2: 'C', USER_VARIABLE: 'user value' })
)
end
@@ -226,6 +222,10 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
expect(configs).to all(match(a_hash_including(original_config)))
end
+ it 'has parallelized jobs' do
+ is_expected.to include(*expanded_job_names.map(&:to_sym))
+ end
+
it_behaves_like 'parallel dependencies'
it_behaves_like 'parallel needs'
end
@@ -238,5 +238,11 @@ RSpec.describe Gitlab::Ci::Config::Normalizer do
is_expected.to match(config)
end
end
+
+ context 'when jobs config is nil' do
+ let(:config) { nil }
+
+ it { is_expected.to eq({}) }
+ end
end
end
diff --git a/spec/lib/gitlab/ci/config_spec.rb b/spec/lib/gitlab/ci/config_spec.rb
index 18be9558829..41a45fe4ab7 100644
--- a/spec/lib/gitlab/ci/config_spec.rb
+++ b/spec/lib/gitlab/ci/config_spec.rb
@@ -312,7 +312,7 @@ RSpec.describe Gitlab::Ci::Config do
HEREDOC
end
- it 'raises error YamlProcessor validationError' do
+ it 'raises ConfigError' do
expect { config }.to raise_error(
described_class::ConfigError,
"Included file `invalid` does not have YAML extension!"
@@ -329,7 +329,7 @@ RSpec.describe Gitlab::Ci::Config do
HEREDOC
end
- it 'raises error YamlProcessor validationError' do
+ it 'raises ConfigError' do
expect { config }.to raise_error(
described_class::ConfigError,
'Include `{"remote":"http://url","local":"/local/file.yml"}` needs to match exactly one accessor!'
diff --git a/spec/lib/gitlab/ci/jwt_spec.rb b/spec/lib/gitlab/ci/jwt_spec.rb
index a15f3310dab..9b133efad9c 100644
--- a/spec/lib/gitlab/ci/jwt_spec.rb
+++ b/spec/lib/gitlab/ci/jwt_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Ci::Jwt do
subject(:payload) { described_class.new(build, ttl: 30).payload }
it 'has correct values for the standard JWT attributes' do
- Timecop.freeze do
+ freeze_time do
now = Time.now.to_i
aggregate_failures do
diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb
new file mode 100644
index 00000000000..077c0fd3162
--- /dev/null
+++ b/spec/lib/gitlab/ci/lint_spec.rb
@@ -0,0 +1,251 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Lint do
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:user) { create(:user) }
+
+ let(:lint) { described_class.new(project: project, current_user: user) }
+
+ describe '#validate' do
+ subject { lint.validate(content, dry_run: dry_run) }
+
+ shared_examples 'content is valid' do
+ let(:content) do
+ <<~YAML
+ build:
+ stage: build
+ before_script:
+ - before_build
+ script: echo
+ environment: staging
+ when: manual
+ rspec:
+ stage: test
+ script: rspec
+ after_script:
+ - after_rspec
+ tags: [docker]
+ YAML
+ end
+
+ it 'returns a valid result', :aggregate_failures do
+ expect(subject).to be_valid
+
+ expect(subject.errors).to be_empty
+ expect(subject.warnings).to be_empty
+ expect(subject.jobs).to be_present
+
+ build_job = subject.jobs.first
+ expect(build_job[:name]).to eq('build')
+ expect(build_job[:stage]).to eq('build')
+ expect(build_job[:before_script]).to eq(['before_build'])
+ expect(build_job[:script]).to eq(['echo'])
+ expect(build_job.fetch(:after_script)).to eq([])
+ expect(build_job[:tag_list]).to eq([])
+ expect(build_job[:environment]).to eq('staging')
+ expect(build_job[:when]).to eq('manual')
+ expect(build_job[:allow_failure]).to eq(true)
+
+ rspec_job = subject.jobs.last
+ expect(rspec_job[:name]).to eq('rspec')
+ expect(rspec_job[:stage]).to eq('test')
+ expect(rspec_job.fetch(:before_script)).to eq([])
+ expect(rspec_job[:script]).to eq(['rspec'])
+ expect(rspec_job[:after_script]).to eq(['after_rspec'])
+ expect(rspec_job[:tag_list]).to eq(['docker'])
+ expect(rspec_job.fetch(:environment)).to be_nil
+ expect(rspec_job[:when]).to eq('on_success')
+ expect(rspec_job[:allow_failure]).to eq(false)
+ end
+ end
+
+ shared_examples 'content with errors and warnings' do
+ context 'when content has errors' do
+ let(:content) do
+ <<~YAML
+ build:
+ invalid: syntax
+ YAML
+ end
+
+ it 'returns a result with errors' do
+ expect(subject).not_to be_valid
+ expect(subject.errors).to include(/jobs build config should implement a script: or a trigger: keyword/)
+ end
+ end
+
+ context 'when content has warnings' do
+ let(:content) do
+ <<~YAML
+ rspec:
+ script: rspec
+ rules:
+ - when: always
+ YAML
+ end
+
+ it 'returns a result with warnings' do
+ expect(subject).to be_valid
+ expect(subject.warnings).to include(/rspec may allow multiple pipelines to run/)
+ end
+ end
+
+ context 'when content has more warnings than max limit' do
+ # content will result in 2 warnings
+ let(:content) do
+ <<~YAML
+ rspec:
+ script: rspec
+ rules:
+ - when: always
+ rspec2:
+ script: rspec
+ rules:
+ - when: always
+ YAML
+ end
+
+ before do
+ stub_const('Gitlab::Ci::Warnings::MAX_LIMIT', 1)
+ end
+
+ it 'returns a result with warnings' do
+ expect(subject).to be_valid
+ expect(subject.warnings.size).to eq(1)
+ end
+ end
+
+ context 'when content has errors and warnings' do
+ let(:content) do
+ <<~YAML
+ rspec:
+ script: rspec
+ rules:
+ - when: always
+ karma:
+ script: karma
+ unknown: key
+ YAML
+ end
+
+ it 'returns a result with errors and warnings' do
+ expect(subject).not_to be_valid
+ expect(subject.errors).to include(/karma config contains unknown keys/)
+ expect(subject.warnings).to include(/rspec may allow multiple pipelines to run/)
+ end
+ end
+ end
+
+ shared_context 'advanced validations' do
+ let(:content) do
+ <<~YAML
+ build:
+ stage: build
+ script: echo
+ rules:
+ - if: '$CI_MERGE_REQUEST_ID'
+ test:
+ stage: test
+ script: echo
+ needs: [build]
+ YAML
+ end
+ end
+
+ context 'when user has permissions to write the ref' do
+ before do
+ project.add_developer(user)
+ end
+
+ context 'when using default static mode' do
+ let(:dry_run) { false }
+
+ it_behaves_like 'content with errors and warnings'
+
+ it_behaves_like 'content is valid' do
+ it 'includes extra attributes' do
+ subject.jobs.each do |job|
+ expect(job[:only]).to eq(refs: %w[branches tags])
+ expect(job.fetch(:except)).to be_nil
+ end
+ end
+ end
+
+ include_context 'advanced validations' do
+ it 'does not catch advanced logical errors' do
+ expect(subject).to be_valid
+ expect(subject.errors).to be_empty
+ end
+ end
+
+ it 'uses YamlProcessor' do
+ expect(Gitlab::Ci::YamlProcessor)
+ .to receive(:new)
+ .and_call_original
+
+ subject
+ end
+ end
+
+ context 'when using dry run mode' do
+ let(:dry_run) { true }
+
+ it_behaves_like 'content with errors and warnings'
+
+ it_behaves_like 'content is valid' do
+ it 'does not include extra attributes' do
+ subject.jobs.each do |job|
+ expect(job.key?(:only)).to be_falsey
+ expect(job.key?(:except)).to be_falsey
+ end
+ end
+ end
+
+ include_context 'advanced validations' do
+ it 'runs advanced logical validations' do
+ expect(subject).not_to be_valid
+ expect(subject.errors).to eq(["test: needs 'build'"])
+ end
+ end
+
+ it 'uses Ci::CreatePipelineService' do
+ expect(::Ci::CreatePipelineService)
+ .to receive(:new)
+ .and_call_original
+
+ subject
+ end
+ end
+ end
+
+ context 'when user does not have permissions to write the ref' do
+ before do
+ project.add_reporter(user)
+ end
+
+ context 'when using default static mode' do
+ let(:dry_run) { false }
+
+ it_behaves_like 'content is valid'
+ end
+
+ context 'when using dry run mode' do
+ let(:dry_run) { true }
+
+ let(:content) do
+ <<~YAML
+ job:
+ script: echo
+ YAML
+ end
+
+ it 'does not allow validation' do
+ expect(subject).not_to be_valid
+ expect(subject.errors).to include('Insufficient permissions to create a new pipeline')
+ end
+ end
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb
index 8b9de16ce5f..11e3f32c7ce 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/remove_unwanted_chat_jobs_spec.rb
@@ -11,7 +11,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
let(:command) do
double(:command,
- config_processor: double(:processor,
+ yaml_processor_result: double(:processor,
jobs: { echo: double(:job_echo), rspec: double(:job_rspec) }),
project: project,
chat_data: { command: 'echo' })
@@ -25,7 +25,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
subject
- expect(command.config_processor.jobs.keys).to eq([:echo])
+ expect(command.yaml_processor_result.jobs.keys).to eq([:echo])
end
it 'does not remove any jobs for non chat-pipelines' do
@@ -33,7 +33,7 @@ RSpec.describe ::Gitlab::Ci::Pipeline::Chain::RemoveUnwantedChatJobs do
subject
- expect(command.config_processor.jobs.keys).to eq([:echo, :rspec])
+ expect(command.yaml_processor_result.jobs.keys).to eq([:echo, :rspec])
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
index de580d2e148..e55281f9705 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -31,20 +31,20 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
CI_YAML
end
- let(:yaml_processor) do
+ let(:yaml_processor_result) do
::Gitlab::Ci::YamlProcessor.new(
ci_yaml, {
project: project,
sha: pipeline.sha,
user: user
}
- )
+ ).execute
end
let(:save_incompleted) { true }
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
- project: project, current_user: user, config_processor: yaml_processor, save_incompleted: save_incompleted
+ project: project, current_user: user, yaml_processor_result: yaml_processor_result, save_incompleted: save_incompleted
)
end
@@ -128,7 +128,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
end
describe '#validation_service_payload' do
- subject(:validation_service_payload) { step.send(:validation_service_payload, pipeline, command.config_processor.stages_attributes) }
+ subject(:validation_service_payload) { step.send(:validation_service_payload, pipeline, command.yaml_processor_result.stages_attributes) }
it 'respects the defined schema' do
expect(validation_service_payload).to match_schema('/external_validation')
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
index 6e242faa885..fc5725a4d17 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
@@ -90,24 +90,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexer do
end
with_them do
- context 'when ci_if_parenthesis_enabled is enabled' do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: true)
- end
-
- it { is_expected.to eq(tokens) }
- end
-
- context 'when ci_if_parenthesis_enabled is disabled' do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: false)
- end
-
- it do
- expect { subject }
- .to raise_error described_class::SyntaxError
- end
- end
+ it { is_expected.to eq(tokens) }
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
index 3394a75ac0a..a02c247925e 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
@@ -3,10 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Expression::Parser do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: true)
- end
-
describe '#tree' do
context 'validates simple operators' do
using RSpec::Parameterized::TableSyntax
@@ -31,36 +27,15 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Parser do
context 'when combining && and OR operators' do
subject { described_class.seed('$VAR1 == "a" || $VAR2 == "b" && $VAR3 == "c" || $VAR4 == "d" && $VAR5 == "e"').tree }
- context 'when parenthesis engine is enabled' do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: true)
- end
-
- it 'returns operations in a correct order' do
- expect(subject.inspect)
- .to eq('or(or(equals($VAR1, "a"), and(equals($VAR2, "b"), equals($VAR3, "c"))), and(equals($VAR4, "d"), equals($VAR5, "e")))')
- end
- end
-
- context 'when parenthesis engine is disabled (legacy)' do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: false)
- end
-
- it 'returns operations in a invalid order' do
- expect(subject.inspect)
- .to eq('or(equals($VAR1, "a"), and(equals($VAR2, "b"), or(equals($VAR3, "c"), and(equals($VAR4, "d"), equals($VAR5, "e")))))')
- end
+ it 'returns operations in a correct order' do
+ expect(subject.inspect)
+ .to eq('or(or(equals($VAR1, "a"), and(equals($VAR2, "b"), equals($VAR3, "c"))), and(equals($VAR4, "d"), equals($VAR5, "e")))')
end
end
context 'when using parenthesis' do
subject { described_class.seed('(($VAR1 == "a" || $VAR2 == "b") && $VAR3 == "c" || $VAR4 == "d") && $VAR5 == "e"').tree }
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: true)
- end
-
it 'returns operations in a correct order' do
expect(subject.inspect)
.to eq('and(or(and(or(equals($VAR1, "a"), equals($VAR2, "b")), equals($VAR3, "c")), equals($VAR4, "d")), equals($VAR5, "e"))')
@@ -96,38 +71,21 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Parser do
end
context 'when parenthesis are unmatched' do
- context 'when parenthesis engine is enabled' do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: true)
- end
-
- where(:expression) do
- [
- '$VAR == (',
- '$VAR2 == ("aa"',
- '$VAR2 == ("aa"))',
- '$VAR2 == "aa")',
- '(($VAR2 == "aa")',
- '($VAR2 == "aa"))'
- ]
- end
-
- with_them do
- it 'raises a ParseError' do
- expect { described_class.seed(expression).tree }
- .to raise_error Gitlab::Ci::Pipeline::Expression::Parser::ParseError
- end
- end
+ where(:expression) do
+ [
+ '$VAR == (',
+ '$VAR2 == ("aa"',
+ '$VAR2 == ("aa"))',
+ '$VAR2 == "aa")',
+ '(($VAR2 == "aa")',
+ '($VAR2 == "aa"))'
+ ]
end
- context 'when parenthesis engine is disabled' do
- before do
- stub_feature_flags(ci_if_parenthesis_enabled: false)
- end
-
- it 'raises an SyntaxError' do
- expect { described_class.seed('$VAR == (').tree }
- .to raise_error Gitlab::Ci::Pipeline::Expression::Lexer::SyntaxError
+ with_them do
+ it 'raises a ParseError' do
+ expect { described_class.seed(expression).tree }
+ .to raise_error Gitlab::Ci::Pipeline::Expression::Parser::ParseError
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 733ab30132d..34df0e86a18 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -931,47 +931,30 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
context 'when using 101 needs' do
let(:needs_count) { 101 }
- context 'when ci_plan_needs_size_limit is disabled' do
+ it "returns an error" do
+ expect(subject.errors).to contain_exactly(
+ "rspec: one job can only need 50 others, but you have listed 101. See needs keyword documentation for more details")
+ end
+
+ context 'when ci_needs_size_limit is set to 100' do
before do
- stub_feature_flags(ci_plan_needs_size_limit: false)
+ project.actual_limits.update!(ci_needs_size_limit: 100)
end
it "returns an error" do
expect(subject.errors).to contain_exactly(
- "rspec: one job can only need 10 others, but you have listed 101. See needs keyword documentation for more details")
+ "rspec: one job can only need 100 others, but you have listed 101. See needs keyword documentation for more details")
end
end
- context 'when ci_plan_needs_size_limit is enabled' do
+ context 'when ci_needs_size_limit is set to 0' do
before do
- stub_feature_flags(ci_plan_needs_size_limit: true)
+ project.actual_limits.update!(ci_needs_size_limit: 0)
end
it "returns an error" do
expect(subject.errors).to contain_exactly(
- "rspec: one job can only need 50 others, but you have listed 101. See needs keyword documentation for more details")
- end
-
- context 'when ci_needs_size_limit is set to 100' do
- before do
- project.actual_limits.update!(ci_needs_size_limit: 100)
- end
-
- it "returns an error" do
- expect(subject.errors).to contain_exactly(
- "rspec: one job can only need 100 others, but you have listed 101. See needs keyword documentation for more details")
- end
- end
-
- context 'when ci_needs_size_limit is set to 0' do
- before do
- project.actual_limits.update!(ci_needs_size_limit: 0)
- end
-
- it "returns an error" do
- expect(subject.errors).to contain_exactly(
- "rspec: one job can only need 0 others, but you have listed 101. See needs keyword documentation for more details")
- end
+ "rspec: one job can only need 0 others, but you have listed 101. See needs keyword documentation for more details")
end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline_object_hierarchy_spec.rb b/spec/lib/gitlab/ci/pipeline_object_hierarchy_spec.rb
new file mode 100644
index 00000000000..89602fe79d1
--- /dev/null
+++ b/spec/lib/gitlab/ci/pipeline_object_hierarchy_spec.rb
@@ -0,0 +1,111 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::PipelineObjectHierarchy do
+ include Ci::SourcePipelineHelpers
+
+ let_it_be(:project) { create(:project, :repository) }
+ let_it_be(:ancestor) { create(:ci_pipeline, project: project) }
+ let_it_be(:parent) { create(:ci_pipeline, project: project) }
+ let_it_be(:child) { create(:ci_pipeline, project: project) }
+ let_it_be(:cousin_parent) { create(:ci_pipeline, project: project) }
+ let_it_be(:cousin) { create(:ci_pipeline, project: project) }
+ let_it_be(:triggered_pipeline) { create(:ci_pipeline) }
+
+ before_all do
+ create_source_pipeline(ancestor, parent)
+ create_source_pipeline(ancestor, cousin_parent)
+ create_source_pipeline(parent, child)
+ create_source_pipeline(cousin_parent, cousin)
+ create_source_pipeline(child, triggered_pipeline)
+ end
+
+ describe '#base_and_ancestors' do
+ it 'includes the base and its ancestors' do
+ relation = described_class.new(::Ci::Pipeline.where(id: parent.id),
+ options: { same_project: true }).base_and_ancestors
+
+ expect(relation).to contain_exactly(ancestor, parent)
+ end
+
+ it 'can find ancestors upto a certain level' do
+ relation = described_class.new(::Ci::Pipeline.where(id: child.id),
+ options: { same_project: true }).base_and_ancestors(upto: ancestor.id)
+
+ expect(relation).to contain_exactly(parent, child)
+ end
+
+ describe 'hierarchy_order option' do
+ let(:relation) do
+ described_class.new(::Ci::Pipeline.where(id: child.id),
+ options: { same_project: true }).base_and_ancestors(hierarchy_order: hierarchy_order)
+ end
+
+ context ':asc' do
+ let(:hierarchy_order) { :asc }
+
+ it 'orders by child to ancestor' do
+ expect(relation).to eq([child, parent, ancestor])
+ end
+ end
+
+ context ':desc' do
+ let(:hierarchy_order) { :desc }
+
+ it 'orders by ancestor to child' do
+ expect(relation).to eq([ancestor, parent, child])
+ end
+ end
+ end
+ end
+
+ describe '#base_and_descendants' do
+ it 'includes the base and its descendants' do
+ relation = described_class.new(::Ci::Pipeline.where(id: parent.id),
+ options: { same_project: true }).base_and_descendants
+
+ expect(relation).to contain_exactly(parent, child)
+ end
+
+ context 'when with_depth is true' do
+ let(:relation) do
+ described_class.new(::Ci::Pipeline.where(id: ancestor.id),
+ options: { same_project: true }).base_and_descendants(with_depth: true)
+ end
+
+ it 'includes depth in the results' do
+ object_depths = {
+ ancestor.id => 1,
+ parent.id => 2,
+ cousin_parent.id => 2,
+ child.id => 3,
+ cousin.id => 3
+ }
+
+ relation.each do |object|
+ expect(object.depth).to eq(object_depths[object.id])
+ end
+ end
+ end
+ end
+
+ describe '#all_objects' do
+ it 'includes its ancestors and descendants' do
+ relation = described_class.new(::Ci::Pipeline.where(id: parent.id),
+ options: { same_project: true }).all_objects
+
+ expect(relation).to contain_exactly(ancestor, parent, child)
+ end
+
+ it 'returns all family tree' do
+ relation = described_class.new(
+ ::Ci::Pipeline.where(id: child.id),
+ described_class.new(::Ci::Pipeline.where(id: child.id), options: { same_project: true }).base_and_ancestors,
+ options: { same_project: true }
+ ).all_objects
+
+ expect(relation).to contain_exactly(ancestor, parent, cousin_parent, child, cousin)
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/reports/test_case_spec.rb b/spec/lib/gitlab/ci/reports/test_case_spec.rb
index 8882defbd9e..7fb208213c1 100644
--- a/spec/lib/gitlab/ci/reports/test_case_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_case_spec.rb
@@ -4,7 +4,7 @@ require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::TestCase do
describe '#initialize' do
- let(:test_case) { described_class.new(params)}
+ let(:test_case) { described_class.new(params) }
context 'when both classname and name are given' do
context 'when test case is passed' do
@@ -62,7 +62,9 @@ RSpec.describe Gitlab::Ci::Reports::TestCase do
end
context 'when attachment is present' do
- let(:attachment_test_case) { build(:test_case, :failed_with_attachment) }
+ let_it_be(:job) { create(:ci_build) }
+
+ let(:attachment_test_case) { build(:test_case, :failed_with_attachment, job: job) }
it "initializes the attachment if present" do
expect(attachment_test_case.attachment).to eq("some/path.png")
diff --git a/spec/lib/gitlab/ci/reports/test_suite_spec.rb b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
index fbe3473f6b0..15fa78444e5 100644
--- a/spec/lib/gitlab/ci/reports/test_suite_spec.rb
+++ b/spec/lib/gitlab/ci/reports/test_suite_spec.rb
@@ -176,6 +176,37 @@ RSpec.describe Gitlab::Ci::Reports::TestSuite do
end
end
+ describe '#sorted' do
+ subject { test_suite.sorted }
+
+ context 'when there are multiple failed test cases' do
+ before do
+ test_suite.add_test_case(create_test_case_rspec_failed('test_spec_1', 1.11))
+ test_suite.add_test_case(create_test_case_rspec_failed('test_spec_2', 4.44))
+ end
+
+ it 'returns test cases sorted by execution time desc' do
+ expect(subject.test_cases['failed'].each_value.first.execution_time).to eq(4.44)
+ expect(subject.test_cases['failed'].values.second.execution_time).to eq(1.11)
+ end
+ end
+
+ context 'when there are multiple test cases' do
+ let(:status_ordered) { %w(error failed success skipped) }
+
+ before do
+ test_suite.add_test_case(test_case_success)
+ test_suite.add_test_case(test_case_failed)
+ test_suite.add_test_case(test_case_error)
+ test_suite.add_test_case(test_case_skipped)
+ end
+
+ it 'returns test cases sorted by status' do
+ expect(subject.test_cases.keys).to eq(status_ordered)
+ end
+ end
+ end
+
Gitlab::Ci::Reports::TestCase::STATUS_TYPES.each do |status_type|
describe "##{status_type}" do
subject { test_suite.public_send("#{status_type}") }
diff --git a/spec/lib/gitlab/ci/status/bridge/common_spec.rb b/spec/lib/gitlab/ci/status/bridge/common_spec.rb
new file mode 100644
index 00000000000..92600b21afc
--- /dev/null
+++ b/spec/lib/gitlab/ci/status/bridge/common_spec.rb
@@ -0,0 +1,49 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Gitlab::Ci::Status::Bridge::Common do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:bridge) { create(:ci_bridge) }
+ let_it_be(:downstream_pipeline) { create(:ci_pipeline) }
+
+ before_all do
+ create(:ci_sources_pipeline,
+ source_pipeline: bridge.pipeline,
+ source_project: bridge.pipeline.project,
+ source_job: bridge,
+ pipeline: downstream_pipeline,
+ project: downstream_pipeline.project)
+ end
+
+ subject do
+ Gitlab::Ci::Status::Core
+ .new(bridge, user)
+ .extend(described_class)
+ end
+
+ describe '#details_path' do
+ context 'when user has access to read downstream pipeline' do
+ before do
+ downstream_pipeline.project.add_developer(user)
+ end
+
+ it { expect(subject).to have_details }
+ it { expect(subject.details_path).to include "pipelines/#{downstream_pipeline.id}" }
+
+ context 'when ci_bridge_pipeline_details is disabled' do
+ before do
+ stub_feature_flags(ci_bridge_pipeline_details: false)
+ end
+
+ it { expect(subject).not_to have_details }
+ it { expect(subject.details_path).to be_nil }
+ end
+ end
+
+ context 'when user does not have access to read downstream pipeline' do
+ it { expect(subject).not_to have_details }
+ it { expect(subject.details_path).to be_nil }
+ end
+ end
+end
diff --git a/spec/lib/gitlab/ci/status/composite_spec.rb b/spec/lib/gitlab/ci/status/composite_spec.rb
index e1dcd05373f..bcfb9f19792 100644
--- a/spec/lib/gitlab/ci/status/composite_spec.rb
+++ b/spec/lib/gitlab/ci/status/composite_spec.rb
@@ -20,7 +20,7 @@ RSpec.describe Gitlab::Ci::Status::Composite do
shared_examples 'compares status and warnings' do
let(:composite_status) do
- described_class.new(all_statuses)
+ described_class.new(all_statuses, dag: dag)
end
it 'returns status and warnings?' do
@@ -30,21 +30,29 @@ RSpec.describe Gitlab::Ci::Status::Composite do
end
context 'allow_failure: false' do
- where(:build_statuses, :result, :has_warnings) do
- %i(skipped) | 'skipped' | false
- %i(skipped success) | 'success' | false
- %i(created) | 'created' | false
- %i(preparing) | 'preparing' | false
- %i(canceled success skipped) | 'canceled' | false
- %i(pending created skipped) | 'pending' | false
- %i(pending created skipped success) | 'running' | false
- %i(running created skipped success) | 'running' | false
- %i(success waiting_for_resource) | 'waiting_for_resource' | false
- %i(success manual) | 'manual' | false
- %i(success scheduled) | 'scheduled' | false
- %i(created preparing) | 'preparing' | false
- %i(created success pending) | 'running' | false
- %i(skipped success failed) | 'failed' | false
+ where(:build_statuses, :dag, :result, :has_warnings) do
+ %i(skipped) | false | 'skipped' | false
+ %i(skipped success) | false | 'success' | false
+ %i(skipped success) | true | 'skipped' | false
+ %i(created) | false | 'created' | false
+ %i(preparing) | false | 'preparing' | false
+ %i(canceled success skipped) | false | 'canceled' | false
+ %i(canceled success skipped) | true | 'skipped' | false
+ %i(pending created skipped) | false | 'pending' | false
+ %i(pending created skipped success) | false | 'running' | false
+ %i(running created skipped success) | false | 'running' | false
+ %i(pending created skipped) | true | 'skipped' | false
+ %i(pending created skipped success) | true | 'skipped' | false
+ %i(running created skipped success) | true | 'skipped' | false
+ %i(success waiting_for_resource) | false | 'waiting_for_resource' | false
+ %i(success manual) | false | 'manual' | false
+ %i(success scheduled) | false | 'scheduled' | false
+ %i(created preparing) | false | 'preparing' | false
+ %i(created success pending) | false | 'running' | false
+ %i(skipped success failed) | false | 'failed' | false
+ %i(skipped success failed) | true | 'skipped' | false
+ %i(success manual) | true | 'pending' | false
+ %i(success failed created) | true | 'pending' | false
end
with_them do
@@ -57,11 +65,12 @@ RSpec.describe Gitlab::Ci::Status::Composite do
end
context 'allow_failure: true' do
- where(:build_statuses, :result, :has_warnings) do
- %i(manual) | 'skipped' | false
- %i(skipped failed) | 'success' | true
- %i(created failed) | 'created' | true
- %i(preparing manual) | 'preparing' | false
+ where(:build_statuses, :dag, :result, :has_warnings) do
+ %i(manual) | false | 'skipped' | false
+ %i(skipped failed) | false | 'success' | true
+ %i(skipped failed) | true | 'skipped' | true
+ %i(created failed) | false | 'created' | true
+ %i(preparing manual) | false | 'preparing' | false
end
with_them do
diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb
index def4d1b3bf6..768256ee6b3 100644
--- a/spec/lib/gitlab/ci/templates/templates_spec.rb
+++ b/spec/lib/gitlab/ci/templates/templates_spec.rb
@@ -3,21 +3,21 @@
require 'spec_helper'
RSpec.describe 'CI YML Templates' do
- subject { Gitlab::Ci::YamlProcessor.new(content) }
+ subject { Gitlab::Ci::YamlProcessor.new(content).execute }
let(:all_templates) { Gitlab::Template::GitlabCiYmlTemplate.all.map(&:full_name) }
- let(:disabled_templates) do
- Gitlab::Template::GitlabCiYmlTemplate.disabled_templates.map do |template|
- template + Gitlab::Template::GitlabCiYmlTemplate.extension
+ let(:excluded_templates) do
+ all_templates.select do |name|
+ Gitlab::Template::GitlabCiYmlTemplate.excluded_patterns.any? { |pattern| pattern.match?(name) }
end
end
- context 'included in a CI YAML configuration' do
+ context 'when including available templates in a CI YAML configuration' do
using RSpec::Parameterized::TableSyntax
where(:template_name) do
- all_templates - disabled_templates
+ all_templates - excluded_templates
end
with_them do
@@ -33,7 +33,7 @@ RSpec.describe 'CI YML Templates' do
end
it 'is valid' do
- expect { subject }.not_to raise_error
+ expect(subject).to be_valid
end
it 'require default stages to be included' do
@@ -41,4 +41,29 @@ RSpec.describe 'CI YML Templates' do
end
end
end
+
+ context 'when including unavailable templates in a CI YAML configuration' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:template_name) do
+ excluded_templates
+ end
+
+ with_them do
+ let(:content) do
+ <<~EOS
+ include:
+ - template: #{template_name}
+
+ concrete_build_implemented_by_a_user:
+ stage: test
+ script: do something
+ EOS
+ end
+
+ it 'is not valid' do
+ expect(subject).not_to be_valid
+ end
+ end
+ end
end
diff --git a/spec/lib/gitlab/ci/trace/stream_spec.rb b/spec/lib/gitlab/ci/trace/stream_spec.rb
index e28469c9404..d65b6fb41f6 100644
--- a/spec/lib/gitlab/ci/trace/stream_spec.rb
+++ b/spec/lib/gitlab/ci/trace/stream_spec.rb
@@ -151,6 +151,28 @@ RSpec.describe Gitlab::Ci::Trace::Stream, :clean_gitlab_redis_cache do
it_behaves_like 'appends'
end
+
+ describe 'metrics' do
+ let(:metrics) { spy('metrics') }
+ let(:io) { StringIO.new }
+ let(:stream) { described_class.new(metrics) { io } }
+
+ it 'increments trace streamed operation' do
+ stream.append(+'123456', 0)
+
+ expect(metrics)
+ .to have_received(:increment_trace_operation)
+ .with(operation: :streamed)
+ end
+
+ it 'increments trace bytes counter' do
+ stream.append(+'123456', 0)
+
+ expect(metrics)
+ .to have_received(:increment_trace_bytes)
+ .with(6)
+ end
+ end
end
describe '#set' do
diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb
index 85edf27d3e7..171877dbaee 100644
--- a/spec/lib/gitlab/ci/trace_spec.rb
+++ b/spec/lib/gitlab/ci/trace_spec.rb
@@ -11,6 +11,29 @@ RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state do
it { expect(trace).to delegate_method(:old_trace).to(:job) }
end
+ context 'when trace is migrated to object storage' do
+ let!(:job) { create(:ci_build, :trace_artifact) }
+ let!(:artifact1) { job.job_artifacts_trace }
+ let!(:artifact2) { job.reload.job_artifacts_trace }
+ let(:test_data) { "hello world" }
+
+ before do
+ stub_artifacts_object_storage
+
+ artifact1.file.migrate!(ObjectStorage::Store::REMOTE)
+ end
+
+ it 'reloads the trace after is it migrated' do
+ stub_const('Gitlab::HttpIO::BUFFER_SIZE', test_data.length)
+
+ expect_next_instance_of(Gitlab::HttpIO) do |http_io|
+ expect(http_io).to receive(:get_chunk).and_return(test_data, "")
+ end
+
+ expect(artifact2.job.trace.raw).to eq(test_data)
+ end
+ end
+
context 'when live trace feature is disabled' do
before do
stub_feature_flags(ci_enable_live_trace: false)
diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb
index 1c81cc83cd1..d596494a987 100644
--- a/spec/lib/gitlab/ci/yaml_processor_spec.rb
+++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb
@@ -7,10 +7,16 @@ module Gitlab
RSpec.describe YamlProcessor do
include StubRequests
- subject { described_class.new(config, user: nil) }
+ subject { described_class.new(config, user: nil).execute }
+
+ shared_examples 'returns errors' do |error_message|
+ it 'adds a message when an error is encountered' do
+ expect(subject.errors).to include(error_message)
+ end
+ end
describe '#build_attributes' do
- subject { described_class.new(config, user: nil).build_attributes(:rspec) }
+ subject { described_class.new(config, user: nil).execute.build_attributes(:rspec) }
describe 'attributes list' do
let(:config) do
@@ -92,7 +98,7 @@ module Gitlab
config = YAML.dump({ default: { tags: %w[A B] },
rspec: { script: "rspec" } })
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -139,7 +145,7 @@ module Gitlab
config = YAML.dump({ default: { interruptible: true },
rspec: { script: "rspec" } })
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -345,9 +351,7 @@ module Gitlab
EOYML
end
- it 'parses the workflow:rules configuration' do
- expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'workflow config contains unknown keys: variables')
- end
+ it_behaves_like 'returns errors', 'workflow config contains unknown keys: variables'
end
context 'with rules and variables' do
@@ -470,12 +474,11 @@ module Gitlab
end
it 'is propagated all the way up into the raised exception' do
- expect { subject }.to raise_error do |error|
- expect(error).to be_a(described_class::ValidationError)
- expect(error.message).to eq('jobs:invalid:artifacts config should be a hash')
- expect(error.warnings).to contain_exactly(/jobs:rspec may allow multiple pipelines to run/)
- end
+ expect(subject).not_to be_valid
+ expect(subject.warnings).to contain_exactly(/jobs:rspec may allow multiple pipelines to run/)
end
+
+ it_behaves_like 'returns errors', 'jobs:invalid:artifacts config should be a hash'
end
context 'when error is raised before composing the config' do
@@ -489,23 +492,18 @@ module Gitlab
EOYML
end
- it 'raises an exception with empty warnings array' do
- expect { subject }.to raise_error do |error|
- expect(error).to be_a(described_class::ValidationError)
- expect(error.message).to eq('Local file `unknown/file.yml` does not have project!')
- expect(error.warnings).to be_empty
- end
+ it 'has empty warnings' do
+ expect(subject.warnings).to be_empty
end
+
+ it_behaves_like 'returns errors', 'Local file `unknown/file.yml` does not have project!'
end
context 'when error is raised after composing the config with warnings' do
shared_examples 'has warnings and expected error' do |error_message|
- it 'raises an exception including warnings' do
- expect { subject }.to raise_error do |error|
- expect(error).to be_a(described_class::ValidationError)
- expect(error.message).to match(error_message)
- expect(error.warnings).to be_present
- end
+ it 'returns errors and warnings', :aggregate_failures do
+ expect(subject.errors).to include(error_message)
+ expect(subject.warnings).to be_present
end
end
@@ -585,72 +583,56 @@ module Gitlab
describe 'only / except policies validations' do
context 'when `only` has an invalid value' do
let(:config) { { rspec: { script: "rspec", type: "test", only: only } } }
- let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
context 'when it is integer' do
let(:only) { 1 }
- it do
- expect { processor }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:only has to be either an array of conditions or a hash')
- end
+ it_behaves_like 'returns errors', 'jobs:rspec:only has to be either an array of conditions or a hash'
end
context 'when it is an array of integers' do
let(:only) { [1, 1] }
- it do
- expect { processor }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:only config should be an array of strings or regexps')
- end
+ it_behaves_like 'returns errors', 'jobs:rspec:only config should be an array of strings or regexps'
end
context 'when it is invalid regex' do
let(:only) { ["/*invalid/"] }
- it do
- expect { processor }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:only config should be an array of strings or regexps')
- end
+ it_behaves_like 'returns errors', 'jobs:rspec:only config should be an array of strings or regexps'
end
end
context 'when `except` has an invalid value' do
let(:config) { { rspec: { script: "rspec", except: except } } }
- let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
context 'when it is integer' do
let(:except) { 1 }
- it do
- expect { processor }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:except has to be either an array of conditions or a hash')
- end
+ it_behaves_like 'returns errors', 'jobs:rspec:except has to be either an array of conditions or a hash'
end
context 'when it is an array of integers' do
let(:except) { [1, 1] }
- it do
- expect { processor }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:except config should be an array of strings or regexps')
- end
+ it_behaves_like 'returns errors', 'jobs:rspec:except config should be an array of strings or regexps'
end
context 'when it is invalid regex' do
let(:except) { ["/*invalid/"] }
- it do
- expect { processor }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:except config should be an array of strings or regexps')
- end
+ it_behaves_like 'returns errors', 'jobs:rspec:except config should be an array of strings or regexps'
end
end
end
describe "Scripts handling" do
let(:config_data) { YAML.dump(config) }
- let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data) }
+ let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config_data).execute }
subject { config_processor.stage_builds_attributes('test').first }
@@ -819,7 +801,7 @@ module Gitlab
before_script: ["pwd"],
rspec: { script: "rspec" } })
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -852,7 +834,7 @@ module Gitlab
command: ["/usr/local/bin/init", "run"] }, "docker:dind"],
script: "rspec" } })
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -883,7 +865,7 @@ module Gitlab
before_script: ["pwd"],
rspec: { script: "rspec" } })
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -910,7 +892,7 @@ module Gitlab
before_script: ["pwd"],
rspec: { image: "ruby:2.5", services: ["postgresql", "docker:dind"], script: "rspec" } })
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -934,9 +916,9 @@ module Gitlab
end
describe 'Variables' do
- let(:config_processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
- subject { config_processor.builds.first[:yaml_variables] }
+ let(:build_variables) { subject.builds.first[:yaml_variables] }
context 'when global variables are defined' do
let(:variables) do
@@ -952,7 +934,7 @@ module Gitlab
end
it 'returns global variables' do
- expect(subject).to contain_exactly(
+ expect(build_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
@@ -980,7 +962,7 @@ module Gitlab
let(:inherit) { }
it 'returns all unique variables' do
- expect(subject).to contain_exactly(
+ expect(build_variables).to contain_exactly(
{ key: 'VAR4', value: 'global4', public: true },
{ key: 'VAR3', value: 'global3', public: true },
{ key: 'VAR1', value: 'value1', public: true },
@@ -993,7 +975,7 @@ module Gitlab
let(:inherit) { { variables: false } }
it 'does not inherit variables' do
- expect(subject).to contain_exactly(
+ expect(build_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
@@ -1004,7 +986,7 @@ module Gitlab
let(:inherit) { { variables: %w[VAR1 VAR4] } }
it 'returns all unique variables and inherits only specified variables' do
- expect(subject).to contain_exactly(
+ expect(build_variables).to contain_exactly(
{ key: 'VAR4', value: 'global4', public: true },
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
@@ -1027,7 +1009,7 @@ module Gitlab
end
it 'returns job variables' do
- expect(subject).to contain_exactly(
+ expect(build_variables).to contain_exactly(
{ key: 'VAR1', value: 'value1', public: true },
{ key: 'VAR2', value: 'value2', public: true }
)
@@ -1040,11 +1022,7 @@ module Gitlab
%w(VAR1 value1 VAR2 value2)
end
- it 'raises error' do
- expect { subject }
- .to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- /jobs:rspec:variables config should be a hash of key value pairs/)
- end
+ it_behaves_like 'returns errors', /jobs:rspec:variables config should be a hash of key value pairs/
end
context 'when variables key defined but value not specified' do
@@ -1057,8 +1035,8 @@ module Gitlab
# When variables config is empty, we assume this is a valid
# configuration, see issue #18775
#
- expect(subject).to be_an_instance_of(Array)
- expect(subject).to be_empty
+ expect(build_variables).to be_an_instance_of(Array)
+ expect(build_variables).to be_empty
end
end
end
@@ -1073,14 +1051,14 @@ module Gitlab
end
it 'returns empty array' do
- expect(subject).to be_an_instance_of(Array)
- expect(subject).to be_empty
+ expect(build_variables).to be_an_instance_of(Array)
+ expect(build_variables).to be_empty
end
end
end
context 'when using `extends`' do
- let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
+ let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config).execute }
subject { config_processor.builds.first }
@@ -1142,31 +1120,25 @@ module Gitlab
}
end
- subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config), opts) }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config), opts).execute }
context "when validating a ci config file with no project context" do
context "when a single string is provided" do
let(:include_content) { "/local.gitlab-ci.yml" }
- it "returns a validation error" do
- expect { subject }.to raise_error /does not have project/
- end
+ it_behaves_like 'returns errors', /does not have project/
end
context "when an array is provided" do
let(:include_content) { ["/local.gitlab-ci.yml"] }
- it "returns a validation error" do
- expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, /does not have project/)
- end
+ it_behaves_like 'returns errors', /does not have project/
end
context "when an array of wrong keyed object is provided" do
let(:include_content) { [{ yolo: "/local.gitlab-ci.yml" }] }
- it "returns a validation error" do
- expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError)
- end
+ it_behaves_like 'returns errors', /needs to match exactly one accessor/
end
context "when an array of mixed typed objects is provided" do
@@ -1185,17 +1157,13 @@ module Gitlab
body: 'prepare: { script: ls -al }')
end
- it "does not return any error" do
- expect { subject }.not_to raise_error
- end
+ it { is_expected.to be_valid }
end
context "when the include type is incorrect" do
let(:include_content) { { name: "/local.gitlab-ci.yml" } }
- it "returns an invalid configuration error" do
- expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError)
- end
+ it_behaves_like 'returns errors', /needs to match exactly one accessor/
end
end
@@ -1210,18 +1178,11 @@ module Gitlab
.and_return(YAML.dump({ job1: { script: 'hello' } }))
end
- it "does not return an error" do
- expect { subject }.not_to raise_error
- end
+ it { is_expected.to be_valid }
end
context "when the included internal file is not present" do
- it "returns an error with missing file details" do
- expect { subject }.to raise_error(
- Gitlab::Ci::YamlProcessor::ValidationError,
- "Local file `#{include_content}` does not exist!"
- )
- end
+ it_behaves_like 'returns errors', "Local file `/local.gitlab-ci.yml` does not exist!"
end
end
end
@@ -1233,7 +1194,7 @@ module Gitlab
rspec: { script: 'rspec', when: when_state }
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
builds = config_processor.stage_builds_attributes("test")
expect(builds.size).to eq(1)
@@ -1243,13 +1204,14 @@ module Gitlab
context 'delayed' do
context 'with start_in' do
- it 'creates one build and sets when:' do
- config = YAML.dump({
+ let(:config) do
+ YAML.dump({
rspec: { script: 'rspec', when: 'delayed', start_in: '1 hour' }
})
+ end
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
- builds = config_processor.stage_builds_attributes("test")
+ it 'creates one build and sets when:' do
+ builds = subject.stage_builds_attributes("test")
expect(builds.size).to eq(1)
expect(builds.first[:when]).to eq('delayed')
@@ -1258,15 +1220,13 @@ module Gitlab
end
context 'without start_in' do
- it 'raises an error' do
- config = YAML.dump({
+ let(:config) do
+ YAML.dump({
rspec: { script: 'rspec', when: 'delayed' }
})
-
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(YamlProcessor::ValidationError, /start in should be a duration/)
end
+
+ it_behaves_like 'returns errors', /start in should be a duration/
end
end
end
@@ -1278,7 +1238,7 @@ module Gitlab
variables: { 'VAR1' => 1 } })
end
- let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
+ let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config).execute }
let(:builds) { config_processor.stage_builds_attributes('test') }
context 'when job is parallelized' do
@@ -1377,16 +1337,13 @@ module Gitlab
describe 'cache' do
context 'when cache definition has unknown keys' do
- it 'raises relevant validation error' do
- config = YAML.dump(
+ let(:config) do
+ YAML.dump(
{ cache: { untracked: true, invalid: 'key' },
rspec: { script: 'rspec' } })
-
- expect { Gitlab::Ci::YamlProcessor.new(config) }.to raise_error(
- Gitlab::Ci::YamlProcessor::ValidationError,
- 'cache config contains unknown keys: invalid'
- )
end
+
+ it_behaves_like 'returns errors', 'cache config contains unknown keys: invalid'
end
it "returns cache when defined globally" do
@@ -1397,7 +1354,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
@@ -1419,7 +1376,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
@@ -1438,7 +1395,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
@@ -1461,7 +1418,7 @@ module Gitlab
}
)
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
@@ -1484,7 +1441,7 @@ module Gitlab
}
)
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes('test').size).to eq(1)
expect(config_processor.stage_builds_attributes('test').first[:cache]).to eq(
@@ -1504,7 +1461,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first[:cache]).to eq(
@@ -1534,7 +1491,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
expect(config_processor.stage_builds_attributes("test").size).to eq(1)
expect(config_processor.stage_builds_attributes("test").first).to eq({
@@ -1570,7 +1527,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
builds = config_processor.stage_builds_attributes("test")
expect(builds.size).to eq(1)
@@ -1586,7 +1543,7 @@ module Gitlab
}
})
- config_processor = Gitlab::Ci::YamlProcessor.new(config)
+ config_processor = Gitlab::Ci::YamlProcessor.new(config).execute
builds = config_processor.stage_builds_attributes("test")
expect(builds.size).to eq(1)
@@ -1594,17 +1551,19 @@ module Gitlab
end
end
- it "gracefully handles errors in artifacts type" do
- config = <<~YAML
- test:
- script:
- - echo "Hello world"
- artifacts:
- - paths:
- - test/
- YAML
+ context 'when artifacts syntax is wrong' do
+ let(:config) do
+ <<~YAML
+ test:
+ script:
+ - echo "Hello world"
+ artifacts:
+ - paths:
+ - test/
+ YAML
+ end
- expect { described_class.new(config) }.to raise_error(described_class::ValidationError)
+ it_behaves_like 'returns errors', 'jobs:test:artifacts config should be a hash'
end
it 'populates a build options with complete artifacts configuration' do
@@ -1620,14 +1579,14 @@ module Gitlab
- my/test/something
YAML
- attributes = Gitlab::Ci::YamlProcessor.new(config).build_attributes('test')
+ attributes = Gitlab::Ci::YamlProcessor.new(config).execute.build_attributes('test')
expect(attributes.dig(*%i[options artifacts exclude])).to eq(%w[my/test/something])
end
end
describe "release" do
- let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+ let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
let(:config) do
{
stages: %w[build test release],
@@ -1672,8 +1631,9 @@ module Gitlab
}
end
- let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
- let(:builds) { processor.stage_builds_attributes('deploy') }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
+
+ let(:builds) { subject.stage_builds_attributes('deploy') }
context 'when a production environment is specified' do
let(:environment) { 'production' }
@@ -1723,18 +1683,13 @@ module Gitlab
context 'is not a string' do
let(:environment) { 1 }
- it 'raises error' do
- expect { builds }.to raise_error(
- 'jobs:deploy_to_production:environment config should be a hash or a string')
- end
+ it_behaves_like 'returns errors', 'jobs:deploy_to_production:environment config should be a hash or a string'
end
context 'is not a valid string' do
let(:environment) { 'production:staging' }
- it 'raises error' do
- expect { builds }.to raise_error("jobs:deploy_to_production:environment name #{Gitlab::Regex.environment_name_regex_message}")
- end
+ it_behaves_like 'returns errors', "jobs:deploy_to_production:environment name #{Gitlab::Regex.environment_name_regex_message}"
end
context 'when on_stop is specified' do
@@ -1753,33 +1708,25 @@ module Gitlab
context 'without matching job' do
let(:close_review) { nil }
- it 'raises error' do
- expect { builds }.to raise_error('review job: on_stop job close_review is not defined')
- end
+ it_behaves_like 'returns errors', 'review job: on_stop job close_review is not defined'
end
context 'with close job without environment' do
let(:close_review) { { stage: 'deploy', script: 'test' } }
- it 'raises error' do
- expect { builds }.to raise_error('review job: on_stop job close_review does not have environment defined')
- end
+ it_behaves_like 'returns errors', 'review job: on_stop job close_review does not have environment defined'
end
context 'with close job for different environment' do
let(:close_review) { { stage: 'deploy', script: 'test', environment: 'production' } }
- it 'raises error' do
- expect { builds }.to raise_error('review job: on_stop job close_review have different environment name')
- end
+ it_behaves_like 'returns errors', 'review job: on_stop job close_review have different environment name'
end
context 'with close job without stop action' do
let(:close_review) { { stage: 'deploy', script: 'test', environment: { name: 'review' } } }
- it 'raises error' do
- expect { builds }.to raise_error('review job: on_stop job close_review needs to have action stop defined')
- end
+ it_behaves_like 'returns errors', 'review job: on_stop job close_review needs to have action stop defined'
end
end
end
@@ -1794,8 +1741,9 @@ module Gitlab
}
end
- let(:processor) { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
- let(:builds) { processor.stage_builds_attributes('deploy') }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
+
+ let(:builds) { subject.stage_builds_attributes('deploy') }
context 'when no timeout was provided' do
it 'does not include job_timeout' do
@@ -1809,9 +1757,7 @@ module Gitlab
config[:deploy_to_production][:timeout] = 'not-a-number'
end
- it 'raises an error for invalid number' do
- expect { builds }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:deploy_to_production:timeout config should be a duration')
- end
+ it_behaves_like 'returns errors', 'jobs:deploy_to_production:timeout config should be a duration'
end
context 'when some valid timeout was provided' do
@@ -1837,36 +1783,36 @@ module Gitlab
}
end
- subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
context 'no dependencies' do
let(:dependencies) { }
- it { expect { subject }.not_to raise_error }
+ it { is_expected.to be_valid }
end
context 'dependencies to builds' do
let(:dependencies) { %w(build1 build2) }
- it { expect { subject }.not_to raise_error }
+ it { is_expected.to be_valid }
end
context 'dependencies to builds defined as symbols' do
let(:dependencies) { [:build1, :build2] }
- it { expect { subject }.not_to raise_error }
+ it { is_expected.to be_valid }
end
context 'undefined dependency' do
let(:dependencies) { ['undefined'] }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'test1 job: undefined dependency: undefined') }
+ it_behaves_like 'returns errors', 'test1 job: undefined dependency: undefined'
end
context 'dependencies to deploy' do
let(:dependencies) { ['deploy'] }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'test1 job: dependency deploy is not defined in prior stages') }
+ it_behaves_like 'returns errors', 'test1 job: dependency deploy is not defined in prior stages'
end
context 'when a job depends on another job that references a not-yet defined stage' do
@@ -1891,7 +1837,7 @@ module Gitlab
}
end
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, /is not defined in prior stages/) }
+ it_behaves_like 'returns errors', /is not defined in prior stages/
end
end
@@ -1910,10 +1856,10 @@ module Gitlab
}
end
- subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
context 'no needs' do
- it { expect { subject }.not_to raise_error }
+ it { is_expected.to be_valid }
end
context 'needs two builds' do
@@ -2053,20 +1999,20 @@ module Gitlab
context 'undefined need' do
let(:needs) { ['undefined'] }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'test1 job: undefined need: undefined') }
+ it_behaves_like 'returns errors', 'test1 job: undefined need: undefined'
end
context 'needs to deploy' do
let(:needs) { ['deploy'] }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'test1 job: need deploy is not defined in prior stages') }
+ it_behaves_like 'returns errors', 'test1 job: need deploy is not defined in prior stages'
end
context 'needs and dependencies that are mismatching' do
let(:needs) { %w(build1) }
let(:dependencies) { %w(build2) }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:test1 dependencies the build2 should be part of needs') }
+ it_behaves_like 'returns errors', 'jobs:test1 dependencies the build2 should be part of needs'
end
context 'needs with a Hash type and dependencies with a string type that are mismatching' do
@@ -2079,33 +2025,33 @@ module Gitlab
let(:dependencies) { %w(build3) }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:test1 dependencies the build3 should be part of needs') }
+ it_behaves_like 'returns errors', 'jobs:test1 dependencies the build3 should be part of needs'
end
context 'needs with an array type and dependency with a string type' do
let(:needs) { %w(build1) }
let(:dependencies) { 'deploy' }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:test1 dependencies should be an array of strings') }
+ it_behaves_like 'returns errors', 'jobs:test1 dependencies should be an array of strings'
end
context 'needs with a string type and dependency with an array type' do
let(:needs) { 'build1' }
let(:dependencies) { %w(deploy) }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:test1:needs config can only be a hash or an array') }
+ it_behaves_like 'returns errors', 'jobs:test1:needs config can only be a hash or an array'
end
context 'needs with a Hash type and dependency with a string type' do
let(:needs) { { job: 'build1' } }
let(:dependencies) { 'deploy' }
- it { expect { subject }.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:test1 dependencies should be an array of strings') }
+ it_behaves_like 'returns errors', 'jobs:test1 dependencies should be an array of strings'
end
end
context 'with when/rules conflict' do
- subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)) }
+ subject { Gitlab::Ci::YamlProcessor.new(YAML.dump(config)).execute }
let(:config) do
{
@@ -2121,9 +2067,7 @@ module Gitlab
}
end
- it 'raises no exceptions' do
- expect { subject }.not_to raise_error
- end
+ it { is_expected.to be_valid }
it 'returns all jobs regardless of their inclusion' do
expect(subject.builds.count).to eq(config.keys.count)
@@ -2141,9 +2085,7 @@ module Gitlab
}
end
- it 'raises a ValidationError' do
- expect { subject }.to raise_error(YamlProcessor::ValidationError, /may not be used with `rules`: when/)
- end
+ it_behaves_like 'returns errors', /may not be used with `rules`: when/
end
context 'used with job-level when:delayed' do
@@ -2159,14 +2101,12 @@ module Gitlab
}
end
- it 'raises a ValidationError' do
- expect { subject }.to raise_error(YamlProcessor::ValidationError, /may not be used with `rules`: when, start_in/)
- end
+ it_behaves_like 'returns errors', /may not be used with `rules`: when, start_in/
end
end
describe "Hidden jobs" do
- let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
+ let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config).execute }
subject { config_processor.stage_builds_attributes("test") }
@@ -2213,7 +2153,7 @@ module Gitlab
end
describe "YAML Alias/Anchor" do
- let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config) }
+ let(:config_processor) { Gitlab::Ci::YamlProcessor.new(config).execute }
subject { config_processor.stage_builds_attributes("build") }
@@ -2310,7 +2250,7 @@ module Gitlab
})
end
- it { expect { subject }.not_to raise_error }
+ it { is_expected.to be_valid }
end
context 'when job is not specified specified while artifact is' do
@@ -2323,11 +2263,7 @@ module Gitlab
})
end
- it do
- expect { subject }.to raise_error(
- described_class::ValidationError,
- /include config must specify the job where to fetch the artifact from/)
- end
+ it_behaves_like 'returns errors', /include config must specify the job where to fetch the artifact from/
end
context 'when include is a string' do
@@ -2343,376 +2279,323 @@ module Gitlab
})
end
- it { expect { subject }.not_to raise_error }
+ it { is_expected.to be_valid }
end
end
describe "Error handling" do
- it "fails to parse YAML" do
- expect do
- Gitlab::Ci::YamlProcessor.new("invalid: yaml: test")
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError)
+ subject { described_class.new(config).execute }
+
+ context 'when YAML syntax is invalid' do
+ let(:config) { 'invalid: yaml: test' }
+
+ it_behaves_like 'returns errors', /mapping values are not allowed/
end
- it "indicates that object is invalid" do
- expect do
- Gitlab::Ci::YamlProcessor.new("invalid_yaml")
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError)
+ context 'when object is invalid' do
+ let(:config) { 'invalid_yaml' }
+
+ it_behaves_like 'returns errors', /Invalid configuration format/
end
- it "returns errors if tags parameter is invalid" do
- config = YAML.dump({ rspec: { script: "test", tags: "mysql" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:tags config should be an array of strings")
+ context 'returns errors if tags parameter is invalid' do
+ let(:config) { YAML.dump({ rspec: { script: "test", tags: "mysql" } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:tags config 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
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "before_script config should be an array containing strings and arrays of strings")
+ context 'returns errors if before_script parameter is invalid' do
+ let(:config) { YAML.dump({ before_script: "bundle update", rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'before_script config should be an array containing strings and arrays of strings'
end
- 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
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array containing strings and arrays of strings")
+ context 'returns errors if job before_script parameter is not an array of strings' do
+ let(:config) { YAML.dump({ rspec: { script: "test", before_script: [10, "test"] } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:before_script config should be an array containing strings and arrays of strings'
end
- it "returns errors if job before_script parameter is multi-level nested array of strings" do
- config = YAML.dump({ rspec: { script: "test", before_script: [["ls", ["pwd"]], "test"] } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:before_script config should be an array containing strings and arrays of strings")
+ context 'returns errors if job before_script parameter is multi-level nested array of strings' do
+ let(:config) { YAML.dump({ rspec: { script: "test", before_script: [["ls", ["pwd"]], "test"] } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:before_script config should be an array containing strings and arrays of strings'
end
- it "returns errors if after_script parameter is invalid" do
- config = YAML.dump({ after_script: "bundle update", rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "after_script config should be an array containing strings and arrays of strings")
+ context 'returns errors if after_script parameter is invalid' do
+ let(:config) { YAML.dump({ after_script: "bundle update", rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'after_script config should be an array containing strings and arrays of strings'
end
- 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"] } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array containing strings and arrays of strings")
+ context 'returns errors if job after_script parameter is not an array of strings' do
+ let(:config) { YAML.dump({ rspec: { script: "test", after_script: [10, "test"] } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:after_script config should be an array containing strings and arrays of strings'
end
- it "returns errors if job after_script parameter is multi-level nested array of strings" do
- config = YAML.dump({ rspec: { script: "test", after_script: [["ls", ["pwd"]], "test"] } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:after_script config should be an array containing strings and arrays of strings")
+ context 'returns errors if job after_script parameter is multi-level nested array of strings' do
+ let(:config) { YAML.dump({ rspec: { script: "test", after_script: [["ls", ["pwd"]], "test"] } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:after_script config should be an array containing strings and arrays of strings'
end
- it "returns errors if image parameter is invalid" do
- config = YAML.dump({ image: ["test"], rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "image config should be a hash or a string")
+ context 'returns errors if image parameter is invalid' do
+ let(:config) { YAML.dump({ image: ["test"], rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'image config should be a hash or a string'
end
- it "returns errors if job name is blank" do
- config = YAML.dump({ '' => { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:job name can't be blank")
+ context 'returns errors if job name is blank' do
+ let(:config) { YAML.dump({ '' => { script: "test" } }) }
+
+ it_behaves_like 'returns errors', "jobs:job name can't be blank"
end
- it "returns errors if job name is non-string" do
- config = YAML.dump({ 10 => { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:10 name should be a symbol")
+ context 'returns errors if job name is non-string' do
+ let(:config) { YAML.dump({ 10 => { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'jobs:10 name should be a symbol'
end
- it "returns errors if job image parameter is invalid" do
- config = YAML.dump({ rspec: { script: "test", image: ["test"] } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:image config should be a hash or a string")
+ context 'returns errors if job image parameter is invalid' do
+ let(:config) { YAML.dump({ rspec: { script: "test", image: ["test"] } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:image config should be a hash or a string'
end
- it "returns errors if services parameter is not an array" do
- config = YAML.dump({ services: "test", rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "services config should be a array")
+ context 'returns errors if services parameter is not an array' do
+ let(:config) { YAML.dump({ services: "test", rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'services config should be a array'
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
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "services:service config should be a hash or a string")
+ context 'returns errors if services parameter is not an array of strings' do
+ let(:config) { YAML.dump({ services: [10, "test"], rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'services:service config should be a hash or a string'
end
- it "returns errors if job services parameter is not an array" do
- config = YAML.dump({ rspec: { script: "test", services: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:services config should be a array")
+ context 'returns errors if job services parameter is not an array' do
+ let(:config) { YAML.dump({ rspec: { script: "test", services: "test" } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:services config should be a array'
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
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:services:service config should be a hash or a string")
+ context 'returns errors if job services parameter is not an array of strings' do
+ let(:config) { YAML.dump({ rspec: { script: "test", services: [10, "test"] } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:services:service config should be a hash or a string'
end
- it "returns error if job configuration is invalid" do
- config = YAML.dump({ extra: "bundle update" })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "root config contains unknown keys: extra")
+ context 'returns error if job configuration is invalid' do
+ let(:config) { YAML.dump({ extra: "bundle update" }) }
+
+ it_behaves_like 'returns errors', 'jobs extra config should implement a script: or a trigger: keyword'
end
- it "returns errors if services configuration is not correct" do
- config = YAML.dump({ extra: { script: 'rspec', services: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:extra:services config should be a array")
+ context 'returns errors if services configuration is not correct' do
+ let(:config) { YAML.dump({ extra: { script: 'rspec', services: "test" } }) }
+
+ it_behaves_like 'returns errors', 'jobs:extra:services config should be a array'
end
- it "returns errors if there are no jobs defined" do
- config = YAML.dump({ before_script: ["bundle update"] })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job")
+ context 'returns errors if there are no jobs defined' do
+ let(:config) { YAML.dump({ before_script: ["bundle update"] }) }
+
+ it_behaves_like 'returns errors', 'jobs config should contain at least one visible job'
end
- it "returns errors if the job script is not defined" do
- config = YAML.dump({ rspec: { before_script: "test" } })
+ context 'returns errors if the job script is not defined' do
+ let(:config) { YAML.dump({ rspec: { before_script: "test" } }) }
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec script can't be blank")
+ it_behaves_like 'returns errors', 'jobs rspec config should implement a script: or a trigger: keyword'
end
- it "returns errors if there are no visible jobs defined" do
- config = YAML.dump({ before_script: ["bundle update"], '.hidden'.to_sym => { script: 'ls' } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs config should contain at least one visible job")
+ context 'returns errors if there are no visible jobs defined' do
+ let(:config) { YAML.dump({ before_script: ["bundle update"], '.hidden'.to_sym => { script: 'ls' } }) }
+
+ it_behaves_like 'returns errors', 'jobs config should contain at least one visible job'
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
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec allow failure should be a boolean value")
+ context 'returns errors if job allow_failure parameter is not an boolean' do
+ let(:config) { YAML.dump({ rspec: { script: "test", allow_failure: "string" } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec allow failure should be a boolean value'
end
- it "returns errors if job stage is not a string" do
- config = YAML.dump({ rspec: { script: "test", type: 1 } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:type config should be a string")
+ context 'returns errors if job stage is not a string' do
+ let(:config) { YAML.dump({ rspec: { script: "test", type: 1 } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:type config should be a string'
end
- it "returns errors if job stage is not a pre-defined stage" do
- config = YAML.dump({ rspec: { script: "test", type: "acceptance" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post")
+ context 'returns errors if job stage is not a pre-defined stage' do
+ let(:config) { YAML.dump({ rspec: { script: "test", type: "acceptance" } }) }
+
+ it_behaves_like 'returns errors', 'rspec job: chosen stage does not exist; available stages are .pre, build, test, deploy, .post'
end
- it "returns errors if job stage is not a defined stage" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", type: "acceptance" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "rspec job: chosen stage does not exist; available stages are .pre, build, test, .post")
+ context 'returns errors if job stage is not a defined stage' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", type: "acceptance" } }) }
+
+ it_behaves_like 'returns errors', 'rspec job: chosen stage does not exist; available stages are .pre, build, test, .post'
end
- it "returns errors if stages is not an array" do
- config = YAML.dump({ stages: "test", rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings")
+ context 'returns errors if stages is not an array' do
+ let(:config) { YAML.dump({ stages: "test", rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'stages config should be an array of strings'
end
- it "returns errors if stages is not an array of strings" do
- config = YAML.dump({ stages: [true, "test"], rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "stages config should be an array of strings")
+ context 'returns errors if stages is not an array of strings' do
+ let(:config) { YAML.dump({ stages: [true, "test"], rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'stages config should be an array of strings'
end
- it "returns errors if variables is not a map" do
- config = YAML.dump({ variables: "test", rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs")
+ context 'returns errors if variables is not a map' do
+ let(:config) { YAML.dump({ variables: "test", rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'variables config should be a hash of key value pairs'
end
- it "returns errors if variables is not a map of key-value strings" do
- config = YAML.dump({ variables: { test: false }, rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "variables config should be a hash of key value pairs")
+ context 'returns errors if variables is not a map of key-value strings' do
+ let(:config) { YAML.dump({ variables: { test: false }, rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'variables config should be a hash of key value pairs'
end
- it "returns errors if job when is not on_success, on_failure or always" do
- config = YAML.dump({ rspec: { script: "test", when: 1 } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec when should be one of: #{Gitlab::Ci::Config::Entry::Job::ALLOWED_WHEN.join(', ')}")
+ context 'returns errors if job when is not on_success, on_failure or always' do
+ let(:config) { YAML.dump({ rspec: { script: "test", when: 1 } }) }
+
+ it_behaves_like 'returns errors', "jobs:rspec when should be one of: #{Gitlab::Ci::Config::Entry::Job::ALLOWED_WHEN.join(', ')}"
end
- it "returns errors if job artifacts:name is not an a string" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { name: 1 } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:artifacts name should be a string")
+ context 'returns errors if job artifacts:name is not an a string' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { name: 1 } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:artifacts name should be a string'
end
- it "returns errors if job artifacts:when is not an a predefined value" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { when: 1 } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:artifacts when should be on_success, on_failure or always")
+ context 'returns errors if job artifacts:when is not an a predefined value' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { when: 1 } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:artifacts when should be on_success, on_failure or always'
end
- it "returns errors if job artifacts:expire_in is not an a string" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { expire_in: 1 } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:artifacts expire in should be a duration")
+ context 'returns errors if job artifacts:expire_in is not an a string' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { expire_in: 1 } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:artifacts expire in should be a duration'
end
- it "returns errors if job artifacts:expire_in is not an a valid duration" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:artifacts expire in should be a duration")
+ context 'returns errors if job artifacts:expire_in is not an a valid duration' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { expire_in: "7 elephants" } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:artifacts expire in should be a duration'
end
- it "returns errors if job artifacts:untracked is not an array of strings" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { untracked: "string" } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:artifacts untracked should be a boolean value")
+ context 'returns errors if job artifacts:untracked is not an array of strings' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { untracked: "string" } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:artifacts untracked should be a boolean value'
end
- it "returns errors if job artifacts:paths is not an array of strings" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { paths: "string" } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:artifacts paths should be an array of strings")
+ context 'returns errors if job artifacts:paths is not an array of strings' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", artifacts: { paths: "string" } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:artifacts paths should be an array of strings'
end
- it "returns errors if cache:untracked is not an array of strings" do
- config = YAML.dump({ cache: { untracked: "string" }, rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "cache:untracked config should be a boolean value")
+ context 'returns errors if cache:untracked is not an array of strings' do
+ let(:config) { YAML.dump({ cache: { untracked: "string" }, rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'cache:untracked config should be a boolean value'
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
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "cache:paths config should be an array of strings")
+ context 'returns errors if cache:paths is not an array of strings' do
+ let(:config) { YAML.dump({ cache: { paths: "string" }, rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', 'cache:paths config should be an array of strings'
end
- it "returns errors if cache:key is not a string" do
- config = YAML.dump({ cache: { key: 1 }, rspec: { script: "test" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "cache:key should be a hash, a string or a symbol")
+ context 'returns errors if cache:key is not a string' do
+ let(:config) { YAML.dump({ cache: { key: 1 }, rspec: { script: "test" } }) }
+
+ it_behaves_like 'returns errors', "cache:key should be a hash, a string or a symbol"
end
- it "returns errors if job cache:key is not an a string" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: 1 } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:cache:key should be a hash, a string or a symbol")
+ context 'returns errors if job cache:key is not an a string' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: 1 } } }) }
+
+ it_behaves_like 'returns errors', "jobs:rspec:cache:key should be a hash, a string or a symbol"
end
- it 'returns errors if job cache:key:files is not an array of strings' do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { files: [1] } } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:rspec:cache:key:files config should be an array of strings')
+ context 'returns errors if job cache:key:files is not an array of strings' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { files: [1] } } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:cache:key:files config should be an array of strings'
end
- it 'returns errors if job cache:key:files is an empty array' do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { files: [] } } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:rspec:cache:key:files config requires at least 1 item')
+ context 'returns errors if job cache:key:files is an empty array' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { files: [] } } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:cache:key:files config requires at least 1 item'
end
- it 'returns errors if job defines only cache:key:prefix' do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { prefix: 'prefix-key' } } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:rspec:cache:key config missing required keys: files')
+ context 'returns errors if job defines only cache:key:prefix' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { prefix: 'prefix-key' } } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:cache:key config missing required keys: files'
end
- it 'returns errors if job cache:key:prefix is not an a string' do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { prefix: 1, files: ['file'] } } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, 'jobs:rspec:cache:key:prefix config should be a string or symbol')
+ context 'returns errors if job cache:key:prefix is not an a string' do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { key: { prefix: 1, files: ['file'] } } } }) }
+
+ it_behaves_like 'returns errors', 'jobs:rspec:cache:key:prefix config should be a string or symbol'
end
- it "returns errors if job cache:untracked is not an array of strings" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { untracked: "string" } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:cache:untracked config should be a boolean value")
+ context "returns errors if job cache:untracked is not an array of strings" do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { untracked: "string" } } }) }
+
+ it_behaves_like 'returns errors', "jobs:rspec:cache:untracked config should be a boolean value"
end
- it "returns errors if job cache:paths is not an array of strings" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { paths: "string" } } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec:cache:paths config should be an array of strings")
+ context "returns errors if job cache:paths is not an array of strings" do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", cache: { paths: "string" } } }) }
+
+ it_behaves_like 'returns errors', "jobs:rspec:cache:paths config should be an array of strings"
end
- it "returns errors if job dependencies is not an array of strings" do
- config = YAML.dump({ types: %w(build test), rspec: { script: "test", dependencies: "string" } })
- expect do
- Gitlab::Ci::YamlProcessor.new(config)
- end.to raise_error(Gitlab::Ci::YamlProcessor::ValidationError, "jobs:rspec dependencies should be an array of strings")
+ context "returns errors if job dependencies is not an array of strings" do
+ let(:config) { YAML.dump({ types: %w(build test), rspec: { script: "test", dependencies: "string" } }) }
+
+ it_behaves_like 'returns errors', "jobs:rspec dependencies should be an array of strings"
end
- it 'returns errors if pipeline variables expression policy is invalid' do
- config = YAML.dump({ rspec: { script: 'test', only: { variables: ['== null'] } } })
+ context 'returns errors if pipeline variables expression policy is invalid' do
+ let(:config) { YAML.dump({ rspec: { script: 'test', only: { variables: ['== null'] } } }) }
- expect { Gitlab::Ci::YamlProcessor.new(config) }
- .to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:only variables invalid expression syntax')
+ it_behaves_like 'returns errors', 'jobs:rspec:only variables invalid expression syntax'
end
- it 'returns errors if pipeline changes policy is invalid' do
- config = YAML.dump({ rspec: { script: 'test', only: { changes: [1] } } })
+ context 'returns errors if pipeline changes policy is invalid' do
+ let(:config) { YAML.dump({ rspec: { script: 'test', only: { changes: [1] } } }) }
- expect { Gitlab::Ci::YamlProcessor.new(config) }
- .to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:only changes should be an array of strings')
+ it_behaves_like 'returns errors', 'jobs:rspec:only changes should be an array of strings'
end
- it 'returns errors if extended hash configuration is invalid' do
- config = YAML.dump({ rspec: { extends: 'something', script: 'test' } })
+ context 'returns errors if extended hash configuration is invalid' do
+ let(:config) { YAML.dump({ rspec: { extends: 'something', script: 'test' } }) }
- expect { Gitlab::Ci::YamlProcessor.new(config) }
- .to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'rspec: unknown keys in `extends` (something)')
+ it_behaves_like 'returns errors', 'rspec: unknown keys in `extends` (something)'
end
- it 'returns errors if parallel is invalid' do
- config = YAML.dump({ rspec: { parallel: 'test', script: 'test' } })
+ context 'returns errors if parallel is invalid' do
+ let(:config) { YAML.dump({ rspec: { parallel: 'test', script: 'test' } }) }
- expect { Gitlab::Ci::YamlProcessor.new(config) }
- .to raise_error(Gitlab::Ci::YamlProcessor::ValidationError,
- 'jobs:rspec:parallel should be an integer or a hash')
+ it_behaves_like 'returns errors', 'jobs:rspec:parallel should be an integer or a hash'
end
end
@@ -2750,8 +2633,8 @@ module Gitlab
end
end
- describe '.new_with_validation_errors' do
- subject { Gitlab::Ci::YamlProcessor.new_with_validation_errors(content) }
+ describe '#execute' do
+ subject { Gitlab::Ci::YamlProcessor.new(content).execute }
context 'when the YAML could not be parsed' do
let(:content) { YAML.dump('invalid: yaml: test') }
@@ -2759,7 +2642,6 @@ module Gitlab
it 'returns errors and empty configuration' do
expect(subject.valid?).to eq(false)
expect(subject.errors).to eq(['Invalid configuration format'])
- expect(subject.config).to be_blank
end
end
@@ -2769,7 +2651,6 @@ module Gitlab
it 'returns errors and empty configuration' do
expect(subject.valid?).to eq(false)
expect(subject.errors).to eq(['jobs:rspec:tags config should be an array of strings'])
- expect(subject.config).to be_blank
end
end
@@ -2781,7 +2662,6 @@ module Gitlab
expect(subject.errors).to contain_exactly(
'jobs:rspec config contains unknown keys: bad_tags',
'jobs:rspec rules should be an array of hashes')
- expect(subject.config).to be_blank
end
end
@@ -2791,7 +2671,6 @@ module Gitlab
it 'returns errors and empty configuration' do
expect(subject.valid?).to eq(false)
expect(subject.errors).to eq(['Please provide content of .gitlab-ci.yml'])
- expect(subject.config).to be_blank
end
end
@@ -2801,7 +2680,6 @@ module Gitlab
it 'returns errors and empty configuration' do
expect(subject.valid?).to eq(false)
expect(subject.errors).to eq(['Unknown alias: bad_alias'])
- expect(subject.config).to be_blank
end
end
@@ -2811,7 +2689,7 @@ module Gitlab
it 'returns errors and empty configuration' do
expect(subject.valid?).to eq(true)
expect(subject.errors).to be_empty
- expect(subject.config).to be_present
+ expect(subject.builds).to be_present
end
end
end