Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-04-21 02:50:22 +0300
commit9dc93a4519d9d5d7be48ff274127136236a3adb3 (patch)
tree70467ae3692a0e35e5ea56bcb803eb512a10bedb /spec/services/ci
parent4b0f34b6d759d6299322b3a54453e930c6121ff0 (diff)
Add latest changes from gitlab-org/gitlab@13-11-stable-eev13.11.0-rc43
Diffstat (limited to 'spec/services/ci')
-rw-r--r--spec/services/ci/abort_pipelines_service_spec.rb94
-rw-r--r--spec/services/ci/abort_project_pipelines_service_spec.rb42
-rw-r--r--spec/services/ci/after_requeue_job_service_spec.rb38
-rw-r--r--spec/services/ci/archive_trace_service_spec.rb46
-rw-r--r--spec/services/ci/cancel_user_pipelines_service_spec.rb35
-rw-r--r--spec/services/ci/create_downstream_pipeline_service_spec.rb4
-rw-r--r--spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb1
-rw-r--r--spec/services/ci/create_pipeline_service/needs_spec.rb2
-rw-r--r--spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb1
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb152
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb37
-rw-r--r--spec/services/ci/create_web_ide_terminal_service_spec.rb19
-rw-r--r--spec/services/ci/disable_user_pipeline_schedules_service_spec.rb19
-rw-r--r--spec/services/ci/drop_pipeline_service_spec.rb60
-rw-r--r--spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/job_artifacts/create_service_spec.rb (renamed from spec/services/ci/create_job_artifacts_service_spec.rb)2
-rw-r--r--spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb (renamed from spec/services/ci/destroy_expired_job_artifacts_service_spec.rb)16
-rw-r--r--spec/services/ci/job_artifacts/destroy_batch_service_spec.rb (renamed from spec/services/ci/job_artifacts_destroy_batch_service_spec.rb)2
-rw-r--r--spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb (renamed from spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb)10
-rw-r--r--spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb8
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_build_test_two_manual_review_test_staging_production.yml171
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false.yml2
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_always.yml2
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_on_failure.yml2
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_deploy_on_failure.yml4
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_fails.yml (renamed from spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true.yml)21
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_succeeds.yml66
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_false.yml2
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true.yml2
-rw-r--r--spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true_deploy_on_failure.yml4
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb11
-rw-r--r--spec/services/ci/play_bridge_service_spec.rb22
-rw-r--r--spec/services/ci/play_build_service_spec.rb22
-rw-r--r--spec/services/ci/process_build_service_spec.rb23
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb52
-rw-r--r--spec/services/ci/register_job_service_spec.rb39
-rw-r--r--spec/services/ci/retry_build_service_spec.rb2
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb2
-rw-r--r--spec/services/ci/test_failure_history_service_spec.rb42
39 files changed, 834 insertions, 247 deletions
diff --git a/spec/services/ci/abort_pipelines_service_spec.rb b/spec/services/ci/abort_pipelines_service_spec.rb
new file mode 100644
index 00000000000..e31a45cb123
--- /dev/null
+++ b/spec/services/ci/abort_pipelines_service_spec.rb
@@ -0,0 +1,94 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::AbortPipelinesService do
+ let_it_be(:user) { create(:user) }
+ let_it_be(:project) { create(:project, namespace: user.namespace) }
+
+ let_it_be(:cancelable_pipeline, reload: true) { create(:ci_pipeline, :running, project: project, user: user) }
+ let_it_be(:manual_pipeline, reload: true) { create(:ci_pipeline, status: :manual, project: project, user: user) } # not cancelable
+ let_it_be(:other_users_pipeline, reload: true) { create(:ci_pipeline, :running, project: project, user: create(:user)) } # not this user's pipeline
+ let_it_be(:cancelable_build, reload: true) { create(:ci_build, :running, pipeline: cancelable_pipeline) }
+ let_it_be(:non_cancelable_build, reload: true) { create(:ci_build, :success, pipeline: cancelable_pipeline) }
+ let_it_be(:cancelable_stage, reload: true) { create(:ci_stage_entity, name: 'stageA', status: :running, pipeline: cancelable_pipeline, project: project) }
+ let_it_be(:non_cancelable_stage, reload: true) { create(:ci_stage_entity, name: 'stageB', status: :success, pipeline: cancelable_pipeline, project: project) }
+
+ describe '#execute' do
+ def expect_correct_cancellations
+ expect(cancelable_pipeline.finished_at).not_to be_nil
+ expect(cancelable_pipeline.status).to eq('failed')
+ expect((cancelable_pipeline.stages - [non_cancelable_stage]).map(&:status)).to all(eq('failed'))
+ expect(cancelable_build.status).to eq('failed')
+ expect(cancelable_build.finished_at).not_to be_nil
+
+ expect(manual_pipeline.status).not_to eq('failed')
+ expect(non_cancelable_stage.status).not_to eq('failed')
+ expect(non_cancelable_build.status).not_to eq('failed')
+ end
+
+ context 'with project pipelines' do
+ def abort_project_pipelines
+ described_class.new.execute(project.all_pipelines, :project_deleted)
+ end
+
+ it 'fails all running pipelines and related jobs' do
+ expect(abort_project_pipelines).to be_success
+
+ expect_correct_cancellations
+
+ expect(other_users_pipeline.status).to eq('failed')
+ expect(other_users_pipeline.failure_reason).to eq('project_deleted')
+ expect(other_users_pipeline.stages.map(&:status)).to all(eq('failed'))
+ end
+
+ it 'avoids N+1 queries' do
+ control_count = ActiveRecord::QueryRecorder.new { abort_project_pipelines }.count
+
+ pipelines = create_list(:ci_pipeline, 5, :running, project: project)
+ create_list(:ci_build, 5, :running, pipeline: pipelines.first)
+
+ expect { abort_project_pipelines }.not_to exceed_query_limit(control_count)
+ end
+
+ context 'with live build logs' do
+ before do
+ create(:ci_build_trace_chunk, build: cancelable_build)
+ end
+
+ it 'makes failed builds with stale trace visible' do
+ expect(Ci::Build.with_stale_live_trace.count).to eq 0
+
+ travel_to(2.days.ago) do
+ abort_project_pipelines
+ end
+
+ expect(Ci::Build.with_stale_live_trace.count).to eq 1
+ end
+ end
+ end
+
+ context 'with user pipelines' do
+ def abort_user_pipelines
+ described_class.new.execute(user.pipelines, :user_blocked)
+ end
+
+ it 'fails all running pipelines and related jobs' do
+ expect(abort_user_pipelines).to be_success
+
+ expect_correct_cancellations
+
+ expect(other_users_pipeline.status).not_to eq('failed')
+ end
+
+ it 'avoids N+1 queries' do
+ control_count = ActiveRecord::QueryRecorder.new { abort_user_pipelines }.count
+
+ pipelines = create_list(:ci_pipeline, 5, :running, project: project, user: user)
+ create_list(:ci_build, 5, :running, pipeline: pipelines.first)
+
+ expect { abort_user_pipelines }.not_to exceed_query_limit(control_count)
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/abort_project_pipelines_service_spec.rb b/spec/services/ci/abort_project_pipelines_service_spec.rb
deleted file mode 100644
index 9af909ac2ab..00000000000
--- a/spec/services/ci/abort_project_pipelines_service_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Ci::AbortProjectPipelinesService do
- let_it_be(:project) { create(:project) }
- let_it_be(:pipeline) { create(:ci_pipeline, :running, project: project) }
- let_it_be(:build) { create(:ci_build, :running, pipeline: pipeline) }
-
- describe '#execute' do
- it 'cancels all running pipelines and related jobs' do
- result = described_class.new.execute(project)
-
- expect(result).to be_success
- expect(pipeline.reload).to be_canceled
- expect(build.reload).to be_canceled
- end
-
- it 'avoids N+1 queries' do
- control_count = ActiveRecord::QueryRecorder.new { described_class.new.execute(project) }.count
-
- pipelines = create_list(:ci_pipeline, 5, :running, project: project)
- create_list(:ci_build, 5, :running, pipeline: pipelines.first)
-
- expect { described_class.new.execute(project) }.not_to exceed_query_limit(control_count)
- end
- end
-
- context 'when feature disabled' do
- before do
- stub_feature_flags(abort_deleted_project_pipelines: false)
- end
-
- it 'does not abort the pipeline' do
- result = described_class.new.execute(project)
-
- expect(result).to be(nil)
- expect(pipeline.reload).to be_running
- expect(build.reload).to be_running
- end
- end
-end
diff --git a/spec/services/ci/after_requeue_job_service_spec.rb b/spec/services/ci/after_requeue_job_service_spec.rb
new file mode 100644
index 00000000000..a2147759dba
--- /dev/null
+++ b/spec/services/ci/after_requeue_job_service_spec.rb
@@ -0,0 +1,38 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::AfterRequeueJobService do
+ let_it_be(:project) { create(:project) }
+ let_it_be(:user) { project.owner }
+
+ let(:pipeline) { create(:ci_pipeline, project: project) }
+
+ let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 0) }
+ let!(:test1) { create(:ci_build, :success, pipeline: pipeline, stage_idx: 1) }
+ let!(:test2) { create(:ci_build, :skipped, pipeline: pipeline, stage_idx: 1) }
+
+ subject(:execute_service) { described_class.new(project, user).execute(build) }
+
+ it 'marks subsequent skipped jobs as processable' do
+ expect(test1.reload).to be_success
+ expect(test2.reload).to be_skipped
+
+ execute_service
+
+ expect(test1.reload).to be_success
+ expect(test2.reload).to be_created
+ end
+
+ context 'when the pipeline is a downstream pipeline and the bridge is depended' do
+ let!(:trigger_job) { create(:ci_bridge, :strategy_depend, status: 'success') }
+
+ before do
+ create(:ci_sources_pipeline, pipeline: pipeline, source_job: trigger_job)
+ end
+
+ it 'marks source bridge as pending' do
+ expect { execute_service }.to change { trigger_job.reload.status }.from('success').to('pending')
+ end
+ end
+end
diff --git a/spec/services/ci/archive_trace_service_spec.rb b/spec/services/ci/archive_trace_service_spec.rb
index 07ea314debc..a4f498f17c3 100644
--- a/spec/services/ci/archive_trace_service_spec.rb
+++ b/spec/services/ci/archive_trace_service_spec.rb
@@ -24,6 +24,52 @@ RSpec.describe Ci::ArchiveTraceService, '#execute' do
it 'does not create an archived trace' do
expect { subject }.not_to change { Ci::JobArtifact.trace.count }
end
+
+ context 'when live trace chunks still exist' do
+ before do
+ create(:ci_build_trace_chunk, build: job)
+ end
+
+ context 'when the feature flag `erase_traces_from_already_archived_jobs_when_archiving_again` is enabled' do
+ before do
+ stub_feature_flags(erase_traces_from_already_archived_jobs_when_archiving_again: true)
+ end
+
+ it 'removes the trace chunks' do
+ expect { subject }.to change { job.trace_chunks.count }.to(0)
+ end
+
+ context 'when associated data does not exist' do
+ before do
+ job.job_artifacts_trace.file.remove!
+ end
+
+ it 'removes the trace artifact' do
+ expect { subject }.to change { job.reload.job_artifacts_trace }.to(nil)
+ end
+ end
+ end
+
+ context 'when the feature flag `erase_traces_from_already_archived_jobs_when_archiving_again` is disabled' do
+ before do
+ stub_feature_flags(erase_traces_from_already_archived_jobs_when_archiving_again: false)
+ end
+
+ it 'does not remove the trace chunks' do
+ expect { subject }.not_to change { job.trace_chunks.count }
+ end
+
+ context 'when associated data does not exist' do
+ before do
+ job.job_artifacts_trace.file.remove!
+ end
+
+ it 'does not remove the trace artifact' do
+ expect { subject }.not_to change { job.reload.job_artifacts_trace }
+ end
+ end
+ end
+ end
end
context 'when job does not have trace' do
diff --git a/spec/services/ci/cancel_user_pipelines_service_spec.rb b/spec/services/ci/cancel_user_pipelines_service_spec.rb
deleted file mode 100644
index 8491242dfd5..00000000000
--- a/spec/services/ci/cancel_user_pipelines_service_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-
-RSpec.describe Ci::CancelUserPipelinesService do
- describe '#execute' do
- let(:user) { create(:user) }
-
- subject { described_class.new.execute(user) }
-
- context 'when user has running CI pipelines' do
- let(:pipeline) { create(:ci_pipeline, :running, user: user) }
- let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
-
- it 'cancels all running pipelines and related jobs', :sidekiq_might_not_need_inline do
- subject
-
- expect(pipeline.reload).to be_canceled
- expect(build.reload).to be_canceled
- end
- end
-
- context 'when an error ocurrs' do
- it 'raises a service level error' do
- service = double(execute: ServiceResponse.error(message: 'Error canceling pipeline'))
- allow(::Ci::CancelUserPipelinesService).to receive(:new).and_return(service)
-
- result = subject
-
- expect(result).to be_a(ServiceResponse)
- expect(result).to be_error
- end
- end
- end
-end
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb
index 860932d4fde..dd10fb017aa 100644
--- a/spec/services/ci/create_downstream_pipeline_service_spec.rb
+++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb
@@ -112,7 +112,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'updates bridge status when downstream pipeline gets processed' do
pipeline = service.execute(bridge)
- expect(pipeline.reload).to be_pending
+ expect(pipeline.reload).to be_created
expect(bridge.reload).to be_success
end
@@ -227,7 +227,7 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do
it 'updates bridge status when downstream pipeline gets processed' do
pipeline = service.execute(bridge)
- expect(pipeline.reload).to be_pending
+ expect(pipeline.reload).to be_created
expect(bridge.reload).to be_success
end
diff --git a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
index 9cf66dfceb0..d4e9946ac46 100644
--- a/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb
@@ -40,6 +40,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
it 'creates bridge job with resource group' do
pipeline = create_pipeline!
+ Ci::InitialPipelineProcessWorker.new.perform(pipeline.id)
test = pipeline.statuses.find_by(name: 'instrumentation_test')
expect(pipeline).to be_created_successfully
diff --git a/spec/services/ci/create_pipeline_service/needs_spec.rb b/spec/services/ci/create_pipeline_service/needs_spec.rb
index a6b0a9662c9..4521067cd52 100644
--- a/spec/services/ci/create_pipeline_service/needs_spec.rb
+++ b/spec/services/ci/create_pipeline_service/needs_spec.rb
@@ -202,7 +202,7 @@ RSpec.describe Ci::CreatePipelineService do
YAML
end
- it 'creates a pipeline with build_a and test_b pending; deploy_b manual' do
+ it 'creates a pipeline with build_a and test_b pending; deploy_b manual', :sidekiq_inline do
processables = pipeline.processables
build_a = processables.find { |processable| processable.name == 'build_a' }
diff --git a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
index a3818937113..5ea75c2253b 100644
--- a/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
+++ b/spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb
@@ -91,6 +91,7 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do
it 'creates bridge job with resource group', :aggregate_failures do
pipeline = create_pipeline!
+ Ci::InitialPipelineProcessWorker.new.perform(pipeline.id)
test = pipeline.statuses.find_by(name: 'instrumentation_test')
expect(pipeline).to be_created_successfully
diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb
index e97e74c1515..33ec6aacc44 100644
--- a/spec/services/ci/create_pipeline_service/rules_spec.rb
+++ b/spec/services/ci/create_pipeline_service/rules_spec.rb
@@ -151,11 +151,29 @@ RSpec.describe Ci::CreatePipelineService do
context 'variables:' do
let(:config) do
<<-EOY
- job:
+ variables:
+ VAR4: workflow var 4
+ VAR5: workflow var 5
+ VAR7: workflow var 7
+
+ workflow:
+ rules:
+ - if: $CI_COMMIT_REF_NAME =~ /master/
+ variables:
+ VAR4: overridden workflow var 4
+ - if: $CI_COMMIT_REF_NAME =~ /feature/
+ variables:
+ VAR5: overridden workflow var 5
+ VAR6: new workflow var 6
+ VAR7: overridden workflow var 7
+ - when: always
+
+ job1:
script: "echo job1"
variables:
- VAR1: my var 1
- VAR2: my var 2
+ VAR1: job var 1
+ VAR2: job var 2
+ VAR5: job var 5
rules:
- if: $CI_COMMIT_REF_NAME =~ /master/
variables:
@@ -164,45 +182,117 @@ RSpec.describe Ci::CreatePipelineService do
variables:
VAR2: overridden var 2
VAR3: new var 3
+ VAR7: overridden var 7
+ - when: on_success
+
+ job2:
+ script: "echo job2"
+ inherit:
+ variables: [VAR4, VAR6, VAR7]
+ variables:
+ VAR4: job var 4
+ rules:
+ - if: $CI_COMMIT_REF_NAME =~ /master/
+ variables:
+ VAR7: overridden var 7
- when: on_success
EOY
end
- let(:job) { pipeline.builds.find_by(name: 'job') }
+ let(:job1) { pipeline.builds.find_by(name: 'job1') }
+ let(:job2) { pipeline.builds.find_by(name: 'job2') }
+
+ let(:variable_keys) { %w(VAR1 VAR2 VAR3 VAR4 VAR5 VAR6 VAR7) }
+
+ context 'when no match' do
+ let(:ref) { 'refs/heads/wip' }
+
+ it 'does not affect vars' do
+ expect(job1.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ ['job var 1', 'job var 2', nil, 'workflow var 4', 'job var 5', nil, 'workflow var 7']
+ )
+
+ expect(job2.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ [nil, nil, nil, 'job var 4', nil, nil, 'workflow var 7']
+ )
+ end
+ end
context 'when matching to the first rule' do
let(:ref) { 'refs/heads/master' }
- it 'overrides VAR1' do
- variables = job.scoped_variables.to_hash
+ it 'overrides variables' do
+ expect(job1.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ ['overridden var 1', 'job var 2', nil, 'overridden workflow var 4', 'job var 5', nil, 'workflow var 7']
+ )
- expect(variables['VAR1']).to eq('overridden var 1')
- expect(variables['VAR2']).to eq('my var 2')
- expect(variables['VAR3']).to be_nil
+ expect(job2.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ [nil, nil, nil, 'job var 4', nil, nil, 'overridden var 7']
+ )
+ end
+
+ context 'when FF ci_workflow_rules_variables is disabled' do
+ before do
+ stub_feature_flags(ci_workflow_rules_variables: false)
+ end
+
+ it 'does not affect workflow variables but job variables' do
+ expect(job1.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ ['overridden var 1', 'job var 2', nil, 'workflow var 4', 'job var 5', nil, 'workflow var 7']
+ )
+
+ expect(job2.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ [nil, nil, nil, 'job var 4', nil, nil, 'overridden var 7']
+ )
+ end
end
end
context 'when matching to the second rule' do
let(:ref) { 'refs/heads/feature' }
- it 'overrides VAR2 and adds VAR3' do
- variables = job.scoped_variables.to_hash
+ it 'overrides variables' do
+ expect(job1.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ ['job var 1', 'overridden var 2', 'new var 3', 'workflow var 4', 'job var 5', 'new workflow var 6', 'overridden var 7']
+ )
- expect(variables['VAR1']).to eq('my var 1')
- expect(variables['VAR2']).to eq('overridden var 2')
- expect(variables['VAR3']).to eq('new var 3')
+ expect(job2.scoped_variables.to_hash.values_at(*variable_keys)).to eq(
+ [nil, nil, nil, 'job var 4', nil, 'new workflow var 6', 'overridden workflow var 7']
+ )
end
end
- context 'when no match' do
- let(:ref) { 'refs/heads/wip' }
+ context 'using calculated workflow var in job rules' do
+ let(:config) do
+ <<-EOY
+ variables:
+ VAR1: workflow var 4
+
+ workflow:
+ rules:
+ - if: $CI_COMMIT_REF_NAME =~ /master/
+ variables:
+ VAR1: overridden workflow var 4
+ - when: always
+
+ job:
+ script: "echo job1"
+ rules:
+ - if: $VAR1 =~ "overridden workflow var 4"
+ variables:
+ VAR1: overridden var 1
+ - when: on_success
+ EOY
+ end
- it 'does not affect vars' do
- variables = job.scoped_variables.to_hash
+ let(:job) { pipeline.builds.find_by(name: 'job') }
+
+ context 'when matching the first workflow condition' do
+ let(:ref) { 'refs/heads/master' }
- expect(variables['VAR1']).to eq('my var 1')
- expect(variables['VAR2']).to eq('my var 2')
- expect(variables['VAR3']).to be_nil
+ it 'uses VAR1 of job rules result' do
+ expect(job.scoped_variables.to_hash['VAR1']).to eq('overridden var 1')
+ end
end
end
end
@@ -230,8 +320,8 @@ RSpec.describe Ci::CreatePipelineService do
end
context 'matching the first rule in the list' do
- it 'saves a pending pipeline' do
- expect(pipeline).to be_pending
+ it 'saves a created pipeline' do
+ expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
@@ -239,8 +329,8 @@ RSpec.describe Ci::CreatePipelineService do
context 'matching the last rule in the list' do
let(:ref) { 'refs/heads/feature' }
- it 'saves a pending pipeline' do
- expect(pipeline).to be_pending
+ it 'saves a created pipeline' do
+ expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
@@ -280,8 +370,8 @@ RSpec.describe Ci::CreatePipelineService do
end
context 'matching the first rule in the list' do
- it 'saves a pending pipeline' do
- expect(pipeline).to be_pending
+ it 'saves a created pipeline' do
+ expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
@@ -305,8 +395,8 @@ RSpec.describe Ci::CreatePipelineService do
context 'with partial match' do
let(:ref) { 'refs/heads/feature' }
- it 'saves a pending pipeline' do
- expect(pipeline).to be_pending
+ it 'saves a created pipeline' do
+ expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
@@ -349,8 +439,8 @@ RSpec.describe Ci::CreatePipelineService do
context 'where workflow passes and the job passes' do
let(:ref) { 'refs/heads/feature' }
- it 'saves a pending pipeline' do
- expect(pipeline).to be_pending
+ it 'saves a created pipeline' do
+ expect(pipeline).to be_created
expect(pipeline).to be_persisted
end
end
diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb
index 9fafc57a770..98c85234fe7 100644
--- a/spec/services/ci/create_pipeline_service_spec.rb
+++ b/spec/services/ci/create_pipeline_service_spec.rb
@@ -63,7 +63,7 @@ RSpec.describe Ci::CreatePipelineService do
expect(pipeline).to be_push
expect(pipeline).to eq(project.ci_pipelines.last)
expect(pipeline).to have_attributes(user: user)
- expect(pipeline).to have_attributes(status: 'pending')
+ expect(pipeline).to have_attributes(status: 'created')
expect(pipeline.iid).not_to be_nil
expect(pipeline.repository_source?).to be true
expect(pipeline.builds.first).to be_kind_of(Ci::Build)
@@ -71,19 +71,21 @@ RSpec.describe Ci::CreatePipelineService do
end
it 'increments the prometheus counter' do
- expect(Gitlab::Metrics).to receive(:counter)
- .with(:pipelines_created_total, "Counter of pipelines created")
- .and_call_original
- allow(Gitlab::Metrics).to receive(:counter).and_call_original # allow other counters
+ counter = spy('pipeline created counter')
+
+ allow(Gitlab::Ci::Pipeline::Metrics)
+ .to receive(:pipelines_created_counter).and_return(counter)
pipeline
+
+ expect(counter).to have_received(:increment)
end
it 'records pipeline size in a prometheus histogram' do
histogram = spy('pipeline size histogram')
allow(Gitlab::Ci::Pipeline::Metrics)
- .to receive(:new).and_return(histogram)
+ .to receive(:pipeline_size_histogram).and_return(histogram)
execute_service
@@ -253,7 +255,7 @@ RSpec.describe Ci::CreatePipelineService do
pipeline
pipeline_on_previous_commit
- expect(pipeline.reload).to have_attributes(status: 'pending', auto_canceled_by_id: nil)
+ expect(pipeline.reload).to have_attributes(status: 'created', auto_canceled_by_id: nil)
end
it 'auto cancel pending non-HEAD pipelines', :sidekiq_might_not_need_inline do
@@ -263,8 +265,8 @@ RSpec.describe Ci::CreatePipelineService do
expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'canceled', auto_canceled_by_id: pipeline.id)
end
- it 'cancels running outdated pipelines', :sidekiq_might_not_need_inline do
- pipeline_on_previous_commit.run
+ it 'cancels running outdated pipelines', :sidekiq_inline do
+ pipeline_on_previous_commit.reload.run
head_pipeline = execute_service
expect(pipeline_on_previous_commit.reload).to have_attributes(status: 'canceled', auto_canceled_by_id: head_pipeline.id)
@@ -278,13 +280,13 @@ RSpec.describe Ci::CreatePipelineService do
end
it 'does not cancel pipelines from the other branches' do
- pending_pipeline = execute_service(
+ new_pipeline = execute_service(
ref: 'refs/heads/feature',
after: previous_commit_sha_from_ref('feature')
)
pipeline
- expect(pending_pipeline.reload).to have_attributes(status: 'pending', auto_canceled_by_id: nil)
+ expect(new_pipeline.reload).to have_attributes(status: 'created', auto_canceled_by_id: nil)
end
context 'when the interruptible attribute is' do
@@ -465,12 +467,12 @@ RSpec.describe Ci::CreatePipelineService do
project.update!(auto_cancel_pending_pipelines: 'disabled')
end
- it 'does not auto cancel pending non-HEAD pipelines' do
+ it 'does not auto cancel created non-HEAD pipelines' do
pipeline_on_previous_commit
pipeline
expect(pipeline_on_previous_commit.reload)
- .to have_attributes(status: 'pending', auto_canceled_by_id: nil)
+ .to have_attributes(status: 'created', auto_canceled_by_id: nil)
end
end
@@ -580,6 +582,13 @@ RSpec.describe Ci::CreatePipelineService do
it_behaves_like 'a failed pipeline'
+ it 'increments the error metric' do
+ stub_ci_pipeline_yaml_file(ci_yaml)
+
+ counter = Gitlab::Metrics.counter(:gitlab_ci_pipeline_failure_reasons, 'desc')
+ expect { execute_service }.to change { counter.get(reason: 'config_error') }.by(1)
+ end
+
context 'when receive git commit' do
before do
allow_any_instance_of(Ci::Pipeline).to receive(:git_commit_message) { message }
@@ -770,7 +779,7 @@ RSpec.describe Ci::CreatePipelineService do
stub_ci_pipeline_yaml_file(config)
end
- it 'does not create a new pipeline' do
+ it 'does not create a new pipeline', :sidekiq_inline do
result = execute_service
expect(result).to be_persisted
diff --git a/spec/services/ci/create_web_ide_terminal_service_spec.rb b/spec/services/ci/create_web_ide_terminal_service_spec.rb
index c1c94e30018..c1acf8fd60c 100644
--- a/spec/services/ci/create_web_ide_terminal_service_spec.rb
+++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb
@@ -66,6 +66,25 @@ RSpec.describe Ci::CreateWebIdeTerminalService do
it_behaves_like 'be successful'
end
+
+ context 'for configuration with variables' do
+ let(:config_content) do
+ <<-EOS
+ terminal:
+ script: rspec
+ variables:
+ KEY1: VAL1
+ EOS
+ end
+
+ it_behaves_like 'be successful'
+
+ it 'saves the variables' do
+ expect(subject[:pipeline].builds[0].variables).to include(
+ key: 'KEY1', value: 'VAL1', public: true, masked: false
+ )
+ end
+ end
end
end
diff --git a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb
new file mode 100644
index 00000000000..4ff8dcf075b
--- /dev/null
+++ b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::DisableUserPipelineSchedulesService do
+ describe '#execute' do
+ let(:user) { create(:user) }
+
+ subject(:service) { described_class.new.execute(user) }
+
+ context 'when user has active pipeline schedules' do
+ let(:owned_pipeline_schedule) { create(:ci_pipeline_schedule, active: true, owner: user) }
+
+ it 'disables all active pipeline schedules', :aggregate_failures do
+ expect { service }.to change { owned_pipeline_schedule.reload.active? }
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/drop_pipeline_service_spec.rb b/spec/services/ci/drop_pipeline_service_spec.rb
new file mode 100644
index 00000000000..4adbb99b9e2
--- /dev/null
+++ b/spec/services/ci/drop_pipeline_service_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::DropPipelineService do
+ let_it_be(:user) { create(:user) }
+
+ let(:failure_reason) { :user_blocked }
+
+ let!(:cancelable_pipeline) { create(:ci_pipeline, :running, user: user) }
+ let!(:running_build) { create(:ci_build, :running, pipeline: cancelable_pipeline) }
+ let!(:success_pipeline) { create(:ci_pipeline, :success, user: user) }
+ let!(:success_build) { create(:ci_build, :success, pipeline: success_pipeline) }
+
+ describe '#execute_async_for_all' do
+ subject { described_class.new.execute_async_for_all(user.pipelines, failure_reason, user) }
+
+ it 'drops only cancelable pipelines asynchronously', :sidekiq_inline do
+ subject
+
+ expect(cancelable_pipeline.reload).to be_failed
+ expect(running_build.reload).to be_failed
+
+ expect(success_pipeline.reload).to be_success
+ expect(success_build.reload).to be_success
+ end
+ end
+
+ describe '#execute' do
+ subject { described_class.new.execute(cancelable_pipeline.id, failure_reason) }
+
+ def drop_pipeline!(pipeline)
+ described_class.new.execute(pipeline, failure_reason)
+ end
+
+ it 'drops each cancelable build in the pipeline', :aggregate_failures do
+ drop_pipeline!(cancelable_pipeline)
+
+ expect(running_build.reload).to be_failed
+ expect(running_build.failure_reason).to eq(failure_reason.to_s)
+
+ expect(success_build.reload).to be_success
+ end
+
+ it 'avoids N+1 queries when reading data' do
+ control_count = ActiveRecord::QueryRecorder.new do
+ drop_pipeline!(cancelable_pipeline)
+ end.count
+
+ writes_per_build = 2
+ expected_reads_count = control_count - writes_per_build
+
+ create_list(:ci_build, 5, :running, pipeline: cancelable_pipeline)
+
+ expect do
+ drop_pipeline!(cancelable_pipeline)
+ end.not_to exceed_query_limit(expected_reads_count + (5 * writes_per_build))
+ end
+ end
+end
diff --git a/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb b/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb
index e2bdfae27f0..0cbeaa5446b 100644
--- a/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb
+++ b/spec/services/ci/external_pull_requests/create_pipeline_service_spec.rb
@@ -34,7 +34,7 @@ RSpec.describe Ci::ExternalPullRequests::CreatePipelineService do
expect(subject).to eq(project.ci_pipelines.last)
expect(subject.external_pull_request).to eq(pull_request)
expect(subject.user).to eq(user)
- expect(subject.status).to eq('pending')
+ expect(subject.status).to eq('created')
expect(subject.ref).to eq(pull_request.source_branch)
expect(subject.sha).to eq(pull_request.source_sha)
expect(subject.source_sha).to eq(pull_request.source_sha)
diff --git a/spec/services/ci/create_job_artifacts_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb
index 1efd1d390a2..22aa9e62c6f 100644
--- a/spec/services/ci/create_job_artifacts_service_spec.rb
+++ b/spec/services/ci/job_artifacts/create_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::CreateJobArtifactsService do
+RSpec.describe Ci::JobArtifacts::CreateService do
let_it_be(:project) { create(:project) }
let(:service) { described_class.new(job) }
let(:job) { create(:ci_build, project: project) }
diff --git a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
index d315dd35632..04fa55068f2 100644
--- a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared_state do
+RSpec.describe Ci::JobArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_shared_state do
include ExclusiveLeaseHelpers
let(:service) { described_class.new }
@@ -24,7 +24,7 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
job = create(:ci_build, pipeline: artifact.job.pipeline)
create(:ci_job_artifact, :archive, :expired, job: job)
- stub_const('Ci::DestroyExpiredJobArtifactsService::LOOP_LIMIT', 1)
+ stub_const("#{described_class}::LOOP_LIMIT", 1)
end
it 'performs the smallest number of queries for job_artifacts' do
@@ -113,7 +113,7 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
context 'when failed to destroy artifact' do
before do
- stub_const('Ci::DestroyExpiredJobArtifactsService::LOOP_LIMIT', 10)
+ stub_const("#{described_class}::LOOP_LIMIT", 10)
end
context 'when the import fails' do
@@ -159,8 +159,8 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
let!(:second_artifact) { create(:ci_job_artifact, expire_at: 1.day.ago) }
before do
- stub_const('Ci::DestroyExpiredJobArtifactsService::LOOP_TIMEOUT', 0.seconds)
- stub_const('Ci::DestroyExpiredJobArtifactsService::BATCH_SIZE', 1)
+ stub_const("#{described_class}::LOOP_TIMEOUT", 0.seconds)
+ stub_const("#{described_class}::BATCH_SIZE", 1)
second_artifact.job.pipeline.unlocked!
end
@@ -176,8 +176,8 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
context 'when loop reached loop limit' do
before do
- stub_const('Ci::DestroyExpiredJobArtifactsService::LOOP_LIMIT', 1)
- stub_const('Ci::DestroyExpiredJobArtifactsService::BATCH_SIZE', 1)
+ stub_const("#{described_class}::LOOP_LIMIT", 1)
+ stub_const("#{described_class}::BATCH_SIZE", 1)
second_artifact.job.pipeline.unlocked!
end
@@ -209,7 +209,7 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared
context 'when there are artifacts more than batch sizes' do
before do
- stub_const('Ci::DestroyExpiredJobArtifactsService::BATCH_SIZE', 1)
+ stub_const("#{described_class}::BATCH_SIZE", 1)
second_artifact.job.pipeline.unlocked!
end
diff --git a/spec/services/ci/job_artifacts_destroy_batch_service_spec.rb b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
index 74fbbf28ef1..52aaf73d67e 100644
--- a/spec/services/ci/job_artifacts_destroy_batch_service_spec.rb
+++ b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::JobArtifactsDestroyBatchService do
+RSpec.describe Ci::JobArtifacts::DestroyBatchService do
include ExclusiveLeaseHelpers
let(:artifacts) { Ci::JobArtifact.all }
diff --git a/spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb b/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb
index ac1a590face..3dc4f35df22 100644
--- a/spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb
+++ b/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Ci::PipelineArtifacts::DestroyExpiredArtifactsService do
+RSpec.describe Ci::PipelineArtifacts::DestroyAllExpiredService do
let(:service) { described_class.new }
describe '.execute' do
@@ -10,7 +10,7 @@ RSpec.describe Ci::PipelineArtifacts::DestroyExpiredArtifactsService do
context 'when timeout happens' do
before do
- stub_const('Ci::PipelineArtifacts::DestroyExpiredArtifactsService::LOOP_TIMEOUT', 0.1.seconds)
+ stub_const('Ci::PipelineArtifacts::DestroyAllExpiredService::LOOP_TIMEOUT', 0.1.seconds)
allow(service).to receive(:destroy_artifacts_batch) { true }
end
@@ -27,8 +27,8 @@ RSpec.describe Ci::PipelineArtifacts::DestroyExpiredArtifactsService do
context 'when the loop limit is reached' do
before do
- stub_const('::Ci::PipelineArtifacts::DestroyExpiredArtifactsService::LOOP_LIMIT', 1)
- stub_const('::Ci::PipelineArtifacts::DestroyExpiredArtifactsService::BATCH_SIZE', 1)
+ stub_const('::Ci::PipelineArtifacts::DestroyAllExpiredService::LOOP_LIMIT', 1)
+ stub_const('::Ci::PipelineArtifacts::DestroyAllExpiredService::BATCH_SIZE', 1)
create_list(:ci_pipeline_artifact, 2, expire_at: 1.week.ago)
end
@@ -44,7 +44,7 @@ RSpec.describe Ci::PipelineArtifacts::DestroyExpiredArtifactsService do
context 'when there are artifacts more than batch sizes' do
before do
- stub_const('Ci::PipelineArtifacts::DestroyExpiredArtifactsService::BATCH_SIZE', 1)
+ stub_const('Ci::PipelineArtifacts::DestroyAllExpiredService::BATCH_SIZE', 1)
create_list(:ci_pipeline_artifact, 2, expire_at: 1.week.ago)
end
diff --git a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb
index a9f9db8c689..572808cd2db 100644
--- a/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb
+++ b/spec/services/ci/pipeline_processing/shared_processing_service_tests_with_yaml.rb
@@ -49,7 +49,13 @@ RSpec.shared_context 'Pipeline Processing Service Tests With Yaml' do
statuses = pipeline.latest_statuses.by_name(job_names).to_a
expect(statuses.count).to eq(job_names.count) # ensure that we have the same counts
- statuses.each { |status| status.public_send("#{event}!") }
+ statuses.each do |status|
+ if event == 'play'
+ status.play(user)
+ else
+ status.public_send("#{event}!")
+ end
+ end
end
end
end
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_build_test_two_manual_review_test_staging_production.yml b/spec/services/ci/pipeline_processing/test_cases/dag_build_test_two_manual_review_test_staging_production.yml
new file mode 100644
index 00000000000..ed009ee4f25
--- /dev/null
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_build_test_two_manual_review_test_staging_production.yml
@@ -0,0 +1,171 @@
+config:
+ stages: [build, test, review, deploy, post_deploy]
+
+ build:
+ stage: build
+ script: exit 0
+
+ test:
+ stage: test
+ script: exit 0
+
+ release_test1:
+ stage: test
+ when: manual
+ script: exit 0
+
+ release_test2:
+ stage: test
+ when: manual
+ script: exit 0
+
+ review:
+ stage: review
+ script: exit 0
+ needs: [test, release_test1, release_test2]
+
+ staging:
+ stage: deploy
+ script: exit 0
+ needs: [release_test1]
+
+ production:
+ stage: deploy
+ script: exit 0
+ needs: [release_test2]
+
+ after_deploy:
+ stage: post_deploy
+ script: exit 0
+ needs: [production]
+
+ handle_failure:
+ stage: post_deploy
+ when: on_failure
+ script: exit 0
+
+init:
+ expect:
+ pipeline: pending
+ stages:
+ build: pending
+ test: created
+ review: created
+ deploy: created
+ post_deploy: created
+ jobs:
+ build: pending
+ test: created
+ release_test1: created
+ release_test2: created
+ review: created
+ staging: created
+ production: created
+ after_deploy: created
+ handle_failure: created
+
+transitions:
+ - event: success
+ jobs: [build]
+ expect:
+ pipeline: running
+ stages:
+ build: success
+ test: pending
+ review: skipped
+ deploy: skipped
+ post_deploy: pending
+ jobs:
+ build: success
+ test: pending
+ release_test1: manual
+ release_test2: manual
+ review: skipped
+ staging: skipped
+ production: skipped
+ after_deploy: skipped
+ handle_failure: created
+
+ - event: success
+ jobs: [test]
+ expect:
+ pipeline: success
+ stages:
+ build: success
+ test: success
+ review: skipped
+ deploy: skipped
+ post_deploy: skipped
+ jobs:
+ build: success
+ test: success
+ release_test1: manual
+ release_test2: manual
+ review: skipped
+ staging: skipped
+ production: skipped
+ after_deploy: skipped
+ handle_failure: skipped
+
+ - event: play
+ jobs: [release_test1]
+ expect:
+ pipeline: running
+ stages:
+ build: success
+ test: running
+ review: skipped
+ deploy: pending
+ post_deploy: pending
+ jobs:
+ build: success
+ test: success
+ release_test1: pending
+ release_test2: manual
+ review: skipped
+ staging: created
+ production: skipped
+ after_deploy: skipped
+ handle_failure: created
+
+ - event: success
+ jobs: [release_test1]
+ expect:
+ pipeline: running
+ stages:
+ build: success
+ test: success
+ review: skipped
+ deploy: pending
+ post_deploy: pending
+ jobs:
+ build: success
+ test: success
+ release_test1: success
+ release_test2: manual
+ review: skipped
+ staging: pending
+ production: skipped
+ after_deploy: skipped
+ handle_failure: created
+
+ - event: success
+ jobs: [staging]
+ expect:
+ pipeline: success
+ stages:
+ build: success
+ test: success
+ review: skipped
+ deploy: success
+ post_deploy: skipped
+ jobs:
+ build: success
+ test: success
+ release_test1: success
+ release_test2: manual
+ review: skipped
+ staging: success
+ production: skipped
+ after_deploy: skipped
+ handle_failure: skipped
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false.yml b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false.yml
index 1d61cd24f8c..7987f4568a4 100644
--- a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false.yml
@@ -21,7 +21,7 @@ init:
deploy: created
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_always.yml b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_always.yml
index bb8723aa303..ea7f0f06c50 100644
--- a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_always.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_always.yml
@@ -22,7 +22,7 @@ init:
deploy: created
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_on_failure.yml b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_on_failure.yml
index 3099a94befb..5c839ebc0e9 100644
--- a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_on_failure.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_false_deploy_on_failure.yml
@@ -22,7 +22,7 @@ init:
deploy: created
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_deploy_on_failure.yml b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_deploy_on_failure.yml
index 81aad4940b6..2d379f2d7c5 100644
--- a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_deploy_on_failure.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_deploy_on_failure.yml
@@ -22,7 +22,7 @@ init:
deploy: skipped
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
@@ -31,7 +31,7 @@ transitions:
deploy: skipped
jobs:
test: pending
- deploy: skipped
+ deploy: created
- event: drop
jobs: [test]
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true.yml b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_fails.yml
index b8fcdd1566a..fbe04c7e18e 100644
--- a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_fails.yml
@@ -21,7 +21,7 @@ init:
deploy: skipped
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
@@ -30,7 +30,7 @@ transitions:
deploy: skipped
jobs:
test: pending
- deploy: skipped
+ deploy: created
- event: run
jobs: [test]
@@ -41,15 +41,26 @@ transitions:
deploy: skipped
jobs:
test: running
- deploy: skipped
+ deploy: created
- event: drop
jobs: [test]
expect:
+ pipeline: running
+ stages:
+ test: success
+ deploy: pending
+ jobs:
+ test: failed
+ deploy: pending
+
+ - event: success
+ jobs: [deploy]
+ expect:
pipeline: success
stages:
test: success
- deploy: skipped
+ deploy: success
jobs:
test: failed
- deploy: skipped
+ deploy: success
diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_succeeds.yml b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_succeeds.yml
new file mode 100644
index 00000000000..68ef057f62d
--- /dev/null
+++ b/spec/services/ci/pipeline_processing/test_cases/dag_test_manual_allow_failure_true_succeeds.yml
@@ -0,0 +1,66 @@
+config:
+ test:
+ stage: test
+ when: manual
+ allow_failure: true
+ script: exit 0
+
+ deploy:
+ stage: deploy
+ script: exit 0
+ needs: [test]
+
+init:
+ expect:
+ pipeline: skipped
+ stages:
+ test: skipped
+ deploy: skipped
+ jobs:
+ test: manual
+ deploy: skipped
+
+transitions:
+ - event: play
+ jobs: [test]
+ expect:
+ pipeline: pending
+ stages:
+ test: pending
+ deploy: skipped
+ jobs:
+ test: pending
+ deploy: created
+
+ - event: run
+ jobs: [test]
+ expect:
+ pipeline: running
+ stages:
+ test: running
+ deploy: skipped
+ jobs:
+ test: running
+ deploy: created
+
+ - event: success
+ jobs: [test]
+ expect:
+ pipeline: running
+ stages:
+ test: success
+ deploy: pending
+ jobs:
+ test: success
+ deploy: pending
+
+ - event: success
+ jobs: [deploy]
+ expect:
+ pipeline: success
+ stages:
+ test: success
+ deploy: success
+ jobs:
+ test: success
+ deploy: success
diff --git a/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_false.yml b/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_false.yml
index 2ffa35b56d7..759b4d0ae75 100644
--- a/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_false.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_false.yml
@@ -20,7 +20,7 @@ init:
deploy: created
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
diff --git a/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true.yml b/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true.yml
index 088fab5ca09..93eecae8fcf 100644
--- a/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true.yml
@@ -31,7 +31,7 @@ transitions:
test: manual
deploy: success
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: running
diff --git a/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true_deploy_on_failure.yml b/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true_deploy_on_failure.yml
index 2b30316aef6..301f9631845 100644
--- a/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true_deploy_on_failure.yml
+++ b/spec/services/ci/pipeline_processing/test_cases/stage_test_manual_allow_failure_true_deploy_on_failure.yml
@@ -21,7 +21,7 @@ init:
deploy: skipped
transitions:
- - event: enqueue
+ - event: play
jobs: [test]
expect:
pipeline: pending
@@ -30,7 +30,7 @@ transitions:
deploy: skipped
jobs:
test: pending
- deploy: skipped
+ deploy: created
- event: drop
jobs: [test]
diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb
index 89d3da89011..36055779a2e 100644
--- a/spec/services/ci/pipeline_trigger_service_spec.rb
+++ b/spec/services/ci/pipeline_trigger_service_spec.rb
@@ -55,17 +55,6 @@ RSpec.describe Ci::PipelineTriggerService do
expect(var.variable_type).to eq('file')
end
- context 'when FF ci_trigger_payload_into_pipeline is disabled' do
- before do
- stub_feature_flags(ci_trigger_payload_into_pipeline: false)
- end
-
- it 'does not store the payload as a variable' do
- expect { result }.not_to change { Ci::PipelineVariable.count }
- expect(result[:pipeline].variables).to be_empty
- end
- end
-
context 'when commit message has [ci skip]' do
before do
allow_next(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' }
diff --git a/spec/services/ci/play_bridge_service_spec.rb b/spec/services/ci/play_bridge_service_spec.rb
index 0482ad4d76f..d6130325b5a 100644
--- a/spec/services/ci/play_bridge_service_spec.rb
+++ b/spec/services/ci/play_bridge_service_spec.rb
@@ -35,6 +35,28 @@ RSpec.describe Ci::PlayBridgeService, '#execute' do
expect(bridge.reload.user).to eq(user)
end
+ context 'when a subsequent job is skipped' do
+ let!(:job) { create(:ci_build, :skipped, pipeline: pipeline, stage_idx: bridge.stage_idx + 1) }
+
+ before do
+ create(:ci_build_need, build: job, name: bridge.name)
+ end
+
+ it 'marks the subsequent job as processable' do
+ expect { execute_service }.to change { job.reload.status }.from('skipped').to('created')
+ end
+
+ context 'when the FF ci_fix_pipeline_status_for_dag_needs_manual is disabled' do
+ before do
+ stub_feature_flags(ci_fix_pipeline_status_for_dag_needs_manual: false)
+ end
+
+ it 'does not change the subsequent job' do
+ expect { execute_service }.not_to change { job.reload.status }.from('skipped')
+ end
+ end
+ end
+
context 'when bridge is not playable' do
let(:bridge) { create(:ci_bridge, :failed, pipeline: pipeline, downstream: downstream_project) }
diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb
index 00c6de7681d..78de91675f9 100644
--- a/spec/services/ci/play_build_service_spec.rb
+++ b/spec/services/ci/play_build_service_spec.rb
@@ -61,6 +61,28 @@ RSpec.describe Ci::PlayBuildService, '#execute' do
expect(build.reload.user).to eq user
end
+ context 'when a subsequent job is skipped' do
+ let!(:job) { create(:ci_build, :skipped, pipeline: pipeline, stage_idx: build.stage_idx + 1) }
+
+ before do
+ create(:ci_build_need, build: job, name: build.name)
+ end
+
+ it 'marks the subsequent job as processable' do
+ expect { service.execute(build) }.to change { job.reload.status }.from('skipped').to('created')
+ end
+
+ context 'when the FF ci_fix_pipeline_status_for_dag_needs_manual is disabled' do
+ before do
+ stub_feature_flags(ci_fix_pipeline_status_for_dag_needs_manual: false)
+ end
+
+ it 'does not change the subsequent job' do
+ expect { service.execute(build) }.not_to change { job.reload.status }.from('skipped')
+ end
+ end
+ end
+
context 'when variables are supplied' do
let(:job_variables) do
[{ key: 'first', secret_value: 'first' },
diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb
index 42a92504839..b54fc45d36a 100644
--- a/spec/services/ci/process_build_service_spec.rb
+++ b/spec/services/ci/process_build_service_spec.rb
@@ -145,28 +145,5 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do
expect { subject }.to change { build.status }.to(after_status)
end
end
-
- context 'when FF skip_dag_manual_and_delayed_jobs is disabled on the project' do
- let_it_be(:other_project) { create(:project) }
-
- before do
- stub_feature_flags(skip_dag_manual_and_delayed_jobs: other_project)
- end
-
- where(:build_when, :current_status, :after_status) do
- :on_success | 'success' | 'pending'
- :on_success | 'skipped' | 'skipped'
- :manual | 'success' | 'manual'
- :manual | 'skipped' | 'manual'
- :delayed | 'success' | 'manual'
- :delayed | 'skipped' | 'manual'
- end
-
- with_them do
- it 'proceeds the build' do
- expect { subject }.to change { build.status }.to(after_status)
- end
- end
- end
end
end
diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb
index e02536fd07f..254bd19c808 100644
--- a/spec/services/ci/process_pipeline_service_spec.rb
+++ b/spec/services/ci/process_pipeline_service_spec.rb
@@ -10,6 +10,14 @@ RSpec.describe Ci::ProcessPipelineService do
create(:ci_empty_pipeline, ref: 'master', project: project)
end
+ let(:pipeline_processing_events_counter) { double(increment: true) }
+ let(:legacy_update_jobs_counter) { double(increment: true) }
+
+ let(:metrics) do
+ double(pipeline_processing_events_counter: pipeline_processing_events_counter,
+ legacy_update_jobs_counter: legacy_update_jobs_counter)
+ end
+
subject { described_class.new(pipeline) }
before do
@@ -17,22 +25,13 @@ RSpec.describe Ci::ProcessPipelineService do
stub_not_protect_default_branch
project.add_developer(user)
+
+ allow(subject).to receive(:metrics).and_return(metrics)
end
describe 'processing events counter' do
- let(:metrics) { double('pipeline metrics') }
- let(:counter) { double('events counter') }
-
- before do
- allow(subject)
- .to receive(:metrics).and_return(metrics)
- allow(metrics)
- .to receive(:pipeline_processing_events_counter)
- .and_return(counter)
- end
-
it 'increments processing events counter' do
- expect(counter).to receive(:increment)
+ expect(pipeline_processing_events_counter).to receive(:increment)
subject.execute
end
@@ -64,33 +63,22 @@ RSpec.describe Ci::ProcessPipelineService do
expect(all_builds.retried).to contain_exactly(build_retried)
end
- context 'counter ci_legacy_update_jobs_as_retried_total' do
- let(:counter) { double(increment: true) }
+ it 'increments the counter' do
+ expect(legacy_update_jobs_counter).to receive(:increment)
+ subject.execute
+ end
+
+ context 'when the previous build has already retried column true' do
before do
- allow(Gitlab::Metrics).to receive(:counter).and_call_original
- allow(Gitlab::Metrics).to receive(:counter)
- .with(:ci_legacy_update_jobs_as_retried_total, anything)
- .and_return(counter)
+ build_retried.update_columns(retried: true)
end
- it 'increments the counter' do
- expect(counter).to receive(:increment)
+ it 'does not increment the counter' do
+ expect(legacy_update_jobs_counter).not_to receive(:increment)
subject.execute
end
-
- context 'when the previous build has already retried column true' do
- before do
- build_retried.update_columns(retried: true)
- end
-
- it 'does not increment the counter' do
- expect(counter).not_to receive(:increment)
-
- subject.execute
- end
- end
end
end
diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb
index 9187dd4f300..02b48e8ba06 100644
--- a/spec/services/ci/register_job_service_spec.rb
+++ b/spec/services/ci/register_job_service_spec.rb
@@ -225,6 +225,28 @@ module Ci
end
end
+ context 'when the use_distinct_in_register_job_object_hierarchy feature flag is enabled' do
+ before do
+ stub_feature_flags(use_distinct_in_register_job_object_hierarchy: true)
+ stub_feature_flags(use_distinct_for_all_object_hierarchy: true)
+ end
+
+ it 'calls DISTINCT' do
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).to_sql).to include("DISTINCT")
+ end
+ end
+
+ context 'when the use_distinct_in_register_job_object_hierarchy feature flag is disabled' do
+ before do
+ stub_feature_flags(use_distinct_in_register_job_object_hierarchy: false)
+ stub_feature_flags(use_distinct_for_all_object_hierarchy: false)
+ end
+
+ it 'does not call DISTINCT' do
+ expect(described_class.new(group_runner).send(:builds_for_group_runner).to_sql).not_to include("DISTINCT")
+ end
+ end
+
context 'group runner' do
let(:build) { execute(group_runner) }
@@ -593,9 +615,22 @@ module Ci
create(:ci_build, pipeline: pipeline, tag_list: %w[non-matching])
end
- it "observes queue size of only matching jobs" do
+ it 'observes queue size of only matching jobs' do
# pending_job + 2 x matching ones
- expect(Gitlab::Ci::Queue::Metrics.queue_size_total).to receive(:observe).with({}, 3)
+ expect(Gitlab::Ci::Queue::Metrics.queue_size_total).to receive(:observe)
+ .with({ runner_type: specific_runner.runner_type }, 3)
+
+ expect(execute(specific_runner)).to eq(pending_job)
+ end
+
+ it 'observes queue processing time by the runner type' do
+ expect(Gitlab::Ci::Queue::Metrics.queue_iteration_duration_seconds)
+ .to receive(:observe)
+ .with({ runner_type: specific_runner.runner_type }, anything)
+
+ expect(Gitlab::Ci::Queue::Metrics.queue_retrieval_duration_seconds)
+ .to receive(:observe)
+ .with({ runner_type: specific_runner.runner_type }, anything)
expect(execute(specific_runner)).to eq(pending_job)
end
diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb
index bdf60bb3fdc..7dd3d963e56 100644
--- a/spec/services/ci/retry_build_service_spec.rb
+++ b/spec/services/ci/retry_build_service_spec.rb
@@ -181,7 +181,7 @@ RSpec.describe Ci::RetryBuildService do
end
it 'resolves todos for old build that failed' do
- expect(MergeRequests::AddTodoWhenBuildFailsService)
+ expect(::MergeRequests::AddTodoWhenBuildFailsService)
.to receive_message_chain(:new, :close)
service.execute(build)
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index 3c6a99efbf8..3e2e9f07723 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -272,7 +272,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
end
it 'closes all todos about failed jobs for pipeline' do
- expect(MergeRequests::AddTodoWhenBuildFailsService)
+ expect(::MergeRequests::AddTodoWhenBuildFailsService)
.to receive_message_chain(:new, :close_all)
service.execute(pipeline)
diff --git a/spec/services/ci/test_failure_history_service_spec.rb b/spec/services/ci/test_failure_history_service_spec.rb
index d9c1c8dc3fa..c19df6e217b 100644
--- a/spec/services/ci/test_failure_history_service_spec.rb
+++ b/spec/services/ci/test_failure_history_service_spec.rb
@@ -11,15 +11,15 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
context 'when pipeline has failed builds with test reports' do
before do
- # The test report has 2 test case failures
+ # The test report has 2 unit test failures
create(:ci_build, :failed, :test_reports, pipeline: pipeline, project: project)
end
- it 'creates test case failures records' do
+ it 'creates unit test failures records' do
execute_service
- expect(Ci::TestCase.count).to eq(2)
- expect(Ci::TestCaseFailure.count).to eq(2)
+ expect(Ci::UnitTest.count).to eq(2)
+ expect(Ci::UnitTestFailure.count).to eq(2)
end
context 'when pipeline is not for the default branch' do
@@ -30,8 +30,8 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
it 'does not persist data' do
execute_service
- expect(Ci::TestCase.count).to eq(0)
- expect(Ci::TestCaseFailure.count).to eq(0)
+ expect(Ci::UnitTest.count).to eq(0)
+ expect(Ci::UnitTestFailure.count).to eq(0)
end
end
@@ -43,12 +43,12 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
it 'does not fail but does not persist new data' do
expect { described_class.new(pipeline).execute }.not_to raise_error
- expect(Ci::TestCase.count).to eq(2)
- expect(Ci::TestCaseFailure.count).to eq(2)
+ expect(Ci::UnitTest.count).to eq(2)
+ expect(Ci::UnitTestFailure.count).to eq(2)
end
end
- context 'when number of failed test cases exceed the limit' do
+ context 'when number of failed unit tests exceed the limit' do
before do
stub_const("#{described_class.name}::MAX_TRACKABLE_FAILURES", 1)
end
@@ -56,16 +56,16 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
it 'does not persist data' do
execute_service
- expect(Ci::TestCase.count).to eq(0)
- expect(Ci::TestCaseFailure.count).to eq(0)
+ expect(Ci::UnitTest.count).to eq(0)
+ expect(Ci::UnitTestFailure.count).to eq(0)
end
end
- context 'when number of failed test cases across multiple builds exceed the limit' do
+ context 'when number of failed unit tests across multiple builds exceed the limit' do
before do
stub_const("#{described_class.name}::MAX_TRACKABLE_FAILURES", 2)
- # This other test report has 1 unique test case failure which brings us to 3 total failures across all builds
+ # This other test report has 1 unique unit test failure which brings us to 3 total failures across all builds
# thus exceeding the limit of 2 for MAX_TRACKABLE_FAILURES
create(:ci_build, :failed, :test_reports_with_duplicate_failed_test_names, pipeline: pipeline, project: project)
end
@@ -73,23 +73,23 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
it 'does not persist data' do
execute_service
- expect(Ci::TestCase.count).to eq(0)
- expect(Ci::TestCaseFailure.count).to eq(0)
+ expect(Ci::UnitTest.count).to eq(0)
+ expect(Ci::UnitTestFailure.count).to eq(0)
end
end
end
- context 'when test failure data have duplicates within the same payload (happens when the JUnit report has duplicate test case names but have different failures)' do
+ context 'when test failure data have duplicates within the same payload (happens when the JUnit report has duplicate unit test names but have different failures)' do
before do
- # The test report has 2 test case failures but with the same test case keys
+ # The test report has 2 unit test failures but with the same unit test keys
create(:ci_build, :failed, :test_reports_with_duplicate_failed_test_names, pipeline: pipeline, project: project)
end
it 'does not fail but does not persist duplicate data' do
expect { execute_service }.not_to raise_error
- expect(Ci::TestCase.count).to eq(1)
- expect(Ci::TestCaseFailure.count).to eq(1)
+ expect(Ci::UnitTest.count).to eq(1)
+ expect(Ci::UnitTestFailure.count).to eq(1)
end
end
@@ -102,8 +102,8 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do
it 'does not persist data' do
execute_service
- expect(Ci::TestCase.count).to eq(0)
- expect(Ci::TestCaseFailure.count).to eq(0)
+ expect(Ci::UnitTest.count).to eq(0)
+ expect(Ci::UnitTestFailure.count).to eq(0)
end
end
end