diff options
Diffstat (limited to 'spec/services/ci')
-rw-r--r-- | spec/services/ci/archive_trace_service_spec.rb | 10 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service/needs_spec.rb | 175 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service/rules_spec.rb | 148 | ||||
-rw-r--r-- | spec/services/ci/create_pipeline_service_spec.rb | 53 | ||||
-rw-r--r-- | spec/services/ci/pipeline_trigger_service_spec.rb | 8 | ||||
-rw-r--r-- | spec/services/ci/play_manual_stage_service_spec.rb | 5 | ||||
-rw-r--r-- | spec/services/ci/prepare_build_service_spec.rb | 4 | ||||
-rw-r--r-- | spec/services/ci/process_pipeline_service_spec.rb | 6 | ||||
-rw-r--r-- | spec/services/ci/register_job_service_spec.rb | 8 | ||||
-rw-r--r-- | spec/services/ci/retry_pipeline_service_spec.rb | 21 |
10 files changed, 309 insertions, 129 deletions
diff --git a/spec/services/ci/archive_trace_service_spec.rb b/spec/services/ci/archive_trace_service_spec.rb index 47bc26c0521..ba94013b574 100644 --- a/spec/services/ci/archive_trace_service_spec.rb +++ b/spec/services/ci/archive_trace_service_spec.rb @@ -41,7 +41,9 @@ describe Ci::ArchiveTraceService, '#execute' do context 'when job failed to archive trace but did not raise an exception' do before do - allow_any_instance_of(Gitlab::Ci::Trace).to receive(:archive!) {} + allow_next_instance_of(Gitlab::Ci::Trace) do |instance| + allow(instance).to receive(:archive!) {} + end end it 'leaves a warning message in sidekiq log' do @@ -59,11 +61,11 @@ describe Ci::ArchiveTraceService, '#execute' do let(:job) { create(:ci_build, :running, :trace_live) } it 'increments Prometheus counter, sends crash report to Sentry and ignore an error for continuing to archive' do - expect(Gitlab::Sentry) - .to receive(:track_exception) + expect(Gitlab::ErrorTracking) + .to receive(:track_and_raise_for_dev_exception) .with(::Gitlab::Ci::Trace::ArchiveError, issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/51502', - extra: { job_id: job.id } ).once + job_id: job.id).once expect(Sidekiq.logger).to receive(:warn).with( class: ArchiveTraceWorker.name, diff --git a/spec/services/ci/create_pipeline_service/needs_spec.rb b/spec/services/ci/create_pipeline_service/needs_spec.rb new file mode 100644 index 00000000000..5ef7e592b36 --- /dev/null +++ b/spec/services/ci/create_pipeline_service/needs_spec.rb @@ -0,0 +1,175 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe Ci::CreatePipelineService do + context 'needs' do + let_it_be(:user) { create(:admin) } + let_it_be(:project) { create(:project, :repository, creator: user) } + + let(:ref) { 'refs/heads/master' } + let(:source) { :push } + let(:service) { described_class.new(project, user, { ref: ref }) } + let(:pipeline) { service.execute(source) } + + before do + stub_ci_pipeline_yaml_file(config) + end + + context 'with a valid config' do + let(:config) do + <<~YAML + build_a: + stage: build + script: + - make + artifacts: + paths: + - binaries/ + build_b: + stage: build + script: + - make + artifacts: + paths: + - other_binaries/ + build_c: + stage: build + script: + - make + build_d: + stage: build + script: + - make + parallel: 3 + + test_a: + stage: test + script: + - ls + needs: + - build_a + - job: build_b + artifacts: true + - job: build_c + artifacts: false + dependencies: + - build_a + + test_b: + stage: test + script: + - ls + parallel: 2 + needs: + - build_a + - job: build_b + artifacts: true + - job: build_d + artifacts: false + + test_c: + stage: test + script: + - ls + needs: + - build_a + - job: build_b + - job: build_c + artifacts: true + YAML + end + + let(:test_a_build) { pipeline.builds.find_by!(name: 'test_a') } + + it 'creates a pipeline with builds' do + expected_builds = [ + 'build_a', 'build_b', 'build_c', 'build_d 1/3', 'build_d 2/3', + 'build_d 3/3', 'test_a', 'test_b 1/2', 'test_b 2/2', 'test_c' + ] + + expect(pipeline).to be_persisted + expect(pipeline.builds.pluck(:name)).to contain_exactly(*expected_builds) + end + + it 'saves needs' do + expect(test_a_build.needs.map(&:attributes)) + .to contain_exactly( + a_hash_including('name' => 'build_a', 'artifacts' => true), + a_hash_including('name' => 'build_b', 'artifacts' => true), + a_hash_including('name' => 'build_c', 'artifacts' => false) + ) + end + + it 'saves dependencies' do + expect(test_a_build.options) + .to match(a_hash_including('dependencies' => ['build_a'])) + end + + it 'artifacts default to true' do + test_job = pipeline.builds.find_by!(name: 'test_c') + + expect(test_job.needs.map(&:attributes)) + .to contain_exactly( + a_hash_including('name' => 'build_a', 'artifacts' => true), + a_hash_including('name' => 'build_b', 'artifacts' => true), + a_hash_including('name' => 'build_c', 'artifacts' => true) + ) + end + + it 'saves parallel jobs' do + ['1/2', '2/2'].each do |part| + test_job = pipeline.builds.find_by(name: "test_b #{part}") + + expect(test_job.needs.map(&:attributes)) + .to contain_exactly( + a_hash_including('name' => 'build_a', 'artifacts' => true), + a_hash_including('name' => 'build_b', 'artifacts' => true), + a_hash_including('name' => 'build_d 1/3', 'artifacts' => false), + a_hash_including('name' => 'build_d 2/3', 'artifacts' => false), + a_hash_including('name' => 'build_d 3/3', 'artifacts' => false) + ) + end + end + end + + context 'with an invalid config' do + let(:config) do + <<~YAML + build_a: + stage: build + script: + - make + artifacts: + paths: + - binaries/ + + build_b: + stage: build + script: + - make + artifacts: + paths: + - other_binaries/ + + test_a: + stage: test + script: + - ls + needs: + - build_a + - job: build_b + artifacts: string + YAML + end + + it { expect(pipeline).to be_persisted } + it { expect(pipeline.builds.any?).to be_falsey } + + it 'assigns an error to the pipeline' do + expect(pipeline.yaml_errors) + .to eq('jobs:test_a:needs:need artifacts should be a boolean value') + end + end + end +end diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index c922266647b..0a2c5724ce4 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -13,7 +13,9 @@ describe Ci::CreatePipelineService do context 'job:rules' do before do stub_ci_pipeline_yaml_file(config) - allow_any_instance_of(Ci::BuildScheduleWorker).to receive(:perform).and_return(true) + allow_next_instance_of(Ci::BuildScheduleWorker) do |instance| + allow(instance).to receive(:perform).and_return(true) + end end context 'exists:' do @@ -98,6 +100,17 @@ describe Ci::CreatePipelineService do stub_ci_pipeline_yaml_file(config) end + shared_examples 'workflow:rules feature disabled' do + before do + stub_feature_flags(workflow_rules: false) + end + + it 'presents a message that rules are disabled' do + expect(pipeline.errors[:base]).to include('Workflow rules are disabled') + expect(pipeline).to be_persisted + end + end + context 'with a single regex-matching if: clause' do let(:config) do <<-EOY @@ -114,48 +127,36 @@ describe Ci::CreatePipelineService do end context 'matching the first rule in the list' do - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end context 'matching the last rule in the list' do let(:ref) { 'refs/heads/feature' } - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end context 'matching the when:never rule' do let(:ref) { 'refs/heads/wip' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches errors' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end end context 'matching no rules in the list' do let(:ref) { 'refs/heads/fix' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches errors' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end end end @@ -176,12 +177,9 @@ describe Ci::CreatePipelineService do end context 'matching the first rule in the list' do - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end end @@ -204,24 +202,18 @@ describe Ci::CreatePipelineService do context 'with partial match' do let(:ref) { 'refs/heads/feature' } - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end end context 'with complete match' do let(:ref) { 'refs/heads/feature_conflict' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches errors' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end end end @@ -245,105 +237,45 @@ describe Ci::CreatePipelineService do context 'where workflow passes and the job fails' do let(:ref) { 'refs/heads/master' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about no job in the pipeline' do + it 'invalidates the pipeline with an empty jobs error' do expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + expect(pipeline).not_to be_persisted end - context 'with workflow:rules shut off' do - before do - stub_feature_flags(workflow_rules: false) - end - - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about no job in the pipeline' do - expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') - end - end + it_behaves_like 'workflow:rules feature disabled' end context 'where workflow passes and the job passes' do let(:ref) { 'refs/heads/feature' } - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do + it 'saves a pending pipeline' do expect(pipeline).to be_pending + expect(pipeline).to be_persisted end - context 'with workflow:rules shut off' do - before do - stub_feature_flags(workflow_rules: false) - end - - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do - expect(pipeline).to be_pending - end - end + it_behaves_like 'workflow:rules feature disabled' end context 'where workflow fails and the job fails' do let(:ref) { 'refs/heads/fix' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about workflow rules' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end - context 'with workflow:rules shut off' do - before do - stub_feature_flags(workflow_rules: false) - end - - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about job rules' do - expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') - end - end + it_behaves_like 'workflow:rules feature disabled' end context 'where workflow fails and the job passes' do let(:ref) { 'refs/heads/wip' } - it 'does not save the pipeline' do - expect(pipeline).not_to be_persisted - end - - it 'attaches an error about workflow rules' do + it 'invalidates the pipeline with a workflow rules error' do expect(pipeline.errors[:base]).to include('Pipeline filtered out by workflow rules.') + expect(pipeline).not_to be_persisted end - context 'with workflow:rules shut off' do - before do - stub_feature_flags(workflow_rules: false) - end - - it 'saves the pipeline' do - expect(pipeline).to be_persisted - end - - it 'sets the pipeline state to pending' do - expect(pipeline).to be_pending - end - end + it_behaves_like 'workflow:rules feature disabled' end end end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index de0f4841215..04e57b1a2d4 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -10,7 +10,7 @@ describe Ci::CreatePipelineService do let(:ref_name) { 'refs/heads/master' } before do - stub_repository_ci_yaml_file(sha: anything) + stub_ci_pipeline_yaml_file(gitlab_ci_yaml) end describe '#execute' do @@ -510,7 +510,7 @@ describe Ci::CreatePipelineService do it 'attaches errors to the pipeline' do pipeline = execute_service - expect(pipeline.errors.full_messages).to eq ['Missing .gitlab-ci.yml file'] + expect(pipeline.errors.full_messages).to eq ['Missing CI config file'] expect(pipeline).not_to be_persisted end end @@ -528,7 +528,7 @@ describe Ci::CreatePipelineService do end it 'logs error' do - expect(Gitlab::Sentry).to receive(:track_acceptable_exception).and_call_original + expect(Gitlab::ErrorTracking).to receive(:track_exception).and_call_original execute_service end @@ -613,7 +613,7 @@ describe Ci::CreatePipelineService do end it 'logs error' do - expect(Gitlab::Sentry).to receive(:track_acceptable_exception).and_call_original + expect(Gitlab::ErrorTracking).to receive(:track_exception).and_call_original execute_service end @@ -781,6 +781,25 @@ describe Ci::CreatePipelineService do end end + context 'with environment with auto_stop_in' do + before do + config = YAML.dump( + deploy: { + environment: { name: "review/$CI_COMMIT_REF_NAME", auto_stop_in: '1 day' }, + script: 'ls' + }) + + stub_ci_pipeline_yaml_file(config) + end + + it 'creates the environment with auto stop in' do + result = execute_service + + expect(result).to be_persisted + expect(result.builds.first.options[:environment][:auto_stop_in]).to eq('1 day') + end + end + context 'with environment name including persisted variables' do before do config = YAML.dump( @@ -801,6 +820,32 @@ describe Ci::CreatePipelineService do end end + context 'environment with Kubernetes configuration' do + let(:kubernetes_namespace) { 'custom-namespace' } + + before do + config = YAML.dump( + deploy: { + environment: { + name: "environment-name", + kubernetes: { namespace: kubernetes_namespace } + }, + script: 'ls' + } + ) + + stub_ci_pipeline_yaml_file(config) + end + + it 'stores the requested namespace' do + result = execute_service + build = result.builds.first + + expect(result).to be_persisted + expect(build.options.dig(:environment, :kubernetes, :namespace)).to eq(kubernetes_namespace) + end + end + context 'when environment with invalid name' do before do config = YAML.dump(deploy: { environment: { name: 'name,with,commas' }, script: 'ls' }) diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 24d42f402f4..44ce1ff699b 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -45,7 +45,9 @@ describe Ci::PipelineTriggerService do context 'when commit message has [ci skip]' do before do - allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' } + allow_next_instance_of(Ci::Pipeline) do |instance| + allow(instance).to receive(:git_commit_message) { '[ci skip]' } + end end it 'ignores [ci skip] and create as general' do @@ -124,7 +126,9 @@ describe Ci::PipelineTriggerService do context 'when commit message has [ci skip]' do before do - allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' } + allow_next_instance_of(Ci::Pipeline) do |instance| + allow(instance).to receive(:git_commit_message) { '[ci skip]' } + end end it 'ignores [ci skip] and create as general' do diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb index 5d812745c7f..e2946111a13 100644 --- a/spec/services/ci/play_manual_stage_service_spec.rb +++ b/spec/services/ci/play_manual_stage_service_spec.rb @@ -51,8 +51,9 @@ describe Ci::PlayManualStageService, '#execute' do context 'when user does not have permission on a specific build' do before do - allow_any_instance_of(Ci::Build).to receive(:play) - .and_raise(Gitlab::Access::AccessDeniedError) + allow_next_instance_of(Ci::Build) do |instance| + allow(instance).to receive(:play).and_raise(Gitlab::Access::AccessDeniedError) + end service.execute(stage) end diff --git a/spec/services/ci/prepare_build_service_spec.rb b/spec/services/ci/prepare_build_service_spec.rb index 2d027f13e52..3c3d8b90bb0 100644 --- a/spec/services/ci/prepare_build_service_spec.rb +++ b/spec/services/ci/prepare_build_service_spec.rb @@ -51,8 +51,8 @@ describe Ci::PrepareBuildService do it 'drops the build and notifies Sentry' do expect(build).to receive(:drop).with(:unmet_prerequisites).once - expect(Gitlab::Sentry).to receive(:track_acceptable_exception) - .with(instance_of(Kubeclient::HttpError), hash_including(extra: { build_id: build.id })) + expect(Gitlab::ErrorTracking).to receive(:track_exception) + .with(instance_of(Kubeclient::HttpError), hash_including(build_id: build.id)) subject end diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 991f8cdfac5..ba5891c8694 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -426,7 +426,9 @@ describe Ci::ProcessPipelineService, '#execute' do before do successful_build('test', stage_idx: 0) - allow_any_instance_of(Ci::PersistentRef).to receive(:delete_refs) { raise ArgumentError } + allow_next_instance_of(Ci::PersistentRef) do |instance| + allow(instance).to receive(:delete_refs) { raise ArgumentError } + end end it 'process the pipeline' do @@ -845,7 +847,7 @@ describe Ci::ProcessPipelineService, '#execute' do end def process_pipeline - described_class.new(pipeline.project, user).execute(pipeline) + described_class.new(pipeline).execute end def all_builds diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 04334fb8915..0339c6cc2d6 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -514,8 +514,8 @@ module Ci subject { execute(specific_runner, {}) } it 'does drop the build and logs both failures' do - expect(Gitlab::Sentry).to receive(:track_acceptable_exception) - .with(anything, a_hash_including(extra: a_hash_including(build_id: pending_job.id))) + expect(Gitlab::ErrorTracking).to receive(:track_exception) + .with(anything, a_hash_including(build_id: pending_job.id)) .twice .and_call_original @@ -540,8 +540,8 @@ module Ci subject { execute(specific_runner, {}) } it 'does drop the build and logs failure' do - expect(Gitlab::Sentry).to receive(:track_acceptable_exception) - .with(anything, a_hash_including(extra: a_hash_including(build_id: pending_job.id))) + expect(Gitlab::ErrorTracking).to receive(:track_exception) + .with(anything, a_hash_including(build_id: pending_job.id)) .once .and_call_original diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index e42de3cd48f..4b949761b8f 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -91,6 +91,25 @@ describe Ci::RetryPipelineService, '#execute' do end end + context 'when there is a failed test in a DAG' do + before do + create_build('build', :success, 0) + create_build('build2', :success, 0) + test_build = create_build('test', :failed, 1) + create(:ci_build_need, build: test_build, name: 'build') + create(:ci_build_need, build: test_build, name: 'build2') + end + + it 'retries the test' do + service.execute(pipeline) + + expect(build('build')).to be_success + expect(build('build2')).to be_success + expect(build('test')).to be_pending + expect(build('test').needs.map(&:name)).to match_array(%w(build build2)) + end + end + context 'when the last stage was skipepd' do before do create_build('build 1', :success, 0) @@ -223,7 +242,7 @@ describe Ci::RetryPipelineService, '#execute' do end it 'reprocesses the pipeline' do - expect(pipeline).to receive(:process!) + expect_any_instance_of(Ci::ProcessPipelineService).to receive(:execute) service.execute(pipeline) end |