diff options
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline')
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 |