diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-12-17 11:59:07 +0000 |
commit | 8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca (patch) | |
tree | 544930fb309b30317ae9797a9683768705d664c4 /spec/lib/gitlab/ci/pipeline | |
parent | 4b1de649d0168371549608993deac953eb692019 (diff) | |
download | gitlab-ce-8b573c94895dc0ac0e1d9d59cf3e8745e8b539ca.tar.gz |
Add latest changes from gitlab-org/gitlab@13-7-stable-eev13.7.0-rc42
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline')
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb | 109 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb | 62 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb | 95 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/seed/build_spec.rb | 66 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb | 10 | ||||
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb | 75 |
6 files changed, 377 insertions, 40 deletions
diff --git a/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb new file mode 100644 index 00000000000..78363be7f36 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/chain/limit/deployments_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Gitlab::Ci::Pipeline::Chain::Limit::Deployments do + let_it_be(:namespace) { create(:namespace) } + let_it_be(:project, reload: true) { create(:project, namespace: namespace) } + let_it_be(:plan_limits, reload: true) { create(:plan_limits, :default_plan) } + + let(:pipeline_seed) { double(:pipeline_seed, deployments_count: 2) } + let(:save_incompleted) { false } + + let(:command) do + double(:command, + project: project, + pipeline_seed: pipeline_seed, + save_incompleted: save_incompleted + ) + end + + let(:pipeline) { build(:ci_pipeline, project: project) } + let(:step) { described_class.new(pipeline, command) } + + subject(:perform) { step.perform! } + + context 'when pipeline deployments limit is exceeded' do + before do + plan_limits.update!(ci_pipeline_deployments: 1) + end + + context 'when saving incompleted pipelines' do + let(:save_incompleted) { true } + + it 'drops the pipeline' do + perform + + expect(pipeline).to be_persisted + expect(pipeline.reload).to be_failed + end + + it 'breaks the chain' do + perform + + expect(step.break?).to be true + end + + it 'sets a valid failure reason' do + perform + + expect(pipeline.deployments_limit_exceeded?).to be true + end + end + + context 'when not saving incomplete pipelines' do + let(:save_incompleted) { false } + + it 'does not persist the pipeline' do + perform + + expect(pipeline).not_to be_persisted + end + + it 'breaks the chain' do + perform + + expect(step.break?).to be true + end + + it 'adds an informative error to the pipeline' do + perform + + expect(pipeline.errors.messages).to include(base: ['Pipeline has too many deployments! Requested 2, but the limit is 1.']) + end + end + + it 'logs the error' do + expect(Gitlab::ErrorTracking).to receive(:track_exception).with( + instance_of(Gitlab::Ci::Limit::LimitExceededError), + project_id: project.id, plan: namespace.actual_plan_name + ) + + perform + end + end + + context 'when pipeline deployments limit is not exceeded' do + before do + plan_limits.update!(ci_pipeline_deployments: 100) + end + + it 'does not break the chain' do + perform + + expect(step.break?).to be false + end + + it 'does not invalidate the pipeline' do + perform + + expect(pipeline.errors).to be_empty + end + + it 'does not log any error' do + expect(Gitlab::ErrorTracking).not_to receive(:track_exception) + + perform + end + end +end diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb index d849c768a3c..0ce8b80902e 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb @@ -50,8 +50,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do it 'sets the seeds in the command object' do run_chain - expect(command.stage_seeds).to all(be_a Gitlab::Ci::Pipeline::Seed::Base) - expect(command.stage_seeds.count).to eq 1 + expect(command.pipeline_seed).to be_a(Gitlab::Ci::Pipeline::Seed::Pipeline) + expect(command.pipeline_seed.size).to eq 1 end context 'when no ref policy is specified' do @@ -63,16 +63,18 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do } end - it 'correctly fabricates a stage seeds object' do + it 'correctly fabricates stages and builds' do run_chain - seeds = command.stage_seeds - expect(seeds.size).to eq 2 - expect(seeds.first.attributes[:name]).to eq 'test' - expect(seeds.second.attributes[:name]).to eq 'deploy' - expect(seeds.dig(0, 0, :name)).to eq 'rspec' - expect(seeds.dig(0, 1, :name)).to eq 'spinach' - expect(seeds.dig(1, 0, :name)).to eq 'production' + seed = command.pipeline_seed + + expect(seed.stages.size).to eq 2 + expect(seed.size).to eq 3 + expect(seed.stages.first.name).to eq 'test' + expect(seed.stages.second.name).to eq 'deploy' + expect(seed.stages[0].statuses[0].name).to eq 'rspec' + expect(seed.stages[0].statuses[1].name).to eq 'spinach' + expect(seed.stages[1].statuses[0].name).to eq 'production' end end @@ -88,14 +90,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do } end - it 'returns stage seeds only assigned to master' do + it 'returns pipeline seed with jobs only assigned to master' do run_chain - seeds = command.stage_seeds + seed = command.pipeline_seed - expect(seeds.size).to eq 1 - expect(seeds.first.attributes[:name]).to eq 'test' - expect(seeds.dig(0, 0, :name)).to eq 'spinach' + expect(seed.size).to eq 1 + expect(seed.stages.first.name).to eq 'test' + expect(seed.stages[0].statuses[0].name).to eq 'spinach' end end @@ -109,14 +111,14 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do } end - it 'returns stage seeds only assigned to schedules' do + it 'returns pipeline seed with jobs only assigned to schedules' do run_chain - seeds = command.stage_seeds + seed = command.pipeline_seed - expect(seeds.size).to eq 1 - expect(seeds.first.attributes[:name]).to eq 'test' - expect(seeds.dig(0, 0, :name)).to eq 'spinach' + expect(seed.size).to eq 1 + expect(seed.stages.first.name).to eq 'test' + expect(seed.stages[0].statuses[0].name).to eq 'spinach' end end @@ -141,11 +143,11 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do it 'returns seeds for kubernetes dependent job' do run_chain - seeds = command.stage_seeds + seed = command.pipeline_seed - expect(seeds.size).to eq 2 - expect(seeds.dig(0, 0, :name)).to eq 'spinach' - expect(seeds.dig(1, 0, :name)).to eq 'production' + expect(seed.size).to eq 2 + expect(seed.stages[0].statuses[0].name).to eq 'spinach' + expect(seed.stages[1].statuses[0].name).to eq 'production' end end end @@ -154,10 +156,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do it 'does not return seeds for kubernetes dependent job' do run_chain - seeds = command.stage_seeds + seed = command.pipeline_seed - expect(seeds.size).to eq 1 - expect(seeds.dig(0, 0, :name)).to eq 'spinach' + expect(seed.size).to eq 1 + expect(seed.stages[0].statuses[0].name).to eq 'spinach' end end end @@ -173,10 +175,10 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do it 'returns stage seeds only when variables expression is truthy' do run_chain - seeds = command.stage_seeds + seed = command.pipeline_seed - expect(seeds.size).to eq 1 - expect(seeds.dig(0, 0, :name)).to eq 'unit' + expect(seed.size).to eq 1 + expect(seed.stages[0].statuses[0].name).to eq 'unit' end end diff --git a/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb b/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb new file mode 100644 index 00000000000..c52994fc6a2 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/quota/deployments_spec.rb @@ -0,0 +1,95 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Pipeline::Quota::Deployments do + let_it_be(:namespace) { create(:namespace) } + let_it_be(:default_plan, reload: true) { create(:default_plan) } + let_it_be(:project, reload: true) { create(:project, :repository, namespace: namespace) } + let_it_be(:plan_limits) { create(:plan_limits, plan: default_plan) } + + let(:pipeline) { build_stubbed(:ci_pipeline, project: project) } + + let(:pipeline_seed) { double(:pipeline_seed, deployments_count: 2)} + + let(:command) do + double(:command, + project: project, + pipeline_seed: pipeline_seed, + save_incompleted: true + ) + end + + let(:ci_pipeline_deployments_limit) { 0 } + + before do + plan_limits.update!(ci_pipeline_deployments: ci_pipeline_deployments_limit) + end + + subject(:quota) { described_class.new(namespace, pipeline, command) } + + shared_context 'limit exceeded' do + let(:ci_pipeline_deployments_limit) { 1 } + end + + shared_context 'limit not exceeded' do + let(:ci_pipeline_deployments_limit) { 2 } + end + + describe '#enabled?' do + context 'when limit is enabled in plan' do + let(:ci_pipeline_deployments_limit) { 10 } + + it 'is enabled' do + expect(quota).to be_enabled + end + end + + context 'when limit is not enabled' do + let(:ci_pipeline_deployments_limit) { 0 } + + it 'is not enabled' do + expect(quota).not_to be_enabled + end + end + + context 'when limit does not exist' do + before do + allow(namespace).to receive(:actual_plan) { create(:default_plan) } + end + + it 'is enabled by default' do + expect(quota).to be_enabled + end + end + end + + describe '#exceeded?' do + context 'when limit is exceeded' do + include_context 'limit exceeded' + + it 'is exceeded' do + expect(quota).to be_exceeded + end + end + + context 'when limit is not exceeded' do + include_context 'limit not exceeded' + + it 'is not exceeded' do + expect(quota).not_to be_exceeded + end + end + end + + describe '#message' do + context 'when limit is exceeded' do + include_context 'limit exceeded' + + it 'returns info about pipeline deployment limit exceeded' do + expect(quota.message) + .to eq "Pipeline has too many deployments! Requested 2, but the limit is 1." + end + 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 0b961336f3f..bc10e94c81d 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/build_spec.rb @@ -71,6 +71,33 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do end end + context 'with job:rules:[variables:]' do + let(:attributes) do + { name: 'rspec', + ref: 'master', + yaml_variables: [{ key: 'VAR1', value: 'var 1', public: true }, + { key: 'VAR2', value: 'var 2', public: true }], + rules: [{ if: '$VAR == null', variables: { VAR1: 'new var 1', VAR3: 'var 3' } }] } + end + + it do + is_expected.to include(yaml_variables: [{ key: 'VAR1', value: 'new var 1', public: true }, + { key: 'VAR2', value: 'var 2', public: true }, + { key: 'VAR3', value: 'var 3', public: true }]) + end + + context 'when FF ci_rules_variables is disabled' do + before do + stub_feature_flags(ci_rules_variables: false) + end + + it do + is_expected.to include(yaml_variables: [{ key: 'VAR1', value: 'var 1', public: true }, + { key: 'VAR2', value: 'var 2', public: true }]) + end + end + end + context 'with cache:key' do let(:attributes) do { @@ -165,6 +192,45 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Build do it { is_expected.to include(options: {}) } end + + context 'with allow_failure' do + let(:options) do + { allow_failure_criteria: { exit_codes: [42] } } + end + + let(:rules) do + [{ if: '$VAR == null', when: 'always' }] + end + + let(:attributes) do + { + name: 'rspec', + ref: 'master', + options: options, + rules: rules + } + end + + context 'when rules does not override allow_failure' do + it { is_expected.to match a_hash_including(options: options) } + end + + context 'when rules set allow_failure to true' do + let(:rules) do + [{ if: '$VAR == null', when: 'always', allow_failure: true }] + end + + it { is_expected.to match a_hash_including(options: { allow_failure_criteria: nil }) } + end + + context 'when rules set allow_failure to false' do + let(:rules) do + [{ if: '$VAR == null', when: 'always', allow_failure: false }] + end + + it { is_expected.to match a_hash_including(options: { allow_failure_criteria: nil }) } + end + end end describe '#bridge?' do diff --git a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb index e62bf042fba..664aaaedf7b 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/environment_spec.rb @@ -85,16 +85,6 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Environment do end it_behaves_like 'returning a correct environment' - - context 'but the environment auto_stop_in on create flag is disabled' do - let(:expected_auto_stop_in) { nil } - - before do - stub_feature_flags(environment_auto_stop_start_on_create: false) - end - - it_behaves_like 'returning a correct environment' - end end end diff --git a/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb new file mode 100644 index 00000000000..1790388da03 --- /dev/null +++ b/spec/lib/gitlab/ci/pipeline/seed/pipeline_spec.rb @@ -0,0 +1,75 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Pipeline::Seed::Pipeline do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:pipeline) { create(:ci_pipeline, project: project) } + + let(:stages_attributes) do + [ + { + name: 'build', + index: 0, + builds: [ + { name: 'init', scheduling_type: :stage }, + { name: 'build', scheduling_type: :stage } + ] + }, + { + name: 'test', + index: 1, + builds: [ + { name: 'rspec', scheduling_type: :stage }, + { name: 'staging', scheduling_type: :stage, environment: 'staging' }, + { name: 'deploy', scheduling_type: :stage, environment: 'production' } + ] + } + ] + end + + subject(:seed) do + described_class.new(pipeline, stages_attributes) + end + + describe '#stages' do + it 'returns the stage resources' do + stages = seed.stages + + expect(stages).to all(be_a(Ci::Stage)) + expect(stages.map(&:name)).to contain_exactly('build', 'test') + end + end + + describe '#size' do + it 'returns the number of jobs' do + expect(seed.size).to eq(5) + end + end + + describe '#errors' do + context 'when attributes are valid' do + it 'returns nil' do + expect(seed.errors).to be_nil + end + end + + context 'when attributes are not valid' do + it 'returns the errors' do + stages_attributes[0][:builds] << { + name: 'invalid_job', + scheduling_type: :dag, + needs_attributes: [{ name: 'non-existent', artifacts: true }] + } + + expect(seed.errors).to contain_exactly("invalid_job: needs 'non-existent'") + end + end + end + + describe '#deployments_count' do + it 'counts the jobs having an environment associated' do + expect(seed.deployments_count).to eq(2) + end + end +end |