diff options
Diffstat (limited to 'spec/services/ci')
12 files changed, 272 insertions, 191 deletions
diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb index bcdb2b4f796..fd978bffacb 100644 --- a/spec/services/ci/create_downstream_pipeline_service_spec.rb +++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb @@ -41,12 +41,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category subject { service.execute(bridge) } - shared_context 'when ci_bridge_remove_sourced_pipelines is disabled' do - before do - stub_feature_flags(ci_bridge_remove_sourced_pipelines: false) - end - end - context 'when downstream project has not been found' do let(:trigger) do { trigger: { project: 'unknown/project' } } @@ -128,19 +122,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category expect(pipeline.source_bridge).to be_a ::Ci::Bridge end - context 'when ci_bridge_remove_sourced_pipelines is disabled' do - include_context 'when ci_bridge_remove_sourced_pipelines is disabled' - - it 'creates a new pipeline in a downstream project' do - expect(pipeline.user).to eq bridge.user - expect(pipeline.project).to eq downstream_project - expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline - expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline - expect(pipeline.source_bridge).to eq bridge - expect(pipeline.source_bridge).to be_a ::Ci::Bridge - end - end - it_behaves_like 'logs downstream pipeline creation' do let(:downstream_pipeline) { pipeline } let(:expected_root_pipeline) { upstream_pipeline } @@ -179,31 +160,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category expect(subject).to be_error expect(subject.message).to eq("Already has a downstream pipeline") end - - context 'when ci_bridge_remove_sourced_pipelines is disabled' do - include_context 'when ci_bridge_remove_sourced_pipelines is disabled' - - before do - bridge.sourced_pipelines.create!( - source_pipeline: bridge.pipeline, - source_project: bridge.project, - project: bridge.project, - pipeline: create(:ci_pipeline, project: bridge.project) - ) - end - - it 'logs an error and exits' do - expect(Gitlab::ErrorTracking) - .to receive(:track_exception) - .with( - instance_of(described_class::DuplicateDownstreamPipelineError), - bridge_id: bridge.id, project_id: bridge.project.id) - .and_call_original - expect(Ci::CreatePipelineService).not_to receive(:new) - expect(subject).to be_error - expect(subject.message).to eq("Already has a downstream pipeline") - end - end end context 'when target ref is not specified' do @@ -237,19 +193,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category expect(pipeline.source_bridge).to be_a ::Ci::Bridge end - context 'when ci_bridge_remove_sourced_pipelines is disabled' do - include_context 'when ci_bridge_remove_sourced_pipelines is disabled' - - it 'creates a new pipeline in a downstream project' do - expect(pipeline.user).to eq bridge.user - expect(pipeline.project).to eq downstream_project - expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline - expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline - expect(pipeline.source_bridge).to eq bridge - expect(pipeline.source_bridge).to be_a ::Ci::Bridge - end - end - it 'updates the bridge status when downstream pipeline gets processed' do expect(pipeline.reload).to be_failed expect(bridge.reload).to be_failed @@ -301,20 +244,6 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category expect(pipeline.source_bridge).to be_a ::Ci::Bridge end - context 'when ci_bridge_remove_sourced_pipelines is disabled' do - include_context 'when ci_bridge_remove_sourced_pipelines is disabled' - - it 'creates a child pipeline in the same project' do - expect(pipeline.builds.map(&:name)).to match_array(%w[rspec echo]) - expect(pipeline.user).to eq bridge.user - expect(pipeline.project).to eq bridge.project - expect(bridge.sourced_pipelines.first.pipeline).to eq pipeline - expect(pipeline.triggered_by_pipeline).to eq upstream_pipeline - expect(pipeline.source_bridge).to eq bridge - expect(pipeline.source_bridge).to be_a ::Ci::Bridge - end - end - it 'updates bridge status when downstream pipeline gets processed' do expect(pipeline.reload).to be_created expect(bridge.reload).to be_success @@ -825,11 +754,13 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute', feature_category it 'does not create a pipeline and drops the bridge' do expect { subject }.not_to change(downstream_project.ci_pipelines, :count) expect(subject).to be_error - expect(subject.message).to match_array(["No stages / jobs for this pipeline."]) + expect(subject.message).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) expect(bridge.reload).to be_failed expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed') - expect(bridge.options[:downstream_errors]).to eq(['No stages / jobs for this pipeline.']) + expect(bridge.options[:downstream_errors]).to match_array(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end diff --git a/spec/services/ci/create_pipeline_service/cache_spec.rb b/spec/services/ci/create_pipeline_service/cache_spec.rb index 82c3d374636..f9640f99031 100644 --- a/spec/services/ci/create_pipeline_service/cache_spec.rb +++ b/spec/services/ci/create_pipeline_service/cache_spec.rb @@ -37,6 +37,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes paths: ['logs/', 'binaries/'], policy: 'pull-push', untracked: true, + unprotect: false, when: 'on_success' } @@ -69,7 +70,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes key: /[a-f0-9]{40}/, paths: ['logs/'], policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false } expect(pipeline).to be_persisted @@ -85,7 +87,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes key: /default/, paths: ['logs/'], policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false } expect(pipeline).to be_persisted @@ -118,7 +121,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes key: /\$ENV_VAR-[a-f0-9]{40}/, paths: ['logs/'], policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false } expect(pipeline).to be_persisted @@ -134,7 +138,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes key: /\$ENV_VAR-default/, paths: ['logs/'], policy: 'pull-push', - when: 'on_success' + when: 'on_success', + unprotect: false } expect(pipeline).to be_persisted diff --git a/spec/services/ci/create_pipeline_service/include_spec.rb b/spec/services/ci/create_pipeline_service/include_spec.rb index 3764663fd74..f18b4883aaf 100644 --- a/spec/services/ci/create_pipeline_service/include_spec.rb +++ b/spec/services/ci/create_pipeline_service/include_spec.rb @@ -2,7 +2,10 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, +:yaml_processor_feature_flag_corectness, feature_category: :pipeline_authoring do + include RepoHelpers + context 'include:' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } @@ -16,14 +19,17 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes let(:file_location) { 'spec/fixtures/gitlab/ci/external_files/.gitlab-ci-template-1.yml' } - before do - allow(project.repository) - .to receive(:blob_data_at).with(project.commit.id, '.gitlab-ci.yml') - .and_return(config) + let(:project_files) do + { + '.gitlab-ci.yml' => config, + file_location => File.read(Rails.root.join(file_location)) + } + end - allow(project.repository) - .to receive(:blob_data_at).with(project.commit.id, file_location) - .and_return(File.read(Rails.root.join(file_location))) + around do |example| + create_and_delete_files(project, project_files) do + example.run + end end shared_examples 'not including the file' do diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb index ccb15bfa684..ecb24a61075 100644 --- a/spec/services/ci/create_pipeline_service/logger_spec.rb +++ b/spec/services/ci/create_pipeline_service/logger_spec.rb @@ -139,5 +139,74 @@ RSpec.describe Ci::CreatePipelineService, # rubocop: disable RSpec/FilePath expect(pipeline).to be_created_successfully end end + + describe 'pipeline includes count' do + before do + stub_const('Gitlab::Ci::Config::External::Context::MAX_INCLUDES', 2) + end + + context 'when the includes count exceeds the maximum' do + before do + allow_next_instance_of(Ci::Pipeline) do |pipeline| + allow(pipeline).to receive(:config_metadata) + .and_return({ includes: [{ file: 1 }, { file: 2 }, { file: 3 }] }) + end + end + + it 'creates a log entry' do + expect(Gitlab::AppJsonLogger) + .to receive(:info) + .with(a_hash_including({ 'pipeline_includes_count' => 3 })) + .and_call_original + + expect(pipeline).to be_created_successfully + end + end + + context 'when the includes count does not exceed the maximum' do + before do + allow_next_instance_of(Ci::Pipeline) do |pipeline| + allow(pipeline).to receive(:config_metadata) + .and_return({ includes: [{ file: 1 }, { file: 2 }] }) + end + end + + it 'does not create a log entry but it collects the data' do + expect(Gitlab::AppJsonLogger).not_to receive(:info) + expect(pipeline).to be_created_successfully + + expect(service.logger.observations_hash) + .to match(a_hash_including({ 'pipeline_includes_count' => 2 })) + end + end + + context 'when the includes data is nil' do + before do + allow_next_instance_of(Ci::Pipeline) do |pipeline| + allow(pipeline).to receive(:config_metadata) + .and_return({}) + end + end + + it 'does not create a log entry' do + expect(Gitlab::AppJsonLogger).not_to receive(:info) + expect(pipeline).to be_created_successfully + end + end + + context 'when the pipeline config_metadata is nil' do + before do + allow_next_instance_of(Ci::Pipeline) do |pipeline| + allow(pipeline).to receive(:config_metadata) + .and_return(nil) + end + end + + it 'does not create a log entry but it collects the data' do + expect(Gitlab::AppJsonLogger).not_to receive(:info) + expect(pipeline).to be_created_successfully + end + 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 b866293393b..26bb8b7d006 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :pipeline_authoring do let(:project) { create(:project, :repository) } let(:user) { project.first_owner } let(:ref) { 'refs/heads/master' } @@ -1166,7 +1166,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes let(:ref) { 'refs/heads/master' } it 'invalidates the pipeline with an empty jobs error' do - expect(pipeline.errors[:base]).to include('No stages / jobs for this pipeline.') + expect(pipeline.errors[:base]).to include('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted end end diff --git a/spec/services/ci/create_pipeline_service/variables_spec.rb b/spec/services/ci/create_pipeline_service/variables_spec.rb index e9e0cf2c6e0..fd138bde656 100644 --- a/spec/services/ci/create_pipeline_service/variables_spec.rb +++ b/spec/services/ci/create_pipeline_service/variables_spec.rb @@ -60,27 +60,6 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes { key: 'VAR8', value: "value 8 $CI_PIPELINE_ID", public: true, masked: false, raw: true } ) end - - context 'when the FF ci_raw_variables_in_yaml_config is disabled' do - before do - stub_feature_flags(ci_raw_variables_in_yaml_config: false) - end - - it 'creates the pipeline with a job that has all variables expanded' do - expect(pipeline).to be_created_successfully - - expect(Ci::BuildRunnerPresenter.new(rspec).runner_variables).to include( - { key: 'VAR1', value: "JOBID-#{rspec.id}", public: true, masked: false }, - { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false }, - { key: 'VAR3', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false }, - { key: 'VAR4', value: "JOBID-#{rspec.id}", public: true, masked: false }, - { key: 'VAR5', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false }, - { key: 'VAR6', value: "PIPELINEID-#{pipeline.id} and JOBID-#{rspec.id}", public: true, masked: false }, - { key: 'VAR7', value: "overridden value 7 #{pipeline.id}", public: true, masked: false }, - { key: 'VAR8', value: "value 8 #{pipeline.id}", public: true, masked: false } - ) - end - end end context 'when trigger variables have expand: true/false' do @@ -109,22 +88,6 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes { key: 'VAR3', value: "PIPELINEID-$CI_PIPELINE_ID and $VAR1", raw: true } ) end - - context 'when the FF ci_raw_variables_in_yaml_config is disabled' do - before do - stub_feature_flags(ci_raw_variables_in_yaml_config: false) - end - - it 'creates the pipeline with a job that has all variables expanded' do - expect(pipeline).to be_created_successfully - - expect(child.downstream_variables).to include( - { key: 'VAR1', value: "PROJECTID-#{project.id}" }, - { key: 'VAR2', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" }, - { key: 'VAR3', value: "PIPELINEID-#{pipeline.id} and PROJECTID-$CI_PROJECT_ID" } - ) - end - end end end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 8628e95ba80..b0ba07ea295 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, :clean_gitlab_redis_cache do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, :clean_gitlab_redis_cache, feature_category: :continuous_integration do include ProjectForksHelper let_it_be_with_refind(:project) { create(:project, :repository) } @@ -684,7 +684,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes result = execute_service expect(result).to be_error - expect(result.message).to eq('No stages / jobs for this pipeline.') + expect(result.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(result.payload).not_to be_persisted expect(Ci::Build.all).to be_empty expect(Ci::Pipeline.count).to eq(0) @@ -759,7 +760,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes stub_ci_pipeline_yaml_file(config) end - it 'creates the environment with tags' do + it 'creates the environment with tags', :sidekiq_inline do result = execute_service.payload expect(result).to be_persisted @@ -862,7 +863,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes stub_ci_pipeline_yaml_file(YAML.dump(ci_yaml)) end - it 'creates a pipeline with the environment' do + it 'creates a pipeline with the environment', :sidekiq_inline do result = execute_service.payload expect(result).to be_persisted @@ -1311,9 +1312,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes } end - it 'has a job with environment' do + it 'has a job with environment', :sidekiq_inline do expect(pipeline.builds.count).to eq(1) expect(pipeline.builds.first.persisted_environment.name).to eq('review/master') + expect(pipeline.builds.first.persisted_environment.name).to eq('review/master') expect(pipeline.builds.first.deployment).to be_created end end @@ -1423,9 +1425,11 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes it 'does not create a detached merge request pipeline', :aggregate_failures do expect(response).to be_error - expect(response.message).to eq('No stages / jobs for this pipeline.') + expect(response.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted - expect(pipeline.errors[:base]).to eq(['No stages / jobs for this pipeline.']) + expect(pipeline.errors[:base]).to eq(['Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.']) end end end @@ -1633,7 +1637,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes it 'does not create a detached merge request pipeline', :aggregate_failures do expect(response).to be_error - expect(response.message).to eq('No stages / jobs for this pipeline.') + expect(response.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted end end @@ -1669,7 +1674,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes it 'does not create a detached merge request pipeline', :aggregate_failures do expect(response).to be_error - expect(response.message).to eq('No stages / jobs for this pipeline.') + expect(response.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted end end @@ -1697,7 +1703,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes it 'does not create a detached merge request pipeline', :aggregate_failures do expect(response).to be_error - expect(response.message).to eq('No stages / jobs for this pipeline.') + expect(response.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted end end @@ -1727,7 +1734,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes it 'does not create a detached merge request pipeline', :aggregate_failures do expect(response).to be_error - expect(response.message).to eq('No stages / jobs for this pipeline.') + expect(response.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted end end @@ -1755,7 +1763,8 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes it 'does not create a detached merge request pipeline', :aggregate_failures do expect(response).to be_error - expect(response.message).to eq('No stages / jobs for this pipeline.') + expect(response.message).to eq('Pipeline will not run for the selected trigger. ' \ + 'The rules configuration prevented any jobs from being added to the pipeline.') expect(pipeline).not_to be_persisted end end diff --git a/spec/services/ci/job_artifacts/create_service_spec.rb b/spec/services/ci/job_artifacts/create_service_spec.rb index 5df590a1b78..711002e28af 100644 --- a/spec/services/ci/job_artifacts/create_service_spec.rb +++ b/spec/services/ci/job_artifacts/create_service_spec.rb @@ -61,6 +61,49 @@ RSpec.describe Ci::JobArtifacts::CreateService do expect(new_artifact.locked).to eq(job.pipeline.locked) end + it 'sets accessibility level by default to public' do + expect { subject }.to change { Ci::JobArtifact.count }.by(1) + + new_artifact = job.job_artifacts.last + expect(new_artifact).to be_public_accessibility + end + + context 'when accessibility level passed as private' do + before do + params.merge!('accessibility' => 'private') + end + + it 'sets accessibility level to private' do + expect { subject }.to change { Ci::JobArtifact.count }.by(1) + + new_artifact = job.job_artifacts.last + expect(new_artifact).to be_private_accessibility + end + end + + context 'when accessibility passed as public' do + before do + params.merge!('accessibility' => 'public') + end + + it 'sets accessibility to public level' do + expect { subject }.to change { Ci::JobArtifact.count }.by(1) + + new_artifact = job.job_artifacts.last + expect(new_artifact).to be_public_accessibility + end + end + + context 'when accessibility passed as invalid value' do + before do + params.merge!('accessibility' => 'invalid_value') + end + + it 'fails with argument error' do + expect { subject }.to raise_error(ArgumentError) + end + end + context 'when metadata file is also uploaded' do let(:metadata_file) do file_to_upload('spec/fixtures/ci_build_artifacts_metadata.gz', sha256: artifacts_sha256) @@ -82,6 +125,39 @@ RSpec.describe Ci::JobArtifacts::CreateService do expect(new_artifact.locked).to eq(job.pipeline.locked) end + it 'sets accessibility by default to public' do + expect { subject }.to change { Ci::JobArtifact.count }.by(2) + + new_artifact = job.job_artifacts.last + expect(new_artifact).to be_public_accessibility + end + + context 'when accessibility level passed as private' do + before do + params.merge!('accessibility' => 'private') + end + + it 'sets accessibility to private level' do + expect { subject }.to change { Ci::JobArtifact.count }.by(2) + + new_artifact = job.job_artifacts.last + expect(new_artifact).to be_private_accessibility + end + end + + context 'when accessibility passed as public' do + before do + params.merge!('accessibility' => 'public') + end + + it 'sets accessibility level to public' do + expect { subject }.to change { Ci::JobArtifact.count }.by(2) + + new_artifact = job.job_artifacts.last + expect(new_artifact).to be_public_accessibility + end + end + it 'sets expiration date according to application settings' do expected_expire_at = 1.day.from_now diff --git a/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb index 4f7663d7996..dd10c0df374 100644 --- a/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb +++ b/spec/services/ci/job_artifacts/destroy_all_expired_service_spec.rb @@ -87,12 +87,9 @@ RSpec.describe Ci::JobArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_s expect { subject }.to change { Ci::DeletedObject.count }.by(1) end - it 'resets project statistics' do - expect(ProjectStatistics).to receive(:increment_statistic).once - .with(artifact.project, :build_artifacts_size, -artifact.file.size) - .and_call_original - - subject + it 'resets project statistics', :sidekiq_inline do + expect { subject } + .to change { artifact.project.statistics.reload.build_artifacts_size }.by(-artifact.file.size) end it 'does not remove the files' do diff --git a/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb b/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb index b1a4741851b..ca36c923dcf 100644 --- a/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb +++ b/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb @@ -3,23 +3,23 @@ require 'spec_helper' RSpec.describe Ci::JobArtifacts::DestroyAssociationsService do - let(:artifacts) { Ci::JobArtifact.all } - let(:service) { described_class.new(artifacts) } + let_it_be(:project_1) { create(:project) } + let_it_be(:project_2) { create(:project) } - let_it_be(:artifact, refind: true) do - create(:ci_job_artifact) - end + let_it_be(:artifact_1, refind: true) { create(:ci_job_artifact, :zip, project: project_1) } + let_it_be(:artifact_2, refind: true) { create(:ci_job_artifact, :zip, project: project_2) } + let_it_be(:artifact_3, refind: true) { create(:ci_job_artifact, :zip, project: project_1) } - before do - artifact.file = fixture_file_upload(Rails.root.join('spec/fixtures/ci_build_artifacts.zip'), 'application/zip') - artifact.save! - end + let(:artifacts) { Ci::JobArtifact.where(id: [artifact_1.id, artifact_2.id, artifact_3.id]) } + let(:service) { described_class.new(artifacts) } describe '#destroy_records' do it 'removes artifacts without updating statistics' do - expect(ProjectStatistics).not_to receive(:increment_statistic) + expect_next_instance_of(Ci::JobArtifacts::DestroyBatchService) do |service| + expect(service).to receive(:execute).with(update_stats: false).and_call_original + end - expect { service.destroy_records }.to change { Ci::JobArtifact.count } + expect { service.destroy_records }.to change { Ci::JobArtifact.count }.by(-3) end context 'when there are no artifacts' do @@ -33,12 +33,21 @@ RSpec.describe Ci::JobArtifacts::DestroyAssociationsService do describe '#update_statistics' do before do + stub_const("#{described_class}::BATCH_SIZE", 2) service.destroy_records end it 'updates project statistics' do - expect(ProjectStatistics).to receive(:increment_statistic).once - .with(artifact.project, :build_artifacts_size, -artifact.file.size) + project1_increments = [ + have_attributes(amount: -artifact_1.size, ref: artifact_1.id), + have_attributes(amount: -artifact_3.size, ref: artifact_3.id) + ] + project2_increments = [have_attributes(amount: -artifact_2.size, ref: artifact_2.id)] + + expect(ProjectStatistics).to receive(:bulk_increment_statistic).once + .with(project_1, :build_artifacts_size, match_array(project1_increments)) + expect(ProjectStatistics).to receive(:bulk_increment_statistic).once + .with(project_2, :build_artifacts_size, match_array(project2_increments)) service.update_statistics 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 79920dcb2c7..cde42783d8c 100644 --- a/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb +++ b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb @@ -29,7 +29,7 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do create(:ci_job_artifact, :trace, :expired) end - describe '.execute' do + describe '#execute' do subject(:execute) { service.execute } it 'creates a deleted object for artifact with attached file' do @@ -207,44 +207,58 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do end end - context 'ProjectStatistics' do - it 'resets project statistics' do - expect(ProjectStatistics).to receive(:increment_statistic).once - .with(artifact_with_file.project, :build_artifacts_size, -artifact_with_file.file.size) - .and_call_original - expect(ProjectStatistics).to receive(:increment_statistic).once - .with(artifact_without_file.project, :build_artifacts_size, 0) - .and_call_original + context 'ProjectStatistics', :sidekiq_inline do + let_it_be(:project_1) { create(:project) } + let_it_be(:project_2) { create(:project) } + + let(:artifact_with_file) { create(:ci_job_artifact, :zip, project: project_1) } + let(:artifact_with_file_2) { create(:ci_job_artifact, :zip, project: project_1) } + let(:artifact_without_file) { create(:ci_job_artifact, project: project_2) } + let!(:artifacts) { Ci::JobArtifact.where(id: [artifact_with_file.id, artifact_without_file.id, artifact_with_file_2.id]) } + + it 'updates project statistics by the relevant amount' do + expected_amount = -(artifact_with_file.size + artifact_with_file_2.size) + + expect { execute } + .to change { project_1.statistics.reload.build_artifacts_size }.by(expected_amount) + .and change { project_2.statistics.reload.build_artifacts_size }.by(0) + end + + it 'increments project statistics with artifact size as amount and job artifact id as ref' do + project_1_increments = [ + have_attributes(amount: -artifact_with_file.size, ref: artifact_with_file.id), + have_attributes(amount: -artifact_with_file_2.file.size, ref: artifact_with_file_2.id) + ] + project_2_increments = [have_attributes(amount: 0, ref: artifact_without_file.id)] + + expect(ProjectStatistics).to receive(:bulk_increment_statistic).with(project_1, :build_artifacts_size, match_array(project_1_increments)) + expect(ProjectStatistics).to receive(:bulk_increment_statistic).with(project_2, :build_artifacts_size, match_array(project_2_increments)) execute end context 'with update_stats: false' do - let_it_be(:extra_artifact_with_file) do - create(:ci_job_artifact, :zip, project: artifact_with_file.project) - end - - let(:artifacts) do - Ci::JobArtifact.where(id: [artifact_with_file.id, extra_artifact_with_file.id, - artifact_without_file.id, trace_artifact.id]) - end + subject(:execute) { service.execute(update_stats: false) } it 'does not update project statistics' do - expect(ProjectStatistics).not_to receive(:increment_statistic) - - service.execute(update_stats: false) + expect { execute }.not_to change { [project_1.statistics.reload.build_artifacts_size, project_2.statistics.reload.build_artifacts_size] } end - it 'returns size statistics' do + it 'returns statistic updates per project' do + project_1_updates = [ + have_attributes(amount: -artifact_with_file.size, ref: artifact_with_file.id), + have_attributes(amount: -artifact_with_file_2.file.size, ref: artifact_with_file_2.id) + ] + project_2_updates = [have_attributes(amount: 0, ref: artifact_without_file.id)] + expected_updates = { statistics_updates: { - artifact_with_file.project => -(artifact_with_file.file.size + extra_artifact_with_file.file.size), - artifact_without_file.project => 0 + project_1 => match_array(project_1_updates), + project_2 => project_2_updates } } - expect(service.execute(update_stats: false)).to match( - a_hash_including(expected_updates)) + expect(execute).to match(a_hash_including(expected_updates)) end end end 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 2f2af9f6c85..c1669e0424a 100644 --- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb +++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category: :continuous_integration do + include RepoHelpers + describe 'Pipeline Processing Service Tests With Yaml' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } @@ -956,17 +958,16 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService, feature_category Ci::CreatePipelineService.new(project, user, { ref: 'master' }).execute(:push).payload end - before do - allow_next_instance_of(Repository) do |repository| - allow(repository) - .to receive(:blob_data_at) - .with(an_instance_of(String), '.gitlab-ci.yml') - .and_return(parent_config) - - allow(repository) - .to receive(:blob_data_at) - .with(an_instance_of(String), '.child.yml') - .and_return(child_config) + let(:project_files) do + { + '.gitlab-ci.yml' => parent_config, + '.child.yml' => child_config + } + end + + around do |example| + create_and_delete_files(project, project_files) do + example.run end end |