diff options
Diffstat (limited to 'spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb')
-rw-r--r-- | spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb | 159 |
1 files changed, 141 insertions, 18 deletions
diff --git a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb index 80013cab6ee..264076859cb 100644 --- a/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb @@ -3,24 +3,16 @@ require 'spec_helper' RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do - let(:project) { create(:project, :repository) } - let(:user) { create(:user, developer_projects: [project]) } - let(:seeds_block) { } - - let(:command) do - Gitlab::Ci::Pipeline::Chain::Command.new( - project: project, - current_user: user, - origin_ref: 'master', - seeds_block: seeds_block) - end + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { create(:user, developer_projects: [project]) } + let(:seeds_block) { } + let(:command) { initialize_command } let(:pipeline) { build(:ci_pipeline, project: project) } describe '#perform!' do before do stub_ci_pipeline_yaml_file(YAML.dump(config)) - run_chain end let(:config) do @@ -28,23 +20,25 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do end subject(:run_chain) do - [ - Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command), - Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command) - ].map(&:perform!) - - described_class.new(pipeline, command).perform! + run_previous_chain(pipeline, command) + perform_seed(pipeline, command) end it 'allocates next IID' do + run_chain + expect(pipeline.iid).to be_present end it 'ensures ci_ref' do + run_chain + expect(pipeline.ci_ref).to be_present end it 'sets the seeds in the command object' do + run_chain + expect(command.pipeline_seed).to be_a(Gitlab::Ci::Pipeline::Seed::Pipeline) expect(command.pipeline_seed.size).to eq 1 end @@ -59,6 +53,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do end it 'correctly fabricates stages and builds' do + run_chain + seed = command.pipeline_seed expect(seed.stages.size).to eq 2 @@ -84,6 +80,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do end it 'returns pipeline seed with jobs only assigned to master' do + run_chain + seed = command.pipeline_seed expect(seed.size).to eq 1 @@ -103,6 +101,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do end it 'returns pipeline seed with jobs only assigned to schedules' do + run_chain + seed = command.pipeline_seed expect(seed.size).to eq 1 @@ -130,6 +130,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do let(:pipeline) { build(:ci_pipeline, project: project) } it 'returns seeds for kubernetes dependent job' do + run_chain + seed = command.pipeline_seed expect(seed.size).to eq 2 @@ -141,6 +143,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do context 'when kubernetes is not active' do it 'does not return seeds for kubernetes dependent job' do + run_chain + seed = command.pipeline_seed expect(seed.size).to eq 1 @@ -158,6 +162,8 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do end it 'returns stage seeds only when variables expression is truthy' do + run_chain + seed = command.pipeline_seed expect(seed.size).to eq 1 @@ -171,8 +177,125 @@ RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do end it 'does not execute the block' do + run_chain + expect(pipeline.variables.size).to eq(0) end end + + describe '#root_variables' do + let(:config) do + { + variables: { VAR1: 'var 1' }, + workflow: { + rules: [{ if: '$CI_PIPELINE_SOURCE', + variables: { VAR1: 'overridden var 1' } }, + { when: 'always' }] + }, + rspec: { script: 'rake' } + } + end + + let(:rspec_variables) { command.pipeline_seed.stages[0].statuses[0].variables.to_hash } + + it 'sends root variable with overridden by rules' do + run_chain + + expect(rspec_variables['VAR1']).to eq('overridden var 1') + end + + context 'when the FF ci_workflow_rules_variables is disabled' do + before do + stub_feature_flags(ci_workflow_rules_variables: false) + end + + it 'sends root variable' do + run_chain + + expect(rspec_variables['VAR1']).to eq('var 1') + end + end + end + + context 'N+1 queries' do + it 'avoids N+1 queries when calculating variables of jobs' do + pipeline1, command1 = prepare_pipeline1 + pipeline2, command2 = prepare_pipeline2 + + control = ActiveRecord::QueryRecorder.new do + perform_seed(pipeline1, command1) + end + + expect { perform_seed(pipeline2, command2) }.not_to exceed_query_limit( + control.count + expected_extra_queries + ) + end + + private + + def prepare_pipeline1 + config1 = { build: { stage: 'build', script: 'build' } } + stub_ci_pipeline_yaml_file(YAML.dump(config1)) + pipeline1 = build(:ci_pipeline, project: project) + command1 = initialize_command + + run_previous_chain(pipeline1, command1) + + [pipeline1, command1] + end + + def prepare_pipeline2 + config2 = { build1: { stage: 'build', script: 'build1' }, + build2: { stage: 'build', script: 'build2' }, + test: { stage: 'build', script: 'test' } } + stub_ci_pipeline_yaml_file(YAML.dump(config2)) + pipeline2 = build(:ci_pipeline, project: project) + command2 = initialize_command + + run_previous_chain(pipeline2, command2) + + [pipeline2, command2] + end + + def expected_extra_queries + extra_jobs = 2 + non_handled_sql_queries = 3 + + # 1. Ci::Build Load () SELECT "ci_builds".* FROM "ci_builds" + # WHERE "ci_builds"."type" = 'Ci::Build' + # AND "ci_builds"."commit_id" IS NULL + # AND ("ci_builds"."retried" = FALSE OR "ci_builds"."retried" IS NULL) + # AND (stage_idx < 1) + # 2. Ci::InstanceVariable Load => `Ci::InstanceVariable#cached_data` => already cached with `fetch_memory_cache` + # 3. Ci::Variable Load => `Project#ci_variables_for` => already cached with `Gitlab::SafeRequestStore` + + extra_jobs * non_handled_sql_queries + end + end + + private + + def run_previous_chain(pipeline, command) + [ + Gitlab::Ci::Pipeline::Chain::Config::Content.new(pipeline, command), + Gitlab::Ci::Pipeline::Chain::Config::Process.new(pipeline, command), + Gitlab::Ci::Pipeline::Chain::EvaluateWorkflowRules.new(pipeline, command) + ].map(&:perform!) + end + + def perform_seed(pipeline, command) + described_class.new(pipeline, command).perform! + end + end + + private + + def initialize_command + Gitlab::Ci::Pipeline::Chain::Command.new( + project: project, + current_user: user, + origin_ref: 'master', + seeds_block: seeds_block + ) end end |