debian-mirror-gitlab/spec/lib/gitlab/ci/pipeline/chain/seed_spec.rb

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

313 lines
8.7 KiB
Ruby
Raw Normal View History

2019-12-26 22:10:19 +05:30
# frozen_string_literal: true
require 'spec_helper'
2020-07-28 23:09:34 +05:30
RSpec.describe Gitlab::Ci::Pipeline::Chain::Seed do
2021-04-29 21:17:54 +05:30
let_it_be(:project) { create(:project, :repository) }
let_it_be(:user) { create(:user, developer_projects: [project]) }
2019-12-26 22:10:19 +05:30
2022-08-27 11:52:29 +05:30
let(:seeds_block) {}
2021-04-29 21:17:54 +05:30
let(:command) { initialize_command }
2019-12-26 22:10:19 +05:30
let(:pipeline) { build(:ci_pipeline, project: project) }
describe '#perform!' do
before do
stub_ci_pipeline_yaml_file(YAML.dump(config))
end
let(:config) do
{ rspec: { script: 'rake' } }
end
2021-01-29 00:20:46 +05:30
subject(:run_chain) do
2021-04-29 21:17:54 +05:30
run_previous_chain(pipeline, command)
perform_seed(pipeline, command)
2021-01-29 00:20:46 +05:30
end
2019-12-26 22:10:19 +05:30
it 'allocates next IID' do
2021-04-29 21:17:54 +05:30
run_chain
2019-12-26 22:10:19 +05:30
expect(pipeline.iid).to be_present
end
2020-06-23 00:09:42 +05:30
it 'ensures ci_ref' do
2021-04-29 21:17:54 +05:30
run_chain
2020-06-23 00:09:42 +05:30
expect(pipeline.ci_ref).to be_present
end
2019-12-26 22:10:19 +05:30
it 'sets the seeds in the command object' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
expect(command.pipeline_seed).to be_a(Gitlab::Ci::Pipeline::Seed::Pipeline)
expect(command.pipeline_seed.size).to eq 1
2019-12-26 22:10:19 +05:30
end
context 'when no ref policy is specified' do
let(:config) do
{
production: { stage: 'deploy', script: 'cap prod' },
rspec: { stage: 'test', script: 'rspec' },
spinach: { stage: 'test', script: 'spinach' }
}
end
2021-02-22 17:27:13 +05:30
it 'correctly fabricates stages and builds' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
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'
2019-12-26 22:10:19 +05:30
end
end
context 'when refs policy is specified' do
2022-11-25 23:54:43 +05:30
let(:tag_name) { project.repository.tags.first.name }
2019-12-26 22:10:19 +05:30
let(:pipeline) do
2022-11-25 23:54:43 +05:30
build(:ci_pipeline, project: project, ref: tag_name, tag: true)
2019-12-26 22:10:19 +05:30
end
let(:config) do
{
production: { stage: 'deploy', script: 'cap prod', only: ['master'] },
spinach: { stage: 'test', script: 'spinach', only: ['tags'] }
}
end
2021-02-22 17:27:13 +05:30
it 'returns pipeline seed with jobs only assigned to master' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
seed = command.pipeline_seed
2019-12-26 22:10:19 +05:30
2021-02-22 17:27:13 +05:30
expect(seed.size).to eq 1
expect(seed.stages.first.name).to eq 'test'
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
2019-12-26 22:10:19 +05:30
end
end
context 'when source policy is specified' do
let(:pipeline) { create(:ci_pipeline, source: :schedule) }
let(:config) do
{
production: { stage: 'deploy', script: 'cap prod', only: ['triggers'] },
spinach: { stage: 'test', script: 'spinach', only: ['schedules'] }
}
end
2021-02-22 17:27:13 +05:30
it 'returns pipeline seed with jobs only assigned to schedules' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
seed = command.pipeline_seed
2019-12-26 22:10:19 +05:30
2021-02-22 17:27:13 +05:30
expect(seed.size).to eq 1
expect(seed.stages.first.name).to eq 'test'
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
2019-12-26 22:10:19 +05:30
end
end
context 'when kubernetes policy is specified' do
let(:config) do
{
spinach: { stage: 'test', script: 'spinach' },
production: {
stage: 'deploy',
script: 'cap',
only: { kubernetes: 'active' }
}
}
end
context 'when kubernetes is active' do
context 'when user configured kubernetes from CI/CD > Clusters' do
let!(:cluster) { create(:cluster, :project, :provided_by_gcp) }
let(:project) { cluster.project }
let(:pipeline) { build(:ci_pipeline, project: project) }
it 'returns seeds for kubernetes dependent job' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
seed = command.pipeline_seed
2019-12-26 22:10:19 +05:30
2021-02-22 17:27:13 +05:30
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'
2019-12-26 22:10:19 +05:30
end
end
end
context 'when kubernetes is not active' do
it 'does not return seeds for kubernetes dependent job' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
seed = command.pipeline_seed
2019-12-26 22:10:19 +05:30
2021-02-22 17:27:13 +05:30
expect(seed.size).to eq 1
expect(seed.stages[0].statuses[0].name).to eq 'spinach'
2019-12-26 22:10:19 +05:30
end
end
end
context 'when variables policy is specified' do
let(:config) do
{
unit: { script: 'minitest', only: { variables: ['$CI_PIPELINE_SOURCE'] } },
feature: { script: 'spinach', only: { variables: ['$UNDEFINED'] } }
}
end
it 'returns stage seeds only when variables expression is truthy' do
2021-04-29 21:17:54 +05:30
run_chain
2021-02-22 17:27:13 +05:30
seed = command.pipeline_seed
2019-12-26 22:10:19 +05:30
2021-02-22 17:27:13 +05:30
expect(seed.size).to eq 1
expect(seed.stages[0].statuses[0].name).to eq 'unit'
2019-12-26 22:10:19 +05:30
end
end
2021-01-29 00:20:46 +05:30
context 'when there is seeds_block' do
let(:seeds_block) do
->(pipeline) { pipeline.variables.build(key: 'VAR', value: '123') }
end
2021-03-08 18:12:59 +05:30
it 'does not execute the block' do
2021-04-29 21:17:54 +05:30
run_chain
2021-03-08 18:12:59 +05:30
expect(pipeline.variables.size).to eq(0)
2021-01-29 00:20:46 +05:30
end
end
2021-04-29 21:17:54 +05:30
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
end
2022-08-27 11:52:29 +05:30
describe '#rule_variables' do
let(:config) do
{
variables: { VAR1: 11 },
workflow: {
rules: [{ if: '$CI_PIPELINE_SOURCE',
variables: { SYMBOL: :symbol, STRING: "string", INTEGER: 1 } },
{ when: 'always' }]
},
rspec: { script: 'rake' }
}
end
let(:rspec_variables) { command.pipeline_seed.stages[0].statuses[0].variables.to_hash }
it 'correctly parses rule variables' do
run_chain
expect(rspec_variables['SYMBOL']).to eq("symbol")
expect(rspec_variables['STRING']).to eq("string")
expect(rspec_variables['INTEGER']).to eq("1")
end
end
2021-04-29 21:17:54 +05:30
context 'N+1 queries' do
2021-06-08 01:23:25 +05:30
it 'avoids N+1 queries when calculating variables of jobs', :use_sql_query_cache do
warm_up_pipeline, warm_up_command = prepare_pipeline1
perform_seed(warm_up_pipeline, warm_up_command)
2021-04-29 21:17:54 +05:30
pipeline1, command1 = prepare_pipeline1
pipeline2, command2 = prepare_pipeline2
2021-06-08 01:23:25 +05:30
control = ActiveRecord::QueryRecorder.new(skip_cached: false) do
2021-04-29 21:17:54 +05:30
perform_seed(pipeline1, command1)
end
2021-06-08 01:23:25 +05:30
expect { perform_seed(pipeline2, command2) }.not_to exceed_all_query_limit(
2021-04-29 21:17:54 +05:30
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
2021-06-08 01:23:25 +05:30
non_handled_sql_queries = 2
# 1. Ci::InstanceVariable Load => `Ci::InstanceVariable#cached_data` => already cached with `fetch_memory_cache`
2021-04-29 21:17:54 +05:30
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
)
2019-12-26 22:10:19 +05:30
end
end