diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-18 10:34:06 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-02-18 10:34:06 +0000 |
commit | 859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch) | |
tree | d7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /spec/services/ci | |
parent | 446d496a6d000c73a304be52587cd9bbc7493136 (diff) | |
download | gitlab-ce-859a6fb938bb9ee2a317c46dfa4fcc1af49608f0.tar.gz |
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'spec/services/ci')
14 files changed, 538 insertions, 39 deletions
diff --git a/spec/services/ci/create_job_artifacts_service_spec.rb b/spec/services/ci/create_job_artifacts_service_spec.rb index 29e51a23dea..1efd1d390a2 100644 --- a/spec/services/ci/create_job_artifacts_service_spec.rb +++ b/spec/services/ci/create_job_artifacts_service_spec.rb @@ -27,6 +27,14 @@ RSpec.describe Ci::CreateJobArtifactsService do UploadedFile.new(upload.path, **params) end + def unique_metrics_report_uploaders + Gitlab::UsageDataCounters::HLLRedisCounter.unique_events( + event_names: described_class::METRICS_REPORT_UPLOAD_EVENT_NAME, + start_date: 2.weeks.ago, + end_date: 2.weeks.from_now + ) + end + describe '#execute' do subject { service.execute(artifacts_file, params, metadata_file: metadata_file) } @@ -42,6 +50,12 @@ RSpec.describe Ci::CreateJobArtifactsService do expect(new_artifact.file_sha256).to eq(artifacts_sha256) end + it 'does not track the job user_id' do + subject + + expect(unique_metrics_report_uploaders).to eq(0) + end + context 'when metadata file is also uploaded' do let(:metadata_file) do file_to_upload('spec/fixtures/ci_build_artifacts_metadata.gz', sha256: artifacts_sha256) @@ -174,6 +188,20 @@ RSpec.describe Ci::CreateJobArtifactsService do end end + context 'when artifact_type is metrics' do + before do + allow(job).to receive(:user_id).and_return(123) + end + + let(:params) { { 'artifact_type' => 'metrics', 'artifact_format' => 'gzip' }.with_indifferent_access } + + it 'tracks the job user_id' do + subject + + expect(unique_metrics_report_uploaders).to eq(1) + end + end + context 'when artifact type is cluster_applications' do let(:artifacts_file) do file_to_upload('spec/fixtures/helm/helm_list_v2_prometheus_missing.json.gz', sha256: artifacts_sha256) 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 new file mode 100644 index 00000000000..9cf66dfceb0 --- /dev/null +++ b/spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::CreatePipelineService, '#execute' do + let_it_be(:group) { create(:group, name: 'my-organization') } + let(:upstream_project) { create(:project, :repository, name: 'upstream', group: group) } + let(:downstram_project) { create(:project, :repository, name: 'downstream', group: group) } + let(:user) { create(:user) } + + let(:service) do + described_class.new(upstream_project, user, ref: 'master') + end + + before do + upstream_project.add_developer(user) + downstram_project.add_developer(user) + create_gitlab_ci_yml(upstream_project, upstream_config) + create_gitlab_ci_yml(downstram_project, downstream_config) + end + + context 'with resource group', :aggregate_failures do + let(:upstream_config) do + <<~YAML + instrumentation_test: + stage: test + resource_group: iOS + trigger: + project: my-organization/downstream + strategy: depend + YAML + end + + let(:downstream_config) do + <<~YAML + test: + script: echo "Testing..." + YAML + end + + it 'creates bridge job with resource group' do + pipeline = create_pipeline! + + test = pipeline.statuses.find_by(name: 'instrumentation_test') + expect(pipeline).to be_created_successfully + expect(pipeline.triggered_pipelines).not_to be_exist + expect(upstream_project.resource_groups.count).to eq(1) + expect(test).to be_a Ci::Bridge + expect(test).to be_waiting_for_resource + expect(test.resource_group.key).to eq('iOS') + end + + context 'when sidekiq processes the job', :sidekiq_inline do + it 'transitions to pending status and triggers a downstream pipeline' do + pipeline = create_pipeline! + + test = pipeline.statuses.find_by(name: 'instrumentation_test') + expect(test).to be_pending + expect(pipeline.triggered_pipelines.count).to eq(1) + end + + context 'when the resource is occupied by the other bridge' do + before do + resource_group = create(:ci_resource_group, project: upstream_project, key: 'iOS') + resource_group.assign_resource_to(create(:ci_build, project: upstream_project)) + end + + it 'stays waiting for resource' do + pipeline = create_pipeline! + + test = pipeline.statuses.find_by(name: 'instrumentation_test') + expect(test).to be_waiting_for_resource + expect(pipeline.triggered_pipelines.count).to eq(0) + end + end + end + end + + def create_pipeline! + service.execute(:push) + end + + def create_gitlab_ci_yml(project, content) + project.repository.create_file(user, '.gitlab-ci.yml', content, branch_name: 'master', message: 'test') + end +end 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 new file mode 100644 index 00000000000..4cf52223e38 --- /dev/null +++ b/spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb @@ -0,0 +1,79 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe Ci::CreatePipelineService do + describe '!reference tags' do + let_it_be(:project) { create(:project, :repository) } + let_it_be(:user) { project.owner } + + let(:ref) { 'refs/heads/master' } + let(:source) { :push } + let(:service) { described_class.new(project, user, { ref: ref }) } + let(:pipeline) { service.execute(source) } + + before do + stub_ci_pipeline_yaml_file(config) + end + + context 'with valid config' do + let(:config) do + <<~YAML + .job-1: + script: + - echo doing step 1 of job 1 + + .job-2: + before_script: + - ls + script: !reference [.job-1, script] + + job: + before_script: !reference [.job-2, before_script] + script: + - echo doing my first step + - !reference [.job-2, script] + - echo doing my last step + YAML + end + + it 'creates a pipeline' do + expect(pipeline).to be_persisted + expect(pipeline.builds.first.options).to match(a_hash_including({ + 'before_script' => ['ls'], + 'script' => [ + 'echo doing my first step', + 'echo doing step 1 of job 1', + 'echo doing my last step' + ] + })) + end + end + + context 'with invalid config' do + let(:config) do + <<~YAML + job-1: + script: + - echo doing step 1 of job 1 + - !reference [job-3, script] + + job-2: + script: + - echo doing step 1 of job 2 + - !reference [job-3, script] + + job-3: + script: + - echo doing step 1 of job 3 + - !reference [job-1, script] + YAML + end + + it 'creates a pipeline without builds' do + expect(pipeline).to be_persisted + expect(pipeline.builds).to be_empty + expect(pipeline.yaml_errors).to eq("!reference [\"job-3\", \"script\"] is part of a circular chain") + end + end + end +end 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 8df9b0c3e60..a3818937113 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 @@ -76,6 +76,56 @@ RSpec.describe Ci::CreatePipelineService, '#execute' do } end end + + context 'with resource group' do + let(:config) do + <<~YAML + instrumentation_test: + stage: test + resource_group: iOS + trigger: + include: path/to/child.yml + strategy: depend + YAML + end + + it 'creates bridge job with resource group', :aggregate_failures do + pipeline = create_pipeline! + + test = pipeline.statuses.find_by(name: 'instrumentation_test') + expect(pipeline).to be_created_successfully + expect(pipeline.triggered_pipelines).not_to be_exist + expect(project.resource_groups.count).to eq(1) + expect(test).to be_a Ci::Bridge + expect(test).to be_waiting_for_resource + expect(test.resource_group.key).to eq('iOS') + end + + context 'when sidekiq processes the job', :sidekiq_inline do + it 'transitions to pending status and triggers a downstream pipeline' do + pipeline = create_pipeline! + + test = pipeline.statuses.find_by(name: 'instrumentation_test') + expect(test).to be_pending + expect(pipeline.triggered_pipelines.count).to eq(1) + end + + context 'when the resource is occupied by the other bridge' do + before do + resource_group = create(:ci_resource_group, project: project, key: 'iOS') + resource_group.assign_resource_to(create(:ci_build, project: project)) + end + + it 'stays waiting for resource' do + pipeline = create_pipeline! + + test = pipeline.statuses.find_by(name: 'instrumentation_test') + expect(test).to be_waiting_for_resource + expect(pipeline.triggered_pipelines.count).to eq(0) + end + end + end + end end describe 'child pipeline triggers' do diff --git a/spec/services/ci/create_pipeline_service/rules_spec.rb b/spec/services/ci/create_pipeline_service/rules_spec.rb index ac6c4c188e4..04ecac6a85a 100644 --- a/spec/services/ci/create_pipeline_service/rules_spec.rb +++ b/spec/services/ci/create_pipeline_service/rules_spec.rb @@ -145,20 +145,6 @@ RSpec.describe Ci::CreatePipelineService do expect(find_job('job-2').options.dig(:allow_failure_criteria)).to be_nil expect(find_job('job-3').options.dig(:allow_failure_criteria, :exit_codes)).to eq([42]) end - - context 'with ci_allow_failure_with_exit_codes disabled' do - before do - stub_feature_flags(ci_allow_failure_with_exit_codes: false) - end - - it 'does not persist allow_failure_criteria' do - expect(pipeline).to be_persisted - - expect(find_job('job-1').options.key?(:allow_failure_criteria)).to be_falsey - expect(find_job('job-2').options.key?(:allow_failure_criteria)).to be_falsey - expect(find_job('job-3').options.key?(:allow_failure_criteria)).to be_falsey - end - end end context 'if:' do diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index e1f1bdc41a1..1005985b3e4 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -102,7 +102,6 @@ RSpec.describe Ci::CreatePipelineService do 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 @@ -538,7 +537,7 @@ RSpec.describe Ci::CreatePipelineService do it 'pull it from Auto-DevOps' do pipeline = execute_service expect(pipeline).to be_auto_devops_source - expect(pipeline.builds.map(&:name)).to match_array(%w[build code_quality eslint-sast secret_detection_default_branch test]) + expect(pipeline.builds.map(&:name)).to match_array(%w[brakeman-sast build code_quality eslint-sast secret_detection_default_branch test]) end end @@ -952,9 +951,9 @@ RSpec.describe Ci::CreatePipelineService do expect(result).to be_persisted expect(deploy_job.resource_group.key).to eq(resource_group_key) expect(project.resource_groups.count).to eq(1) - expect(resource_group.builds.count).to eq(1) + expect(resource_group.processables.count).to eq(1) expect(resource_group.resources.count).to eq(1) - expect(resource_group.resources.first.build).to eq(nil) + expect(resource_group.resources.first.processable).to eq(nil) end context 'when resource group key includes predefined variables' do 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 e54f10cc4f4..e58a5de26a1 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 @@ -3,10 +3,12 @@ require 'spec_helper' RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do - let!(:pipeline) { create(:ci_pipeline, created_at: '2020-02-06 00:01:10') } - let!(:rspec_job) { create(:ci_build, pipeline: pipeline, name: '3/3 rspec', coverage: 80) } - let!(:karma_job) { create(:ci_build, pipeline: pipeline, name: '2/2 karma', coverage: 90) } - let!(:extra_job) { create(:ci_build, pipeline: pipeline, name: 'extra', coverage: nil) } + 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) } + let_it_be(:karma_job) { create(:ci_build, pipeline: pipeline, name: 'karma 2/2', coverage: 90) } + let_it_be(:extra_job) { create(:ci_build, pipeline: pipeline, name: 'extra', coverage: nil) } + let(:coverages) { Ci::DailyBuildGroupReportResult.all } it 'creates daily code coverage record for each job in the pipeline that has coverage value' do @@ -19,7 +21,8 @@ RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do ref_path: pipeline.source_ref_path, group_name: rspec_job.group_name, data: { 'coverage' => rspec_job.coverage }, - date: pipeline.created_at.to_date + date: pipeline.created_at.to_date, + group_id: group.id ) end @@ -30,7 +33,8 @@ RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do ref_path: pipeline.source_ref_path, group_name: karma_job.group_name, data: { 'coverage' => karma_job.coverage }, - date: pipeline.created_at.to_date + date: pipeline.created_at.to_date, + group_id: group.id ) end @@ -38,8 +42,8 @@ RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do end context 'when there are multiple builds with the same group name that report coverage' do - let!(:test_job_1) { create(:ci_build, pipeline: pipeline, name: '1/2 test', coverage: 70) } - let!(:test_job_2) { create(:ci_build, pipeline: pipeline, name: '2/2 test', coverage: 80) } + let!(:test_job_1) { create(:ci_build, pipeline: pipeline, name: 'test 1/2', coverage: 70) } + let!(:test_job_2) { create(:ci_build, pipeline: pipeline, name: 'test 2/2', coverage: 80) } it 'creates daily code coverage record with the average as the value' do described_class.new.execute(pipeline) @@ -67,8 +71,8 @@ RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do ) end - let!(:new_rspec_job) { create(:ci_build, pipeline: new_pipeline, name: '4/4 rspec', coverage: 84) } - let!(:new_karma_job) { create(:ci_build, pipeline: new_pipeline, name: '3/3 karma', coverage: 92) } + let!(:new_rspec_job) { create(:ci_build, pipeline: new_pipeline, name: 'rspec 4/4', coverage: 84) } + let!(:new_karma_job) { create(:ci_build, pipeline: new_pipeline, name: 'karma 3/3', coverage: 92) } before do # Create the existing daily code coverage records @@ -107,8 +111,8 @@ RSpec.describe Ci::DailyBuildGroupReportResultService, '#execute' do ) end - let!(:new_rspec_job) { create(:ci_build, pipeline: new_pipeline, name: '4/4 rspec', coverage: 84) } - let!(:new_karma_job) { create(:ci_build, pipeline: new_pipeline, name: '3/3 karma', coverage: 92) } + let!(:new_rspec_job) { create(:ci_build, pipeline: new_pipeline, name: 'rspec 4/4', coverage: 84) } + let!(:new_karma_job) { create(:ci_build, pipeline: new_pipeline, name: 'karma 3/3', coverage: 92) } before do # Create the existing daily code coverage records 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 new file mode 100644 index 00000000000..5d747a09f2a --- /dev/null +++ b/spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb @@ -0,0 +1,51 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::GenerateCodequalityMrDiffReportService do + let(:service) { described_class.new(project) } + let(:project) { create(:project, :repository) } + + describe '#execute' do + subject { service.execute(base_pipeline, head_pipeline) } + + context 'when head pipeline has codequality mr diff report' do + let!(:merge_request) { create(:merge_request, :with_codequality_mr_diff_reports, source_project: project) } + let!(:service) { described_class.new(project, nil, id: merge_request.id) } + let!(:head_pipeline) { merge_request.head_pipeline } + let!(:base_pipeline) { nil } + + it 'returns status and data', :aggregate_failures do + expect_any_instance_of(Ci::PipelineArtifact) do |instance| + expect(instance).to receive(:present) + expect(instance).to receive(:for_files).with(merge_request.new_paths).and_call_original + end + + expect(subject[:status]).to eq(:parsed) + expect(subject[:data]).to eq(files: {}) + end + end + + context 'when head pipeline does not have a codequality mr diff report' do + let!(:merge_request) { create(:merge_request, source_project: project) } + let!(:service) { described_class.new(project, nil, id: merge_request.id) } + let!(:head_pipeline) { merge_request.head_pipeline } + let!(:base_pipeline) { nil } + + it 'returns status and error message' do + expect(subject[:status]).to eq(:error) + expect(subject[:status_reason]).to include('An error occurred while fetching codequality mr diff reports.') + end + end + + context 'when head pipeline has codequality mr diff report and no merge request associated' do + let!(:head_pipeline) { create(:ci_pipeline, :with_codequality_mr_diff_report, project: project) } + let!(:base_pipeline) { nil } + + it 'returns status and error message' do + expect(subject[:status]).to eq(:error) + expect(subject[:status_reason]).to include('An error occurred while fetching codequality mr diff reports.') + end + end + end +end 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 new file mode 100644 index 00000000000..0c48f15d726 --- /dev/null +++ b/spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb @@ -0,0 +1,62 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::Ci::PipelineArtifacts::CreateCodeQualityMrDiffReportService do + describe '#execute' do + subject(:pipeline_artifact) { described_class.new.execute(pipeline) } + + context 'when pipeline has codequality reports' do + let(:project) { create(:project, :repository) } + + describe 'pipeline completed status' do + using RSpec::Parameterized::TableSyntax + + where(:status, :result) do + :success | 1 + :failed | 1 + :canceled | 1 + :skipped | 1 + end + + with_them do + let(:pipeline) { create(:ci_pipeline, :with_codequality_reports, status: status, project: project) } + + it 'creates a pipeline artifact' do + expect { pipeline_artifact }.to change(Ci::PipelineArtifact, :count).by(result) + end + + it 'persists the default file name' do + expect(pipeline_artifact.file.filename).to eq('code_quality_mr_diff.json') + end + + it 'sets expire_at to 1 week' do + freeze_time do + expect(pipeline_artifact.expire_at).to eq(1.week.from_now) + end + end + end + end + + context 'when pipeline artifact has already been created' do + let(:pipeline) { create(:ci_pipeline, :with_codequality_reports, project: project) } + + it 'does not persist the same artifact twice' do + 2.times { described_class.new.execute(pipeline) } + + expect(Ci::PipelineArtifact.count).to eq(1) + end + end + end + + context 'when pipeline is not completed and codequality report does not exist' do + let(:pipeline) { create(:ci_pipeline, :running) } + + it 'does not persist data' do + pipeline_artifact + + expect(Ci::PipelineArtifact.count).to eq(0) + end + end + end +end diff --git a/spec/services/ci/pipeline_trigger_service_spec.rb b/spec/services/ci/pipeline_trigger_service_spec.rb index 0cc66e67b91..89d3da89011 100644 --- a/spec/services/ci/pipeline_trigger_service_spec.rb +++ b/spec/services/ci/pipeline_trigger_service_spec.rb @@ -45,6 +45,27 @@ RSpec.describe Ci::PipelineTriggerService do expect(result[:status]).to eq(:success) end + it 'stores the payload as a variable' do + expect { result }.to change { Ci::PipelineVariable.count }.by(1) + + var = result[:pipeline].variables.first + + expect(var.key).to eq('TRIGGER_PAYLOAD') + expect(var.value).to eq('{"ref":"master","variables":null}') + expect(var.variable_type).to eq('file') + end + + context 'when FF ci_trigger_payload_into_pipeline is disabled' do + before do + stub_feature_flags(ci_trigger_payload_into_pipeline: false) + end + + it 'does not store the payload as a variable' do + expect { result }.not_to change { Ci::PipelineVariable.count } + expect(result[:pipeline].variables).to be_empty + end + end + context 'when commit message has [ci skip]' do before do allow_next(Ci::Pipeline).to receive(:git_commit_message) { '[ci skip]' } @@ -60,8 +81,8 @@ RSpec.describe Ci::PipelineTriggerService do let(:params) { { token: trigger.token, ref: 'master', variables: variables } } let(:variables) { { 'AAA' => 'AAA123' } } - it 'has a variable' do - expect { result }.to change { Ci::PipelineVariable.count }.by(1) + it 'has variables' do + expect { result }.to change { Ci::PipelineVariable.count }.by(2) .and change { Ci::TriggerRequest.count }.by(1) expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables) expect(result[:pipeline].trigger_requests.last.variables).to be_nil @@ -155,8 +176,8 @@ RSpec.describe Ci::PipelineTriggerService do let(:params) { { token: job.token, ref: 'master', variables: variables } } let(:variables) { { 'AAA' => 'AAA123' } } - it 'has a variable' do - expect { result }.to change { Ci::PipelineVariable.count }.by(1) + it 'has variables' do + expect { result }.to change { Ci::PipelineVariable.count }.by(2) .and change { Ci::Sources::Pipeline.count }.by(1) expect(result[:pipeline].variables.map { |v| { v.key => v.value } }.first).to eq(variables) expect(job.sourced_pipelines.last.pipeline_id).to eq(result[:pipeline].id) diff --git a/spec/services/ci/process_build_service_spec.rb b/spec/services/ci/process_build_service_spec.rb index 6d2af81a6e8..42a92504839 100644 --- a/spec/services/ci/process_build_service_spec.rb +++ b/spec/services/ci/process_build_service_spec.rb @@ -146,9 +146,11 @@ RSpec.describe Ci::ProcessBuildService, '#execute' do end end - context 'when FF skip_dag_manual_and_delayed_jobs is disabled' do + context 'when FF skip_dag_manual_and_delayed_jobs is disabled on the project' do + let_it_be(:other_project) { create(:project) } + before do - stub_feature_flags(skip_dag_manual_and_delayed_jobs: false) + stub_feature_flags(skip_dag_manual_and_delayed_jobs: other_project) end where(:build_when, :current_status, :after_status) do diff --git a/spec/services/ci/process_pipeline_service_spec.rb b/spec/services/ci/process_pipeline_service_spec.rb index a7889f0644d..d316c9a262b 100644 --- a/spec/services/ci/process_pipeline_service_spec.rb +++ b/spec/services/ci/process_pipeline_service_spec.rb @@ -50,6 +50,35 @@ RSpec.describe Ci::ProcessPipelineService do expect(all_builds.retried).to contain_exactly(build_retried) end + context 'counter ci_legacy_update_jobs_as_retried_total' do + let(:counter) { double(increment: true) } + + before do + allow(Gitlab::Metrics).to receive(:counter).and_call_original + allow(Gitlab::Metrics).to receive(:counter) + .with(:ci_legacy_update_jobs_as_retried_total, anything) + .and_return(counter) + end + + it 'increments the counter' do + expect(counter).to receive(:increment) + + subject.execute + end + + context 'when the previous build has already retried column true' do + before do + build_retried.update_columns(retried: true) + end + + it 'does not increment the counter' do + expect(counter).not_to receive(:increment) + + subject.execute + end + end + end + def create_build(name, **opts) create(:ci_build, :created, pipeline: pipeline, name: name, **opts) end diff --git a/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb b/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb new file mode 100644 index 00000000000..2eef852b0f4 --- /dev/null +++ b/spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb @@ -0,0 +1,86 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::PrometheusMetrics::ObserveHistogramsService do + let_it_be(:project) { create(:project) } + let(:params) { {} } + + subject(:execute) { described_class.new(project, params).execute } + + before do + Gitlab::Metrics.reset_registry! + end + + context 'with empty data' do + it 'does not raise errors' do + is_expected.to be_success + end + end + + context 'observes metrics successfully' do + let(:params) do + { + histograms: [ + { name: 'pipeline_graph_link_calculation_duration_seconds', value: '1' }, + { name: 'pipeline_graph_links_per_job_ratio', value: '0.9' } + ] + } + end + + it 'increments the metrics' do + execute + + expect(histogram_data).to match(a_hash_including({ 0.8 => 0.0, 1 => 1.0, 2 => 1.0 })) + + expect(histogram_data(:pipeline_graph_links_per_job_ratio)) + .to match(a_hash_including({ 0.8 => 0.0, 0.9 => 1.0, 1 => 1.0 })) + end + + it 'returns an empty body and status code' do + is_expected.to be_success + expect(subject.http_status).to eq(:created) + expect(subject.payload).to eq({}) + end + end + + context 'with unknown histograms' do + let(:params) do + { histograms: [{ name: 'chunky_bacon', value: '4' }] } + end + + it 'raises ActiveRecord::RecordNotFound error' do + expect { subject }.to raise_error ActiveRecord::RecordNotFound + end + end + + context 'with feature flag disabled' do + before do + stub_feature_flags(ci_accept_frontend_prometheus_metrics: false) + end + + let(:params) do + { + histograms: [ + { name: 'pipeline_graph_link_calculation_duration_seconds', value: '4' } + ] + } + end + + it 'does not register the metrics' do + execute + + expect(histogram_data).to be_nil + end + + it 'returns an empty body and status code' do + is_expected.to be_success + expect(subject.http_status).to eq(:accepted) + expect(subject.payload).to eq({}) + end + end + + def histogram_data(name = :pipeline_graph_link_calculation_duration_seconds) + Gitlab::Metrics.registry.get(name)&.get({}) + end +end diff --git a/spec/services/ci/register_job_service_spec.rb b/spec/services/ci/register_job_service_spec.rb index 0cdc8d2c870..88770c8095b 100644 --- a/spec/services/ci/register_job_service_spec.rb +++ b/spec/services/ci/register_job_service_spec.rb @@ -455,7 +455,7 @@ module Ci end before do - stub_feature_flags(ci_disable_validates_dependencies: false) + stub_feature_flags(ci_validate_build_dependencies_override: false) end let!(:pre_stage_job) { create(:ci_build, :success, pipeline: pipeline, name: 'test', stage_idx: 0) } @@ -470,15 +470,31 @@ module Ci context 'when validates for dependencies is enabled' do before do - stub_feature_flags(ci_disable_validates_dependencies: false) + stub_feature_flags(ci_validate_build_dependencies_override: false) end it_behaves_like 'validation is active' + + context 'when the main feature flag is enabled for a specific project' do + before do + stub_feature_flags(ci_validate_build_dependencies: pipeline.project) + end + + it_behaves_like 'validation is active' + end + + context 'when the main feature flag is enabled for a different project' do + before do + stub_feature_flags(ci_validate_build_dependencies: create(:project)) + end + + it_behaves_like 'validation is not active' + end end context 'when validates for dependencies is disabled' do before do - stub_feature_flags(ci_disable_validates_dependencies: true) + stub_feature_flags(ci_validate_build_dependencies_override: true) end it_behaves_like 'validation is not active' |