diff options
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline')
9 files changed, 221 insertions, 120 deletions
diff --git a/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb index 5fa414f5bd1..32c92724f62 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/build/associations_spec.rb @@ -3,10 +3,16 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Pipeline::Chain::Build::Associations do - let(:project) { create(:project, :repository) } - let(:user) { create(:user, developer_projects: [project]) } + let_it_be_with_reload(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user, developer_projects: [project]) } + let(:pipeline) { Ci::Pipeline.new } - let(:step) { described_class.new(pipeline, command) } + let(:bridge) { nil } + + let(:variables_attributes) do + [{ key: 'first', secret_value: 'world' }, + { key: 'second', secret_value: 'second_world' }] + end let(:command) do Gitlab::Ci::Pipeline::Chain::Command.new( @@ -20,7 +26,26 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build::Associations do merge_request: nil, project: project, current_user: user, - bridge: bridge) + bridge: bridge, + variables_attributes: variables_attributes) + end + + let(:step) { described_class.new(pipeline, command) } + + shared_examples 'breaks the chain' do + it 'returns true' do + step.perform! + + expect(step.break?).to be true + end + end + + shared_examples 'does not break the chain' do + it 'returns false' do + step.perform! + + expect(step.break?).to be false + end end context 'when a bridge is passed in to the pipeline creation' do @@ -37,26 +62,83 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build::Associations do ) end - it 'never breaks the chain' do - step.perform! - - expect(step.break?).to eq(false) - end + it_behaves_like 'does not break the chain' end context 'when a bridge is not passed in to the pipeline creation' do - let(:bridge) { nil } - it 'leaves the source pipeline empty' do step.perform! expect(pipeline.source_pipeline).to be_nil end - it 'never breaks the chain' do + it_behaves_like 'does not break the chain' + end + + it 'sets pipeline variables' do + step.perform! + + expect(pipeline.variables.map { |var| var.slice(:key, :secret_value) }) + .to eq variables_attributes.map(&:with_indifferent_access) + end + + context 'when project setting restrict_user_defined_variables is enabled' do + before do + project.update!(restrict_user_defined_variables: true) + end + + context 'when user is developer' do + it_behaves_like 'breaks the chain' + + it 'returns an error on variables_attributes', :aggregate_failures do + step.perform! + + expect(pipeline.errors.full_messages).to eq(['Insufficient permissions to set pipeline variables']) + expect(pipeline.variables).to be_empty + end + + context 'when variables_attributes is not specified' do + let(:variables_attributes) { nil } + + it_behaves_like 'does not break the chain' + + it 'assigns empty variables' do + step.perform! + + expect(pipeline.variables).to be_empty + end + end + end + + context 'when user is maintainer' do + before do + project.add_maintainer(user) + end + + it_behaves_like 'does not break the chain' + + it 'assigns variables_attributes' do + step.perform! + + expect(pipeline.variables.map { |var| var.slice(:key, :secret_value) }) + .to eq variables_attributes.map(&:with_indifferent_access) + end + end + end + + context 'with duplicate pipeline variables' do + let(:variables_attributes) do + [{ key: 'first', secret_value: 'world' }, + { key: 'first', secret_value: 'second_world' }] + end + + it_behaves_like 'breaks the chain' + + it 'returns an error for variables_attributes' do step.perform! - expect(step.break?).to eq(false) + expect(pipeline.errors.full_messages).to eq(['Duplicate variable name: first']) + expect(pipeline.variables).to be_empty end end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb index 7771289abe6..dca2204f544 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/build_spec.rb @@ -8,11 +8,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do let(:pipeline) { Ci::Pipeline.new } - let(:variables_attributes) do - [{ key: 'first', secret_value: 'world' }, - { key: 'second', secret_value: 'second_world' }] - end - let(:command) do Gitlab::Ci::Pipeline::Chain::Command.new( source: :push, @@ -24,100 +19,26 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Build do schedule: nil, merge_request: nil, project: project, - current_user: user, - variables_attributes: variables_attributes) + current_user: user) end let(:step) { described_class.new(pipeline, command) } - shared_examples 'builds pipeline' do - it 'builds a pipeline with the expected attributes' do - step.perform! - - expect(pipeline.sha).not_to be_empty - expect(pipeline.sha).to eq project.commit.id - expect(pipeline.ref).to eq 'master' - expect(pipeline.tag).to be false - expect(pipeline.user).to eq user - expect(pipeline.project).to eq project - end - end - - shared_examples 'breaks the chain' do - it 'returns true' do - step.perform! - - expect(step.break?).to be true - end - end - - shared_examples 'does not break the chain' do - it 'returns false' do - step.perform! - - expect(step.break?).to be false - end - end - - before do - stub_ci_pipeline_yaml_file(gitlab_ci_yaml) - end - - it_behaves_like 'does not break the chain' - it_behaves_like 'builds pipeline' - - it 'sets pipeline variables' do + it 'does not break the chain' do step.perform! - expect(pipeline.variables.map { |var| var.slice(:key, :secret_value) }) - .to eq variables_attributes.map(&:with_indifferent_access) + expect(step.break?).to be false end - context 'when project setting restrict_user_defined_variables is enabled' do - before do - project.update!(restrict_user_defined_variables: true) - end - - context 'when user is developer' do - it_behaves_like 'breaks the chain' - it_behaves_like 'builds pipeline' - - it 'returns an error on variables_attributes', :aggregate_failures do - step.perform! - - expect(pipeline.errors.full_messages).to eq(['Insufficient permissions to set pipeline variables']) - expect(pipeline.variables).to be_empty - end - - context 'when variables_attributes is not specified' do - let(:variables_attributes) { nil } - - it_behaves_like 'does not break the chain' - it_behaves_like 'builds pipeline' - - it 'assigns empty variables' do - step.perform! - - expect(pipeline.variables).to be_empty - end - end - end - - context 'when user is maintainer' do - before do - project.add_maintainer(user) - end - - it_behaves_like 'does not break the chain' - it_behaves_like 'builds pipeline' - - it 'assigns variables_attributes' do - step.perform! + it 'builds a pipeline with the expected attributes' do + step.perform! - expect(pipeline.variables.map { |var| var.slice(:key, :secret_value) }) - .to eq variables_attributes.map(&:with_indifferent_access) - end - end + expect(pipeline.sha).not_to be_empty + expect(pipeline.sha).to eq project.commit.id + expect(pipeline.ref).to eq 'master' + expect(pipeline.tag).to be false + expect(pipeline.user).to eq user + expect(pipeline.project).to eq project end it 'returns a valid pipeline' do diff --git a/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb index 2727f2603cd..27a5abf988c 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/cancel_pending_pipelines_spec.rb @@ -44,6 +44,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::CancelPendingPipelines do expect(build_statuses(pipeline)).to contain_exactly('pending') end + it 'cancels the builds with 2 queries to avoid query timeout' do + second_query_regex = /WHERE "ci_pipelines"\."id" = \d+ AND \(NOT EXISTS/ + recorder = ActiveRecord::QueryRecorder.new { perform } + second_query = recorder.occurrences.keys.filter { |occ| occ =~ second_query_regex } + + expect(second_query).to be_one + end + context 'when the previous pipeline has a child pipeline' do let(:child_pipeline) { create(:ci_pipeline, child_of: prev_pipeline) } diff --git a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb index c22a0e23794..0d78ce3440a 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/command_spec.rb @@ -341,4 +341,40 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Command do end end end + + describe '#observe_step_duration' do + context 'when ci_pipeline_creation_step_duration_tracking is enabled' do + it 'adds the duration to the step duration histogram' do + histogram = double(:histogram) + duration = 1.hour + + expect(::Gitlab::Ci::Pipeline::Metrics).to receive(:pipeline_creation_step_duration_histogram) + .and_return(histogram) + expect(histogram).to receive(:observe) + .with({ step: 'Gitlab::Ci::Pipeline::Chain::Build' }, duration.seconds) + + described_class.new.observe_step_duration( + Gitlab::Ci::Pipeline::Chain::Build, + duration + ) + end + end + + context 'when ci_pipeline_creation_step_duration_tracking is disabled' do + before do + stub_feature_flags(ci_pipeline_creation_step_duration_tracking: false) + end + + it 'does nothing' do + duration = 1.hour + + expect(::Gitlab::Ci::Pipeline::Metrics).not_to receive(:pipeline_creation_step_duration_histogram) + + described_class.new.observe_step_duration( + Gitlab::Ci::Pipeline::Chain::Build, + duration + ) + end + end + end end diff --git a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb index 42ec9ab6f5d..e0d656f456e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/config/content_spec.rb @@ -92,6 +92,27 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Config::Content do expect(pipeline.pipeline_config.content).to eq(config_content_result) expect(command.config_content).to eq(config_content_result) end + + context 'when path specifies a refname' do + let(:ci_config_path) { 'path/to/.gitlab-ci.yml@another-group/another-repo:refname' } + let(:config_content_result) do + <<~EOY + --- + include: + - project: another-group/another-repo + file: path/to/.gitlab-ci.yml + ref: refname + EOY + end + + it 'builds root config including the path and refname to another repository' do + subject.perform! + + expect(pipeline.config_source).to eq 'external_project_source' + expect(pipeline.pipeline_config.content).to eq(config_content_result) + expect(command.config_content).to eq(config_content_result) + end + end end context 'when config is defined in the default .gitlab-ci.yml' do diff --git a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb index 83d47ae6819..e8eb3333b88 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/sequence_spec.rb @@ -8,8 +8,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do let(:pipeline) { build_stubbed(:ci_pipeline) } let(:command) { Gitlab::Ci::Pipeline::Chain::Command.new(project: project) } - let(:first_step) { spy('first step') } - let(:second_step) { spy('second step') } + let(:first_step) { spy('first step', name: 'FirstStep') } + let(:second_step) { spy('second step', name: 'SecondStep') } let(:sequence) { [first_step, second_step] } let(:histogram) { spy('prometheus metric') } @@ -61,6 +61,17 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Sequence do expect(histogram).to have_received(:observe) end + it 'adds step sequence duration to duration histogram' do + expect(command.metrics) + .to receive(:pipeline_creation_step_duration_histogram) + .twice + .and_return(histogram) + expect(histogram).to receive(:observe).with({ step: 'FirstStep' }, any_args).ordered + expect(histogram).to receive(:observe).with({ step: 'SecondStep' }, any_args).ordered + + subject.build! + end + it 'records pipeline size by pipeline source in a histogram' do allow(command.metrics) .to receive(:pipeline_size_histogram) diff --git a/spec/lib/gitlab/ci/pipeline/metrics_spec.rb b/spec/lib/gitlab/ci/pipeline/metrics_spec.rb new file mode 100644 index 00000000000..83b969ff3c4 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/metrics_spec.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Gitlab::Ci::Pipeline::Metrics do + describe '.pipeline_creation_step_duration_histogram' do + around do |example| + described_class.clear_memoization(:pipeline_creation_step_histogram) + + example.run + + described_class.clear_memoization(:pipeline_creation_step_histogram) + end + + it 'adds the step to the step duration histogram' do + expect(::Gitlab::Metrics).to receive(:histogram) + .with( + :gitlab_ci_pipeline_creation_step_duration_seconds, + 'Duration of each pipeline creation step', + { step: nil }, + [0.01, 0.05, 0.1, 0.5, 1.0, 2.0, 5.0, 10.0, 15.0, 20.0, 50.0, 240.0] + ) + + described_class.pipeline_creation_step_duration_histogram + 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 58938251ca1..0c28515b574 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -490,12 +490,21 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do end context 'when job belongs to a resource group' do - let(:attributes) { { name: 'rspec', ref: 'master', resource_group_key: 'iOS' } } + let(:resource_group) { 'iOS' } + let(:attributes) { { name: 'rspec', ref: 'master', resource_group_key: resource_group, environment: 'production' }} it 'returns a job with resource group' do expect(subject.resource_group).not_to be_nil expect(subject.resource_group.key).to eq('iOS') end + + context 'when resource group has $CI_ENVIRONMENT_NAME in it' do + let(:resource_group) { 'test/$CI_ENVIRONMENT_NAME' } + + it 'expands environment name' do + expect(subject.resource_group.key).to eq('test/production') + end + end end end @@ -1140,16 +1149,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do it 'does not have errors' do expect(subject.errors).to be_empty end - - context 'when ci_same_stage_job_needs FF is disabled' do - before do - stub_feature_flags(ci_same_stage_job_needs: false) - end - - it 'has errors' do - expect(subject.errors).to contain_exactly("'rspec' job needs 'build' job, but 'build' is not in any previous stage") - end - end end context 'when using 101 needs' do diff --git a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb index 3424e7d03a3..5d8a9358e10 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb @@ -34,10 +34,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do described_class.new(seed_context, stages_attributes) end - before do - stub_feature_flags(ci_same_stage_job_needs: false) - end - describe '#stages' do it 'returns the stage resources' do stages = seed.stages |