summaryrefslogtreecommitdiff
path: root/spec/services/ci
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services/ci')
-rw-r--r--spec/services/ci/archive_trace_service_spec.rb10
-rw-r--r--spec/services/ci/create_pipeline_service/needs_spec.rb175
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb148
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb53
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb8
-rw-r--r--spec/services/ci/play_manual_stage_service_spec.rb5
-rw-r--r--spec/services/ci/prepare_build_service_spec.rb4
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb6
-rw-r--r--spec/services/ci/register_job_service_spec.rb8
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb21
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