From 14bd84b61276ef29b97d23642d698de769bacfd2 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Mon, 20 Mar 2023 15:19:03 +0000 Subject: Add latest changes from gitlab-org/gitlab@15-10-stable-ee --- spec/services/ci/abort_pipelines_service_spec.rb | 2 +- .../services/ci/append_build_trace_service_spec.rb | 2 +- spec/services/ci/build_cancel_service_spec.rb | 2 +- spec/services/ci/build_erase_service_spec.rb | 2 +- .../ci/build_report_result_service_spec.rb | 2 +- spec/services/ci/build_unschedule_service_spec.rb | 2 +- .../ci/catalog/add_resource_service_spec.rb | 55 + .../ci/catalog/validate_resource_service_spec.rb | 57 + spec/services/ci/change_variable_service_spec.rb | 2 +- spec/services/ci/change_variables_service_spec.rb | 2 +- .../compare_accessibility_reports_service_spec.rb | 2 +- .../ci/compare_codequality_reports_service_spec.rb | 2 +- .../ci/compare_reports_base_service_spec.rb | 2 +- .../ci/compare_test_reports_service_spec.rb | 2 +- spec/services/ci/components/fetch_service_spec.rb | 2 +- ...opy_cross_database_associations_service_spec.rb | 2 +- .../ci/create_pipeline_service/artifacts_spec.rb | 2 +- .../ci/create_pipeline_service/cache_spec.rb | 3 +- .../creation_errors_and_warnings_spec.rb | 2 +- .../cross_project_pipeline_spec.rb | 3 +- .../custom_config_content_spec.rb | 2 +- .../custom_yaml_tags_spec.rb | 3 +- .../ci/create_pipeline_service/dry_run_spec.rb | 3 +- .../ci/create_pipeline_service/environment_spec.rb | 3 +- .../evaluate_runner_tags_spec.rb | 3 +- .../ci/create_pipeline_service/include_spec.rb | 2 +- .../limit_active_jobs_spec.rb | 3 +- .../ci/create_pipeline_service/logger_spec.rb | 2 +- .../create_pipeline_service/merge_requests_spec.rb | 3 +- .../ci/create_pipeline_service/needs_spec.rb | 3 +- .../ci/create_pipeline_service/parallel_spec.rb | 3 +- .../parameter_content_spec.rb | 3 +- .../parent_child_pipeline_spec.rb | 3 +- .../pre_post_stages_spec.rb | 3 +- .../ci/create_pipeline_service/rate_limit_spec.rb | 3 +- .../ci/create_pipeline_service/rules_spec.rb | 36 +- .../ci/create_pipeline_service/scripts_spec.rb | 28 +- .../ci/create_pipeline_service/tags_spec.rb | 2 +- .../ci/create_pipeline_service/variables_spec.rb | 3 +- .../ci/create_web_ide_terminal_service_spec.rb | 2 +- ...daily_build_group_report_result_service_spec.rb | 2 +- spec/services/ci/delete_objects_service_spec.rb | 2 +- spec/services/ci/delete_unit_tests_service_spec.rb | 2 +- .../ci/deployments/destroy_service_spec.rb | 2 +- spec/services/ci/destroy_pipeline_service_spec.rb | 2 +- .../ci/destroy_secure_file_service_spec.rb | 2 +- ...disable_user_pipeline_schedules_service_spec.rb | 2 +- spec/services/ci/drop_pipeline_service_spec.rb | 2 +- spec/services/ci/ensure_stage_service_spec.rb | 2 +- .../ci/expire_pipeline_cache_service_spec.rb | 2 +- .../create_pipeline_service_spec.rb | 2 +- .../ci/find_exposed_artifacts_service_spec.rb | 2 +- ...rate_codequality_mr_diff_report_service_spec.rb | 2 +- .../ci/generate_coverage_reports_service_spec.rb | 2 +- .../ci/generate_kubeconfig_service_spec.rb | 2 +- .../ci/generate_terraform_reports_service_spec.rb | 2 +- .../bulk_delete_by_project_service_spec.rb | 121 ++ .../ci/job_artifacts/create_service_spec.rb | 145 ++- .../delete_project_artifacts_service_spec.rb | 2 +- .../ci/job_artifacts/delete_service_spec.rb | 2 +- .../destroy_all_expired_service_spec.rb | 38 +- .../destroy_associations_service_spec.rb | 31 +- .../ci/job_artifacts/destroy_batch_service_spec.rb | 15 +- .../expire_project_build_artifacts_service_spec.rb | 2 +- .../track_artifact_report_service_spec.rb | 2 +- .../update_unknown_locked_status_service_spec.rb | 3 +- .../ci/list_config_variables_service_spec.rb | 2 +- .../coverage_report_service_spec.rb | 2 +- ...ate_code_quality_mr_diff_report_service_spec.rb | 2 +- .../destroy_all_expired_service_spec.rb | 3 +- .../ci/pipeline_bridge_status_service_spec.rb | 2 +- .../start_pipeline_service_spec.rb | 2 +- .../status_collection_spec.rb | 25 +- .../take_ownership_service_spec.rb | 2 +- spec/services/ci/pipeline_trigger_service_spec.rb | 2 +- spec/services/ci/pipelines/add_job_service_spec.rb | 2 +- spec/services/ci/pipelines/hook_service_spec.rb | 2 +- spec/services/ci/play_bridge_service_spec.rb | 2 +- spec/services/ci/play_build_service_spec.rb | 2 +- spec/services/ci/play_manual_stage_service_spec.rb | 2 +- spec/services/ci/prepare_build_service_spec.rb | 2 +- spec/services/ci/process_build_service_spec.rb | 2 +- spec/services/ci/process_pipeline_service_spec.rb | 2 +- .../ci/process_sync_events_service_spec.rb | 2 +- .../observe_histograms_service_spec.rb | 2 +- .../ci/queue/pending_builds_strategy_spec.rb | 2 +- spec/services/ci/register_job_service_spec.rb | 1160 ++++++++++---------- ...gn_resource_from_resource_group_service_spec.rb | 2 +- spec/services/ci/retry_pipeline_service_spec.rb | 2 +- .../ci/run_scheduled_build_service_spec.rb | 2 +- .../ci/runners/create_runner_service_spec.rb | 43 + .../process_runner_version_update_service_spec.rb | 13 + .../ci/stuck_builds/drop_pending_service_spec.rb | 2 +- .../ci/stuck_builds/drop_running_service_spec.rb | 2 +- .../ci/stuck_builds/drop_scheduled_service_spec.rb | 2 +- .../ci/test_failure_history_service_spec.rb | 2 +- .../services/ci/track_failed_build_service_spec.rb | 2 +- spec/services/ci/unlock_artifacts_service_spec.rb | 10 +- .../services/ci/update_build_queue_service_spec.rb | 2 +- .../ci/update_instance_variables_service_spec.rb | 2 +- .../ci/update_pending_build_service_spec.rb | 2 +- 101 files changed, 1153 insertions(+), 815 deletions(-) create mode 100644 spec/services/ci/catalog/add_resource_service_spec.rb create mode 100644 spec/services/ci/catalog/validate_resource_service_spec.rb create mode 100644 spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb (limited to 'spec/services/ci') diff --git a/spec/services/ci/abort_pipelines_service_spec.rb b/spec/services/ci/abort_pipelines_service_spec.rb index e43faf0af51..60f3ee11442 100644 --- a/spec/services/ci/abort_pipelines_service_spec.rb +++ b/spec/services/ci/abort_pipelines_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::AbortPipelinesService do +RSpec.describe Ci::AbortPipelinesService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, namespace: user.namespace) } diff --git a/spec/services/ci/append_build_trace_service_spec.rb b/spec/services/ci/append_build_trace_service_spec.rb index 20f7967d1f1..113c88dc5f3 100644 --- a/spec/services/ci/append_build_trace_service_spec.rb +++ b/spec/services/ci/append_build_trace_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::AppendBuildTraceService do +RSpec.describe Ci::AppendBuildTraceService, feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } let_it_be_with_reload(:build) { create(:ci_build, :running, pipeline: pipeline) } diff --git a/spec/services/ci/build_cancel_service_spec.rb b/spec/services/ci/build_cancel_service_spec.rb index fe036dc1368..314d2e86bd3 100644 --- a/spec/services/ci/build_cancel_service_spec.rb +++ b/spec/services/ci/build_cancel_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::BuildCancelService do +RSpec.describe Ci::BuildCancelService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/build_erase_service_spec.rb b/spec/services/ci/build_erase_service_spec.rb index e750a163621..35e74f76a26 100644 --- a/spec/services/ci/build_erase_service_spec.rb +++ b/spec/services/ci/build_erase_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::BuildEraseService do +RSpec.describe Ci::BuildEraseService, feature_category: :continuous_integration do let_it_be(:user) { user } let(:build) { create(:ci_build, :artifacts, :trace_artifact, artifacts_expire_at: 100.days.from_now) } diff --git a/spec/services/ci/build_report_result_service_spec.rb b/spec/services/ci/build_report_result_service_spec.rb index c5238b7f5e0..c3ce6714241 100644 --- a/spec/services/ci/build_report_result_service_spec.rb +++ b/spec/services/ci/build_report_result_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::BuildReportResultService do +RSpec.describe Ci::BuildReportResultService, feature_category: :continuous_integration do describe '#execute', :clean_gitlab_redis_shared_state do subject(:build_report_result) { described_class.new.execute(build) } diff --git a/spec/services/ci/build_unschedule_service_spec.rb b/spec/services/ci/build_unschedule_service_spec.rb index d784d9a2754..539c66047e4 100644 --- a/spec/services/ci/build_unschedule_service_spec.rb +++ b/spec/services/ci/build_unschedule_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::BuildUnscheduleService do +RSpec.describe Ci::BuildUnscheduleService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/catalog/add_resource_service_spec.rb b/spec/services/ci/catalog/add_resource_service_spec.rb new file mode 100644 index 00000000000..ecb939e3c2d --- /dev/null +++ b/spec/services/ci/catalog/add_resource_service_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::Catalog::AddResourceService, feature_category: :pipeline_composition do + let_it_be(:project) { create(:project, :repository, description: 'Our components') } + let_it_be(:user) { create(:user) } + + let(:service) { described_class.new(project, user) } + + describe '#execute' do + context 'with an unauthorized user' do + it 'raises an AccessDeniedError' do + expect { service.execute }.to raise_error(Gitlab::Access::AccessDeniedError) + end + end + + context 'with an authorized user' do + before do + project.add_owner(user) + end + + context 'and a valid project' do + it 'creates a catalog resource' do + response = service.execute + + expect(response.payload.project).to eq(project) + end + end + + context 'with an invalid project' do + let_it_be(:project) { create(:project, :repository) } + + it 'does not create a catalog resource' do + response = service.execute + + expect(response.message).to eq('Project must have a description') + end + end + + context 'with an invalid catalog resource' do + it 'does not save the catalog resource' do + catalog_resource = instance_double(::Ci::Catalog::Resource, + valid?: false, + errors: instance_double(ActiveModel::Errors, full_messages: ['not valid'])) + allow(::Ci::Catalog::Resource).to receive(:new).and_return(catalog_resource) + + response = service.execute + + expect(response.message).to eq('not valid') + end + end + end + end +end diff --git a/spec/services/ci/catalog/validate_resource_service_spec.rb b/spec/services/ci/catalog/validate_resource_service_spec.rb new file mode 100644 index 00000000000..3bee37b7e55 --- /dev/null +++ b/spec/services/ci/catalog/validate_resource_service_spec.rb @@ -0,0 +1,57 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::Catalog::ValidateResourceService, feature_category: :pipeline_composition do + describe '#execute' do + context 'with a project that has a README and a description' do + it 'is valid' do + project = create(:project, :repository, description: 'Component project') + response = described_class.new(project, project.default_branch).execute + + expect(response).to be_success + end + end + + context 'with a project that has neither a description nor a README' do + it 'is not valid' do + project = create(:project, :empty_repo) + project.repository.create_file( + project.creator, + 'ruby.rb', + 'I like this', + message: 'Ruby like this', + branch_name: 'master' + ) + response = described_class.new(project, project.default_branch).execute + + expect(response.message).to eq('Project must have a README , Project must have a description') + end + end + + context 'with a project that has a description but not a README' do + it 'is not valid' do + project = create(:project, :empty_repo, description: 'project with no README') + project.repository.create_file( + project.creator, + 'text.txt', + 'I do not like this', + message: 'only text like text', + branch_name: 'master' + ) + response = described_class.new(project, project.default_branch).execute + + expect(response.message).to eq('Project must have a README') + end + end + + context 'with a project that has a README and not a description' do + it 'is not valid' do + project = create(:project, :repository) + response = described_class.new(project, project.default_branch).execute + + expect(response.message).to eq('Project must have a description') + end + end + end +end diff --git a/spec/services/ci/change_variable_service_spec.rb b/spec/services/ci/change_variable_service_spec.rb index f86a87132b1..a9f9e4233d7 100644 --- a/spec/services/ci/change_variable_service_spec.rb +++ b/spec/services/ci/change_variable_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ChangeVariableService do +RSpec.describe Ci::ChangeVariableService, feature_category: :pipeline_composition do let(:service) { described_class.new(container: group, current_user: user, params: params) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/change_variables_service_spec.rb b/spec/services/ci/change_variables_service_spec.rb index b710ca78554..1bc36a78762 100644 --- a/spec/services/ci/change_variables_service_spec.rb +++ b/spec/services/ci/change_variables_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ChangeVariablesService do +RSpec.describe Ci::ChangeVariablesService, feature_category: :pipeline_composition do let(:service) { described_class.new(container: group, current_user: user, params: params) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/compare_accessibility_reports_service_spec.rb b/spec/services/ci/compare_accessibility_reports_service_spec.rb index e0b84219834..57514c18042 100644 --- a/spec/services/ci/compare_accessibility_reports_service_spec.rb +++ b/spec/services/ci/compare_accessibility_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CompareAccessibilityReportsService do +RSpec.describe Ci::CompareAccessibilityReportsService, feature_category: :continuous_integration do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/compare_codequality_reports_service_spec.rb b/spec/services/ci/compare_codequality_reports_service_spec.rb index ef762a2e9ad..de2300c354b 100644 --- a/spec/services/ci/compare_codequality_reports_service_spec.rb +++ b/spec/services/ci/compare_codequality_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CompareCodequalityReportsService do +RSpec.describe Ci::CompareCodequalityReportsService, feature_category: :continuous_integration do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/compare_reports_base_service_spec.rb b/spec/services/ci/compare_reports_base_service_spec.rb index 20d8cd37553..2906d61066d 100644 --- a/spec/services/ci/compare_reports_base_service_spec.rb +++ b/spec/services/ci/compare_reports_base_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CompareReportsBaseService do +RSpec.describe Ci::CompareReportsBaseService, feature_category: :continuous_integration do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/compare_test_reports_service_spec.rb b/spec/services/ci/compare_test_reports_service_spec.rb index f259072fe87..d29cef0c583 100644 --- a/spec/services/ci/compare_test_reports_service_spec.rb +++ b/spec/services/ci/compare_test_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CompareTestReportsService do +RSpec.describe Ci::CompareTestReportsService, feature_category: :continuous_integration do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/components/fetch_service_spec.rb b/spec/services/ci/components/fetch_service_spec.rb index f2eaa8d31b4..532098b3b20 100644 --- a/spec/services/ci/components/fetch_service_spec.rb +++ b/spec/services/ci/components/fetch_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::Components::FetchService, feature_category: :pipeline_authoring do +RSpec.describe Ci::Components::FetchService, feature_category: :pipeline_composition do let_it_be(:project) { create(:project, :repository, create_tag: 'v1.0') } let_it_be(:user) { create(:user) } let_it_be(:current_user) { user } diff --git a/spec/services/ci/copy_cross_database_associations_service_spec.rb b/spec/services/ci/copy_cross_database_associations_service_spec.rb index 5938ac258d0..2be0cbd9582 100644 --- a/spec/services/ci/copy_cross_database_associations_service_spec.rb +++ b/spec/services/ci/copy_cross_database_associations_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CopyCrossDatabaseAssociationsService do +RSpec.describe Ci::CopyCrossDatabaseAssociationsService, feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } let_it_be(:old_build) { create(:ci_build, pipeline: pipeline) } diff --git a/spec/services/ci/create_pipeline_service/artifacts_spec.rb b/spec/services/ci/create_pipeline_service/artifacts_spec.rb index e5e405492a0..c193900b2d3 100644 --- a/spec/services/ci/create_pipeline_service/artifacts_spec.rb +++ b/spec/services/ci/create_pipeline_service/artifacts_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: :build_artifacts do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/cache_spec.rb b/spec/services/ci/create_pipeline_service/cache_spec.rb index f9640f99031..e8d9cec6695 100644 --- a/spec/services/ci/create_pipeline_service/cache_spec.rb +++ b/spec/services/ci/create_pipeline_service/cache_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do context 'cache' do let(:project) { create(:project, :custom_repo, files: files) } let(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb index 0ebcecdd6e6..036116dc037 100644 --- a/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb +++ b/spec/services/ci/create_pipeline_service/creation_errors_and_warnings_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :continuous_integration do describe 'creation errors and warnings' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } 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 0d5017a763f..dc87cc872e3 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 @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do let_it_be(:group) { create(:group, name: 'my-organization') } let(:upstream_project) { create(:project, :repository, name: 'upstream', group: group) } diff --git a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb b/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb index dafa227c4c8..819946bfd27 100644 --- a/spec/services/ci/create_pipeline_service/custom_config_content_spec.rb +++ b/spec/services/ci/create_pipeline_service/custom_config_content_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: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb index 3b042f05fc0..b78ad68194a 100644 --- a/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb +++ b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb @@ -1,7 +1,8 @@ # 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: :continuous_integration do describe '!reference tags' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/dry_run_spec.rb b/spec/services/ci/create_pipeline_service/dry_run_spec.rb index de1ed251c82..7136fa5dc13 100644 --- a/spec/services/ci/create_pipeline_service/dry_run_spec.rb +++ b/spec/services/ci/create_pipeline_service/dry_run_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/environment_spec.rb b/spec/services/ci/create_pipeline_service/environment_spec.rb index b713cad2cad..96e54af43cd 100644 --- a/spec/services/ci/create_pipeline_service/environment_spec.rb +++ b/spec/services/ci/create_pipeline_service/environment_spec.rb @@ -2,7 +2,8 @@ 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_composition do let_it_be(:project) { create(:project, :repository) } let_it_be(:developer) { create(:user) } diff --git a/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb index e84726d31f6..b40e504f99b 100644 --- a/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb +++ b/spec/services/ci/create_pipeline_service/evaluate_runner_tags_spec.rb @@ -2,7 +2,8 @@ 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_composition do let_it_be(:group) { create(:group, :private) } let_it_be(:group_variable) { create(:ci_group_variable, group: group, key: 'RUNNER_TAG', value: 'group') } let_it_be(:project) { create(:project, :repository, group: group) } diff --git a/spec/services/ci/create_pipeline_service/include_spec.rb b/spec/services/ci/create_pipeline_service/include_spec.rb index f18b4883aaf..86f71be5971 100644 --- a/spec/services/ci/create_pipeline_service/include_spec.rb +++ b/spec/services/ci/create_pipeline_service/include_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Ci::CreatePipelineService, -:yaml_processor_feature_flag_corectness, feature_category: :pipeline_authoring do +:yaml_processor_feature_flag_corectness, feature_category: :pipeline_composition do include RepoHelpers context 'include:' do diff --git a/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb b/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb index 003d109a27c..b0730eaf215 100644 --- a/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb +++ b/spec/services/ci/create_pipeline_service/limit_active_jobs_spec.rb @@ -1,7 +1,8 @@ # 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: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } let_it_be(:existing_pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/create_pipeline_service/logger_spec.rb b/spec/services/ci/create_pipeline_service/logger_spec.rb index ecb24a61075..082a09db69e 100644 --- a/spec/services/ci/create_pipeline_service/logger_spec.rb +++ b/spec/services/ci/create_pipeline_service/logger_spec.rb @@ -142,7 +142,7 @@ RSpec.describe Ci::CreatePipelineService, # rubocop: disable RSpec/FilePath describe 'pipeline includes count' do before do - stub_const('Gitlab::Ci::Config::External::Context::MAX_INCLUDES', 2) + stub_const('Gitlab::Ci::Config::External::Context::TEMP_MAX_INCLUDES', 2) end context 'when the includes count exceeds the maximum' do diff --git a/spec/services/ci/create_pipeline_service/merge_requests_spec.rb b/spec/services/ci/create_pipeline_service/merge_requests_spec.rb index 80f48451e5c..8d04b3d020f 100644 --- a/spec/services/ci/create_pipeline_service/merge_requests_spec.rb +++ b/spec/services/ci/create_pipeline_service/merge_requests_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, +feature_category: :continuous_integration do context 'merge requests handling' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/needs_spec.rb b/spec/services/ci/create_pipeline_service/needs_spec.rb index 38e330316ea..068cad68e64 100644 --- a/spec/services/ci/create_pipeline_service/needs_spec.rb +++ b/spec/services/ci/create_pipeline_service/needs_spec.rb @@ -2,7 +2,8 @@ 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_composition do context 'needs' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/parallel_spec.rb b/spec/services/ci/create_pipeline_service/parallel_spec.rb index 5ee378a9719..71434fe0b0c 100644 --- a/spec/services/ci/create_pipeline_service/parallel_spec.rb +++ b/spec/services/ci/create_pipeline_service/parallel_spec.rb @@ -1,7 +1,8 @@ # 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: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/parameter_content_spec.rb b/spec/services/ci/create_pipeline_service/parameter_content_spec.rb index cae88bb67cf..16555dd68d6 100644 --- a/spec/services/ci/create_pipeline_service/parameter_content_spec.rb +++ b/spec/services/ci/create_pipeline_service/parameter_content_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } 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 eb17935967c..e644273df9a 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 @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, '#execute', :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb b/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb index db110bdc608..d935824e6cc 100644 --- a/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb +++ b/spec/services/ci/create_pipeline_service/pre_post_stages_spec.rb @@ -1,7 +1,8 @@ # 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: :continuous_integration do describe '.pre/.post stages' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/rate_limit_spec.rb b/spec/services/ci/create_pipeline_service/rate_limit_spec.rb index dfa74870341..31bea10f062 100644 --- a/spec/services/ci/create_pipeline_service/rate_limit_spec.rb +++ b/spec/services/ci/create_pipeline_service/rate_limit_spec.rb @@ -3,7 +3,8 @@ require 'spec_helper' RSpec.describe Ci::CreatePipelineService, :freeze_time, :clean_gitlab_redis_rate_limiting, - :yaml_processor_feature_flag_corectness do + :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do describe 'rate limiting' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index 26bb8b7d006..19f9e7e3e4a 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -1,25 +1,18 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :pipeline_authoring do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, feature_category: :pipeline_composition do let(:project) { create(:project, :repository) } let(:user) { project.first_owner } let(:ref) { 'refs/heads/master' } let(:source) { :push } - let(:service) { described_class.new(project, user, { ref: ref }) } - let(:response) { execute_service } + let(:service) { described_class.new(project, user, initialization_params) } + let(:response) { service.execute(source) } let(:pipeline) { response.payload } let(:build_names) { pipeline.builds.pluck(:name) } - def execute_service(before: '00000000', variables_attributes: nil) - params = { ref: ref, before: before, after: project.commit(ref).sha, variables_attributes: variables_attributes } - - described_class - .new(project, user, params) - .execute(source) do |pipeline| - yield(pipeline) if block_given? - end - end + let(:base_initialization_params) { { ref: ref, before: '00000000', after: project.commit(ref).sha, variables_attributes: nil } } + let(:initialization_params) { base_initialization_params } context 'job:rules' do let(:regular_job) { find_job('regular-job') } @@ -516,11 +509,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes ) end + let(:initialization_params) { base_initialization_params.merge(before: nil) } let(:changed_file) { 'file2.txt' } let(:ref) { 'feature_2' } - let(:response) { execute_service(before: nil) } - context 'for jobs rules' do let(:config) do <<-EOY @@ -1230,9 +1222,7 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes end context 'with pipeline variables' do - let(:pipeline) do - execute_service(variables_attributes: variables_attributes).payload - end + let(:initialization_params) { base_initialization_params.merge(variables_attributes: variables_attributes) } let(:config) do <<-EOY @@ -1267,10 +1257,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes end context 'with trigger variables' do - let(:pipeline) do - execute_service do |pipeline| + let(:response) do + service.execute(source) do |pipeline| pipeline.variables.build(variables) - end.payload + end end let(:config) do @@ -1434,10 +1424,10 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes [{ key: 'SOME_VARIABLE', secret_value: 'SOME_VAL' }] end - let(:pipeline) do - execute_service do |pipeline| + let(:response) do + service.execute(source) do |pipeline| pipeline.variables.build(variables) - end.payload + end end let(:config) do diff --git a/spec/services/ci/create_pipeline_service/scripts_spec.rb b/spec/services/ci/create_pipeline_service/scripts_spec.rb index 50b558e505a..d541257a086 100644 --- a/spec/services/ci/create_pipeline_service/scripts_spec.rb +++ b/spec/services/ci/create_pipeline_service/scripts_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness do +RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectness, + feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } @@ -83,30 +84,5 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes options: { script: ["echo 'hello job3 script'"] } ) end - - context 'when the FF ci_hooks_pre_get_sources_script is disabled' do - before do - stub_feature_flags(ci_hooks_pre_get_sources_script: false) - end - - it 'creates jobs without hook data' do - expect(pipeline).to be_created_successfully - expect(pipeline.builds.find_by(name: 'job1')).to have_attributes( - name: 'job1', - stage: 'test', - options: { script: ["echo 'hello job1 script'"] } - ) - expect(pipeline.builds.find_by(name: 'job2')).to have_attributes( - name: 'job2', - stage: 'test', - options: { script: ["echo 'hello job2 script'"] } - ) - expect(pipeline.builds.find_by(name: 'job3')).to have_attributes( - name: 'job3', - stage: 'test', - options: { script: ["echo 'hello job3 script'"] } - ) - end - end end end diff --git a/spec/services/ci/create_pipeline_service/tags_spec.rb b/spec/services/ci/create_pipeline_service/tags_spec.rb index 7450df11eac..cb2dbf1c3a4 100644 --- a/spec/services/ci/create_pipeline_service/tags_spec.rb +++ b/spec/services/ci/create_pipeline_service/tags_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: :continuous_integration do describe 'tags:' do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } diff --git a/spec/services/ci/create_pipeline_service/variables_spec.rb b/spec/services/ci/create_pipeline_service/variables_spec.rb index fd138bde656..64f8b90f2f2 100644 --- a/spec/services/ci/create_pipeline_service/variables_spec.rb +++ b/spec/services/ci/create_pipeline_service/variables_spec.rb @@ -2,7 +2,8 @@ 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_composition do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { project.first_owner } 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 3462b48cfe7..b22ca1472b7 100644 --- a/spec/services/ci/create_web_ide_terminal_service_spec.rb +++ b/spec/services/ci/create_web_ide_terminal_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::CreateWebIdeTerminalService do +RSpec.describe Ci::CreateWebIdeTerminalService, feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/daily_build_group_report_result_service_spec.rb b/spec/services/ci/daily_build_group_report_result_service_spec.rb index 32651247adb..bb6ce559fbd 100644 --- a/spec/services/ci/daily_build_group_report_result_service_spec.rb +++ b/spec/services/ci/daily_build_group_report_result_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do +RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute', feature_category: :continuous_integration do let_it_be(:group) { create(:group, :private) } let_it_be(:pipeline) { create(:ci_pipeline, project: create(:project, group: group), created_at: '2020-02-06 00:01:10') } let_it_be(:rspec_job) { create(:ci_build, pipeline: pipeline, name: 'rspec 3/3', coverage: 80) } diff --git a/spec/services/ci/delete_objects_service_spec.rb b/spec/services/ci/delete_objects_service_spec.rb index 448f8979681..d84ee596721 100644 --- a/spec/services/ci/delete_objects_service_spec.rb +++ b/spec/services/ci/delete_objects_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::DeleteObjectsService, :aggregate_failure do +RSpec.describe Ci::DeleteObjectsService, :aggregate_failure, feature_category: :continuous_integration do let(:service) { described_class.new } let(:artifact) { create(:ci_job_artifact, :archive) } let(:data) { [artifact] } diff --git a/spec/services/ci/delete_unit_tests_service_spec.rb b/spec/services/ci/delete_unit_tests_service_spec.rb index 4c63c513d48..2f07e709107 100644 --- a/spec/services/ci/delete_unit_tests_service_spec.rb +++ b/spec/services/ci/delete_unit_tests_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::DeleteUnitTestsService do +RSpec.describe Ci::DeleteUnitTestsService, feature_category: :continuous_integration do describe '#execute' do let!(:unit_test_1) { create(:ci_unit_test) } let!(:unit_test_2) { create(:ci_unit_test) } diff --git a/spec/services/ci/deployments/destroy_service_spec.rb b/spec/services/ci/deployments/destroy_service_spec.rb index 60a57c05728..d0e7f5acb2b 100644 --- a/spec/services/ci/deployments/destroy_service_spec.rb +++ b/spec/services/ci/deployments/destroy_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ::Ci::Deployments::DestroyService do +RSpec.describe ::Ci::Deployments::DestroyService, feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let(:environment) { create(:environment, project: project) } diff --git a/spec/services/ci/destroy_pipeline_service_spec.rb b/spec/services/ci/destroy_pipeline_service_spec.rb index 6bd7fe7559c..a1883d90b0a 100644 --- a/spec/services/ci/destroy_pipeline_service_spec.rb +++ b/spec/services/ci/destroy_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ::Ci::DestroyPipelineService do +RSpec.describe ::Ci::DestroyPipelineService, feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let!(:pipeline) { create(:ci_pipeline, :success, project: project, sha: project.commit.id) } diff --git a/spec/services/ci/destroy_secure_file_service_spec.rb b/spec/services/ci/destroy_secure_file_service_spec.rb index 6a30d33f4ca..321efc2ed71 100644 --- a/spec/services/ci/destroy_secure_file_service_spec.rb +++ b/spec/services/ci/destroy_secure_file_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ::Ci::DestroySecureFileService do +RSpec.describe ::Ci::DestroySecureFileService, feature_category: :continuous_integration do let_it_be(:maintainer_user) { create(:user) } let_it_be(:developer_user) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb index 4ff8dcf075b..d422cf0dab9 100644 --- a/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb +++ b/spec/services/ci/disable_user_pipeline_schedules_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::DisableUserPipelineSchedulesService do +RSpec.describe Ci::DisableUserPipelineSchedulesService, feature_category: :continuous_integration do describe '#execute' do let(:user) { create(:user) } diff --git a/spec/services/ci/drop_pipeline_service_spec.rb b/spec/services/ci/drop_pipeline_service_spec.rb index ddb53712d9c..ed45b3460c1 100644 --- a/spec/services/ci/drop_pipeline_service_spec.rb +++ b/spec/services/ci/drop_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::DropPipelineService do +RSpec.describe Ci::DropPipelineService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let(:failure_reason) { :user_blocked } diff --git a/spec/services/ci/ensure_stage_service_spec.rb b/spec/services/ci/ensure_stage_service_spec.rb index 026814edda6..5d6025095a1 100644 --- a/spec/services/ci/ensure_stage_service_spec.rb +++ b/spec/services/ci/ensure_stage_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::EnsureStageService, '#execute' do +RSpec.describe Ci::EnsureStageService, '#execute', feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/expire_pipeline_cache_service_spec.rb b/spec/services/ci/expire_pipeline_cache_service_spec.rb index 8cfe756faf3..3d0ce456aa5 100644 --- a/spec/services/ci/expire_pipeline_cache_service_spec.rb +++ b/spec/services/ci/expire_pipeline_cache_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ExpirePipelineCacheService do +RSpec.describe Ci::ExpirePipelineCacheService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } let_it_be(:pipeline) { create(:ci_pipeline, project: project) } 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 d5881d3b204..1b548aaf614 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 @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ExternalPullRequests::CreatePipelineService do +RSpec.describe Ci::ExternalPullRequests::CreatePipelineService, feature_category: :continuous_integration do describe '#execute' do let_it_be(:project) { create(:project, :auto_devops, :repository) } let_it_be(:user) { create(:user) } diff --git a/spec/services/ci/find_exposed_artifacts_service_spec.rb b/spec/services/ci/find_exposed_artifacts_service_spec.rb index 6e11c153a75..69360e73b86 100644 --- a/spec/services/ci/find_exposed_artifacts_service_spec.rb +++ b/spec/services/ci/find_exposed_artifacts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::FindExposedArtifactsService do +RSpec.describe Ci::FindExposedArtifactsService, feature_category: :build_artifacts do include Gitlab::Routing let(:metadata) do diff --git a/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb b/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb index 63bc7a1caf8..c33b182e9a9 100644 --- a/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb +++ b/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::GenerateCodequalityMrDiffReportService do +RSpec.describe Ci::GenerateCodequalityMrDiffReportService, feature_category: :code_review_workflow do let(:service) { described_class.new(project) } let(:project) { create(:project, :repository) } diff --git a/spec/services/ci/generate_coverage_reports_service_spec.rb b/spec/services/ci/generate_coverage_reports_service_spec.rb index 212e6be9d07..811431bf9d6 100644 --- a/spec/services/ci/generate_coverage_reports_service_spec.rb +++ b/spec/services/ci/generate_coverage_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::GenerateCoverageReportsService do +RSpec.describe Ci::GenerateCoverageReportsService, feature_category: :code_testing do let_it_be(:project) { create(:project, :repository) } let(:service) { described_class.new(project) } diff --git a/spec/services/ci/generate_kubeconfig_service_spec.rb b/spec/services/ci/generate_kubeconfig_service_spec.rb index c0858b0f0c9..da18dfe04c3 100644 --- a/spec/services/ci/generate_kubeconfig_service_spec.rb +++ b/spec/services/ci/generate_kubeconfig_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::GenerateKubeconfigService do +RSpec.describe Ci::GenerateKubeconfigService, feature_category: :kubernetes_management do describe '#execute' do let_it_be(:group) { create(:group) } let_it_be(:project) { create(:project, group: group) } diff --git a/spec/services/ci/generate_terraform_reports_service_spec.rb b/spec/services/ci/generate_terraform_reports_service_spec.rb index c32e8bcaeb8..b2142d391b8 100644 --- a/spec/services/ci/generate_terraform_reports_service_spec.rb +++ b/spec/services/ci/generate_terraform_reports_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::GenerateTerraformReportsService do +RSpec.describe Ci::GenerateTerraformReportsService, feature_category: :infrastructure_as_code do let_it_be(:project) { create(:project, :repository) } describe '#execute' do diff --git a/spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb b/spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb new file mode 100644 index 00000000000..a180837f9a9 --- /dev/null +++ b/spec/services/ci/job_artifacts/bulk_delete_by_project_service_spec.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Ci::JobArtifacts::BulkDeleteByProjectService, "#execute", feature_category: :build_artifacts do + subject(:execute) do + described_class.new( + job_artifact_ids: job_artifact_ids, + current_user: current_user, + project: project).execute + end + + let_it_be(:current_user) { create(:user) } + let_it_be(:build, reload: true) do + create(:ci_build, :artifacts, :trace_artifact, user: current_user) + end + + let_it_be(:project) { build.project } + let_it_be(:job_artifact_ids) { build.job_artifacts.map(&:id) } + + describe '#execute' do + context 'when number of artifacts exceeds limits to delete' do + let_it_be(:second_build, reload: true) do + create(:ci_build, :artifacts, :trace_artifact, user: current_user, project: project) + end + + let_it_be(:job_artifact_ids) { ::Ci::JobArtifact.all.map(&:id) } + + before do + project.add_maintainer(current_user) + stub_const("#{described_class}::JOB_ARTIFACTS_COUNT_LIMIT", 1) + end + + it 'fails to destroy' do + result = execute + + expect(result).to be_error + expect(result[:message]).to eq('Can only delete up to 1 job artifacts per call') + end + end + + context 'when requested not existing artifacts do delete' do + let_it_be(:deleted_build, reload: true) do + create(:ci_build, :artifacts, :trace_artifact, user: current_user, project: project) + end + + let_it_be(:deleted_job_artifacts) { deleted_build.job_artifacts } + let_it_be(:job_artifact_ids) { ::Ci::JobArtifact.all.map(&:id) } + + before do + project.add_maintainer(current_user) + deleted_job_artifacts.each(&:destroy!) + end + + it 'fails to destroy' do + result = execute + + expect(result).to be_error + expect(result[:message]).to eq("Artifacts (#{deleted_job_artifacts.map(&:id).join(',')}) not found") + end + end + + context 'when maintainer has access to the project' do + before do + project.add_maintainer(current_user) + end + + it 'is successful' do + result = execute + + expect(result).to be_success + expect(result.payload).to eq( + { + destroyed_count: job_artifact_ids.count, + destroyed_ids: job_artifact_ids, + errors: [] + } + ) + expect(::Ci::JobArtifact.where(id: job_artifact_ids).count).to eq(0) + end + + context 'and partially owns artifacts' do + let_it_be(:orphan_artifact) { create(:ci_job_artifact, :archive) } + let_it_be(:orphan_artifact_id) { orphan_artifact.id } + let_it_be(:owned_artifacts_ids) { build.job_artifacts.erasable.map(&:id) } + let_it_be(:job_artifact_ids) { [orphan_artifact_id] + owned_artifacts_ids } + + it 'fails to destroy' do + result = execute + + expect(result).to be_error + expect(result[:message]).to be('Not all artifacts belong to requested project') + expect(::Ci::JobArtifact.where(id: job_artifact_ids).count).to eq(3) + end + end + + context 'and request all artifacts from a different project' do + let_it_be(:different_project_artifact) { create(:ci_job_artifact, :archive) } + let_it_be(:job_artifact_ids) { [different_project_artifact] } + + let_it_be(:different_build, reload: true) do + create(:ci_build, :artifacts, :trace_artifact, user: current_user) + end + + let_it_be(:different_project) { different_build.project } + + before do + different_project.add_maintainer(current_user) + end + + it 'returns a error' do + result = execute + + expect(result).to be_error + expect(result[:message]).to be('Not all artifacts belong to requested project') + expect(::Ci::JobArtifact.where(id: job_artifact_ids).count).to eq(job_artifact_ids.count) + end + end + end + 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 47e9e5994ef..69f760e28ca 100644 --- a/spec/services/ci/job_artifacts/create_service_spec.rb +++ b/spec/services/ci/job_artifacts/create_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::CreateService do +RSpec.describe Ci::JobArtifacts::CreateService, feature_category: :build_artifacts do let_it_be(:project) { create(:project) } let(:service) { described_class.new(job) } @@ -33,6 +33,66 @@ RSpec.describe Ci::JobArtifacts::CreateService do describe '#execute' do subject { service.execute(artifacts_file, params, metadata_file: metadata_file) } + def expect_accessibility_be(accessibility) + if accessibility == :public + expect(job.job_artifacts).to all be_public_accessibility + else + expect(job.job_artifacts).to all be_private_accessibility + end + end + + shared_examples 'job does not have public artifacts in the CI config' do |expected_artifacts_count, accessibility| + it "sets accessibility by default to #{accessibility}" do + expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count) + + expect_accessibility_be(accessibility) + end + end + + shared_examples 'job artifact set as private in the CI config' do |expected_artifacts_count, accessibility| + let!(:job) { create(:ci_build, :with_private_artifacts_config, project: project) } + + it "sets accessibility to #{accessibility}" do + expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count) + + expect_accessibility_be(accessibility) + end + end + + shared_examples 'job artifact set as public in the CI config' do |expected_artifacts_count, accessibility| + let!(:job) { create(:ci_build, :with_public_artifacts_config, project: project) } + + it "sets accessibility to #{accessibility}" do + expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count) + + expect_accessibility_be(accessibility) + end + end + + shared_examples 'when accessibility level passed as private' do |expected_artifacts_count, accessibility| + before do + params.merge!('accessibility' => 'private') + end + + it 'sets accessibility to private level' do + expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count) + + expect_accessibility_be(accessibility) + end + end + + shared_examples 'when accessibility passed as public' do |expected_artifacts_count| + before do + params.merge!('accessibility' => 'public') + end + + it 'sets accessibility level to public' do + expect { subject }.to change { Ci::JobArtifact.count }.by(expected_artifacts_count) + + expect(job.job_artifacts).to all be_public_accessibility + end + end + context 'when artifacts file is uploaded' do it 'logs the created artifact' do expect(Gitlab::Ci::Artifacts::Logger) @@ -61,37 +121,19 @@ 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 + context 'when non_public_artifacts feature flag is disabled' do before do - params.merge!('accessibility' => 'private') + stub_feature_flags(non_public_artifacts: false) 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 + context 'when accessibility level not passed to the service' do + it_behaves_like 'job does not have public artifacts in the CI config', 1, :public + it_behaves_like 'job artifact set as private in the CI config', 1, :public + it_behaves_like 'job artifact set as public in the CI config', 1, :public 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 + it_behaves_like 'when accessibility level passed as private', 1, :public + it_behaves_like 'when accessibility passed as public', 1 end context 'when accessibility passed as invalid value' do @@ -104,6 +146,16 @@ RSpec.describe Ci::JobArtifacts::CreateService do end end + context 'when accessibility level not passed to the service' do + it_behaves_like 'job does not have public artifacts in the CI config', 1, :public + it_behaves_like 'job artifact set as private in the CI config', 1, :private + it_behaves_like 'job artifact set as public in the CI config', 1, :public + end + + it_behaves_like 'when accessibility level passed as private', 1, :private + + it_behaves_like 'when accessibility passed as public', 1 + 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) @@ -125,13 +177,16 @@ 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 + context 'when accessibility level not passed to the service' do + it_behaves_like 'job does not have public artifacts in the CI config', 2, :public + it_behaves_like 'job artifact set as private in the CI config', 2, :private + it_behaves_like 'job artifact set as public in the CI config', 2, :public end + it_behaves_like 'when accessibility level passed as private', 2, :privatge + + it_behaves_like 'when accessibility passed as public', 2 + it 'logs the created artifact and metadata' do expect(Gitlab::Ci::Artifacts::Logger) .to receive(:log_created) @@ -140,32 +195,6 @@ RSpec.describe Ci::JobArtifacts::CreateService do subject 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/delete_project_artifacts_service_spec.rb b/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb index 74fa42962f3..9c711e54b00 100644 --- a/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb +++ b/spec/services/ci/job_artifacts/delete_project_artifacts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::DeleteProjectArtifactsService do +RSpec.describe Ci::JobArtifacts::DeleteProjectArtifactsService, feature_category: :build_artifacts do let_it_be(:project) { create(:project) } subject { described_class.new(project: project) } diff --git a/spec/services/ci/job_artifacts/delete_service_spec.rb b/spec/services/ci/job_artifacts/delete_service_spec.rb index 78e8be48255..1560d0fc6f4 100644 --- a/spec/services/ci/job_artifacts/delete_service_spec.rb +++ b/spec/services/ci/job_artifacts/delete_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::DeleteService do +RSpec.describe Ci::JobArtifacts::DeleteService, feature_category: :build_artifacts do let_it_be(:build, reload: true) do create(:ci_build, :artifacts, :trace_artifact, artifacts_expire_at: 100.days.from_now) end 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 457be67c1ea..d1ec2a1d3a6 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 @@ -39,32 +39,12 @@ feature_category: :build_artifacts do second_artifact end - context 'with ci_destroy_unlocked_job_artifacts feature flag disabled' do - before do - stub_feature_flags(ci_destroy_unlocked_job_artifacts: false) - end - - it 'performs a consistent number of queries' do - control = ActiveRecord::QueryRecorder.new { service.execute } - - more_artifacts - - expect { subject }.not_to exceed_query_limit(control.count) - end - end - - context 'with ci_destroy_unlocked_job_artifacts feature flag enabled' do - before do - stub_feature_flags(ci_destroy_unlocked_job_artifacts: true) - end - - it 'performs a consistent number of queries' do - control = ActiveRecord::QueryRecorder.new { service.execute } + it 'performs a consistent number of queries' do + control = ActiveRecord::QueryRecorder.new { service.execute } - more_artifacts + more_artifacts - expect { subject }.not_to exceed_query_limit(control.count) - end + expect { subject }.not_to exceed_query_limit(control.count) end end @@ -251,6 +231,16 @@ feature_category: :build_artifacts do end end + context 'when some artifacts are trace' do + let!(:artifact) { create(:ci_job_artifact, :expired, job: job, locked: job.pipeline.locked) } + let!(:trace_artifact) { create(:ci_job_artifact, :trace, :expired, job: job, locked: job.pipeline.locked) } + + it 'destroys only non trace artifacts' do + expect { subject }.to change { Ci::JobArtifact.count }.by(-1) + expect(trace_artifact).to be_persisted + end + end + context 'when all artifacts are locked' do let!(:artifact) { create(:ci_job_artifact, :expired, job: locked_job, locked: locked_job.pipeline.locked) } 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 ca36c923dcf..f4839ccb04b 100644 --- a/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb +++ b/spec/services/ci/job_artifacts/destroy_associations_service_spec.rb @@ -2,24 +2,37 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::DestroyAssociationsService do +RSpec.describe Ci::JobArtifacts::DestroyAssociationsService, feature_category: :build_artifacts do let_it_be(:project_1) { create(:project) } let_it_be(:project_2) { create(:project) } 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) } + let_it_be(:artifact_2, refind: true) { create(:ci_job_artifact, :junit, project: project_2) } + let_it_be(:artifact_3, refind: true) { create(:ci_job_artifact, :terraform, project: project_1) } + let_it_be(:artifact_4, refind: true) { create(:ci_job_artifact, :trace, project: project_2) } + let_it_be(:artifact_5, refind: true) { create(:ci_job_artifact, :metadata, project: project_2) } - let(:artifacts) { Ci::JobArtifact.where(id: [artifact_1.id, artifact_2.id, artifact_3.id]) } + let_it_be(:locked_artifact, refind: true) { create(:ci_job_artifact, :zip, :locked, project: project_1) } + + let(:artifact_ids_to_be_removed) { [artifact_1.id, artifact_2.id, artifact_3.id, artifact_4.id, artifact_5.id] } + let(:artifacts) { Ci::JobArtifact.where(id: artifact_ids_to_be_removed) } let(:service) { described_class.new(artifacts) } describe '#destroy_records' do - it 'removes artifacts without updating statistics' do + it 'removes all types of artifacts without updating statistics' do 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 }.by(-3) + expect { service.destroy_records }.to change { Ci::JobArtifact.count }.by(-artifact_ids_to_be_removed.count) + end + + context 'with a locked artifact' do + let(:artifact_ids_to_be_removed) { [artifact_1.id, locked_artifact.id] } + + it 'removes all artifacts' do + expect { service.destroy_records }.to change { Ci::JobArtifact.count }.by(-artifact_ids_to_be_removed.count) + end end context 'when there are no artifacts' do @@ -42,7 +55,11 @@ RSpec.describe Ci::JobArtifacts::DestroyAssociationsService do 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)] + project2_increments = [ + have_attributes(amount: -artifact_2.size, ref: artifact_2.id), + have_attributes(amount: -artifact_4.size, ref: artifact_4.id), + have_attributes(amount: -artifact_5.size, ref: artifact_5.id) + ] expect(ProjectStatistics).to receive(:bulk_increment_statistic).once .with(project_1, :build_artifacts_size, match_array(project1_increments)) 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 cde42783d8c..6f9dcf47535 100644 --- a/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb +++ b/spec/services/ci/job_artifacts/destroy_batch_service_spec.rb @@ -2,8 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::DestroyBatchService do - let(:artifacts) { Ci::JobArtifact.where(id: [artifact_with_file.id, artifact_without_file.id, trace_artifact.id]) } +RSpec.describe Ci::JobArtifacts::DestroyBatchService, feature_category: :build_artifacts do + let(:artifacts) { Ci::JobArtifact.where(id: [artifact_with_file.id, artifact_without_file.id]) } let(:skip_projects_on_refresh) { false } let(:service) do described_class.new( @@ -25,10 +25,6 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do create(:ci_job_artifact) end - let_it_be(:trace_artifact, refind: true) do - create(:ci_job_artifact, :trace, :expired) - end - describe '#execute' do subject(:execute) { service.execute } @@ -60,11 +56,6 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do execute end - it 'preserves trace artifacts' do - expect { subject } - .to not_change { Ci::JobArtifact.exists?(trace_artifact.id) } - end - context 'when artifact belongs to a project that is undergoing stats refresh' do let!(:artifact_under_refresh_1) do create(:ci_job_artifact, :zip) @@ -287,7 +278,7 @@ RSpec.describe Ci::JobArtifacts::DestroyBatchService do end it 'reports the number of destroyed artifacts' do - is_expected.to eq(destroyed_artifacts_count: 0, statistics_updates: {}, status: :success) + is_expected.to eq(destroyed_artifacts_count: 0, destroyed_ids: [], statistics_updates: {}, status: :success) end end end diff --git a/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb b/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb index fb9dd6b876b..69cdf39107a 100644 --- a/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb +++ b/spec/services/ci/job_artifacts/expire_project_build_artifacts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::ExpireProjectBuildArtifactsService do +RSpec.describe Ci::JobArtifacts::ExpireProjectBuildArtifactsService, feature_category: :build_artifacts do let_it_be(:project) { create(:project) } let_it_be(:pipeline, reload: true) { create(:ci_pipeline, :unlocked, project: project) } diff --git a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb index d4d56825e1f..5355bec2d6c 100644 --- a/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb +++ b/spec/services/ci/job_artifacts/track_artifact_report_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::TrackArtifactReportService do +RSpec.describe Ci::JobArtifacts::TrackArtifactReportService, feature_category: :build_artifacts do describe '#execute', :clean_gitlab_redis_shared_state do let_it_be(:group) { create(:group, :private) } let_it_be(:project) { create(:project, group: group) } diff --git a/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb b/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb index 67412e41fb8..5f6a89b89e1 100644 --- a/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb +++ b/spec/services/ci/job_artifacts/update_unknown_locked_status_service_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::JobArtifacts::UpdateUnknownLockedStatusService, :clean_gitlab_redis_shared_state do +RSpec.describe Ci::JobArtifacts::UpdateUnknownLockedStatusService, :clean_gitlab_redis_shared_state, + feature_category: :build_artifacts do include ExclusiveLeaseHelpers let(:service) { described_class.new } diff --git a/spec/services/ci/list_config_variables_service_spec.rb b/spec/services/ci/list_config_variables_service_spec.rb index e2bbdefef7f..56a392221be 100644 --- a/spec/services/ci/list_config_variables_service_spec.rb +++ b/spec/services/ci/list_config_variables_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe Ci::ListConfigVariablesService, -:use_clean_rails_memory_store_caching, feature_category: :pipeline_authoring do +:use_clean_rails_memory_store_caching, feature_category: :pipeline_composition do include ReactiveCachingHelpers let(:ci_config) { {} } diff --git a/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb b/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb index c4558bddc85..b7b32d2a0af 100644 --- a/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb +++ b/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PipelineArtifacts::CoverageReportService do +RSpec.describe Ci::PipelineArtifacts::CoverageReportService, feature_category: :build_artifacts do describe '#execute' do let_it_be(:project) { create(:project, :repository) } diff --git a/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb b/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb index 5d854b61f14..20265a0ca48 100644 --- a/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb +++ b/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe ::Ci::PipelineArtifacts::CreateCodeQualityMrDiffReportService do +RSpec.describe ::Ci::PipelineArtifacts::CreateCodeQualityMrDiffReportService, feature_category: :build_artifacts do describe '#execute' do let(:merge_request) { create(:merge_request) } let(:project) { merge_request.project } diff --git a/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb b/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb index 47e8766c215..b46648760e1 100644 --- a/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb +++ b/spec/services/ci/pipeline_artifacts/destroy_all_expired_service_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::PipelineArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_shared_state do +RSpec.describe Ci::PipelineArtifacts::DestroyAllExpiredService, :clean_gitlab_redis_shared_state, + feature_category: :build_artifacts do let(:service) { described_class.new } describe '.execute' do diff --git a/spec/services/ci/pipeline_bridge_status_service_spec.rb b/spec/services/ci/pipeline_bridge_status_service_spec.rb index 1346f68c952..3d8219251d6 100644 --- a/spec/services/ci/pipeline_bridge_status_service_spec.rb +++ b/spec/services/ci/pipeline_bridge_status_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PipelineBridgeStatusService do +RSpec.describe Ci::PipelineBridgeStatusService, feature_category: :continuous_integration do let(:user) { build(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb b/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb index ab4ba20e716..06139c091b9 100644 --- a/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb +++ b/spec/services/ci/pipeline_creation/start_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PipelineCreation::StartPipelineService do +RSpec.describe Ci::PipelineCreation::StartPipelineService, feature_category: :continuous_integration do let(:pipeline) { build(:ci_pipeline) } subject(:service) { described_class.new(pipeline) } diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb index d0aa1ba4c6c..46ea0036e49 100644 --- a/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb +++ b/spec/services/ci/pipeline_processing/atomic_processing_service/status_collection_spec.rb @@ -2,7 +2,8 @@ require 'spec_helper' -RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection do +RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection, + feature_category: :continuous_integration do using RSpec::Parameterized::TableSyntax let_it_be(:pipeline) { create(:ci_pipeline) } @@ -35,7 +36,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection it 'does update existing status of processable' do collection.set_processable_status(test_a.id, 'success', 100) - expect(collection.status_for_names(['test-a'], dag: false)).to eq('success') + expect(collection.status_of_processables(['test-a'], dag: false)).to eq('success') end it 'ignores a missing processable' do @@ -49,7 +50,7 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection end end - describe '#status_for_names' do + describe '#status_of_processables' do where(:names, :status, :dag) do %w[build-a] | 'success' | false %w[build-a build-b] | 'failed' | false @@ -61,12 +62,12 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection with_them do it 'returns composite status of given names' do - expect(collection.status_for_names(names, dag: dag)).to eq(status) + expect(collection.status_of_processables(names, dag: dag)).to eq(status) end end end - describe '#status_for_prior_stage_position' do + describe '#status_of_processables_prior_to_stage' do where(:stage, :status) do 0 | 'success' 1 | 'failed' @@ -75,12 +76,12 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection with_them do it 'returns composite status for processables in prior stages' do - expect(collection.status_for_prior_stage_position(stage)).to eq(status) + expect(collection.status_of_processables_prior_to_stage(stage)).to eq(status) end end end - describe '#status_for_stage_position' do + describe '#status_of_stage' do where(:stage, :status) do 0 | 'failed' 1 | 'running' @@ -89,16 +90,16 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService::StatusCollection with_them do it 'returns composite status for processables at a given stages' do - expect(collection.status_for_stage_position(stage)).to eq(status) + expect(collection.status_of_stage(stage)).to eq(status) end end end - describe '#created_processable_ids_for_stage_position' do + describe '#created_processable_ids_in_stage' do it 'returns IDs of processables at a given stage position' do - expect(collection.created_processable_ids_for_stage_position(0)).to be_empty - expect(collection.created_processable_ids_for_stage_position(1)).to be_empty - expect(collection.created_processable_ids_for_stage_position(2)).to contain_exactly(deploy.id) + expect(collection.created_processable_ids_in_stage(0)).to be_empty + expect(collection.created_processable_ids_in_stage(1)).to be_empty + expect(collection.created_processable_ids_in_stage(2)).to contain_exactly(deploy.id) end end diff --git a/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb index 9a3aad20d89..1d45a06f9ea 100644 --- a/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb +++ b/spec/services/ci/pipeline_schedules/take_ownership_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PipelineSchedules::TakeOwnershipService do +RSpec.describe Ci::PipelineSchedules::TakeOwnershipService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:owner) { create(:user) } let_it_be(:reporter) { create(:user) } diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 4946367380e..b6e07e82bb5 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PipelineTriggerService do +RSpec.describe Ci::PipelineTriggerService, feature_category: :continuous_integration do include AfterNextHelpers let_it_be(:project) { create(:project, :repository) } diff --git a/spec/services/ci/pipelines/add_job_service_spec.rb b/spec/services/ci/pipelines/add_job_service_spec.rb index c62aa9506bd..9fb1d6933c6 100644 --- a/spec/services/ci/pipelines/add_job_service_spec.rb +++ b/spec/services/ci/pipelines/add_job_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::Pipelines::AddJobService do +RSpec.describe Ci::Pipelines::AddJobService, feature_category: :continuous_integration do include ExclusiveLeaseHelpers let_it_be_with_reload(:pipeline) { create(:ci_pipeline) } diff --git a/spec/services/ci/pipelines/hook_service_spec.rb b/spec/services/ci/pipelines/hook_service_spec.rb index 8d138a3d957..e773ae2d2c3 100644 --- a/spec/services/ci/pipelines/hook_service_spec.rb +++ b/spec/services/ci/pipelines/hook_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::Pipelines::HookService do +RSpec.describe Ci::Pipelines::HookService, feature_category: :continuous_integration do describe '#execute_hooks' do let_it_be(:namespace) { create(:namespace) } let_it_be(:project) { create(:project, :repository, namespace: namespace) } diff --git a/spec/services/ci/play_bridge_service_spec.rb b/spec/services/ci/play_bridge_service_spec.rb index 56b1615a56d..5727ed64f8b 100644 --- a/spec/services/ci/play_bridge_service_spec.rb +++ b/spec/services/ci/play_bridge_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PlayBridgeService, '#execute' do +RSpec.describe Ci::PlayBridgeService, '#execute', feature_category: :continuous_integration do let(:project) { create(:project) } let(:user) { create(:user) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index fc07801b672..f439538b4cc 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PlayBuildService, '#execute' do +RSpec.describe Ci::PlayBuildService, '#execute', feature_category: :continuous_integration do let(:user) { create(:user, developer_projects: [project]) } let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/play_manual_stage_service_spec.rb b/spec/services/ci/play_manual_stage_service_spec.rb index 24f0a21f3dd..1aca4ffec2d 100644 --- a/spec/services/ci/play_manual_stage_service_spec.rb +++ b/spec/services/ci/play_manual_stage_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PlayManualStageService, '#execute' do +RSpec.describe Ci::PlayManualStageService, '#execute', feature_category: :continuous_integration do let(:current_user) { create(:user) } let(:pipeline) { create(:ci_pipeline, user: current_user) } let(:project) { pipeline.project } diff --git a/spec/services/ci/prepare_build_service_spec.rb b/spec/services/ci/prepare_build_service_spec.rb index f75cb322fe9..8583b8e667c 100644 --- a/spec/services/ci/prepare_build_service_spec.rb +++ b/spec/services/ci/prepare_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PrepareBuildService do +RSpec.describe Ci::PrepareBuildService, feature_category: :continuous_integration do describe '#execute' do let(:build) { create(:ci_build, :preparing) } diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index de308bb1a87..d1442b75731 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'spec_helper' -RSpec.describe Ci::ProcessBuildService, '#execute' do +RSpec.describe Ci::ProcessBuildService, '#execute', feature_category: :continuous_integration do using RSpec::Parameterized::TableSyntax let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project) } diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index 404e1bf7c87..d1586ad4c8b 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ProcessPipelineService do +RSpec.describe Ci::ProcessPipelineService, feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let(:pipeline) do diff --git a/spec/services/ci/process_sync_events_service_spec.rb b/spec/services/ci/process_sync_events_service_spec.rb index 7ab7911e578..c042a9bd46e 100644 --- a/spec/services/ci/process_sync_events_service_spec.rb +++ b/spec/services/ci/process_sync_events_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ProcessSyncEventsService do +RSpec.describe Ci::ProcessSyncEventsService, feature_category: :continuous_integration do let!(:group) { create(:group) } let!(:project1) { create(:project, group: group) } let!(:project2) { create(:project, group: group) } diff --git a/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb b/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb index 0b100af5902..a9ee5216d81 100644 --- a/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb +++ b/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::PrometheusMetrics::ObserveHistogramsService do +RSpec.describe Ci::PrometheusMetrics::ObserveHistogramsService, feature_category: :continuous_integration do let_it_be(:project) { create(:project) } let(:params) { {} } diff --git a/spec/services/ci/queue/pending_builds_strategy_spec.rb b/spec/services/ci/queue/pending_builds_strategy_spec.rb index 6f22c256c17..ea9207ddb8f 100644 --- a/spec/services/ci/queue/pending_builds_strategy_spec.rb +++ b/spec/services/ci/queue/pending_builds_strategy_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::Queue::PendingBuildsStrategy do +RSpec.describe Ci::Queue::PendingBuildsStrategy, feature_category: :continuous_integration do let_it_be(:group) { create(:group) } let_it_be(:group_runner) { create(:ci_runner, :group, groups: [group]) } let_it_be(:project) { create(:project, group: group) } diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 9183df359b4..18cb016f94a 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -16,126 +16,155 @@ module Ci describe '#execute' do subject(:execute) { described_class.new(runner, runner_machine).execute } - context 'with runner_machine specified' do - let(:runner) { project_runner } - let!(:runner_machine) { create(:ci_runner_machine, runner: project_runner) } + let(:runner_machine) { nil } + + context 'checks database loadbalancing stickiness' do + let(:runner) { shared_runner } before do - pending_job.update!(tag_list: ["linux"]) - pending_job.reload - pending_job.create_queuing_entry! - project_runner.update!(tag_list: ["linux"]) + project.update!(shared_runners_enabled: false) end - it 'sets runner_machine on job' do - expect { execute }.to change { pending_job.reload.runner_machine }.from(nil).to(runner_machine) + it 'result is valid if replica did caught-up', :aggregate_failures do + expect(ApplicationRecord.sticking).to receive(:all_caught_up?).with(:runner, runner.id) { true } - expect(execute.build).to eq(pending_job) + expect { execute }.not_to change { Ci::RunnerMachineBuild.count }.from(0) + expect(execute).to be_valid + expect(execute.build).to be_nil + expect(execute.build_json).to be_nil end - end - - context 'with no runner machine' do - let(:runner_machine) { nil } - - context 'checks database loadbalancing stickiness' do - let(:runner) { shared_runner } - - before do - project.update!(shared_runners_enabled: false) - end - it 'result is valid if replica did caught-up', :aggregate_failures do - expect(ApplicationRecord.sticking).to receive(:all_caught_up?).with(:runner, runner.id) { true } + it 'result is invalid if replica did not caught-up', :aggregate_failures do + expect(ApplicationRecord.sticking).to receive(:all_caught_up?) + .with(:runner, shared_runner.id) { false } - expect(execute).to be_valid - expect(execute.build).to be_nil - expect(execute.build_json).to be_nil - end + expect(subject).not_to be_valid + expect(subject.build).to be_nil + expect(subject.build_json).to be_nil + end + end - it 'result is invalid if replica did not caught-up', :aggregate_failures do - expect(ApplicationRecord.sticking).to receive(:all_caught_up?) - .with(:runner, shared_runner.id) { false } + shared_examples 'handles runner assignment' do + context 'runner follows tag list' do + subject(:build) { build_on(project_runner, runner_machine: project_runner_machine) } - expect(subject).not_to be_valid - expect(subject.build).to be_nil - expect(subject.build_json).to be_nil - end - end + let(:project_runner_machine) { nil } - shared_examples 'handles runner assignment' do - context 'runner follow tag list' do - it "picks build with the same tag" do + context 'when job has tag' do + before do pending_job.update!(tag_list: ["linux"]) pending_job.reload pending_job.create_queuing_entry! - project_runner.update!(tag_list: ["linux"]) - expect(build_on(project_runner)).to eq(pending_job) end - it "does not pick build with different tag" do - pending_job.update!(tag_list: ["linux"]) - pending_job.reload - pending_job.create_queuing_entry! - project_runner.update!(tag_list: ["win32"]) - expect(build_on(project_runner)).to be_falsey + context 'and runner has matching tag' do + before do + project_runner.update!(tag_list: ["linux"]) + end + + context 'with no runner machine specified' do + it 'picks build' do + expect(build).to eq(pending_job) + expect(pending_job.runner_machine).to be_nil + end + end + + context 'with runner machine specified' do + let(:project_runner_machine) { create(:ci_runner_machine, runner: project_runner) } + + it 'picks build and assigns runner machine' do + expect(build).to eq(pending_job) + expect(pending_job.runner_machine).to eq(project_runner_machine) + end + end end - it "picks build without tag" do - expect(build_on(project_runner)).to eq(pending_job) + it 'does not pick build with different tag' do + project_runner.update!(tag_list: ["win32"]) + expect(build).to be_falsey end - it "does not pick build with tag" do - pending_job.update!(tag_list: ["linux"]) - pending_job.reload + it 'does not pick build with tag' do pending_job.create_queuing_entry! - expect(build_on(project_runner)).to be_falsey + expect(build).to be_falsey end + end - it "pick build without tag" do - project_runner.update!(tag_list: ["win32"]) - expect(build_on(project_runner)).to eq(pending_job) + context 'when job has no tag' do + it 'picks build' do + expect(build).to eq(pending_job) + end + + context 'when runner has tag' do + before do + project_runner.update!(tag_list: ["win32"]) + end + + it 'picks build' do + expect(build).to eq(pending_job) + end end end + end - context 'deleted projects' do + context 'deleted projects' do + before do + project.update!(pending_delete: true) + end + + context 'for shared runners' do before do - project.update!(pending_delete: true) + project.update!(shared_runners_enabled: true) end - context 'for shared runners' do - before do - project.update!(shared_runners_enabled: true) - end + it 'does not pick a build' do + expect(build_on(shared_runner)).to be_nil + end + end + + context 'for project runner' do + subject(:build) { build_on(project_runner, runner_machine: project_runner_machine) } + let(:project_runner_machine) { nil } + + context 'with no runner machine specified' do it 'does not pick a build' do - expect(build_on(shared_runner)).to be_nil + expect(build).to be_nil + expect(pending_job.reload).to be_failed + expect(pending_job.queuing_entry).to be_nil + expect(Ci::RunnerMachineBuild.all).to be_empty end end - context 'for project runner' do + context 'with runner machine specified' do + let(:project_runner_machine) { create(:ci_runner_machine, runner: project_runner) } + it 'does not pick a build' do - expect(build_on(project_runner)).to be_nil + expect(build).to be_nil expect(pending_job.reload).to be_failed expect(pending_job.queuing_entry).to be_nil + expect(Ci::RunnerMachineBuild.all).to be_empty end end end + end - context 'allow shared runners' do - before do - project.update!(shared_runners_enabled: true) - pipeline.reload - pending_job.reload - pending_job.create_queuing_entry! - end + context 'allow shared runners' do + before do + project.update!(shared_runners_enabled: true) + pipeline.reload + pending_job.reload + pending_job.create_queuing_entry! + end - context 'when build owner has been blocked' do - let(:user) { create(:user, :blocked) } + context 'when build owner has been blocked' do + let(:user) { create(:user, :blocked) } - before do - pending_job.update!(user: user) - end + before do + pending_job.update!(user: user) + end + context 'with no runner machine specified' do it 'does not pick the build and drops the build' do expect(build_on(shared_runner)).to be_falsey @@ -143,690 +172,701 @@ module Ci end end - context 'for multiple builds' do - let!(:project2) { create :project, shared_runners_enabled: true } - let!(:pipeline2) { create :ci_pipeline, project: project2 } - let!(:project3) { create :project, shared_runners_enabled: true } - let!(:pipeline3) { create :ci_pipeline, project: project3 } - let!(:build1_project1) { pending_job } - let!(:build2_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - let!(:build3_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - let!(:build1_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) } - let!(:build2_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) } - let!(:build1_project3) { create(:ci_build, :pending, :queued, pipeline: pipeline3) } + context 'with runner machine specified' do + let(:runner_machine) { create(:ci_runner_machine, runner: runner) } - it 'picks builds one-by-one' do - expect(Ci::Build).to receive(:find).with(pending_job.id).and_call_original + it 'does not pick the build and does not create join record' do + expect(build_on(shared_runner, runner_machine: runner_machine)).to be_falsey - expect(build_on(shared_runner)).to eq(build1_project1) + expect(Ci::RunnerMachineBuild.all).to be_empty end + end + end - context 'when using fair scheduling' do - context 'when all builds are pending' do - it 'prefers projects without builds first' do - # it gets for one build from each of the projects - expect(build_on(shared_runner)).to eq(build1_project1) - expect(build_on(shared_runner)).to eq(build1_project2) - expect(build_on(shared_runner)).to eq(build1_project3) - - # then it gets a second build from each of the projects - expect(build_on(shared_runner)).to eq(build2_project1) - expect(build_on(shared_runner)).to eq(build2_project2) - - # in the end the third build - expect(build_on(shared_runner)).to eq(build3_project1) - end - end + context 'for multiple builds' do + let!(:project2) { create :project, shared_runners_enabled: true } + let!(:pipeline2) { create :ci_pipeline, project: project2 } + let!(:project3) { create :project, shared_runners_enabled: true } + let!(:pipeline3) { create :ci_pipeline, project: project3 } + let!(:build1_project1) { pending_job } + let!(:build2_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + let!(:build3_project1) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + let!(:build1_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) } + let!(:build2_project2) { create(:ci_build, :pending, :queued, pipeline: pipeline2) } + let!(:build1_project3) { create(:ci_build, :pending, :queued, pipeline: pipeline3) } + + it 'picks builds one-by-one' do + expect(Ci::Build).to receive(:find).with(pending_job.id).and_call_original + + expect(build_on(shared_runner)).to eq(build1_project1) + end - context 'when some builds transition to success' do - it 'equalises number of running builds' do - # after finishing the first build for project 1, get a second build from the same project - expect(build_on(shared_runner)).to eq(build1_project1) - build1_project1.reload.success - expect(build_on(shared_runner)).to eq(build2_project1) - - expect(build_on(shared_runner)).to eq(build1_project2) - build1_project2.reload.success - expect(build_on(shared_runner)).to eq(build2_project2) - expect(build_on(shared_runner)).to eq(build1_project3) - expect(build_on(shared_runner)).to eq(build3_project1) - end + context 'when using fair scheduling' do + context 'when all builds are pending' do + it 'prefers projects without builds first' do + # it gets for one build from each of the projects + expect(build_on(shared_runner)).to eq(build1_project1) + expect(build_on(shared_runner)).to eq(build1_project2) + expect(build_on(shared_runner)).to eq(build1_project3) + + # then it gets a second build from each of the projects + expect(build_on(shared_runner)).to eq(build2_project1) + expect(build_on(shared_runner)).to eq(build2_project2) + + # in the end the third build + expect(build_on(shared_runner)).to eq(build3_project1) end end - context 'when using DEFCON mode that disables fair scheduling' do - before do - stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: true) + context 'when some builds transition to success' do + it 'equalises number of running builds' do + # after finishing the first build for project 1, get a second build from the same project + expect(build_on(shared_runner)).to eq(build1_project1) + build1_project1.reload.success + expect(build_on(shared_runner)).to eq(build2_project1) + + expect(build_on(shared_runner)).to eq(build1_project2) + build1_project2.reload.success + expect(build_on(shared_runner)).to eq(build2_project2) + expect(build_on(shared_runner)).to eq(build1_project3) + expect(build_on(shared_runner)).to eq(build3_project1) end + end + end - context 'when all builds are pending' do - it 'returns builds in order of creation (FIFO)' do - # it gets for one build from each of the projects - expect(build_on(shared_runner)).to eq(build1_project1) - expect(build_on(shared_runner)).to eq(build2_project1) - expect(build_on(shared_runner)).to eq(build3_project1) - expect(build_on(shared_runner)).to eq(build1_project2) - expect(build_on(shared_runner)).to eq(build2_project2) - expect(build_on(shared_runner)).to eq(build1_project3) - end + context 'when using DEFCON mode that disables fair scheduling' do + before do + stub_feature_flags(ci_queueing_disaster_recovery_disable_fair_scheduling: true) + end + + context 'when all builds are pending' do + it 'returns builds in order of creation (FIFO)' do + # it gets for one build from each of the projects + expect(build_on(shared_runner)).to eq(build1_project1) + expect(build_on(shared_runner)).to eq(build2_project1) + expect(build_on(shared_runner)).to eq(build3_project1) + expect(build_on(shared_runner)).to eq(build1_project2) + expect(build_on(shared_runner)).to eq(build2_project2) + expect(build_on(shared_runner)).to eq(build1_project3) end + end - context 'when some builds transition to success' do - it 'returns builds in order of creation (FIFO)' do - expect(build_on(shared_runner)).to eq(build1_project1) - build1_project1.reload.success - expect(build_on(shared_runner)).to eq(build2_project1) - - expect(build_on(shared_runner)).to eq(build3_project1) - build2_project1.reload.success - expect(build_on(shared_runner)).to eq(build1_project2) - expect(build_on(shared_runner)).to eq(build2_project2) - expect(build_on(shared_runner)).to eq(build1_project3) - end + context 'when some builds transition to success' do + it 'returns builds in order of creation (FIFO)' do + expect(build_on(shared_runner)).to eq(build1_project1) + build1_project1.reload.success + expect(build_on(shared_runner)).to eq(build2_project1) + + expect(build_on(shared_runner)).to eq(build3_project1) + build2_project1.reload.success + expect(build_on(shared_runner)).to eq(build1_project2) + expect(build_on(shared_runner)).to eq(build2_project2) + expect(build_on(shared_runner)).to eq(build1_project3) end end end + end - context 'shared runner' do - let(:response) { described_class.new(shared_runner, nil).execute } - let(:build) { response.build } + context 'shared runner' do + let(:response) { described_class.new(shared_runner, nil).execute } + let(:build) { response.build } - it { expect(build).to be_kind_of(Build) } - it { expect(build).to be_valid } - it { expect(build).to be_running } - it { expect(build.runner).to eq(shared_runner) } - it { expect(Gitlab::Json.parse(response.build_json)['id']).to eq(build.id) } - end + it { expect(build).to be_kind_of(Build) } + it { expect(build).to be_valid } + it { expect(build).to be_running } + it { expect(build.runner).to eq(shared_runner) } + it { expect(Gitlab::Json.parse(response.build_json)['id']).to eq(build.id) } + end - context 'project runner' do - let(:build) { build_on(project_runner) } + context 'project runner' do + let(:build) { build_on(project_runner) } - it { expect(build).to be_kind_of(Build) } - it { expect(build).to be_valid } - it { expect(build).to be_running } - it { expect(build.runner).to eq(project_runner) } - end + it { expect(build).to be_kind_of(Build) } + it { expect(build).to be_valid } + it { expect(build).to be_running } + it { expect(build.runner).to eq(project_runner) } end + end - context 'disallow shared runners' do - before do - project.update!(shared_runners_enabled: false) - end + context 'disallow shared runners' do + before do + project.update!(shared_runners_enabled: false) + end - context 'shared runner' do - let(:build) { build_on(shared_runner) } + context 'shared runner' do + let(:build) { build_on(shared_runner) } - it { expect(build).to be_nil } - end + it { expect(build).to be_nil } + end - context 'project runner' do - let(:build) { build_on(project_runner) } + context 'project runner' do + let(:build) { build_on(project_runner) } - it { expect(build).to be_kind_of(Build) } - it { expect(build).to be_valid } - it { expect(build).to be_running } - it { expect(build.runner).to eq(project_runner) } - end + it { expect(build).to be_kind_of(Build) } + it { expect(build).to be_valid } + it { expect(build).to be_running } + it { expect(build.runner).to eq(project_runner) } end + end - context 'disallow when builds are disabled' do - before do - project.update!(shared_runners_enabled: true, group_runners_enabled: true) - project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED) + context 'disallow when builds are disabled' do + before do + project.update!(shared_runners_enabled: true, group_runners_enabled: true) + project.project_feature.update_attribute(:builds_access_level, ProjectFeature::DISABLED) - pending_job.reload.create_queuing_entry! - end + pending_job.reload.create_queuing_entry! + end - context 'and uses shared runner' do - let(:build) { build_on(shared_runner) } + context 'and uses shared runner' do + let(:build) { build_on(shared_runner) } - it { expect(build).to be_nil } - end + it { expect(build).to be_nil } + end - context 'and uses group runner' do - let(:build) { build_on(group_runner) } + context 'and uses group runner' do + let(:build) { build_on(group_runner) } - it { expect(build).to be_nil } - end + it { expect(build).to be_nil } + end - context 'and uses project runner' do - let(:build) { build_on(project_runner) } + context 'and uses project runner' do + let(:build) { build_on(project_runner) } - it 'does not pick a build' do - expect(build).to be_nil - expect(pending_job.reload).to be_failed - expect(pending_job.queuing_entry).to be_nil - end + it 'does not pick a build' do + expect(build).to be_nil + expect(pending_job.reload).to be_failed + expect(pending_job.queuing_entry).to be_nil end end + end - context 'allow group runners' do - before do - project.update!(group_runners_enabled: true) - end + context 'allow group runners' do + before do + project.update!(group_runners_enabled: true) + end - context 'for multiple builds' do - let!(:project2) { create(:project, group_runners_enabled: true, group: group) } - let!(:pipeline2) { create(:ci_pipeline, project: project2) } - let!(:project3) { create(:project, group_runners_enabled: true, group: group) } - let!(:pipeline3) { create(:ci_pipeline, project: project3) } + context 'for multiple builds' do + let!(:project2) { create(:project, group_runners_enabled: true, group: group) } + let!(:pipeline2) { create(:ci_pipeline, project: project2) } + let!(:project3) { create(:project, group_runners_enabled: true, group: group) } + let!(:pipeline3) { create(:ci_pipeline, project: project3) } - let!(:build1_project1) { pending_job } - let!(:build2_project1) { create(:ci_build, :queued, pipeline: pipeline) } - let!(:build3_project1) { create(:ci_build, :queued, pipeline: pipeline) } - let!(:build1_project2) { create(:ci_build, :queued, pipeline: pipeline2) } - let!(:build2_project2) { create(:ci_build, :queued, pipeline: pipeline2) } - let!(:build1_project3) { create(:ci_build, :queued, pipeline: pipeline3) } + let!(:build1_project1) { pending_job } + let!(:build2_project1) { create(:ci_build, :queued, pipeline: pipeline) } + let!(:build3_project1) { create(:ci_build, :queued, pipeline: pipeline) } + let!(:build1_project2) { create(:ci_build, :queued, pipeline: pipeline2) } + let!(:build2_project2) { create(:ci_build, :queued, pipeline: pipeline2) } + let!(:build1_project3) { create(:ci_build, :queued, pipeline: pipeline3) } - # these shouldn't influence the scheduling - let!(:unrelated_group) { create(:group) } - let!(:unrelated_project) { create(:project, group_runners_enabled: true, group: unrelated_group) } - let!(:unrelated_pipeline) { create(:ci_pipeline, project: unrelated_project) } - let!(:build1_unrelated_project) { create(:ci_build, :pending, :queued, pipeline: unrelated_pipeline) } - let!(:unrelated_group_runner) { create(:ci_runner, :group, groups: [unrelated_group]) } + # these shouldn't influence the scheduling + let!(:unrelated_group) { create(:group) } + let!(:unrelated_project) { create(:project, group_runners_enabled: true, group: unrelated_group) } + let!(:unrelated_pipeline) { create(:ci_pipeline, project: unrelated_project) } + let!(:build1_unrelated_project) { create(:ci_build, :pending, :queued, pipeline: unrelated_pipeline) } + let!(:unrelated_group_runner) { create(:ci_runner, :group, groups: [unrelated_group]) } - it 'does not consider builds from other group runners' do - queue = ::Ci::Queue::BuildQueueService.new(group_runner) + it 'does not consider builds from other group runners' do + queue = ::Ci::Queue::BuildQueueService.new(group_runner) - expect(queue.builds_for_group_runner.size).to eq 6 - build_on(group_runner) + expect(queue.builds_for_group_runner.size).to eq 6 + build_on(group_runner) - expect(queue.builds_for_group_runner.size).to eq 5 - build_on(group_runner) + expect(queue.builds_for_group_runner.size).to eq 5 + build_on(group_runner) - expect(queue.builds_for_group_runner.size).to eq 4 - build_on(group_runner) + expect(queue.builds_for_group_runner.size).to eq 4 + build_on(group_runner) - expect(queue.builds_for_group_runner.size).to eq 3 - build_on(group_runner) + expect(queue.builds_for_group_runner.size).to eq 3 + build_on(group_runner) - expect(queue.builds_for_group_runner.size).to eq 2 - build_on(group_runner) + expect(queue.builds_for_group_runner.size).to eq 2 + build_on(group_runner) - expect(queue.builds_for_group_runner.size).to eq 1 - build_on(group_runner) + expect(queue.builds_for_group_runner.size).to eq 1 + build_on(group_runner) - expect(queue.builds_for_group_runner.size).to eq 0 - expect(build_on(group_runner)).to be_nil - end + expect(queue.builds_for_group_runner.size).to eq 0 + expect(build_on(group_runner)).to be_nil end + end - context 'group runner' do - let(:build) { build_on(group_runner) } + context 'group runner' do + let(:build) { build_on(group_runner) } - it { expect(build).to be_kind_of(Build) } - it { expect(build).to be_valid } - it { expect(build).to be_running } - it { expect(build.runner).to eq(group_runner) } - end + it { expect(build).to be_kind_of(Build) } + it { expect(build).to be_valid } + it { expect(build).to be_running } + it { expect(build.runner).to eq(group_runner) } end + end - context 'disallow group runners' do - before do - project.update!(group_runners_enabled: false) + context 'disallow group runners' do + before do + project.update!(group_runners_enabled: false) - pending_job.reload.create_queuing_entry! - end + pending_job.reload.create_queuing_entry! + end - context 'group runner' do - let(:build) { build_on(group_runner) } + context 'group runner' do + let(:build) { build_on(group_runner) } - it { expect(build).to be_nil } - end + it { expect(build).to be_nil } end + end - context 'when first build is stalled' do - before do - allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!).and_call_original - allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!) - .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError) - end + context 'when first build is stalled' do + before do + allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!).and_call_original + allow_any_instance_of(Ci::RegisterJobService).to receive(:assign_runner!) + .with(pending_job, anything).and_raise(ActiveRecord::StaleObjectError) + end - subject { described_class.new(project_runner, nil).execute } + subject { described_class.new(project_runner, nil).execute } - context 'with multiple builds are in queue' do - let!(:other_build) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + context 'with multiple builds are in queue' do + let!(:other_build) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - before do - allow_any_instance_of(::Ci::Queue::BuildQueueService) - .to receive(:execute) - .and_return(Ci::Build.where(id: [pending_job, other_build]).pluck(:id)) - end + before do + allow_any_instance_of(::Ci::Queue::BuildQueueService) + .to receive(:execute) + .and_return(Ci::Build.where(id: [pending_job, other_build]).pluck(:id)) + end - it "receives second build from the queue" do - expect(subject).to be_valid - expect(subject.build).to eq(other_build) - end + it "receives second build from the queue" do + expect(subject).to be_valid + expect(subject.build).to eq(other_build) end + end - context 'when single build is in queue' do - before do - allow_any_instance_of(::Ci::Queue::BuildQueueService) - .to receive(:execute) - .and_return(Ci::Build.where(id: pending_job).pluck(:id)) - end + context 'when single build is in queue' do + before do + allow_any_instance_of(::Ci::Queue::BuildQueueService) + .to receive(:execute) + .and_return(Ci::Build.where(id: pending_job).pluck(:id)) + end - it "does not receive any valid result" do - expect(subject).not_to be_valid - end + it "does not receive any valid result" do + expect(subject).not_to be_valid end + end - context 'when there is no build in queue' do - before do - allow_any_instance_of(::Ci::Queue::BuildQueueService) - .to receive(:execute) - .and_return([]) - end + context 'when there is no build in queue' do + before do + allow_any_instance_of(::Ci::Queue::BuildQueueService) + .to receive(:execute) + .and_return([]) + end - it "does not receive builds but result is valid" do - expect(subject).to be_valid - expect(subject.build).to be_nil - end + it "does not receive builds but result is valid" do + expect(subject).to be_valid + expect(subject.build).to be_nil end end + end - context 'when access_level of runner is not_protected' do - let!(:project_runner) { create(:ci_runner, :project, projects: [project]) } + context 'when access_level of runner is not_protected' do + let!(:project_runner) { create(:ci_runner, :project, projects: [project]) } - context 'when a job is protected' do - let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) } + context 'when a job is protected' do + let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) } - it 'picks the job' do - expect(build_on(project_runner)).to eq(pending_job) - end + it 'picks the job' do + expect(build_on(project_runner)).to eq(pending_job) end + end - context 'when a job is unprotected' do - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + context 'when a job is unprotected' do + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - it 'picks the job' do - expect(build_on(project_runner)).to eq(pending_job) - end + it 'picks the job' do + expect(build_on(project_runner)).to eq(pending_job) end + end - context 'when protected attribute of a job is nil' do - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + context 'when protected attribute of a job is nil' do + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - before do - pending_job.update_attribute(:protected, nil) - end + before do + pending_job.update_attribute(:protected, nil) + end - it 'picks the job' do - expect(build_on(project_runner)).to eq(pending_job) - end + it 'picks the job' do + expect(build_on(project_runner)).to eq(pending_job) end end + end - context 'when access_level of runner is ref_protected' do - let!(:project_runner) { create(:ci_runner, :project, :ref_protected, projects: [project]) } + context 'when access_level of runner is ref_protected' do + let!(:project_runner) { create(:ci_runner, :project, :ref_protected, projects: [project]) } - context 'when a job is protected' do - let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) } + context 'when a job is protected' do + let!(:pending_job) { create(:ci_build, :pending, :queued, :protected, pipeline: pipeline) } - it 'picks the job' do - expect(build_on(project_runner)).to eq(pending_job) - end + it 'picks the job' do + expect(build_on(project_runner)).to eq(pending_job) end + end - context 'when a job is unprotected' do - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + context 'when a job is unprotected' do + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - it 'does not pick the job' do - expect(build_on(project_runner)).to be_nil - end + it 'does not pick the job' do + expect(build_on(project_runner)).to be_nil end + end - context 'when protected attribute of a job is nil' do - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + context 'when protected attribute of a job is nil' do + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - before do - pending_job.update_attribute(:protected, nil) - end + before do + pending_job.update_attribute(:protected, nil) + end - it 'does not pick the job' do - expect(build_on(project_runner)).to be_nil - end + it 'does not pick the job' do + expect(build_on(project_runner)).to be_nil end end + end - context 'runner feature set is verified' do - let(:options) { { artifacts: { reports: { junit: "junit.xml" } } } } - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) } + context 'runner feature set is verified' do + let(:options) { { artifacts: { reports: { junit: "junit.xml" } } } } + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) } - subject { build_on(project_runner, params: params) } + subject { build_on(project_runner, params: params) } - context 'when feature is missing by runner' do - let(:params) { {} } + context 'when feature is missing by runner' do + let(:params) { {} } - it 'does not pick the build and drops the build' do - expect(subject).to be_nil - expect(pending_job.reload).to be_failed - expect(pending_job).to be_runner_unsupported - end + it 'does not pick the build and drops the build' do + expect(subject).to be_nil + expect(pending_job.reload).to be_failed + expect(pending_job).to be_runner_unsupported end + end - context 'when feature is supported by runner' do - let(:params) do - { info: { features: { upload_multiple_artifacts: true } } } - end + context 'when feature is supported by runner' do + let(:params) do + { info: { features: { upload_multiple_artifacts: true } } } + end - it 'does pick job' do - expect(subject).not_to be_nil - end + it 'does pick job' do + expect(subject).not_to be_nil end end + end - context 'when "dependencies" keyword is specified' do - let!(:pre_stage_job) do - create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'test', stage_idx: 0) - end + context 'when "dependencies" keyword is specified' do + let!(:pre_stage_job) do + create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'test', stage_idx: 0) + end - let!(:pending_job) do - create(:ci_build, :pending, :queued, - pipeline: pipeline, stage_idx: 1, - options: { script: ["bash"], dependencies: dependencies }) - end + let!(:pending_job) do + create(:ci_build, :pending, :queued, + pipeline: pipeline, stage_idx: 1, + options: { script: ["bash"], dependencies: dependencies }) + end - let(:dependencies) { %w[test] } + let(:dependencies) { %w[test] } - subject { build_on(project_runner) } + subject { build_on(project_runner) } - it 'picks a build with a dependency' do - picked_build = build_on(project_runner) + it 'picks a build with a dependency' do + picked_build = build_on(project_runner) - expect(picked_build).to be_present + expect(picked_build).to be_present + end + + context 'when there are multiple dependencies with artifacts' do + let!(:pre_stage_job_second) do + create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'deploy', stage_idx: 0) end - context 'when there are multiple dependencies with artifacts' do - let!(:pre_stage_job_second) do - create(:ci_build, :success, :artifacts, pipeline: pipeline, name: 'deploy', stage_idx: 0) - end + let(:dependencies) { %w[test deploy] } - let(:dependencies) { %w[test deploy] } + it 'logs build artifacts size' do + build_on(project_runner) - it 'logs build artifacts size' do - build_on(project_runner) + artifacts_size = [pre_stage_job, pre_stage_job_second].sum do |job| + job.job_artifacts_archive.size + end - artifacts_size = [pre_stage_job, pre_stage_job_second].sum do |job| - job.job_artifacts_archive.size - end + expect(artifacts_size).to eq 107464 * 2 + expect(Gitlab::ApplicationContext.current).to include({ + 'meta.artifacts_dependencies_size' => artifacts_size, + 'meta.artifacts_dependencies_count' => 2 + }) + end + end - expect(artifacts_size).to eq 107464 * 2 - expect(Gitlab::ApplicationContext.current).to include({ - 'meta.artifacts_dependencies_size' => artifacts_size, - 'meta.artifacts_dependencies_count' => 2 - }) - end + shared_examples 'not pick' do + it 'does not pick the build and drops the build' do + expect(subject).to be_nil + expect(pending_job.reload).to be_failed + expect(pending_job).to be_missing_dependency_failure end + end - shared_examples 'not pick' do - it 'does not pick the build and drops the build' do - expect(subject).to be_nil - expect(pending_job.reload).to be_failed - expect(pending_job).to be_missing_dependency_failure + shared_examples 'validation is active' do + context 'when depended job has not been completed yet' do + let!(:pre_stage_job) do + create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0) end - end - shared_examples 'validation is active' do - context 'when depended job has not been completed yet' do - let!(:pre_stage_job) do - create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0) - end + it { is_expected.to eq(pending_job) } + end - it { is_expected.to eq(pending_job) } + context 'when artifacts of depended job has been expired' do + let!(:pre_stage_job) do + create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0) end - context 'when artifacts of depended job has been expired' do - let!(:pre_stage_job) do - create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0) + context 'when the pipeline is locked' do + before do + pipeline.artifacts_locked! end - context 'when the pipeline is locked' do - before do - pipeline.artifacts_locked! - end + it { is_expected.to eq(pending_job) } + end - it { is_expected.to eq(pending_job) } + context 'when the pipeline is unlocked' do + before do + pipeline.unlocked! end - context 'when the pipeline is unlocked' do - before do - pipeline.unlocked! - end + it_behaves_like 'not pick' + end + end - it_behaves_like 'not pick' - end + context 'when artifacts of depended job has been erased' do + let!(:pre_stage_job) do + create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago) end - context 'when artifacts of depended job has been erased' do - let!(:pre_stage_job) do - create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago) - end + it_behaves_like 'not pick' + end - it_behaves_like 'not pick' + context 'when job object is staled' do + let!(:pre_stage_job) do + create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0) end - context 'when job object is staled' do - let!(:pre_stage_job) do - create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0) - end - - before do - pipeline.unlocked! + before do + pipeline.unlocked! - allow_next_instance_of(Ci::Build) do |build| - expect(build).to receive(:drop!) - .and_raise(ActiveRecord::StaleObjectError.new(pending_job, :drop!)) - end + allow_next_instance_of(Ci::Build) do |build| + expect(build).to receive(:drop!) + .and_raise(ActiveRecord::StaleObjectError.new(pending_job, :drop!)) end + end - it 'does not drop nor pick' do - expect(subject).to be_nil - end + it 'does not drop nor pick' do + expect(subject).to be_nil end end + end - shared_examples 'validation is not active' do - context 'when depended job has not been completed yet' do - let!(:pre_stage_job) do - create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0) - end - - it { expect(subject).to eq(pending_job) } + shared_examples 'validation is not active' do + context 'when depended job has not been completed yet' do + let!(:pre_stage_job) do + create(:ci_build, :pending, :queued, :manual, pipeline: pipeline, name: 'test', stage_idx: 0) end - context 'when artifacts of depended job has been expired' do - let!(:pre_stage_job) do - create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0) - end + it { expect(subject).to eq(pending_job) } + end - it { expect(subject).to eq(pending_job) } + context 'when artifacts of depended job has been expired' do + let!(:pre_stage_job) do + create(:ci_build, :success, :expired, pipeline: pipeline, name: 'test', stage_idx: 0) end - context 'when artifacts of depended job has been erased' do - let!(:pre_stage_job) do - create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago) - end + it { expect(subject).to eq(pending_job) } + end - it { expect(subject).to eq(pending_job) } + context 'when artifacts of depended job has been erased' do + let!(:pre_stage_job) do + create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0, erased_at: 1.minute.ago) end - end - it_behaves_like 'validation is active' + it { expect(subject).to eq(pending_job) } + end end - context 'when build is degenerated' do - let!(:pending_job) { create(:ci_build, :pending, :queued, :degenerated, pipeline: pipeline) } + it_behaves_like 'validation is active' + end - subject { build_on(project_runner) } + context 'when build is degenerated' do + let!(:pending_job) { create(:ci_build, :pending, :queued, :degenerated, pipeline: pipeline) } - it 'does not pick the build and drops the build' do - expect(subject).to be_nil + subject { build_on(project_runner) } - pending_job.reload - expect(pending_job).to be_failed - expect(pending_job).to be_archived_failure - end + it 'does not pick the build and drops the build' do + expect(subject).to be_nil + + pending_job.reload + expect(pending_job).to be_failed + expect(pending_job).to be_archived_failure end + end - context 'when build has data integrity problem' do - let!(:pending_job) do - create(:ci_build, :pending, :queued, pipeline: pipeline) - end + context 'when build has data integrity problem' do + let!(:pending_job) do + create(:ci_build, :pending, :queued, pipeline: pipeline) + end - before do - pending_job.update_columns(options: "string") - end + before do + pending_job.update_columns(options: "string") + end - subject { build_on(project_runner) } + subject { build_on(project_runner) } - it 'does drop the build and logs both failures' do - expect(Gitlab::ErrorTracking).to receive(:track_exception) - .with(anything, a_hash_including(build_id: pending_job.id)) - .twice - .and_call_original + it 'does drop the build and logs both failures' do + expect(Gitlab::ErrorTracking).to receive(:track_exception) + .with(anything, a_hash_including(build_id: pending_job.id)) + .twice + .and_call_original - expect(subject).to be_nil + expect(subject).to be_nil - pending_job.reload - expect(pending_job).to be_failed - expect(pending_job).to be_data_integrity_failure - end + pending_job.reload + expect(pending_job).to be_failed + expect(pending_job).to be_data_integrity_failure end + end - context 'when build fails to be run!' do - let!(:pending_job) do - create(:ci_build, :pending, :queued, pipeline: pipeline) - end + context 'when build fails to be run!' do + let!(:pending_job) do + create(:ci_build, :pending, :queued, pipeline: pipeline) + end - before do - expect_any_instance_of(Ci::Build).to receive(:run!) - .and_raise(RuntimeError, 'scheduler error') - end + before do + expect_any_instance_of(Ci::Build).to receive(:run!) + .and_raise(RuntimeError, 'scheduler error') + end - subject { build_on(project_runner) } + subject { build_on(project_runner) } - it 'does drop the build and logs failure' do - expect(Gitlab::ErrorTracking).to receive(:track_exception) - .with(anything, a_hash_including(build_id: pending_job.id)) - .once - .and_call_original + it 'does drop the build and logs failure' do + expect(Gitlab::ErrorTracking).to receive(:track_exception) + .with(anything, a_hash_including(build_id: pending_job.id)) + .once + .and_call_original - expect(subject).to be_nil + expect(subject).to be_nil - pending_job.reload - expect(pending_job).to be_failed - expect(pending_job).to be_scheduler_failure - end + pending_job.reload + expect(pending_job).to be_failed + expect(pending_job).to be_scheduler_failure end + end - context 'when an exception is raised during a persistent ref creation' do - before do - allow_any_instance_of(Ci::PersistentRef).to receive(:exist?) { false } - allow_any_instance_of(Ci::PersistentRef).to receive(:create_ref) { raise ArgumentError } - end + context 'when an exception is raised during a persistent ref creation' do + before do + allow_any_instance_of(Ci::PersistentRef).to receive(:exist?) { false } + allow_any_instance_of(Ci::PersistentRef).to receive(:create_ref) { raise ArgumentError } + end - subject { build_on(project_runner) } + subject { build_on(project_runner) } - it 'picks the build' do - expect(subject).to eq(pending_job) + it 'picks the build' do + expect(subject).to eq(pending_job) - pending_job.reload - expect(pending_job).to be_running - end + pending_job.reload + expect(pending_job).to be_running end + end - context 'when only some builds can be matched by runner' do - let!(:project_runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[matching]) } - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[matching]) } + context 'when only some builds can be matched by runner' do + let!(:project_runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[matching]) } + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[matching]) } - before do - # create additional matching and non-matching jobs - create_list(:ci_build, 2, :pending, :queued, pipeline: pipeline, tag_list: %w[matching]) - create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[non-matching]) - end + before do + # create additional matching and non-matching jobs + create_list(:ci_build, 2, :pending, :queued, pipeline: pipeline, tag_list: %w[matching]) + create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[non-matching]) + end - 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({ runner_type: project_runner.runner_type }, 3) + 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({ runner_type: project_runner.runner_type }, 3) - expect(build_on(project_runner)).to eq(pending_job) - end + expect(build_on(project_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: project_runner.runner_type }, anything) + 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: project_runner.runner_type }, anything) - expect(Gitlab::Ci::Queue::Metrics.queue_retrieval_duration_seconds) - .to receive(:observe) - .with({ runner_type: project_runner.runner_type }, anything) + expect(Gitlab::Ci::Queue::Metrics.queue_retrieval_duration_seconds) + .to receive(:observe) + .with({ runner_type: project_runner.runner_type }, anything) - expect(build_on(project_runner)).to eq(pending_job) - end + expect(build_on(project_runner)).to eq(pending_job) end + end - context 'when ci_register_job_temporary_lock is enabled' do - before do - stub_feature_flags(ci_register_job_temporary_lock: true) + context 'when ci_register_job_temporary_lock is enabled' do + before do + stub_feature_flags(ci_register_job_temporary_lock: true) + + allow(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) + end - allow(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) + context 'when a build is temporarily locked' do + let(:service) { described_class.new(project_runner, nil) } + + before do + service.send(:acquire_temporary_lock, pending_job.id) end - context 'when a build is temporarily locked' do - let(:service) { described_class.new(project_runner, nil) } + it 'skips this build and marks queue as invalid' do + expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) + .with(operation: :queue_iteration) + expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) + .with(operation: :build_temporary_locked) - before do - service.send(:acquire_temporary_lock, pending_job.id) - end + expect(service.execute).not_to be_valid + end - it 'skips this build and marks queue as invalid' do + context 'when there is another build in queue' do + let!(:next_pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } + + it 'skips this build and picks another build' do expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) - .with(operation: :queue_iteration) + .with(operation: :queue_iteration).twice expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) .with(operation: :build_temporary_locked) - expect(service.execute).not_to be_valid - end - - context 'when there is another build in queue' do - let!(:next_pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline) } - - it 'skips this build and picks another build' do - expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) - .with(operation: :queue_iteration).twice - expect(Gitlab::Ci::Queue::Metrics.queue_operations_total).to receive(:increment) - .with(operation: :build_temporary_locked) + result = service.execute - result = service.execute - - expect(result.build).to eq(next_pending_job) - expect(result).to be_valid - end + expect(result.build).to eq(next_pending_job) + expect(result).to be_valid end end end end + end - context 'when using pending builds table' do - include_examples 'handles runner assignment' + context 'when using pending builds table' do + let!(:runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[conflict]) } - context 'when a conflicting data is stored in denormalized table' do - let!(:runner) { create(:ci_runner, :project, projects: [project], tag_list: %w[conflict]) } - let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[conflict]) } + include_examples 'handles runner assignment' - before do - pending_job.update_column(:status, :running) - end + context 'when a conflicting data is stored in denormalized table' do + let!(:pending_job) { create(:ci_build, :pending, :queued, pipeline: pipeline, tag_list: %w[conflict]) } - it 'removes queuing entry upon build assignment attempt' do - expect(pending_job.reload).to be_running - expect(pending_job.queuing_entry).to be_present + before do + pending_job.update_column(:status, :running) + end - expect(execute).not_to be_valid - expect(pending_job.reload.queuing_entry).not_to be_present - end + it 'removes queuing entry upon build assignment attempt' do + expect(pending_job.reload).to be_running + expect(pending_job.queuing_entry).to be_present + + expect(execute).not_to be_valid + expect(pending_job.reload.queuing_entry).not_to be_present end end end diff --git a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb index 3d1abe290bc..ea15e3ea2c0 100644 --- a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb +++ b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do +RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService, feature_category: :continuous_integration do include ConcurrentHelpers let_it_be(:project) { create(:project) } diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 07518c35fab..51a894640ab 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::RetryPipelineService, '#execute' do +RSpec.describe Ci::RetryPipelineService, '#execute', feature_category: :continuous_integration do include ProjectForksHelper let_it_be_with_refind(:user) { create(:user) } diff --git a/spec/services/ci/run_scheduled_build_service_spec.rb b/spec/services/ci/run_scheduled_build_service_spec.rb index 27d25e88944..e3ae1d93e5e 100644 --- a/spec/services/ci/run_scheduled_build_service_spec.rb +++ b/spec/services/ci/run_scheduled_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::RunScheduledBuildService do +RSpec.describe Ci::RunScheduledBuildService, feature_category: :continuous_integration do let(:user) { create(:user) } let(:project) { create(:project) } let(:pipeline) { create(:ci_pipeline, project: project) } diff --git a/spec/services/ci/runners/create_runner_service_spec.rb b/spec/services/ci/runners/create_runner_service_spec.rb index 673bf3ef90e..52acfcbb7af 100644 --- a/spec/services/ci/runners/create_runner_service_spec.rb +++ b/spec/services/ci/runners/create_runner_service_spec.rb @@ -83,6 +83,49 @@ RSpec.describe ::Ci::Runners::CreateRunnerService, "#execute", feature_category: expect(runner.authenticated_user_registration_type?).to be_truthy expect(runner.runner_type).to eq 'instance_type' end + + context 'with a nil paused value' do + let(:args) do + { + paused: nil, + description: 'some description', + maintenance_note: 'a note', + tag_list: %w[tag1 tag2], + access_level: 'ref_protected', + locked: true, + maximum_timeout: 600, + run_untagged: false + } + end + + it { is_expected.to be_success } + + it 'creates runner with active set to true' do + expect(runner).to be_an_instance_of(::Ci::Runner) + expect(runner.active).to eq true + end + end + + context 'with no paused value given' do + let(:args) do + { + description: 'some description', + maintenance_note: 'a note', + tag_list: %w[tag1 tag2], + access_level: 'ref_protected', + locked: true, + maximum_timeout: 600, + run_untagged: false + } + end + + it { is_expected.to be_success } + + it 'creates runner with active set to true' do + expect(runner).to be_an_instance_of(::Ci::Runner) + expect(runner.active).to eq true + end + end end end diff --git a/spec/services/ci/runners/process_runner_version_update_service_spec.rb b/spec/services/ci/runners/process_runner_version_update_service_spec.rb index e62cb1ec3e3..f8b7aa281af 100644 --- a/spec/services/ci/runners/process_runner_version_update_service_spec.rb +++ b/spec/services/ci/runners/process_runner_version_update_service_spec.rb @@ -29,6 +29,19 @@ RSpec.describe Ci::Runners::ProcessRunnerVersionUpdateService, feature_category: end end + context 'when fetching runner releases is disabled' do + before do + stub_application_setting(update_runner_versions_enabled: false) + end + + it 'does not update ci_runner_versions records', :aggregate_failures do + expect do + expect(execute).to be_error + expect(execute.message).to eq 'version update disabled' + end.not_to change(Ci::RunnerVersion, :count).from(0) + end + end + context 'with successful result from upgrade check' do before do url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url diff --git a/spec/services/ci/stuck_builds/drop_pending_service_spec.rb b/spec/services/ci/stuck_builds/drop_pending_service_spec.rb index a452a65829a..6d91f5098eb 100644 --- a/spec/services/ci/stuck_builds/drop_pending_service_spec.rb +++ b/spec/services/ci/stuck_builds/drop_pending_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::StuckBuilds::DropPendingService do +RSpec.describe Ci::StuckBuilds::DropPendingService, feature_category: :runner_fleet do let_it_be(:runner) { create(:ci_runner) } let_it_be(:pipeline) { create(:ci_empty_pipeline) } let_it_be_with_reload(:job) do diff --git a/spec/services/ci/stuck_builds/drop_running_service_spec.rb b/spec/services/ci/stuck_builds/drop_running_service_spec.rb index c1c92c2b8e2..deb807753c2 100644 --- a/spec/services/ci/stuck_builds/drop_running_service_spec.rb +++ b/spec/services/ci/stuck_builds/drop_running_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::StuckBuilds::DropRunningService do +RSpec.describe Ci::StuckBuilds::DropRunningService, feature_category: :runner_fleet do let!(:runner) { create :ci_runner } let!(:job) { create(:ci_build, runner: runner, created_at: created_at, updated_at: updated_at, status: status) } diff --git a/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb b/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb index a4f9f97fffc..f2e658c3ae3 100644 --- a/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb +++ b/spec/services/ci/stuck_builds/drop_scheduled_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::StuckBuilds::DropScheduledService do +RSpec.describe Ci::StuckBuilds::DropScheduledService, feature_category: :runner_fleet do let_it_be(:runner) { create :ci_runner } let!(:job) { create :ci_build, :scheduled, scheduled_at: scheduled_at, runner: runner } diff --git a/spec/services/ci/test_failure_history_service_spec.rb b/spec/services/ci/test_failure_history_service_spec.rb index 10f6c6f5007..e77c6533483 100644 --- a/spec/services/ci/test_failure_history_service_spec.rb +++ b/spec/services/ci/test_failure_history_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do +RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures, feature_category: :continuous_integration do let_it_be(:project) { create(:project, :repository) } let_it_be_with_reload(:pipeline) do diff --git a/spec/services/ci/track_failed_build_service_spec.rb b/spec/services/ci/track_failed_build_service_spec.rb index 676769d2fc7..23e7cee731d 100644 --- a/spec/services/ci/track_failed_build_service_spec.rb +++ b/spec/services/ci/track_failed_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::TrackFailedBuildService do +RSpec.describe Ci::TrackFailedBuildService, feature_category: :continuous_integration do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :public) } let_it_be(:pipeline) { create(:ci_pipeline, project: project, user: user) } diff --git a/spec/services/ci/unlock_artifacts_service_spec.rb b/spec/services/ci/unlock_artifacts_service_spec.rb index c15e1cb2b5d..1921ea4bdba 100644 --- a/spec/services/ci/unlock_artifacts_service_spec.rb +++ b/spec/services/ci/unlock_artifacts_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::UnlockArtifactsService do +RSpec.describe Ci::UnlockArtifactsService, feature_category: :continuous_integration do using RSpec::Parameterized::TableSyntax where(:tag) do @@ -24,7 +24,7 @@ RSpec.describe Ci::UnlockArtifactsService do let!(:older_ambiguous_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: !tag, project: project, locked: :artifacts_locked) } let!(:code_coverage_pipeline) { create(:ci_pipeline, :with_coverage_report_artifact, ref: ref, tag: tag, project: project, locked: :artifacts_locked) } let!(:pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, project: project, locked: :artifacts_locked) } - let!(:child_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, project: project, locked: :artifacts_locked) } + let!(:child_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, child_of: pipeline, project: project, locked: :artifacts_locked) } let!(:newer_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: ref, tag: tag, project: project, locked: :artifacts_locked) } let!(:other_ref_pipeline) { create(:ci_pipeline, :with_persisted_artifacts, ref: 'other_ref', tag: tag, project: project, locked: :artifacts_locked) } let!(:sources_pipeline) { create(:ci_sources_pipeline, source_job: source_job, source_project: project, pipeline: child_pipeline, project: project) } @@ -201,8 +201,7 @@ RSpec.describe Ci::UnlockArtifactsService do describe '#unlock_job_artifacts_query' do subject { described_class.new(pipeline.project, pipeline.user).unlock_job_artifacts_query(pipeline_ids) } - context 'when running on a ref before a pipeline' do - let(:before_pipeline) { pipeline } + context 'when given a single pipeline ID' do let(:pipeline_ids) { [older_pipeline.id] } it 'produces the expected SQL string' do @@ -226,8 +225,7 @@ RSpec.describe Ci::UnlockArtifactsService do end end - context 'when running on just the ref' do - let(:before_pipeline) { nil } + context 'when given multiple pipeline IDs' do let(:pipeline_ids) { [older_pipeline.id, newer_pipeline.id, pipeline.id] } it 'produces the expected SQL string' do diff --git a/spec/services/ci/update_build_queue_service_spec.rb b/spec/services/ci/update_build_queue_service_spec.rb index dd26339831c..4fd4492278d 100644 --- a/spec/services/ci/update_build_queue_service_spec.rb +++ b/spec/services/ci/update_build_queue_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::UpdateBuildQueueService do +RSpec.describe Ci::UpdateBuildQueueService, feature_category: :continuous_integration do let(:project) { create(:project, :repository) } let(:pipeline) { create(:ci_pipeline, project: project) } let(:build) { create(:ci_build, pipeline: pipeline) } diff --git a/spec/services/ci/update_instance_variables_service_spec.rb b/spec/services/ci/update_instance_variables_service_spec.rb index f235d006e34..19f28793f90 100644 --- a/spec/services/ci/update_instance_variables_service_spec.rb +++ b/spec/services/ci/update_instance_variables_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::UpdateInstanceVariablesService do +RSpec.describe Ci::UpdateInstanceVariablesService, feature_category: :pipeline_composition do let(:params) { { variables_attributes: variables_attributes } } subject { described_class.new(params) } diff --git a/spec/services/ci/update_pending_build_service_spec.rb b/spec/services/ci/update_pending_build_service_spec.rb index e49b22299f0..abf31dd5184 100644 --- a/spec/services/ci/update_pending_build_service_spec.rb +++ b/spec/services/ci/update_pending_build_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Ci::UpdatePendingBuildService do +RSpec.describe Ci::UpdatePendingBuildService, feature_category: :continuous_integration do let_it_be(:group) { create(:group) } let_it_be(:project) { create(:project, namespace: group) } let_it_be_with_reload(:pending_build_1) { create(:ci_pending_build, project: project, instance_runners_enabled: false) } -- cgit v1.2.3