Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/services/ci')
-rw-r--r--spec/services/ci/create_job_artifacts_service_spec.rb28
-rw-r--r--spec/services/ci/create_pipeline_service/cross_project_pipeline_spec.rb86
-rw-r--r--spec/services/ci/create_pipeline_service/custom_yaml_tags_spec.rb79
-rw-r--r--spec/services/ci/create_pipeline_service/parent_child_pipeline_spec.rb50
-rw-r--r--spec/services/ci/create_pipeline_service/rules_spec.rb14
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb7
-rw-r--r--spec/services/ci/daily_build_group_report_result_service_spec.rb28
-rw-r--r--spec/services/ci/generate_codequality_mr_diff_report_service_spec.rb51
-rw-r--r--spec/services/ci/pipeline_artifacts/create_code_quality_mr_diff_report_service_spec.rb62
-rw-r--r--spec/services/ci/pipeline_trigger_service_spec.rb29
-rw-r--r--spec/services/ci/process_build_service_spec.rb6
-rw-r--r--spec/services/ci/process_pipeline_service_spec.rb29
-rw-r--r--spec/services/ci/prometheus_metrics/observe_histograms_service_spec.rb86
-rw-r--r--spec/services/ci/register_job_service_spec.rb22
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'