From 6438df3a1e0fb944485cebf07976160184697d72 Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Wed, 20 Jan 2021 13:34:23 -0600 Subject: Add latest changes from gitlab-org/gitlab@13-8-stable-ee --- .../ci/build_report_result_service_spec.rb | 6 -- .../ci/create_downstream_pipeline_service_spec.rb | 47 +++++++++++++ .../ci/create_pipeline_service/dry_run_spec.rb | 2 +- spec/services/ci/create_pipeline_service_spec.rb | 73 ++++++++----------- .../destroy_expired_job_artifacts_service_spec.rb | 76 ++++++++------------ .../coverage_report_service_spec.rb | 58 ++++++++++++++++ .../destroy_expired_artifacts_service_spec.rb | 81 ++++++++++++++++++++++ ...uild_fails_deploy_is_delayed_and_needs_test.yml | 41 +++++++++++ ...build_fails_deploy_is_manual_and_needs_test.yml | 40 +++++++++++ spec/services/ci/pipeline_trigger_service_spec.rb | 14 ++-- .../ci/pipelines/create_artifact_service_spec.rb | 58 ---------------- spec/services/ci/play_build_service_spec.rb | 25 +++++++ spec/services/ci/process_build_service_spec.rb | 40 ++++++++--- spec/services/ci/retry_build_service_spec.rb | 16 +++++ spec/services/ci/retry_pipeline_service_spec.rb | 22 ++++++ .../ci/test_failure_history_service_spec.rb | 21 ------ .../services/ci/update_build_state_service_spec.rb | 21 +++++- 17 files changed, 446 insertions(+), 195 deletions(-) create mode 100644 spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb create mode 100644 spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb create mode 100644 spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_delayed_and_needs_test.yml create mode 100644 spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_manual_and_needs_test.yml delete mode 100644 spec/services/ci/pipelines/create_artifact_service_spec.rb (limited to 'spec/services/ci') diff --git a/spec/services/ci/build_report_result_service_spec.rb b/spec/services/ci/build_report_result_service_spec.rb index 244ffbf4bbd..7c2702af086 100644 --- a/spec/services/ci/build_report_result_service_spec.rb +++ b/spec/services/ci/build_report_result_service_spec.rb @@ -6,12 +6,6 @@ RSpec.describe Ci::BuildReportResultService do describe '#execute', :clean_gitlab_redis_shared_state do subject(:build_report_result) { described_class.new.execute(build) } - around do |example| - travel_to(DateTime.parse('2020-07-01')) do - example.run - end - end - context 'when build is finished' do let(:build) { create(:ci_build, :success, :test_reports) } diff --git a/spec/services/ci/create_downstream_pipeline_service_spec.rb b/spec/services/ci/create_downstream_pipeline_service_spec.rb index 03cea4074bf..860932d4fde 100644 --- a/spec/services/ci/create_downstream_pipeline_service_spec.rb +++ b/spec/services/ci/create_downstream_pipeline_service_spec.rb @@ -371,6 +371,26 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do expect { service.execute(bridge) }.to change { Ci::Pipeline.count }.by(1) end end + + context 'when downstream project does not allow user-defined variables for child pipelines' do + before do + bridge.yaml_variables = [{ key: 'BRIDGE', value: '$PIPELINE_VARIABLE-var', public: true }] + + upstream_pipeline.project.update!(restrict_user_defined_variables: true) + end + + it 'creates a new pipeline allowing variables to be passed downstream' do + expect { service.execute(bridge) }.to change { Ci::Pipeline.count }.by(1) + end + + it 'passes variables downstream from the bridge' do + pipeline = service.execute(bridge) + + pipeline.variables.map(&:key).tap do |variables| + expect(variables).to include 'BRIDGE' + end + end + end end end @@ -460,6 +480,33 @@ RSpec.describe Ci::CreateDownstreamPipelineService, '#execute' do expect(variable.value).to eq 'my-value-var' end end + + context 'when downstream project does not allow user-defined variables for multi-project pipelines' do + before do + downstream_project.update!(restrict_user_defined_variables: true) + end + + it 'does not create a new pipeline' do + expect { service.execute(bridge) } + .not_to change { Ci::Pipeline.count } + end + + it 'ignores variables passed downstream from the bridge' do + pipeline = service.execute(bridge) + + pipeline.variables.map(&:key).tap do |variables| + expect(variables).not_to include 'BRIDGE' + end + end + + it 'sets errors', :aggregate_failures do + service.execute(bridge) + + expect(bridge.reload).to be_failed + expect(bridge.failure_reason).to eq('downstream_pipeline_creation_failed') + expect(bridge.options[:downstream_errors]).to eq(['Insufficient permissions to set pipeline variables']) + end + end end end 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 60c56ed0f67..c21a4ef0917 100644 --- a/spec/services/ci/create_pipeline_service/dry_run_spec.rb +++ b/spec/services/ci/create_pipeline_service/dry_run_spec.rb @@ -108,7 +108,7 @@ RSpec.describe Ci::CreatePipelineService do it_behaves_like 'returns a non persisted pipeline' it 'returns a pipeline with errors', :aggregate_failures do - error_message = "test: needs 'build'" + error_message = "'test' job needs 'build' job, but it was not added to the pipeline" expect(subject.error_messages.map(&:content)).to eq([error_message]) expect(subject.errors).not_to be_empty diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index f9015752644..e1f1bdc41a1 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -91,6 +91,23 @@ RSpec.describe Ci::CreatePipelineService do .with({ source: 'push' }, 5) end + it 'tracks included template usage' do + expect_next_instance_of(Gitlab::Ci::Pipeline::Chain::TemplateUsage) do |instance| + expect(instance).to receive(:perform!) + end + + execute_service + end + + describe 'recording a conversion event' do + it 'schedules a record conversion event worker' do + expect(Experiments::RecordConversionEventWorker).to receive(:perform_async).with(:ci_syntax_templates, user.id) + expect(Experiments::RecordConversionEventWorker).to receive(:perform_async).with(:pipelines_empty_state, user.id) + + pipeline + end + end + context 'when merge requests already exist for this source branch' do let(:merge_request_1) do create(:merge_request, source_branch: 'feature', target_branch: "master", source_project: project) @@ -481,6 +498,7 @@ RSpec.describe Ci::CreatePipelineService do expect(execute_service).not_to be_persisted expect(Ci::Pipeline.count).to eq(0) + expect(Namespaces::OnboardingPipelineCreatedWorker).not_to receive(:perform_async) end shared_examples 'a failed pipeline' do @@ -1418,6 +1436,13 @@ RSpec.describe Ci::CreatePipelineService do pipeline end + it 'schedules a namespace onboarding create action worker' do + expect(Namespaces::OnboardingPipelineCreatedWorker) + .to receive(:perform_async).with(project.namespace_id) + + pipeline + end + context 'when target sha is specified' do let(:target_sha) { merge_request.target_branch_sha } @@ -1688,9 +1713,11 @@ RSpec.describe Ci::CreatePipelineService do shared_examples 'has errors' do it 'contains the expected errors' do expect(pipeline.builds).to be_empty - expect(pipeline.yaml_errors).to eq("test_a: needs 'build_a'") - expect(pipeline.error_messages.map(&:content)).to contain_exactly("test_a: needs 'build_a'") - expect(pipeline.errors[:base]).to contain_exactly("test_a: needs 'build_a'") + + error_message = "'test_a' job needs 'build_a' job, but it was not added to the pipeline" + expect(pipeline.yaml_errors).to eq(error_message) + expect(pipeline.error_messages.map(&:content)).to contain_exactly(error_message) + expect(pipeline.errors[:base]).to contain_exactly(error_message) end end @@ -2385,16 +2412,6 @@ RSpec.describe Ci::CreatePipelineService do expect(build_names).to contain_exactly('regular-job') end - context 'when FF ci_seed_block_run_before_workflow_rules is disabled' do - before do - stub_feature_flags(ci_seed_block_run_before_workflow_rules: false) - end - - it 'does not a pipeline' do - expect(pipeline).not_to be_persisted - end - end - context 'when a job requires the same variable' do let(:config) do <<-EOY @@ -2423,16 +2440,6 @@ RSpec.describe Ci::CreatePipelineService do expect(pipeline).to be_persisted expect(build_names).to contain_exactly('build', 'test1', 'test2') end - - context 'when FF ci_seed_block_run_before_workflow_rules is disabled' do - before do - stub_feature_flags(ci_seed_block_run_before_workflow_rules: false) - end - - it 'does not a pipeline' do - expect(pipeline).not_to be_persisted - end - end end end @@ -2443,16 +2450,6 @@ RSpec.describe Ci::CreatePipelineService do expect(pipeline).not_to be_persisted end - context 'when FF ci_seed_block_run_before_workflow_rules is disabled' do - before do - stub_feature_flags(ci_seed_block_run_before_workflow_rules: false) - end - - it 'does not create a pipeline' do - expect(pipeline).not_to be_persisted - end - end - context 'when a job requires the same variable' do let(:config) do <<-EOY @@ -2480,16 +2477,6 @@ RSpec.describe Ci::CreatePipelineService do it 'does not create a pipeline' do expect(pipeline).not_to be_persisted end - - context 'when FF ci_seed_block_run_before_workflow_rules is disabled' do - before do - stub_feature_flags(ci_seed_block_run_before_workflow_rules: false) - end - - it 'does not create a pipeline' do - expect(pipeline).not_to be_persisted - end - end end end end diff --git a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb b/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb index c8d426ee657..1edcef2977b 100644 --- a/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb +++ b/spec/services/ci/destroy_expired_job_artifacts_service_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared describe '.execute' do subject { service.execute } - let_it_be(:artifact, reload: true) do + let_it_be(:artifact, refind: true) do create(:ci_job_artifact, expire_at: 1.day.ago) end @@ -30,14 +30,16 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared it 'performs the smallest number of queries for job_artifacts' do log = ActiveRecord::QueryRecorder.new { subject } - # SELECT expired ci_job_artifacts + # SELECT expired ci_job_artifacts - 3 queries from each_batch # PRELOAD projects, routes, project_statistics # BEGIN # INSERT into ci_deleted_objects # DELETE loaded ci_job_artifacts # DELETE security_findings -- for EE # COMMIT - expect(log.count).to be_within(1).of(8) + # SELECT next expired ci_job_artifacts + + expect(log.count).to be_within(1).of(11) end end @@ -162,13 +164,21 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared end context 'when timeout happens' do + let!(:second_artifact) { create(:ci_job_artifact, expire_at: 1.day.ago) } + before do - stub_const('Ci::DestroyExpiredJobArtifactsService::LOOP_TIMEOUT', 1.second) - allow_any_instance_of(described_class).to receive(:destroy_artifacts_batch) { true } + stub_const('Ci::DestroyExpiredJobArtifactsService::LOOP_TIMEOUT', 0.seconds) + stub_const('Ci::DestroyExpiredJobArtifactsService::BATCH_SIZE', 1) + + second_artifact.job.pipeline.unlocked! + end + + it 'destroys one artifact' do + expect { subject }.to change { Ci::JobArtifact.count }.by(-1) end - it 'returns false and does not continue destroying' do - is_expected.to be_falsy + it 'reports the number of destroyed artifacts' do + is_expected.to eq(1) end end @@ -182,13 +192,13 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared let!(:second_artifact) { create(:ci_job_artifact, expire_at: 1.day.ago) } - it 'raises an error and does not continue destroying' do - is_expected.to be_falsy - end - it 'destroys one artifact' do expect { subject }.to change { Ci::JobArtifact.count }.by(-1) end + + it 'reports the number of destroyed artifacts' do + is_expected.to eq(1) + end end context 'when there are no artifacts' do @@ -199,6 +209,10 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared it 'does not raise error' do expect { subject }.not_to raise_error end + + it 'reports the number of destroyed artifacts' do + is_expected.to eq(0) + end end context 'when there are artifacts more than batch sizes' do @@ -213,33 +227,9 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared it 'destroys all expired artifacts' do expect { subject }.to change { Ci::JobArtifact.count }.by(-2) end - end - - context 'when artifact is a pipeline artifact' do - context 'when artifacts are expired' do - let!(:pipeline_artifact_1) { create(:ci_pipeline_artifact, expire_at: 1.week.ago) } - let!(:pipeline_artifact_2) { create(:ci_pipeline_artifact, expire_at: 1.week.ago) } - before do - [pipeline_artifact_1, pipeline_artifact_2].each { |pipeline_artifact| pipeline_artifact.pipeline.unlocked! } - end - - it 'destroys pipeline artifacts' do - expect { subject }.to change { Ci::PipelineArtifact.count }.by(-2) - end - end - - context 'when artifacts are not expired' do - let!(:pipeline_artifact_1) { create(:ci_pipeline_artifact, expire_at: 2.days.from_now) } - let!(:pipeline_artifact_2) { create(:ci_pipeline_artifact, expire_at: 2.days.from_now) } - - before do - [pipeline_artifact_1, pipeline_artifact_2].each { |pipeline_artifact| pipeline_artifact.pipeline.unlocked! } - end - - it 'does not destroy pipeline artifacts' do - expect { subject }.not_to change { Ci::PipelineArtifact.count } - end + it 'reports the number of destroyed artifacts' do + is_expected.to eq(2) end end @@ -255,16 +245,4 @@ RSpec.describe Ci::DestroyExpiredJobArtifactsService, :clean_gitlab_redis_shared end end end - - describe '.destroy_job_artifacts_batch' do - it 'returns a falsy value without artifacts' do - expect(service.send(:destroy_job_artifacts_batch)).to be_falsy - end - end - - describe '.destroy_pipeline_artifacts_batch' do - it 'returns a falsy value without artifacts' do - expect(service.send(:destroy_pipeline_artifacts_batch)).to be_falsy - end - end end diff --git a/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb b/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb new file mode 100644 index 00000000000..b48ea70aa4c --- /dev/null +++ b/spec/services/ci/pipeline_artifacts/coverage_report_service_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Ci::PipelineArtifacts::CoverageReportService do + describe '#execute' do + subject { described_class.new.execute(pipeline) } + + context 'when pipeline has coverage reports' do + let(:project) { create(:project, :repository) } + let(:pipeline) { create(:ci_pipeline, :with_coverage_reports, project: project) } + + context 'when pipeline is finished' do + it 'creates a pipeline artifact' do + subject + + expect(Ci::PipelineArtifact.count).to eq(1) + end + + it 'persists the default file name' do + subject + + file = Ci::PipelineArtifact.first.file + + expect(file.filename).to eq('code_coverage.json') + end + + it 'sets expire_at to 1 week' do + freeze_time do + subject + + pipeline_artifact = Ci::PipelineArtifact.first + + expect(pipeline_artifact.expire_at).to eq(1.week.from_now) + end + end + end + + context 'when pipeline artifact has already been created' do + it 'do not raise an error and do not persist the same artifact twice' do + expect { 2.times { described_class.new.execute(pipeline) } }.not_to raise_error(ActiveRecord::RecordNotUnique) + + expect(Ci::PipelineArtifact.count).to eq(1) + end + end + end + + context 'when pipeline is running and coverage report does not exist' do + let(:pipeline) { create(:ci_pipeline, :running) } + + it 'does not persist data' do + subject + + expect(Ci::PipelineArtifact.count).to eq(0) + end + end + end +end diff --git a/spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb b/spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb new file mode 100644 index 00000000000..ac1a590face --- /dev/null +++ b/spec/services/ci/pipeline_artifacts/destroy_expired_artifacts_service_spec.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::PipelineArtifacts::DestroyExpiredArtifactsService do + let(:service) { described_class.new } + + describe '.execute' do + subject { service.execute } + + context 'when timeout happens' do + before do + stub_const('Ci::PipelineArtifacts::DestroyExpiredArtifactsService::LOOP_TIMEOUT', 0.1.seconds) + allow(service).to receive(:destroy_artifacts_batch) { true } + end + + it 'returns 0 and does not continue destroying' do + is_expected.to eq(0) + end + end + + context 'when there are no artifacts' do + it 'does not raise error' do + expect { subject }.not_to raise_error + end + end + + context 'when the loop limit is reached' do + before do + stub_const('::Ci::PipelineArtifacts::DestroyExpiredArtifactsService::LOOP_LIMIT', 1) + stub_const('::Ci::PipelineArtifacts::DestroyExpiredArtifactsService::BATCH_SIZE', 1) + + create_list(:ci_pipeline_artifact, 2, expire_at: 1.week.ago) + end + + it 'destroys one artifact' do + expect { subject }.to change { Ci::PipelineArtifact.count }.by(-1) + end + + it 'reports the number of destroyed artifacts' do + is_expected.to eq(1) + end + end + + context 'when there are artifacts more than batch sizes' do + before do + stub_const('Ci::PipelineArtifacts::DestroyExpiredArtifactsService::BATCH_SIZE', 1) + + create_list(:ci_pipeline_artifact, 2, expire_at: 1.week.ago) + end + + it 'destroys all expired artifacts' do + expect { subject }.to change { Ci::PipelineArtifact.count }.by(-2) + end + + it 'reports the number of destroyed artifacts' do + is_expected.to eq(2) + end + end + + context 'when artifacts are not expired' do + before do + create(:ci_pipeline_artifact, expire_at: 2.days.from_now) + end + + it 'does not destroy pipeline artifacts' do + expect { subject }.not_to change { Ci::PipelineArtifact.count } + end + + it 'reports the number of destroyed artifacts' do + is_expected.to eq(0) + end + end + end + + describe '.destroy_artifacts_batch' do + it 'returns a falsy value without artifacts' do + expect(service.send(:destroy_artifacts_batch)).to be_falsy + end + end +end diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_delayed_and_needs_test.yml b/spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_delayed_and_needs_test.yml new file mode 100644 index 00000000000..b729efaeab2 --- /dev/null +++ b/spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_delayed_and_needs_test.yml @@ -0,0 +1,41 @@ +config: + build: + stage: build + script: exit 1 + + test: + stage: test + script: exit 0 + + deploy: + stage: deploy + script: exit 0 + when: delayed + start_in: 5 seconds + needs: [test] + +init: + expect: + pipeline: pending + stages: + build: pending + test: created + deploy: created + jobs: + build: pending + test: created + deploy: created + +transitions: + - event: drop + jobs: [build] + expect: + pipeline: failed + stages: + build: failed + test: skipped + deploy: skipped + jobs: + build: failed + test: skipped + deploy: skipped diff --git a/spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_manual_and_needs_test.yml b/spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_manual_and_needs_test.yml new file mode 100644 index 00000000000..479fc8fd72d --- /dev/null +++ b/spec/services/ci/pipeline_processing/test_cases/dag_build_fails_deploy_is_manual_and_needs_test.yml @@ -0,0 +1,40 @@ +config: + build: + stage: build + script: exit 1 + + test: + stage: test + script: exit 0 + + deploy: + stage: deploy + script: exit 0 + when: manual + needs: [test] + +init: + expect: + pipeline: pending + stages: + build: pending + test: created + deploy: created + jobs: + build: pending + test: created + deploy: created + +transitions: + - event: drop + jobs: [build] + expect: + pipeline: failed + stages: + build: failed + test: skipped + deploy: skipped + jobs: + build: failed + test: skipped + deploy: skipped diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index ac077e3c30e..0cc66e67b91 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -3,14 +3,16 @@ require 'spec_helper' RSpec.describe Ci::PipelineTriggerService do - let(:project) { create(:project, :repository) } + include AfterNextHelpers + + let_it_be(:project) { create(:project, :repository) } before do stub_ci_pipeline_to_return_yaml_file end describe '#execute' do - let(:user) { create(:user) } + let_it_be(:user) { create(:user) } let(:result) { described_class.new(project, user, params).execute } before do @@ -29,8 +31,8 @@ RSpec.describe Ci::PipelineTriggerService do end end - context 'when params have an existsed trigger token' do - context 'when params have an existsed ref' do + context 'when params have an existing trigger token' do + context 'when params have an existing ref' do let(:params) { { token: trigger.token, ref: 'master', variables: nil } } it 'triggers a pipeline' do @@ -45,9 +47,7 @@ RSpec.describe Ci::PipelineTriggerService do context 'when commit message has [ci skip]' do before do - allow_next_instance_of(Ci::Pipeline) do |instance| - allow(instance).to receive(:git_commit_message) { '[ci skip]' } - end + allow_next(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' } end it 'ignores [ci skip] and create as general' do diff --git a/spec/services/ci/pipelines/create_artifact_service_spec.rb b/spec/services/ci/pipelines/create_artifact_service_spec.rb deleted file mode 100644 index 4e9248d9d1a..00000000000 --- a/spec/services/ci/pipelines/create_artifact_service_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe ::Ci::Pipelines::CreateArtifactService do - describe '#execute' do - subject { described_class.new.execute(pipeline) } - - context 'when pipeline has coverage reports' do - let(:project) { create(:project, :repository) } - let(:pipeline) { create(:ci_pipeline, :with_coverage_reports, project: project) } - - context 'when pipeline is finished' do - it 'creates a pipeline artifact' do - subject - - expect(Ci::PipelineArtifact.count).to eq(1) - end - - it 'persists the default file name' do - subject - - file = Ci::PipelineArtifact.first.file - - expect(file.filename).to eq('code_coverage.json') - end - - it 'sets expire_at to 1 week' do - freeze_time do - subject - - pipeline_artifact = Ci::PipelineArtifact.first - - expect(pipeline_artifact.expire_at).to eq(1.week.from_now) - end - end - end - - context 'when pipeline artifact has already been created' do - it 'do not raise an error and do not persist the same artifact twice' do - expect { 2.times { described_class.new.execute(pipeline) } }.not_to raise_error(ActiveRecord::RecordNotUnique) - - expect(Ci::PipelineArtifact.count).to eq(1) - end - end - end - - context 'when pipeline is running and coverage report does not exist' do - let(:pipeline) { create(:ci_pipeline, :running) } - - it 'does not persist data' do - subject - - expect(Ci::PipelineArtifact.count).to eq(0) - end - end - end -end diff --git a/spec/services/ci/play_build_service_spec.rb b/spec/services/ci/play_build_service_spec.rb index c9ecbad3167..00c6de7681d 100644 --- a/spec/services/ci/play_build_service_spec.rb +++ b/spec/services/ci/play_build_service_spec.rb @@ -72,6 +72,31 @@ RSpec.describe Ci::PlayBuildService, '#execute' do expect(build.reload.job_variables.map(&:key)).to contain_exactly('first', 'second') end + + context 'when user defined variables are restricted' do + before do + project.update!(restrict_user_defined_variables: true) + end + + context 'when user is maintainer' do + before do + project.add_maintainer(user) + end + + it 'assigns the variables to the build' do + service.execute(build, job_variables) + + expect(build.reload.job_variables.map(&:key)).to contain_exactly('first', 'second') + end + end + + context 'when user is developer' do + it 'raises an error' do + expect { service.execute(build, job_variables) } + .to raise_error Gitlab::Access::AccessDeniedError + end + end + end end end diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index a6e8732f5ff..6d2af81a6e8 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -124,24 +124,46 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do end context 'when build is scheduled with DAG' do + using RSpec::Parameterized::TableSyntax + let(:pipeline) { create(:ci_pipeline, ref: 'master', project: project) } - let!(:build) { create(:ci_build, :created, when: :on_success, pipeline: pipeline, scheduling_type: :dag) } + let!(:build) { create(:ci_build, :created, when: build_when, pipeline: pipeline, scheduling_type: :dag) } let!(:other_build) { create(:ci_build, :created, when: :on_success, pipeline: pipeline) } let!(:build_on_other_build) { create(:ci_build_need, build: build, name: other_build.name) } - context 'when current status is success' do - let(:current_status) { 'success' } + where(:build_when, :current_status, :after_status) do + :on_success | 'success' | 'pending' + :on_success | 'skipped' | 'skipped' + :manual | 'success' | 'manual' + :manual | 'skipped' | 'skipped' + :delayed | 'success' | 'manual' + :delayed | 'skipped' | 'skipped' + end - it 'enqueues the build' do - expect { subject }.to change { build.status }.to('pending') + with_them do + it 'proceeds the build' do + expect { subject }.to change { build.status }.to(after_status) end end - context 'when current status is skipped' do - let(:current_status) { 'skipped' } + context 'when FF skip_dag_manual_and_delayed_jobs is disabled' do + before do + stub_feature_flags(skip_dag_manual_and_delayed_jobs: false) + end - it 'skips the build' do - expect { subject }.to change { build.status }.to('skipped') + where(:build_when, :current_status, :after_status) do + :on_success | 'success' | 'pending' + :on_success | 'skipped' | 'skipped' + :manual | 'success' | 'manual' + :manual | 'skipped' | 'manual' + :delayed | 'success' | 'manual' + :delayed | 'skipped' | 'manual' + end + + with_them do + it 'proceeds the build' do + expect { subject }.to change { build.status }.to(after_status) + end end end end diff --git a/spec/services/ci/retry_build_service_spec.rb b/spec/services/ci/retry_build_service_spec.rb index 81d56a0e42a..bdf60bb3fdc 100644 --- a/spec/services/ci/retry_build_service_spec.rb +++ b/spec/services/ci/retry_build_service_spec.rb @@ -206,6 +206,22 @@ RSpec.describe Ci::RetryBuildService do expect(subsequent_build.reload).to be_created expect(subsequent_bridge.reload).to be_created end + + it 'updates ownership for subsequent builds' do + expect { service.execute(build) }.to change { subsequent_build.reload.user }.to(user) + end + + it 'updates ownership for subsequent bridges' do + expect { service.execute(build) }.to change { subsequent_bridge.reload.user }.to(user) + end + + it 'does not cause n+1 when updaing build ownership' do + control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { service.execute(build) }.count + + create_list(:ci_build, 2, :skipped, stage_idx: build.stage_idx + 1, pipeline: pipeline, stage: 'deploy') + + expect { service.execute(build) }.not_to exceed_all_query_limit(control_count) + end end context 'when pipeline has other builds' do diff --git a/spec/services/ci/retry_pipeline_service_spec.rb b/spec/services/ci/retry_pipeline_service_spec.rb index 526c2f39b46..3c6a99efbf8 100644 --- a/spec/services/ci/retry_pipeline_service_spec.rb +++ b/spec/services/ci/retry_pipeline_service_spec.rb @@ -64,6 +64,18 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do expect(build('spinach 1')).to be_created expect(pipeline.reload).to be_running end + + it 'changes ownership of subsequent builds' do + expect(build('rspec 2').user).not_to eq(user) + expect(build('rspec 3').user).not_to eq(user) + expect(build('spinach 1').user).not_to eq(user) + + service.execute(pipeline) + + expect(build('rspec 2').user).to eq(user) + expect(build('rspec 3').user).to eq(user) + expect(build('spinach 1').user).to eq(user) + end end context 'when there is failed build present which was run on failure' do @@ -161,6 +173,16 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do expect(build('rspec 2')).to be_created expect(pipeline.reload).to be_running end + + it 'changes ownership of subsequent builds' do + expect(build('staging').user).not_to eq(user) + expect(build('rspec 2').user).not_to eq(user) + + service.execute(pipeline) + + expect(build('staging').user).to eq(user) + expect(build('rspec 2').user).to eq(user) + end end end diff --git a/spec/services/ci/test_failure_history_service_spec.rb b/spec/services/ci/test_failure_history_service_spec.rb index e858c85490d..d9c1c8dc3fa 100644 --- a/spec/services/ci/test_failure_history_service_spec.rb +++ b/spec/services/ci/test_failure_history_service_spec.rb @@ -22,19 +22,6 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do expect(Ci::TestCaseFailure.count).to eq(2) end - context 'when feature flag for test failure history is disabled' do - before do - stub_feature_flags(test_failure_history: false) - end - - it 'does not persist data' do - execute_service - - expect(Ci::TestCase.count).to eq(0) - expect(Ci::TestCaseFailure.count).to eq(0) - end - end - context 'when pipeline is not for the default branch' do before do pipeline.update_column(:ref, 'new-feature') @@ -136,14 +123,6 @@ RSpec.describe Ci::TestFailureHistoryService, :aggregate_failures do it { is_expected.to eq(true) } end - context 'when feature flag is disabled' do - before do - stub_feature_flags(test_failure_history: false) - end - - it { is_expected.to eq(false) } - end - context 'when pipeline is not equal to the project default branch' do before do pipeline.update_column(:ref, 'some-other-branch') diff --git a/spec/services/ci/update_build_state_service_spec.rb b/spec/services/ci/update_build_state_service_spec.rb index 3112e5dda1b..63190cc5d49 100644 --- a/spec/services/ci/update_build_state_service_spec.rb +++ b/spec/services/ci/update_build_state_service_spec.rb @@ -82,8 +82,9 @@ RSpec.describe Ci::UpdateBuildStateService do let(:params) do { output: { checksum: 'crc32:12345678', bytesize: 123 }, + state: 'failed', failure_reason: 'script_failure', - state: 'failed' + exit_code: 42 } end @@ -95,6 +96,15 @@ RSpec.describe Ci::UpdateBuildStateService do expect(result.status).to eq 200 end + it 'updates the allow_failure flag' do + expect(build) + .to receive(:drop_with_exit_code!) + .with('script_failure', 42) + .and_call_original + + subject.execute + end + it 'does not increment invalid trace metric' do execute_with_stubbed_metrics! @@ -115,6 +125,15 @@ RSpec.describe Ci::UpdateBuildStateService do expect(build).to be_failed end + it 'updates the allow_failure flag' do + expect(build) + .to receive(:drop_with_exit_code!) + .with('script_failure', 42) + .and_call_original + + subject.execute + end + it 'responds with 200 OK status' do result = subject.execute -- cgit v1.2.1