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:
Diffstat (limited to 'spec/services/ci')
-rw-r--r--spec/services/ci/job_artifacts/create_service_spec.rb41
-rw-r--r--spec/services/ci/parse_annotations_artifact_service_spec.rb182
-rw-r--r--spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb36
-rw-r--r--spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb14
-rw-r--r--spec/services/ci/pipeline_schedules/create_service_spec.rb8
-rw-r--r--spec/services/ci/pipeline_schedules/update_service_spec.rb12
-rw-r--r--spec/services/ci/retry_job_service_spec.rb78
-rw-r--r--spec/services/ci/retry_pipeline_service_spec.rb16
8 files changed, 333 insertions, 54 deletions
diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb
index 7e471bf39a1..a23ba250daf 100644
--- a/spec/services/ci/job_artifacts/create_service_spec.rb
+++ b/spec/services/ci/job_artifacts/create_service_spec.rb
@@ -321,6 +321,45 @@ RSpec.describe Ci::JobArtifacts::CreateService, :clean_gitlab_redis_shared_state
end
end
+ shared_examples_for 'handling annotations' do |storage_type|
+ context 'when artifact type is annotations' do
+ let(:params) do
+ {
+ 'artifact_type' => 'annotations',
+ 'artifact_format' => 'gzip'
+ }.with_indifferent_access
+ end
+
+ if storage_type == :object_storage
+ let(:object_body) { File.read('spec/fixtures/gl-annotations.json.gz') }
+ let(:upload_filename) { 'gl-annotations.json.gz' }
+
+ before do
+ stub_request(:get, %r{s3.amazonaws.com/#{remote_path}})
+ .to_return(status: 200, body: File.read('spec/fixtures/gl-annotations.json.gz'))
+ end
+ else
+ let(:artifacts_file) do
+ file_to_upload('spec/fixtures/gl-annotations.json.gz', sha256: artifacts_sha256)
+ end
+ end
+
+ it 'calls parse service' do
+ expect_any_instance_of(Ci::ParseAnnotationsArtifactService) do |service|
+ expect(service).to receive(:execute).once.and_call_original
+ end
+
+ expect(execute[:status]).to eq(:success)
+ expect(job.job_annotations.as_json).to contain_exactly(
+ hash_including('name' => 'external_links', 'data' => [
+ hash_including('external_link' => hash_including('label' => 'URL 1', 'url' => 'https://url1.example.com/')),
+ hash_including('external_link' => hash_including('label' => 'URL 2', 'url' => 'https://url2.example.com/'))
+ ])
+ )
+ end
+ end
+ end
+
shared_examples_for 'handling object storage errors' do
shared_examples 'rescues object storage error' do |klass, message, expected_message|
it "handles #{klass}" do
@@ -495,6 +534,7 @@ RSpec.describe Ci::JobArtifacts::CreateService, :clean_gitlab_redis_shared_state
it_behaves_like 'handling uploads'
it_behaves_like 'handling dotenv', :object_storage
+ it_behaves_like 'handling annotations', :object_storage
it_behaves_like 'handling object storage errors'
it_behaves_like 'validating requirements'
end
@@ -506,6 +546,7 @@ RSpec.describe Ci::JobArtifacts::CreateService, :clean_gitlab_redis_shared_state
it_behaves_like 'handling uploads'
it_behaves_like 'handling dotenv', :local_storage
+ it_behaves_like 'handling annotations', :local_storage
it_behaves_like 'validating requirements'
end
end
diff --git a/spec/services/ci/parse_annotations_artifact_service_spec.rb b/spec/services/ci/parse_annotations_artifact_service_spec.rb
new file mode 100644
index 00000000000..4847447230b
--- /dev/null
+++ b/spec/services/ci/parse_annotations_artifact_service_spec.rb
@@ -0,0 +1,182 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+RSpec.describe Ci::ParseAnnotationsArtifactService, feature_category: :build_artifacts do
+ let_it_be(:project) { create(:project) }
+
+ let_it_be_with_reload(:build) { create(:ci_build, project: project) }
+ let(:service) { described_class.new(project, nil) }
+
+ describe '#execute' do
+ subject { service.execute(artifact) }
+
+ context 'when build has an annotations artifact' do
+ let_it_be(:artifact) { create(:ci_job_artifact, :annotations, job: build) }
+
+ context 'when artifact does not have the specified blob' do
+ before do
+ allow(artifact).to receive(:each_blob)
+ end
+
+ it 'parses nothing' do
+ expect(subject[:status]).to eq(:success)
+
+ expect(build.job_annotations).to be_empty
+ end
+ end
+
+ context 'when artifact has the specified blob' do
+ let(:blob) { data.to_json }
+
+ before do
+ allow(artifact).to receive(:each_blob).and_yield(blob)
+ end
+
+ context 'when valid annotations are given' do
+ let(:data) do
+ {
+ external_links: [
+ {
+ external_link: {
+ label: 'URL 1',
+ url: 'https://url1.example.com/'
+ }
+ },
+ {
+ external_link: {
+ label: 'URL 2',
+ url: 'https://url2.example.com/'
+ }
+ }
+ ]
+ }
+ end
+
+ it 'parses the artifact' do
+ subject
+
+ expect(build.job_annotations.as_json).to contain_exactly(
+ hash_including('name' => 'external_links', 'data' => [
+ hash_including('external_link' => hash_including('label' => 'URL 1', 'url' => 'https://url1.example.com/')),
+ hash_including('external_link' => hash_including('label' => 'URL 2', 'url' => 'https://url2.example.com/'))
+ ])
+ )
+ end
+ end
+
+ context 'when valid annotations are given and annotation list name is the same' do
+ before do
+ build.job_annotations.create!(name: 'external_links', data: [
+ {
+ external_link: {
+ label: 'URL 1',
+ url: 'https://url1.example.com/'
+ }
+ }
+ ])
+ end
+
+ let(:data) do
+ {
+ external_links: [
+ {
+ external_link: {
+ label: 'URL 2',
+ url: 'https://url2.example.com/'
+ }
+ }
+ ]
+ }
+ end
+
+ it 'parses the artifact' do
+ subject
+
+ expect(build.job_annotations.as_json).to contain_exactly(
+ hash_including('name' => 'external_links', 'data' => [
+ hash_including('external_link' => hash_including('label' => 'URL 2', 'url' => 'https://url2.example.com/'))
+ ])
+ )
+ end
+ end
+
+ context 'when invalid JSON is given' do
+ let(:blob) { 'Invalid JSON!' }
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:http_status]).to eq(:bad_request)
+ end
+ end
+
+ context 'when root is not an object' do
+ let(:data) { [] }
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Annotations files must be a JSON object')
+ expect(subject[:http_status]).to eq(:bad_request)
+ end
+ end
+
+ context 'when item is not a valid annotation list' do
+ let(:data) { { external_links: {} } }
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq('Validation failed: Data must be a valid json schema')
+ expect(subject[:http_status]).to eq(:bad_request)
+ end
+ end
+
+ context 'when more than limitated annotations are specified in annotations' do
+ let(:data) do
+ {
+ external_links_1: [
+ {
+ external_link: {
+ label: 'URL',
+ url: 'https://example.com/'
+ }
+ }
+ ],
+ external_links_2: [
+ {
+ external_link: {
+ label: 'URL',
+ url: 'https://example.com/'
+ }
+ }
+ ]
+ }
+ end
+
+ before do
+ allow(service).to receive(:annotations_num_limit).and_return(1)
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq(
+ "Annotations files cannot have more than #{service.send(:annotations_num_limit)} annotation lists")
+ expect(subject[:http_status]).to eq(:bad_request)
+ end
+ end
+ end
+
+ context 'when artifact size is too big' do
+ before do
+ allow(artifact.file).to receive(:size) { service.send(:annotations_size_limit) + 1.kilobyte }
+ end
+
+ it 'returns error' do
+ expect(subject[:status]).to eq(:error)
+ expect(subject[:message]).to eq(
+ "Annotations Artifact Too Big. Maximum Allowable Size: #{service.send(:annotations_size_limit)}")
+ expect(subject[:http_status]).to eq(:bad_request)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
index 905ccf164ca..82a8e425cd0 100644
--- a/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
+++ b/spec/services/ci/pipeline_creation/cancel_redundant_pipelines_service_spec.rb
@@ -20,6 +20,38 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
create(:ci_build, :interruptible, pipeline: pipeline)
end
+ shared_examples 'time limits pipeline cancellation' do
+ context 'with old pipelines' do
+ let(:old_pipeline) { create(:ci_pipeline, project: project, created_at: 5.days.ago) }
+
+ before do
+ create(:ci_build, :interruptible, :pending, pipeline: old_pipeline)
+ end
+
+ it 'ignores old pipelines' do
+ execute
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('canceled', 'success', 'canceled')
+ expect(build_statuses(pipeline)).to contain_exactly('pending')
+ expect(build_statuses(old_pipeline)).to contain_exactly('pending')
+ end
+
+ context 'with lower_interval_for_canceling_redundant_pipelines disabled' do
+ before do
+ stub_feature_flags(lower_interval_for_canceling_redundant_pipelines: false)
+ end
+
+ it 'cancels pipelines created more than 3 days ago' do
+ execute
+
+ expect(build_statuses(prev_pipeline)).to contain_exactly('canceled', 'success', 'canceled')
+ expect(build_statuses(pipeline)).to contain_exactly('pending')
+ expect(build_statuses(old_pipeline)).to contain_exactly('canceled')
+ end
+ end
+ end
+ end
+
describe '#execute!' do
subject(:execute) { service.execute }
@@ -218,6 +250,8 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
expect(build_statuses(pipeline.reload)).to contain_exactly('pending')
end
+
+ it_behaves_like 'time limits pipeline cancellation'
end
context 'when auto-cancel is disabled' do
@@ -452,6 +486,8 @@ RSpec.describe Ci::PipelineCreation::CancelRedundantPipelinesService, feature_ca
expect(build_statuses(pipeline.reload)).to contain_exactly('pending')
end
+
+ it_behaves_like 'time limits pipeline cancellation'
end
context 'when auto-cancel is disabled' do
diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
index 15f2cc0990c..93dc9481bf0 100644
--- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
+++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb
@@ -4,6 +4,7 @@ require 'spec_helper'
RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category: :continuous_integration do
include RepoHelpers
+ include ExclusiveLeaseHelpers
describe 'Pipeline Processing Service Tests With Yaml' do
let_it_be(:project) { create(:project, :repository) }
@@ -1233,6 +1234,19 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category
end
end
+ context 'when the exclusive lease is taken' do
+ let(:lease_key) { "ci/pipeline_processing/atomic_processing_service::pipeline_id:#{pipeline.id}" }
+
+ it 'skips pipeline processing' do
+ create_build('linux', stage_idx: 0)
+
+ stub_exclusive_lease_taken(lease_key)
+
+ expect(Gitlab::AppJsonLogger).to receive(:info).with(a_hash_including(message: /^Cannot obtain an exclusive lease/))
+ expect(process_pipeline).to be_falsy
+ end
+ end
+
private
def all_builds
diff --git a/spec/services/ci/pipeline_schedules/create_service_spec.rb b/spec/services/ci/pipeline_schedules/create_service_spec.rb
index a01c71432c3..3fc093c13da 100644
--- a/spec/services/ci/pipeline_schedules/create_service_spec.rb
+++ b/spec/services/ci/pipeline_schedules/create_service_spec.rb
@@ -3,9 +3,11 @@
require 'spec_helper'
RSpec.describe Ci::PipelineSchedules::CreateService, feature_category: :continuous_integration do
- let_it_be(:user) { create(:user) }
let_it_be(:reporter) { create(:user) }
- let_it_be(:project) { create(:project, :public, :repository) }
+ let_it_be_with_reload(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :public, :repository) }
+
+ subject(:service) { described_class.new(project, user, params) }
before_all do
project.add_maintainer(user)
@@ -82,5 +84,7 @@ RSpec.describe Ci::PipelineSchedules::CreateService, feature_category: :continuo
end
end
end
+
+ it_behaves_like 'pipeline schedules checking variables permission'
end
end
diff --git a/spec/services/ci/pipeline_schedules/update_service_spec.rb b/spec/services/ci/pipeline_schedules/update_service_spec.rb
index 5c1354bd5aa..834bbcfcfeb 100644
--- a/spec/services/ci/pipeline_schedules/update_service_spec.rb
+++ b/spec/services/ci/pipeline_schedules/update_service_spec.rb
@@ -3,18 +3,18 @@
require 'spec_helper'
RSpec.describe Ci::PipelineSchedules::UpdateService, feature_category: :continuous_integration do
- let_it_be(:user) { create(:user) }
+ let_it_be_with_reload(:user) { create(:user) }
+ let_it_be_with_reload(:project) { create(:project, :public, :repository) }
+ let_it_be_with_reload(:pipeline_schedule) { create(:ci_pipeline_schedule, project: project, owner: user) }
let_it_be(:reporter) { create(:user) }
- let_it_be(:project) { create(:project, :public, :repository) }
- let_it_be(:pipeline_schedule) do
- create(:ci_pipeline_schedule, project: project, owner: user, ref: 'master')
- end
let_it_be(:pipeline_schedule_variable) do
create(:ci_pipeline_schedule_variable,
key: 'foo', value: 'foovalue', pipeline_schedule: pipeline_schedule)
end
+ subject(:service) { described_class.new(pipeline_schedule, user, params) }
+
before_all do
project.add_maintainer(user)
project.add_reporter(reporter)
@@ -125,5 +125,7 @@ RSpec.describe Ci::PipelineSchedules::UpdateService, feature_category: :continuo
end
end
end
+
+ it_behaves_like 'pipeline schedules checking variables permission'
end
end
diff --git a/spec/services/ci/retry_job_service_spec.rb b/spec/services/ci/retry_job_service_spec.rb
index f15f4a16d4f..caed9815fb3 100644
--- a/spec/services/ci/retry_job_service_spec.rb
+++ b/spec/services/ci/retry_job_service_spec.rb
@@ -208,6 +208,45 @@ RSpec.describe Ci::RetryJobService, feature_category: :continuous_integration do
end
end
+ shared_examples_for 'creates associations for a deployable job' do |factory_type|
+ context 'when a job with a deployment is retried' do
+ let!(:job) do
+ create(factory_type, :with_deployment, :deploy_to_production, pipeline: pipeline, ci_stage: stage)
+ end
+
+ it 'creates a new deployment' do
+ expect { new_job }.to change { Deployment.count }.by(1)
+ end
+
+ it 'does not create a new environment' do
+ expect { new_job }.not_to change { Environment.count }
+ end
+ end
+
+ context 'when a job with a dynamic environment is retried' do
+ let_it_be(:other_developer) { create(:user).tap { |u| project.add_developer(u) } }
+
+ let(:environment_name) { 'review/$CI_COMMIT_REF_SLUG-$GITLAB_USER_ID' }
+
+ let!(:job) do
+ create(factory_type, :with_deployment,
+ environment: environment_name,
+ options: { environment: { name: environment_name } },
+ pipeline: pipeline,
+ ci_stage: stage,
+ user: other_developer)
+ end
+
+ it 'creates a new deployment' do
+ expect { new_job }.to change { Deployment.count }.by(1)
+ end
+
+ it 'does not create a new environment' do
+ expect { new_job }.not_to change { Environment.count }
+ end
+ end
+ end
+
describe '#clone!' do
let(:new_job) { service.clone!(job) }
@@ -219,6 +258,7 @@ RSpec.describe Ci::RetryJobService, feature_category: :continuous_integration do
include_context 'retryable bridge'
it_behaves_like 'clones the job'
+ it_behaves_like 'creates associations for a deployable job', :ci_bridge
context 'when given variables' do
let(:new_job) { service.clone!(job, variables: job_variables_attributes) }
@@ -235,43 +275,7 @@ RSpec.describe Ci::RetryJobService, feature_category: :continuous_integration do
let(:job) { job_to_clone }
it_behaves_like 'clones the job'
-
- context 'when a build with a deployment is retried' do
- let!(:job) do
- create(:ci_build, :with_deployment, :deploy_to_production, pipeline: pipeline, ci_stage: stage)
- end
-
- it 'creates a new deployment' do
- expect { new_job }.to change { Deployment.count }.by(1)
- end
-
- it 'does not create a new environment' do
- expect { new_job }.not_to change { Environment.count }
- end
- end
-
- context 'when a build with a dynamic environment is retried' do
- let_it_be(:other_developer) { create(:user).tap { |u| project.add_developer(u) } }
-
- let(:environment_name) { 'review/$CI_COMMIT_REF_SLUG-$GITLAB_USER_ID' }
-
- let!(:job) do
- create(:ci_build, :with_deployment,
- environment: environment_name,
- options: { environment: { name: environment_name } },
- pipeline: pipeline,
- ci_stage: stage,
- user: other_developer)
- end
-
- it 'creates a new deployment' do
- expect { new_job }.to change { Deployment.count }.by(1)
- end
-
- it 'does not create a new environment' do
- expect { new_job }.not_to change { Environment.count }
- end
- end
+ it_behaves_like 'creates associations for a deployable job', :ci_build
context 'when given variables' do
let(:new_job) { service.clone!(job, variables: job_variables_attributes) }
diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb
index fc2c66e7f73..6d991baafd0 100644
--- a/spec/services/ci/retry_pipeline_service_spec.rb
+++ b/spec/services/ci/retry_pipeline_service_spec.rb
@@ -451,22 +451,18 @@ RSpec.describe Ci::RetryPipelineService, '#execute', feature_category: :continuo
before do
project.add_maintainer(user)
- create(:merge_request,
- source_project: forked_project,
- target_project: project,
- source_branch: 'fixes',
- allow_collaboration: true)
- create_build('rspec 1', :failed, test_stage)
- end
- it 'allows to retry failed pipeline' do
- allow_any_instance_of(Project).to receive(:branch_allows_collaboration?).and_return(true)
+ create_build('rspec 1', :failed, test_stage, project: project, ref: pipeline.ref)
+
allow_any_instance_of(Project).to receive(:empty_repo?).and_return(false)
+ allow_any_instance_of(Project).to receive(:branch_allows_collaboration?).and_return(true)
+ end
+ it 'allows to retry failed pipeline' do
service.execute(pipeline)
expect(build('rspec 1')).to be_pending
- expect(pipeline.reload).to be_running
+ expect(pipeline).to be_running
end
end