summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/ci/pipeline
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline')
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb8
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb28
-rw-r--r--spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb1
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb2
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb29
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb117
-rw-r--r--spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb14
-rw-r--r--spec/lib/gitlab/ci/pipeline/seed/build_spec.rb56
14 files changed, 208 insertions, 59 deletions
diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
index 5d20b1b8fda..cc4aaffb0a4 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb
@@ -23,9 +23,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do
end
it 'does not process the second step' do
- subject.build! do |pipeline, sequence|
- expect(sequence).not_to be_complete
- end
+ subject.build!
expect(second_step).not_to have_received(:perform!)
end
@@ -43,9 +41,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do
end
it 'iterates through entire sequence' do
- subject.build! do |pipeline, sequence|
- expect(sequence).to be_complete
- end
+ subject.build!
expect(first_step).to have_received(:perform!)
expect(second_step).to have_received(:perform!)
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 931c62701ce..de580d2e148 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb
@@ -41,9 +41,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
)
end
+ let(:save_incompleted) { true }
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
- project: project, current_user: user, config_processor: yaml_processor
+ project: project, current_user: user, config_processor: yaml_processor, save_incompleted: save_incompleted
)
end
@@ -84,6 +85,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
perform!
expect(pipeline.status).to eq('failed')
+ expect(pipeline).to be_persisted
expect(pipeline.errors.to_a).to include('External validation failed')
end
@@ -98,6 +100,30 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do
perform!
end
+
+ context 'when save_incompleted is false' do
+ let(:save_incompleted) { false}
+
+ it 'adds errors to the pipeline without dropping it' do
+ perform!
+
+ expect(pipeline.status).to eq('pending')
+ expect(pipeline).not_to be_persisted
+ expect(pipeline.errors.to_a).to include('External validation failed')
+ end
+
+ it 'breaks the chain' do
+ perform!
+
+ expect(step.break?).to be true
+ end
+
+ it 'logs the authorization' do
+ expect(Gitlab::AppLogger).to receive(:info).with(message: 'Pipeline not authorized', project_id: project.id, user_id: user.id)
+
+ perform!
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
index 1dc2e0a1822..7eefb4d7876 100644
--- a/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/chain/validate/repository_spec.rb
@@ -68,6 +68,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::Repository do
proj.repository.add_tag(user, 'master', 'master')
end
end
+
let(:command) do
Gitlab::Ci::Pipeline::Chain::Command.new(
project: project, current_user: user, origin_ref: 'master')
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb
index 6601537a2d3..1448b045b18 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/and_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::And do
describe '.type' do
it 'is an operator' do
- expect(described_class.type).to eq :operator
+ expect(described_class.type).to eq :logical_operator
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
index 2bed47f0a87..ab223ae41fa 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/equals_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Equals do
describe '.type' do
it 'is an operator' do
- expect(described_class.type).to eq :operator
+ expect(described_class.type).to eq :logical_operator
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb
index efcea0b0e09..0da04d8dcf7 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/matches_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Matches do
describe '.type' do
it 'is an operator' do
- expect(described_class.type).to eq :operator
+ expect(described_class.type).to eq :logical_operator
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb
index a81e1713ef0..3cde4c5d9dc 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_equals_spec.rb
@@ -27,7 +27,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotEquals do
describe '.type' do
it 'is an operator' do
- expect(described_class.type).to eq :operator
+ expect(described_class.type).to eq :logical_operator
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb
index f44fe19f86d..9bff2355d58 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/not_matches_spec.rb
@@ -28,7 +28,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::NotMatches do
describe '.type' do
it 'is an operator' do
- expect(described_class.type).to eq :operator
+ expect(described_class.type).to eq :logical_operator
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb
index 7fe445975eb..c7d89c4e1e9 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/or_spec.rb
@@ -24,7 +24,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Or do
describe '.type' do
it 'is an operator' do
- expect(described_class.type).to eq :operator
+ expect(described_class.type).to eq :logical_operator
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
index 1a56a91c471..fa4f8a20984 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexeme/pattern_spec.rb
@@ -70,7 +70,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexeme::Pattern do
.to eq Gitlab::UntrustedRegexp.new('pattern')
end
- it 'is a eager scanner for regexp boundaries' do
+ it 'is an eager scanner for regexp boundaries' do
scanner = StringScanner.new('/some .* / pattern/')
token = described_class.scan(scanner)
diff --git a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
index 61c6ced4dac..6e242faa885 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/lexer_spec.rb
@@ -81,6 +81,35 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Lexer do
with_them do
it { is_expected.to eq(tokens) }
end
+
+ context 'with parentheses are used' do
+ where(:expression, :tokens) do
+ '($PRESENT_VARIABLE =~ /my var/) && $EMPTY_VARIABLE =~ /nope/' | ['(', '$PRESENT_VARIABLE', '=~', '/my var/', ')', '&&', '$EMPTY_VARIABLE', '=~', '/nope/']
+ '$PRESENT_VARIABLE =~ /my var/ || ($EMPTY_VARIABLE =~ /nope/)' | ['$PRESENT_VARIABLE', '=~', '/my var/', '||', '(', '$EMPTY_VARIABLE', '=~', '/nope/', ')']
+ '($PRESENT_VARIABLE && (null || $EMPTY_VARIABLE == ""))' | ['(', '$PRESENT_VARIABLE', '&&', '(', 'null', '||', '$EMPTY_VARIABLE', '==', '""', ')', ')']
+ 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
+ end
+ 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 1704cabfd2e..3394a75ac0a 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/parser_spec.rb
@@ -1,51 +1,79 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
+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 'when using two operators' do
- it 'returns a reverse descent parse tree' do
- expect(described_class.seed('$VAR1 == "123"').tree)
- .to be_a Gitlab::Ci::Pipeline::Expression::Lexeme::Equals
+ context 'validates simple operators' do
+ using RSpec::Parameterized::TableSyntax
+
+ where(:expression, :result_tree) do
+ '$VAR1 == "123"' | 'equals($VAR1, "123")'
+ '$VAR1 == "123" == $VAR2' | 'equals(equals($VAR1, "123"), $VAR2)'
+ '$VAR' | '$VAR'
+ '"some value"' | '"some value"'
+ 'null' | 'null'
+ '$VAR1 || $VAR2 && $VAR3' | 'or($VAR1, and($VAR2, $VAR3))'
+ '$VAR1 && $VAR2 || $VAR3' | 'or(and($VAR1, $VAR2), $VAR3)'
+ '$VAR1 && $VAR2 || $VAR3 && $VAR4' | 'or(and($VAR1, $VAR2), and($VAR3, $VAR4))'
+ '$VAR1 && ($VAR2 || $VAR3) && $VAR4' | 'and(and($VAR1, or($VAR2, $VAR3)), $VAR4)'
end
- end
- context 'when using three operators' do
- it 'returns a reverse descent parse tree' do
- expect(described_class.seed('$VAR1 == "123" == $VAR2').tree)
- .to be_a Gitlab::Ci::Pipeline::Expression::Lexeme::Equals
+ with_them do
+ it { expect(described_class.seed(expression).tree.inspect).to eq(result_tree) }
end
end
- context 'when using a single variable token' do
- it 'returns a single token instance' do
- expect(described_class.seed('$VAR').tree)
- .to be_a Gitlab::Ci::Pipeline::Expression::Lexeme::Variable
+ 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
end
end
- context 'when using a single string token' do
- it 'returns a single token instance' do
- expect(described_class.seed('"some value"').tree)
- .to be_a Gitlab::Ci::Pipeline::Expression::Lexeme::String
+ 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"))')
end
end
context 'when expression is empty' do
- it 'returns a null token' do
+ it 'raises a parsing error' do
expect { described_class.seed('').tree }
.to raise_error Gitlab::Ci::Pipeline::Expression::Parser::ParseError
end
end
- context 'when expression is null' do
- it 'returns a null token' do
- expect(described_class.seed('null').tree)
- .to be_a Gitlab::Ci::Pipeline::Expression::Lexeme::Null
- end
- end
-
context 'when two value tokens have no operator' do
it 'raises a parsing error' do
expect { described_class.seed('$VAR "text"').tree }
@@ -66,5 +94,42 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Parser do
.to raise_error Gitlab::Ci::Pipeline::Expression::Lexeme::Operator::OperatorError
end
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
+ 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
+ end
+ end
+ end
end
end
diff --git a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
index 642d6816030..cf3644c9ad5 100644
--- a/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/expression/statement_spec.rb
@@ -1,7 +1,6 @@
# frozen_string_literal: true
-require 'fast_spec_helper'
-require 'rspec-parameterized'
+require 'spec_helper'
RSpec.describe Gitlab::Ci::Pipeline::Expression::Statement do
subject do
@@ -109,6 +108,17 @@ RSpec.describe Gitlab::Ci::Pipeline::Expression::Statement do
'$UNDEFINED_VARIABLE || $PRESENT_VARIABLE' | 'my variable'
'$UNDEFINED_VARIABLE == null || $PRESENT_VARIABLE' | true
'$PRESENT_VARIABLE || $UNDEFINED_VARIABLE == null' | 'my variable'
+
+ '($PRESENT_VARIABLE)' | 'my variable'
+ '(($PRESENT_VARIABLE))' | 'my variable'
+ '(($PRESENT_VARIABLE && null) || $EMPTY_VARIABLE == "")' | true
+ '($PRESENT_VARIABLE) && (null || $EMPTY_VARIABLE == "")' | true
+ '("string" || "test") == "string"' | true
+ '(null || ("test" == "string"))' | false
+ '("string" == ("test" && "string"))' | true
+ '("string" == ("test" || "string"))' | false
+ '("string" == "test" || "string")' | "string"
+ '("string" == ("string" || (("1" == "1") && ("2" == "3"))))' | true
end
with_them do
diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
index 2dea554fe56..733ab30132d 100644
--- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
+++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb
@@ -928,29 +928,51 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do
end
end
- context 'when lower limit of needs is reached' do
- before do
- stub_feature_flags(ci_dag_limit_needs: true)
- end
+ context 'when using 101 needs' do
+ let(:needs_count) { 101 }
- let(:needs_count) { described_class::LOW_NEEDS_LIMIT + 1 }
+ context 'when ci_plan_needs_size_limit is disabled' do
+ before do
+ stub_feature_flags(ci_plan_needs_size_limit: false)
+ end
- it "returns an error" do
- expect(subject.errors).to contain_exactly(
- "rspec: one job can only need 10 others, but you have listed 11. See needs keyword documentation for more details")
+ 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")
+ end
end
- end
- context 'when upper limit of needs is reached' do
- before do
- stub_feature_flags(ci_dag_limit_needs: false)
- end
+ context 'when ci_plan_needs_size_limit is enabled' do
+ before do
+ stub_feature_flags(ci_plan_needs_size_limit: true)
+ end
- let(:needs_count) { described_class::HARD_NEEDS_LIMIT + 1 }
+ 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
- it "returns an error" do
- expect(subject.errors).to contain_exactly(
- "rspec: one job can only need 50 others, but you have listed 51. See needs keyword documentation for more details")
+ 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
+ end
end
end
end