From a5f4bba440d7f9ea47046a0a561d49adf0a1e6d4 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Wed, 16 Jun 2021 18:25:58 +0000 Subject: Add latest changes from gitlab-org/gitlab@14-0-stable-ee --- spec/lib/gitlab/ci/ansi2json/line_spec.rb | 26 +++- spec/lib/gitlab/ci/badge/coverage/template_spec.rb | 52 +------ spec/lib/gitlab/ci/badge/pipeline/template_spec.rb | 52 +------ spec/lib/gitlab/ci/build/auto_retry_spec.rb | 4 +- spec/lib/gitlab/ci/config/entry/need_spec.rb | 20 --- .../lib/gitlab/ci/config/entry/processable_spec.rb | 8 - spec/lib/gitlab/ci/config/entry/reports_spec.rb | 1 - spec/lib/gitlab/ci/jwt_spec.rb | 1 + spec/lib/gitlab/ci/matching/build_matcher_spec.rb | 64 ++++++++ spec/lib/gitlab/ci/matching/runner_matcher_spec.rb | 113 ++++++++++++++ spec/lib/gitlab/ci/parsers/test/junit_spec.rb | 24 +++ .../ci/pipeline/chain/validate/external_spec.rb | 59 +------- spec/lib/gitlab/ci/pipeline/preloader_spec.rb | 8 +- spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 11 -- .../gitlab/ci/pipeline/seed/environment_spec.rb | 2 +- spec/lib/gitlab/ci/templates/npm_spec.rb | 4 +- spec/lib/gitlab/ci/templates/templates_spec.rb | 162 ++++++++++++++++----- spec/lib/gitlab/ci/trace/chunked_io_spec.rb | 2 +- .../gitlab/ci/variables/collection/item_spec.rb | 39 ++++- .../gitlab/ci/variables/collection/sort_spec.rb | 11 +- spec/lib/gitlab/ci/variables/collection_spec.rb | 76 +++++++++- spec/lib/gitlab/ci/yaml_processor/result_spec.rb | 53 +++++++ spec/lib/gitlab/ci/yaml_processor_spec.rb | 25 ---- 23 files changed, 538 insertions(+), 279 deletions(-) create mode 100644 spec/lib/gitlab/ci/matching/build_matcher_spec.rb create mode 100644 spec/lib/gitlab/ci/matching/runner_matcher_spec.rb (limited to 'spec/lib/gitlab/ci') diff --git a/spec/lib/gitlab/ci/ansi2json/line_spec.rb b/spec/lib/gitlab/ci/ansi2json/line_spec.rb index d681447a0e8..909c0f1b3ea 100644 --- a/spec/lib/gitlab/ci/ansi2json/line_spec.rb +++ b/spec/lib/gitlab/ci/ansi2json/line_spec.rb @@ -76,10 +76,30 @@ RSpec.describe Gitlab::Ci::Ansi2json::Line do end describe '#set_section_duration' do - it 'sets and formats the section_duration' do - subject.set_section_duration(75) + shared_examples 'set_section_duration' do + it 'sets and formats the section_duration' do + subject.set_section_duration(75) - expect(subject.section_duration).to eq('01:15') + expect(subject.section_duration).to eq('01:15') + end + end + + context 'with default timezone' do + it_behaves_like 'set_section_duration' + end + + context 'with a timezone carrying minutes offset' do + before do + # The actual call by does use Time.at(...).utc that the following + # rubocop rule (Rails/TimeZone) suggests, but for this specific + # test's purposes we needed to mock at the Time.at call point. + + # rubocop:disable Rails/TimeZone + allow(Time).to receive(:at).with(75).and_return(Time.at(75, in: '+05:30')) + # rubocop:enable Rails/TimeZone + end + + it_behaves_like 'set_section_duration' end end diff --git a/spec/lib/gitlab/ci/badge/coverage/template_spec.rb b/spec/lib/gitlab/ci/badge/coverage/template_spec.rb index f010d1bce50..b03ca3c93ca 100644 --- a/spec/lib/gitlab/ci/badge/coverage/template_spec.rb +++ b/spec/lib/gitlab/ci/badge/coverage/template_spec.rb @@ -6,31 +6,7 @@ RSpec.describe Gitlab::Ci::Badge::Coverage::Template do let(:badge) { double(entity: 'coverage', status: 90.00, customization: {}) } let(:template) { described_class.new(badge) } - describe '#key_text' do - it 'says coverage by default' do - expect(template.key_text).to eq 'coverage' - end - - context 'when custom key_text is defined' do - before do - allow(badge).to receive(:customization).and_return({ key_text: "custom text" }) - end - - it 'returns custom value' do - expect(template.key_text).to eq "custom text" - end - - context 'when its size is larger than the max allowed value' do - before do - allow(badge).to receive(:customization).and_return({ key_text: 't' * 65 }) - end - - it 'returns default value' do - expect(template.key_text).to eq 'coverage' - end - end - end - end + it_behaves_like 'a badge template', 'coverage' describe '#value_text' do context 'when coverage is known' do @@ -60,32 +36,6 @@ RSpec.describe Gitlab::Ci::Badge::Coverage::Template do end end - describe '#key_width' do - it 'is fixed by default' do - expect(template.key_width).to eq 62 - end - - context 'when custom key_width is defined' do - before do - allow(badge).to receive(:customization).and_return({ key_width: 101 }) - end - - it 'returns custom value' do - expect(template.key_width).to eq 101 - end - - context 'when it is larger than the max allowed value' do - before do - allow(badge).to receive(:customization).and_return({ key_width: 513 }) - end - - it 'returns default value' do - expect(template.key_width).to eq 62 - end - end - end - end - describe '#value_width' do context 'when coverage is known' do it 'is narrower when coverage is known' do diff --git a/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb b/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb index 696bb62b4d6..9392ccef147 100644 --- a/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb +++ b/spec/lib/gitlab/ci/badge/pipeline/template_spec.rb @@ -6,31 +6,7 @@ RSpec.describe Gitlab::Ci::Badge::Pipeline::Template do let(:badge) { double(entity: 'pipeline', status: 'success', customization: {}) } let(:template) { described_class.new(badge) } - describe '#key_text' do - it 'says pipeline by default' do - expect(template.key_text).to eq 'pipeline' - end - - context 'when custom key_text is defined' do - before do - allow(badge).to receive(:customization).and_return({ key_text: 'custom text' }) - end - - it 'returns custom value' do - expect(template.key_text).to eq 'custom text' - end - - context 'when its size is larger than the max allowed value' do - before do - allow(badge).to receive(:customization).and_return({ key_text: 't' * 65 }) - end - - it 'returns default value' do - expect(template.key_text).to eq 'pipeline' - end - end - end - end + it_behaves_like 'a badge template', 'pipeline' describe '#value_text' do it 'is status value' do @@ -38,32 +14,6 @@ RSpec.describe Gitlab::Ci::Badge::Pipeline::Template do end end - describe '#key_width' do - it 'is fixed by default' do - expect(template.key_width).to eq 62 - end - - context 'when custom key_width is defined' do - before do - allow(badge).to receive(:customization).and_return({ key_width: 101 }) - end - - it 'returns custom value' do - expect(template.key_width).to eq 101 - end - - context 'when it is larger than the max allowed value' do - before do - allow(badge).to receive(:customization).and_return({ key_width: 513 }) - end - - it 'returns default value' do - expect(template.key_width).to eq 62 - end - end - end - end - describe 'widths and text anchors' do it 'has fixed width and text anchors' do expect(template.width).to eq 116 diff --git a/spec/lib/gitlab/ci/build/auto_retry_spec.rb b/spec/lib/gitlab/ci/build/auto_retry_spec.rb index cfa8c9cd938..b107553bbce 100644 --- a/spec/lib/gitlab/ci/build/auto_retry_spec.rb +++ b/spec/lib/gitlab/ci/build/auto_retry_spec.rb @@ -8,7 +8,7 @@ RSpec.describe Gitlab::Ci::Build::AutoRetry do describe '#allowed?' do using RSpec::Parameterized::TableSyntax - let(:build) { create(:ci_build) } + let(:build) { build_stubbed(:ci_build) } subject { auto_retry.allowed? } @@ -22,6 +22,8 @@ RSpec.describe Gitlab::Ci::Build::AutoRetry do "not matching reason" | 0 | { when: %w[script_error], max: 2 } | :api_failure | false "scheduler failure override" | 1 | { when: %w[scheduler_failure], max: 1 } | :scheduler_failure | false "default for scheduler failure" | 1 | {} | :scheduler_failure | true + "quota is exceeded" | 0 | { max: 2 } | :ci_quota_exceeded | false + "no matching runner" | 0 | { max: 2 } | :no_matching_runner | false end with_them do diff --git a/spec/lib/gitlab/ci/config/entry/need_spec.rb b/spec/lib/gitlab/ci/config/entry/need_spec.rb index a0a5dd52ad4..ab2e8d4db78 100644 --- a/spec/lib/gitlab/ci/config/entry/need_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/need_spec.rb @@ -25,16 +25,6 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do it 'returns job needs configuration' do expect(need.value).to eq(name: 'job_name', artifacts: true, optional: false) end - - context 'when the FF ci_needs_optional is disabled' do - before do - stub_feature_flags(ci_needs_optional: false) - end - - it 'returns job needs configuration without `optional`' do - expect(need.value).to eq(name: 'job_name', artifacts: true) - end - end end it_behaves_like 'job type' @@ -134,16 +124,6 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Need do it 'returns job needs configuration' do expect(need.value).to eq(name: 'job_name', artifacts: true, optional: true) end - - context 'when the FF ci_needs_optional is disabled' do - before do - stub_feature_flags(ci_needs_optional: false) - end - - it 'returns job needs configuration without `optional`' do - expect(need.value).to eq(name: 'job_name', artifacts: true) - end - end end end diff --git a/spec/lib/gitlab/ci/config/entry/processable_spec.rb b/spec/lib/gitlab/ci/config/entry/processable_spec.rb index 016d59e98b9..f98a6a869d6 100644 --- a/spec/lib/gitlab/ci/config/entry/processable_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/processable_spec.rb @@ -271,10 +271,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do context 'when workflow rules is not used' do let(:workflow) { double('workflow', 'has_rules?' => false) } - let(:feature_flag_value) { true } before do - stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: feature_flag_value) entry.compose!(deps) end @@ -298,12 +296,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Processable do it 'raises a warning' do expect(entry.warnings).to contain_exactly(/may allow multiple pipelines/) end - - context 'when feature flag is disabled' do - let(:feature_flag_value) { false } - - it_behaves_like 'has no warnings' - end end context 'and its value is `never`' do diff --git a/spec/lib/gitlab/ci/config/entry/reports_spec.rb b/spec/lib/gitlab/ci/config/entry/reports_spec.rb index 98105ebcd55..d8907f7015b 100644 --- a/spec/lib/gitlab/ci/config/entry/reports_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/reports_spec.rb @@ -41,7 +41,6 @@ RSpec.describe Gitlab::Ci::Config::Entry::Reports do :dependency_scanning | 'gl-dependency-scanning-report.json' :container_scanning | 'gl-container-scanning-report.json' :dast | 'gl-dast-report.json' - :license_management | 'gl-license-management-report.json' :license_scanning | 'gl-license-scanning-report.json' :performance | 'performance.json' :browser_performance | 'browser-performance.json' diff --git a/spec/lib/gitlab/ci/jwt_spec.rb b/spec/lib/gitlab/ci/jwt_spec.rb index 480a4a05379..b0d6f5adfb1 100644 --- a/spec/lib/gitlab/ci/jwt_spec.rb +++ b/spec/lib/gitlab/ci/jwt_spec.rb @@ -42,6 +42,7 @@ RSpec.describe Gitlab::Ci::Jwt do expect(payload[:user_email]).to eq(user.email) expect(payload[:user_login]).to eq(user.username) expect(payload[:pipeline_id]).to eq(pipeline.id.to_s) + expect(payload[:pipeline_source]).to eq(pipeline.source.to_s) expect(payload[:job_id]).to eq(build.id.to_s) expect(payload[:ref]).to eq(pipeline.source_ref) expect(payload[:ref_protected]).to eq(build.protected.to_s) diff --git a/spec/lib/gitlab/ci/matching/build_matcher_spec.rb b/spec/lib/gitlab/ci/matching/build_matcher_spec.rb new file mode 100644 index 00000000000..f12e85da9c2 --- /dev/null +++ b/spec/lib/gitlab/ci/matching/build_matcher_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' + +RSpec.describe Gitlab::Ci::Matching::BuildMatcher do + let(:dummy_attributes) do + { + protected: true, + tag_list: %w[tag1 tag2], + build_ids: [1, 2, 3], + project: :my_project + } + end + + subject(:matcher) { described_class.new(attributes) } + + describe '.new' do + context 'when attributes are missing' do + let(:attributes) { {} } + + it { expect { matcher }.to raise_error(KeyError) } + end + + context 'with attributes' do + let(:attributes) { dummy_attributes } + + it { expect(matcher.protected).to eq(true) } + + it { expect(matcher.tag_list).to eq(%w[tag1 tag2]) } + + it { expect(matcher.build_ids).to eq([1, 2, 3]) } + + it { expect(matcher.project).to eq(:my_project) } + end + end + + describe '#protected?' do + context 'when protected is set to true' do + let(:attributes) { dummy_attributes } + + it { expect(matcher.protected?).to be_truthy } + end + + context 'when protected is set to false' do + let(:attributes) { dummy_attributes.merge(protected: false) } + + it { expect(matcher.protected?).to be_falsey } + end + end + + describe '#has_tags?' do + context 'when tags are present' do + let(:attributes) { dummy_attributes } + + it { expect(matcher.has_tags?).to be_truthy } + end + + context 'when tags are empty' do + let(:attributes) { dummy_attributes.merge(tag_list: []) } + + it { expect(matcher.has_tags?).to be_falsey } + end + end +end diff --git a/spec/lib/gitlab/ci/matching/runner_matcher_spec.rb b/spec/lib/gitlab/ci/matching/runner_matcher_spec.rb new file mode 100644 index 00000000000..d6492caa31a --- /dev/null +++ b/spec/lib/gitlab/ci/matching/runner_matcher_spec.rb @@ -0,0 +1,113 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Matching::RunnerMatcher do + let(:dummy_attributes) do + { + runner_type: 'instance_type', + public_projects_minutes_cost_factor: 0, + private_projects_minutes_cost_factor: 1, + run_untagged: false, + access_level: 'ref_protected', + tag_list: %w[tag1 tag2] + } + end + + subject(:matcher) { described_class.new(attributes) } + + describe '.new' do + context 'when attributes are missing' do + let(:attributes) { {} } + + it { expect { matcher }.to raise_error(KeyError) } + end + + context 'with attributes' do + let(:attributes) { dummy_attributes } + + it { expect(matcher.runner_type).to eq('instance_type') } + + it { expect(matcher.public_projects_minutes_cost_factor).to eq(0) } + + it { expect(matcher.private_projects_minutes_cost_factor).to eq(1) } + + it { expect(matcher.run_untagged).to eq(false) } + + it { expect(matcher.access_level).to eq('ref_protected') } + + it { expect(matcher.tag_list).to eq(%w[tag1 tag2]) } + end + end + + describe '#instance_type?' do + let(:attributes) { dummy_attributes } + + it { expect(matcher.instance_type?).to be_truthy } + + context 'context with private runners' do + let(:attributes) { dummy_attributes.merge(runner_type: 'project_type') } + + it { expect(matcher.instance_type?).to be_falsey } + end + end + + describe '#matches?' do + let(:build) { build_stubbed(:ci_build, build_attributes) } + let(:runner_matcher) { described_class.new(dummy_attributes.merge(runner_attributes)) } + + subject { runner_matcher.matches?(record) } + + context 'with an instance of BuildMatcher' do + using RSpec::Parameterized::TableSyntax + + where(:ref_protected, :build_protected, :run_untagged, :runner_tags, :build_tags, :result) do + # the `ref_protected? && !build.protected?` part: + true | true | true | [] | [] | true + true | false | true | [] | [] | false + false | true | true | [] | [] | true + false | false | true | [] | [] | true + # `accepting_tags?(build)` bit: + true | true | true | [] | [] | true + true | true | true | [] | ['a'] | false + true | true | true | %w[a b] | ['a'] | true + true | true | true | ['a'] | %w[a b] | false + true | true | true | ['a'] | ['a'] | true + true | true | false | ['a'] | ['a'] | true + true | true | false | ['b'] | ['a'] | false + true | true | false | %w[a b] | ['a'] | true + end + + with_them do + let(:build_attributes) do + { + tag_list: build_tags, + protected: build_protected + } + end + + let(:runner_attributes) do + { + access_level: ref_protected ? 'ref_protected' : 'not_protected', + run_untagged: run_untagged, + tag_list: runner_tags + } + end + + let(:record) { build.build_matcher } + + it { is_expected.to eq(result) } + end + end + + context 'with an instance of Ci::Build' do + let(:runner_attributes) { {} } + let(:build_attributes) { {} } + let(:record) { build } + + it 'raises ArgumentError' do + expect { subject }.to raise_error ArgumentError, /BuildMatcher are allowed/ + end + end + end +end diff --git a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb index 7da602251a5..4ca8f74e57f 100644 --- a/spec/lib/gitlab/ci/parsers/test/junit_spec.rb +++ b/spec/lib/gitlab/ci/parsers/test/junit_spec.rb @@ -417,6 +417,30 @@ RSpec.describe Gitlab::Ci::Parsers::Test::Junit do end end + context 'when attachment is specified in test case with error' do + let(:junit) do + <<~EOF + + + + Some error + [[ATTACHMENT|some/path.png]] + + + + EOF + end + + it 'assigns correct attributes to the test case' do + expect { subject }.not_to raise_error + + expect(test_cases[0].has_attachment?).to be_truthy + expect(test_cases[0].attachment).to eq("some/path.png") + + expect(test_cases[0].job).to eq(job) + end + end + private def flattened_test_cases(test_suite) 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 e3061f8095b..16517b39a45 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/validate/external_spec.rb @@ -4,7 +4,7 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do let_it_be(:project) { create(:project) } - let_it_be(:user) { create(:user) } + let_it_be(:user) { create(:user, :with_sign_ins) } let(:pipeline) { build(:ci_empty_pipeline, user: user, project: project) } let!(:step) { described_class.new(pipeline, command) } @@ -43,7 +43,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do end let(:save_incompleted) { true } - let(:dot_com) { true } let(:command) do Gitlab::Ci::Pipeline::Chain::Command.new( project: project, current_user: user, yaml_processor_result: yaml_processor_result, save_incompleted: save_incompleted @@ -57,7 +56,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do before do stub_env('EXTERNAL_VALIDATION_SERVICE_URL', validation_service_url) - allow(Gitlab).to receive(:com?).and_return(dot_com) allow(Labkit::Correlation::CorrelationId).to receive(:current_id).and_return('correlation-id') end @@ -199,61 +197,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Validate::External do end end - context 'when the feature flag is disabled' do - before do - stub_feature_flags(ci_external_validation_service: false) - stub_request(:post, validation_service_url) - end - - it 'does not drop the pipeline' do - perform! - - expect(pipeline.status).not_to eq('failed') - expect(pipeline.errors).to be_empty - end - - it 'does not break the chain' do - perform! - - expect(step.break?).to be false - end - - it 'does not make requests' do - perform! - - expect(WebMock).not_to have_requested(:post, validation_service_url) - end - end - - context 'when not on .com' do - let(:dot_com) { false } - - before do - stub_feature_flags(ci_external_validation_service: false) - stub_request(:post, validation_service_url).to_return(status: 404, body: "{}") - end - - it 'drops the pipeline' do - perform! - - expect(pipeline.status).to eq('failed') - expect(pipeline).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 - context 'when validation returns 406 Not Acceptable' do before do stub_request(:post, validation_service_url).to_return(status: 406, body: "{}") diff --git a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb index ae423fa04f9..5b644e42451 100644 --- a/spec/lib/gitlab/ci/pipeline/preloader_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/preloader_spec.rb @@ -5,9 +5,11 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Pipeline::Preloader do let(:stage) { double(:stage) } let(:commit) { double(:commit) } + let(:scheduled_action) { double(:scheduled_action) } + let(:manual_action) { double(:manual_action) } let(:pipeline) do - double(:pipeline, commit: commit, stages: [stage]) + double(:pipeline, commit: commit, stages: [stage], scheduled_actions: [scheduled_action], manual_actions: [manual_action]) end describe '.preload!' do @@ -33,6 +35,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Preloader do expect(pipeline).to receive(:lazy_ref_commit) expect(pipeline).to receive(:number_of_warnings) expect(stage).to receive(:number_of_warnings) + expect(scheduled_action).to receive(:persisted_environment) + expect(manual_action).to receive(:persisted_environment) described_class.preload!([pipeline]) end @@ -42,6 +46,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Preloader do allow(pipeline).to receive(:lazy_ref_commit) allow(pipeline).to receive(:number_of_warnings) allow(stage).to receive(:number_of_warnings) + allow(scheduled_action).to receive(:persisted_environment) + allow(manual_action).to receive(:persisted_environment) pipelines = [pipeline, pipeline] diff --git a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb index 058fb25807d..020f957cf70 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -1101,17 +1101,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do it "does not return an error" do expect(subject.errors).to be_empty end - - context 'when the FF ci_needs_optional is disabled' do - before do - stub_feature_flags(ci_needs_optional: false) - end - - it "returns an error" do - expect(subject.errors).to contain_exactly( - "'rspec' job needs 'build' job, but it was not added to the pipeline") - end - end end end diff --git a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb index 175b12637e6..ad89f1f5cda 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb @@ -128,7 +128,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do context 'when environment has already been created' do before do - create(:environment, :staging, project: project, name: 'customer-portal') + create(:environment, project: project, name: 'customer-portal', tier: :staging) end it 'does not overwrite the specified deployment tier' do diff --git a/spec/lib/gitlab/ci/templates/npm_spec.rb b/spec/lib/gitlab/ci/templates/npm_spec.rb index b10e2b0e057..2456c9ae545 100644 --- a/spec/lib/gitlab/ci/templates/npm_spec.rb +++ b/spec/lib/gitlab/ci/templates/npm_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' -RSpec.describe 'npm.latest.gitlab-ci.yml' do - subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('npm.latest') } +RSpec.describe 'npm.gitlab-ci.yml' do + subject(:template) { Gitlab::Template::GitlabCiYmlTemplate.find('npm') } describe 'the created pipeline' do let(:repo_files) { { 'package.json' => '{}', 'README.md' => '' } } diff --git a/spec/lib/gitlab/ci/templates/templates_spec.rb b/spec/lib/gitlab/ci/templates/templates_spec.rb index 56443e611e8..2e6df7da232 100644 --- a/spec/lib/gitlab/ci/templates/templates_spec.rb +++ b/spec/lib/gitlab/ci/templates/templates_spec.rb @@ -6,26 +6,105 @@ RSpec.describe 'CI YML Templates' do subject { Gitlab::Ci::YamlProcessor.new(content).execute } let(:all_templates) { Gitlab::Template::GitlabCiYmlTemplate.all.map(&:full_name) } - let(:excluded_templates) do - all_templates.select do |name| + excluded = all_templates.select do |name| Gitlab::Template::GitlabCiYmlTemplate.excluded_patterns.any? { |pattern| pattern.match?(name) } end + excluded + ["Terraform.gitlab-ci.yml"] end - context 'when including available templates in a CI YAML configuration' do - using RSpec::Parameterized::TableSyntax + before do + stub_feature_flags( + redirect_to_latest_template_terraform: false, + redirect_to_latest_template_security_api_fuzzing: false, + redirect_to_latest_template_security_dast: false) + end - where(:template_name) do - all_templates - excluded_templates + shared_examples 'require default stages to be included' do + it 'require default stages to be included' do + expect(subject.stages).to include(*Gitlab::Ci::Config::Entry::Stages.default) end + end + + context 'that support autodevops' do + non_autodevops_templates = [ + 'Security/DAST-API.gitlab-ci.yml', + 'Security/API-Fuzzing.gitlab-ci.yml' + ] + + context 'when including available templates in a CI YAML configuration' do + using RSpec::Parameterized::TableSyntax + + where(:template_name) do + all_templates - excluded_templates - non_autodevops_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_expected.to be_valid } + + include_examples 'require default stages to be included' + 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_expected.not_to be_valid } + end + end + end + + describe 'that do not support autodevops' do + context 'when DAST API template' do + # The DAST API template purposly excludes a stages + # definition. - with_them do - let(:content) do - if template_name == 'Security/DAST-API.gitlab-ci.yml' - # The DAST-API template purposly excludes a stages - # definition. + let(:template_name) { 'Security/DAST-API.gitlab-ci.yml' } + context 'with default stages' do + let(:content) do + <<~EOS + include: + - template: #{template_name} + + concrete_build_implemented_by_a_user: + stage: test + script: do something + EOS + end + + it { is_expected.not_to be_valid } + end + + context 'with defined stages' do + let(:content) do <<~EOS include: - template: #{template_name} @@ -40,7 +119,22 @@ RSpec.describe 'CI YML Templates' do stage: test script: do something EOS - else + end + + it { is_expected.to be_valid } + + include_examples 'require default stages to be included' + end + end + + context 'when API Fuzzing template' do + # The API Fuzzing template purposly excludes a stages + # definition. + + let(:template_name) { 'Security/API-Fuzzing.gitlab-ci.yml' } + + context 'with default stages' do + let(:content) do <<~EOS include: - template: #{template_name} @@ -50,39 +144,31 @@ RSpec.describe 'CI YML Templates' do script: do something EOS end - end - - it 'is valid' do - expect(subject).to be_valid - end - it 'require default stages to be included' do - expect(subject.stages).to include(*Gitlab::Ci::Config::Entry::Stages.default) + it { is_expected.not_to be_valid } end - end - end - context 'when including unavailable templates in a CI YAML configuration' do - using RSpec::Parameterized::TableSyntax + context 'with defined stages' do + let(:content) do + <<~EOS + include: + - template: #{template_name} - where(:template_name) do - excluded_templates - end + stages: + - build + - test + - deploy + - fuzz - with_them do - let(:content) do - <<~EOS - include: - - template: #{template_name} + concrete_build_implemented_by_a_user: + stage: test + script: do something + EOS + end - concrete_build_implemented_by_a_user: - stage: test - script: do something - EOS - end + it { is_expected.to be_valid } - it 'is not valid' do - expect(subject).not_to be_valid + include_examples 'require default stages to be included' end end end diff --git a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb index f878d24fe4b..63625244fe8 100644 --- a/spec/lib/gitlab/ci/trace/chunked_io_spec.rb +++ b/spec/lib/gitlab/ci/trace/chunked_io_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Gitlab::Ci::Trace::ChunkedIO, :clean_gitlab_redis_cache do let(:chunked_io) { described_class.new(build) } before do - stub_feature_flags(ci_enable_live_trace: true, gitlab_ci_trace_read_consistency: true) + stub_feature_flags(ci_enable_live_trace: true) end describe "#initialize" do diff --git a/spec/lib/gitlab/ci/variables/collection/item_spec.rb b/spec/lib/gitlab/ci/variables/collection/item_spec.rb index ca9dc95711d..9443bf6d6d5 100644 --- a/spec/lib/gitlab/ci/variables/collection/item_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection/item_spec.rb @@ -70,6 +70,43 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do end end + describe '.possible_var_reference?' do + context 'table tests' do + using RSpec::Parameterized::TableSyntax + + where do + { + "empty value": { + value: '', + result: false + }, + "normal value": { + value: 'some value', + result: false + }, + "simple expansions": { + value: 'key$variable', + result: true + }, + "complex expansions": { + value: 'key${variable}${variable2}', + result: true + }, + "complex expansions for Windows": { + value: 'key%variable%%variable2%', + result: true + } + } + end + + with_them do + subject { Gitlab::Ci::Variables::Collection::Item.possible_var_reference?(value) } + + it { is_expected.to eq(result) } + end + end + end + describe '#depends_on' do let(:item) { Gitlab::Ci::Variables::Collection::Item.new(**variable) } @@ -128,7 +165,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Item do end it 'supports using an active record resource' do - variable = create(:ci_variable, key: 'CI_VAR', value: '123') + variable = build(:ci_variable, key: 'CI_VAR', value: '123') resource = described_class.fabricate(variable) expect(resource).to be_a(described_class) diff --git a/spec/lib/gitlab/ci/variables/collection/sort_spec.rb b/spec/lib/gitlab/ci/variables/collection/sort_spec.rb index 73cf0e19d00..01eef673c35 100644 --- a/spec/lib/gitlab/ci/variables/collection/sort_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection/sort_spec.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true -require 'spec_helper' +require 'fast_spec_helper' +require 'rspec-parameterized' RSpec.describe Gitlab::Ci::Variables::Collection::Sort do describe '#initialize with non-Collection value' do @@ -57,9 +58,9 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sort do }, "variable containing escaped variable reference": { variables: [ - { key: 'variable_a', value: 'value' }, { key: 'variable_b', value: '$$variable_a' }, - { key: 'variable_c', value: '$variable_b' } + { key: 'variable_c', value: '$variable_a' }, + { key: 'variable_a', value: 'value' } ], expected_errors: nil } @@ -144,11 +145,11 @@ RSpec.describe Gitlab::Ci::Variables::Collection::Sort do }, "variable containing escaped variable reference": { variables: [ - { key: 'variable_c', value: '$variable_b' }, { key: 'variable_b', value: '$$variable_a' }, + { key: 'variable_c', value: '$variable_a' }, { key: 'variable_a', value: 'value' } ], - result: %w[variable_a variable_b variable_c] + result: %w[variable_b variable_a variable_c] } } end diff --git a/spec/lib/gitlab/ci/variables/collection_spec.rb b/spec/lib/gitlab/ci/variables/collection_spec.rb index 7b77754190a..abda27f0d6e 100644 --- a/spec/lib/gitlab/ci/variables/collection_spec.rb +++ b/spec/lib/gitlab/ci/variables/collection_spec.rb @@ -44,6 +44,30 @@ RSpec.describe Gitlab::Ci::Variables::Collection do end end + describe '#compact' do + subject do + described_class.new + .append(key: 'STRING', value: 'string') + .append(key: 'NIL', value: nil) + .append(key: nil, value: 'string') + end + + it 'returns a new Collection instance', :aggregate_failures do + collection = subject.compact + + expect(collection).to be_an_instance_of(described_class) + expect(collection).not_to eql(subject) + end + + it 'rejects pair that has nil value', :aggregate_failures do + collection = subject.compact + + expect(collection).not_to include(key: 'NIL', value: nil, public: true) + expect(collection).to include(key: 'STRING', value: 'string', public: true) + expect(collection).to include(key: nil, value: 'string', public: true) + end + end + describe '#concat' do it 'appends all elements from an array' do collection = described_class.new([{ key: 'VAR_1', value: '1' }]) @@ -229,6 +253,11 @@ RSpec.describe Gitlab::Ci::Variables::Collection do value: 'key${MISSING_VAR}-${CI_JOB_NAME}', result: 'key${MISSING_VAR}-test-1', keep_undefined: true + }, + "escaped characters are kept intact": { + value: 'key-$TEST1-%%HOME%%-$${HOME}', + result: 'key-test-3-%%HOME%%-$${HOME}', + keep_undefined: false } } end @@ -291,6 +320,14 @@ RSpec.describe Gitlab::Ci::Variables::Collection do ], keep_undefined: false }, + "escaped characters in complex expansions are kept intact": { + variables: [ + { key: 'variable3', value: 'key_${variable}_$${HOME}_%%HOME%%' }, + { key: 'variable', value: '$variable2' }, + { key: 'variable2', value: 'value2' } + ], + keep_undefined: false + }, "array with cyclic dependency": { variables: [ { key: 'variable', value: '$variable2' }, @@ -391,6 +428,30 @@ RSpec.describe Gitlab::Ci::Variables::Collection do { key: 'variable3', value: 'keyvalueresult' } ] }, + "escaped characters in complex expansions keeping undefined are kept intact": { + variables: [ + { key: 'variable3', value: 'key_${variable}_$${HOME}_%%HOME%%' }, + { key: 'variable', value: '$variable2' }, + { key: 'variable2', value: 'value' } + ], + keep_undefined: true, + result: [ + { key: 'variable', value: 'value' }, + { key: 'variable2', value: 'value' }, + { key: 'variable3', value: 'key_value_$${HOME}_%%HOME%%' } + ] + }, + "escaped characters in complex expansions discarding undefined are kept intact": { + variables: [ + { key: 'variable2', value: 'key_${variable4}_$${HOME}_%%HOME%%' }, + { key: 'variable', value: 'value_$${HOME}_%%HOME%%' } + ], + keep_undefined: false, + result: [ + { key: 'variable', value: 'value_$${HOME}_%%HOME%%' }, + { key: 'variable2', value: 'key__$${HOME}_%%HOME%%' } + ] + }, "out-of-order expansion": { variables: [ { key: 'variable3', value: 'key$variable2$variable' }, @@ -417,7 +478,7 @@ RSpec.describe Gitlab::Ci::Variables::Collection do { key: 'variable3', value: 'keyresultvalue' } ] }, - "missing variable": { + "missing variable discarding original": { variables: [ { key: 'variable2', value: 'key$variable' } ], @@ -461,6 +522,19 @@ RSpec.describe Gitlab::Ci::Variables::Collection do { key: 'variable3', value: 'key_$variable2_value2' } ] }, + "variable value referencing password with special characters": { + variables: [ + { key: 'VAR', value: '$PASSWORD' }, + { key: 'PASSWORD', value: 'my_password$$_%%_$A' }, + { key: 'A', value: 'value' } + ], + keep_undefined: false, + result: [ + { key: 'VAR', value: 'my_password$$_%%_value' }, + { key: 'PASSWORD', value: 'my_password$$_%%_value' }, + { key: 'A', value: 'value' } + ] + }, "cyclic dependency causes original array to be returned": { variables: [ { key: 'variable', value: '$variable2' }, diff --git a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb index e345cd4de9b..25705fd4260 100644 --- a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb @@ -39,6 +39,59 @@ module Gitlab expect(expanded_config).to include(*included_config.keys) end end + + describe '#yaml_variables_for' do + let(:config_content) do + <<~YAML + variables: + VAR1: value 1 + VAR2: value 2 + + job: + script: echo 'hello' + variables: + VAR1: value 11 + YAML + end + + let(:job_name) { :job } + + subject(:yaml_variables_for) { result.yaml_variables_for(job_name) } + + it 'returns calculated variables with root and job variables' do + is_expected.to match_array([ + { key: 'VAR1', value: 'value 11', public: true }, + { key: 'VAR2', value: 'value 2', public: true } + ]) + end + + context 'when an absent job is sent' do + let(:job_name) { :invalid_job } + + it { is_expected.to eq([]) } + end + end + + describe '#stage_for' do + let(:config_content) do + <<~YAML + job: + script: echo 'hello' + YAML + end + + let(:job_name) { :job } + + subject(:stage_for) { result.stage_for(job_name) } + + it { is_expected.to eq('test') } + + context 'when an absent job is sent' do + let(:job_name) { :invalid_job } + + it { is_expected.to be_nil } + end + end end end end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index 94ab4819361..e8e44f884cf 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -485,10 +485,6 @@ module Gitlab end describe '#warnings' do - before do - stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: true) - end - context 'when a warning is raised in a given entry' do let(:config) do <<-EOYML @@ -602,27 +598,6 @@ module Gitlab it_behaves_like 'has warnings and expected error', /build job: need test is not defined in prior stages/ end end - - context 'when feature flag is disabled' do - before do - stub_feature_flags(ci_raise_job_rules_without_workflow_rules_warning: false) - end - - context 'job rules used without workflow rules' do - let(:config) do - <<-EOYML - rspec: - script: rspec - rules: - - when: always - EOYML - end - - it 'does not raise the warning' do - expect(subject.warnings).to be_empty - end - end - end end describe 'only / except policies validations' do -- cgit v1.2.3