summaryrefslogtreecommitdiff
path: root/spec/models/ci/build_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/ci/build_spec.rb')
-rw-r--r--spec/models/ci/build_spec.rb267
1 files changed, 182 insertions, 85 deletions
diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb
index 2ebf75a1d8a..b7de8ca4337 100644
--- a/spec/models/ci/build_spec.rb
+++ b/spec/models/ci/build_spec.rb
@@ -35,7 +35,8 @@ RSpec.describe Ci::Build do
it { is_expected.to respond_to(:has_trace?) }
it { is_expected.to respond_to(:trace) }
- it { is_expected.to respond_to(:runner_features) }
+ it { is_expected.to respond_to(:set_cancel_gracefully) }
+ it { is_expected.to respond_to(:cancel_gracefully?) }
it { is_expected.to delegate_method(:merge_request?).to(:pipeline) }
it { is_expected.to delegate_method(:merge_request_ref?).to(:pipeline) }
@@ -214,6 +215,26 @@ RSpec.describe Ci::Build do
end
end
+ describe '.license_management_jobs' do
+ subject { described_class.license_management_jobs }
+
+ let!(:management_build) { create(:ci_build, :success, name: :license_management) }
+ let!(:scanning_build) { create(:ci_build, :success, name: :license_scanning) }
+ let!(:another_build) { create(:ci_build, :success, name: :another_type) }
+
+ it 'returns license_scanning jobs' do
+ is_expected.to include(scanning_build)
+ end
+
+ it 'returns license_management jobs' do
+ is_expected.to include(management_build)
+ end
+
+ it 'doesnt return filtered out jobs' do
+ is_expected.not_to include(another_build)
+ end
+ end
+
describe '.finished_before' do
subject { described_class.finished_before(date) }
@@ -350,7 +371,7 @@ RSpec.describe Ci::Build do
it 'sticks the build if the status changed' do
job = create(:ci_build, :pending)
- expect(ApplicationRecord.sticking).to receive(:stick)
+ expect(described_class.sticking).to receive(:stick)
.with(:build, job.id)
job.update!(status: :running)
@@ -1290,7 +1311,7 @@ RSpec.describe Ci::Build do
end
end
- shared_examples_for 'state transition as a deployable' do
+ describe 'state transition as a deployable' do
subject { build.send(event) }
let!(:build) { create(:ci_build, :with_deployment, :start_review_app, project: project, pipeline: pipeline) }
@@ -1332,6 +1353,22 @@ RSpec.describe Ci::Build do
expect(deployment).to be_running
end
+
+ context 'when deployment is already running state' do
+ before do
+ build.deployment.success!
+ end
+
+ it 'does not change deployment status and tracks an error' do
+ expect(Gitlab::ErrorTracking)
+ .to receive(:track_exception).with(
+ instance_of(Deployment::StatusSyncError), deployment_id: deployment.id, build_id: build.id)
+
+ with_cross_database_modification_prevented do
+ expect { subject }.not_to change { deployment.reload.status }
+ end
+ end
+ end
end
context 'when transits to success' do
@@ -1399,36 +1436,6 @@ RSpec.describe Ci::Build do
end
end
- it_behaves_like 'state transition as a deployable' do
- context 'when transits to running' do
- let(:event) { :run! }
-
- context 'when deployment is already running state' do
- before do
- build.deployment.success!
- end
-
- it 'does not change deployment status and tracks an error' do
- expect(Gitlab::ErrorTracking)
- .to receive(:track_exception).with(
- instance_of(Deployment::StatusSyncError), deployment_id: deployment.id, build_id: build.id)
-
- with_cross_database_modification_prevented do
- expect { subject }.not_to change { deployment.reload.status }
- end
- end
- end
- end
- end
-
- context 'when update_deployment_after_transaction_commit feature flag is disabled' do
- before do
- stub_feature_flags(update_deployment_after_transaction_commit: false)
- end
-
- it_behaves_like 'state transition as a deployable'
- end
-
describe '#on_stop' do
subject { build.on_stop }
@@ -2759,7 +2766,10 @@ RSpec.describe Ci::Build do
let(:job_dependency_var) { { key: 'job_dependency', value: 'value', public: true, masked: false } }
before do
- allow(build).to receive(:predefined_variables) { [build_pre_var] }
+ allow_next_instance_of(Gitlab::Ci::Variables::Builder) do |builder|
+ allow(builder).to receive(:predefined_variables) { [build_pre_var] }
+ end
+
allow(build).to receive(:yaml_variables) { [build_yaml_var] }
allow(build).to receive(:persisted_variables) { [] }
allow(build).to receive(:job_jwt_variables) { [job_jwt_var] }
@@ -3411,75 +3421,122 @@ RSpec.describe Ci::Build do
end
describe '#scoped_variables' do
- context 'when build has not been persisted yet' do
- let(:build) do
- described_class.new(
- name: 'rspec',
- stage: 'test',
- ref: 'feature',
- project: project,
- pipeline: pipeline,
- scheduling_type: :stage
- )
- end
+ before do
+ pipeline.clear_memoization(:predefined_vars_in_builder_enabled)
+ end
- let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
+ it 'records a prometheus metric' do
+ histogram = double(:histogram)
+ expect(::Gitlab::Ci::Pipeline::Metrics).to receive(:pipeline_builder_scoped_variables_histogram)
+ .and_return(histogram)
- it 'does not persist the build' do
- expect(build).to be_valid
- expect(build).not_to be_persisted
+ expect(histogram).to receive(:observe)
+ .with({}, a_kind_of(ActiveSupport::Duration))
- build.scoped_variables
+ build.scoped_variables
+ end
- expect(build).not_to be_persisted
- end
+ shared_examples 'calculates scoped_variables' do
+ context 'when build has not been persisted yet' do
+ let(:build) do
+ described_class.new(
+ name: 'rspec',
+ stage: 'test',
+ ref: 'feature',
+ project: project,
+ pipeline: pipeline,
+ scheduling_type: :stage
+ )
+ end
- it 'returns static predefined variables' do
- keys = %w[CI_JOB_NAME
- CI_COMMIT_SHA
- CI_COMMIT_SHORT_SHA
- CI_COMMIT_REF_NAME
- CI_COMMIT_REF_SLUG
- CI_JOB_STAGE]
+ let(:pipeline) { create(:ci_pipeline, project: project, ref: 'feature') }
- variables = build.scoped_variables
+ it 'does not persist the build' do
+ expect(build).to be_valid
+ expect(build).not_to be_persisted
- variables.map { |env| env[:key] }.tap do |names|
- expect(names).to include(*keys)
+ build.scoped_variables
+
+ expect(build).not_to be_persisted
end
- expect(variables)
- .to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
+ it 'returns static predefined variables' do
+ keys = %w[CI_JOB_NAME
+ CI_COMMIT_SHA
+ CI_COMMIT_SHORT_SHA
+ CI_COMMIT_REF_NAME
+ CI_COMMIT_REF_SLUG
+ CI_JOB_STAGE]
+
+ variables = build.scoped_variables
+
+ variables.map { |env| env[:key] }.tap do |names|
+ expect(names).to include(*keys)
+ end
+
+ expect(variables)
+ .to include(key: 'CI_COMMIT_REF_NAME', value: 'feature', public: true, masked: false)
+ end
+
+ it 'does not return prohibited variables' do
+ keys = %w[CI_JOB_ID
+ CI_JOB_URL
+ CI_JOB_TOKEN
+ CI_BUILD_ID
+ CI_BUILD_TOKEN
+ CI_REGISTRY_USER
+ CI_REGISTRY_PASSWORD
+ CI_REPOSITORY_URL
+ CI_ENVIRONMENT_URL
+ CI_DEPLOY_USER
+ CI_DEPLOY_PASSWORD]
+
+ build.scoped_variables.map { |env| env[:key] }.tap do |names|
+ expect(names).not_to include(*keys)
+ end
+ end
end
- it 'does not return prohibited variables' do
- keys = %w[CI_JOB_ID
- CI_JOB_URL
- CI_JOB_TOKEN
- CI_BUILD_ID
- CI_BUILD_TOKEN
- CI_REGISTRY_USER
- CI_REGISTRY_PASSWORD
- CI_REPOSITORY_URL
- CI_ENVIRONMENT_URL
- CI_DEPLOY_USER
- CI_DEPLOY_PASSWORD]
+ context 'with dependency variables' do
+ let!(:prepare) { create(:ci_build, name: 'prepare', pipeline: pipeline, stage_idx: 0) }
+ let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 1, options: { dependencies: ['prepare'] }) }
+
+ let!(:job_variable) { create(:ci_job_variable, :dotenv_source, job: prepare) }
- build.scoped_variables.map { |env| env[:key] }.tap do |names|
- expect(names).not_to include(*keys)
+ it 'inherits dependent variables' do
+ expect(build.scoped_variables.to_hash).to include(job_variable.key => job_variable.value)
end
end
end
- context 'with dependency variables' do
- let!(:prepare) { create(:ci_build, name: 'prepare', pipeline: pipeline, stage_idx: 0) }
- let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 1, options: { dependencies: ['prepare'] }) }
+ it_behaves_like 'calculates scoped_variables'
- let!(:job_variable) { create(:ci_job_variable, :dotenv_source, job: prepare) }
+ it 'delegates to the variable builders' do
+ expect_next_instance_of(Gitlab::Ci::Variables::Builder) do |builder|
+ expect(builder)
+ .to receive(:scoped_variables).with(build, hash_including(:environment, :dependencies))
+ .and_call_original
- it 'inherits dependent variables' do
- expect(build.scoped_variables.to_hash).to include(job_variable.key => job_variable.value)
+ expect(builder).to receive(:predefined_variables).and_call_original
end
+
+ build.scoped_variables
+ end
+
+ context 'when ci builder feature flag is disabled' do
+ before do
+ stub_feature_flags(ci_predefined_vars_in_builder: false)
+ end
+
+ it 'does not delegate to the variable builders' do
+ expect_next_instance_of(Gitlab::Ci::Variables::Builder) do |builder|
+ expect(builder).not_to receive(:predefined_variables)
+ end
+
+ build.scoped_variables
+ end
+
+ it_behaves_like 'calculates scoped_variables'
end
end
@@ -3569,6 +3626,27 @@ RSpec.describe Ci::Build do
include_examples "secret CI variables"
end
+ describe '#kubernetes_variables' do
+ let(:build) { create(:ci_build) }
+ let(:service) { double(execute: template) }
+ let(:template) { double(to_yaml: 'example-kubeconfig', valid?: template_valid) }
+ let(:template_valid) { true }
+
+ subject { build.kubernetes_variables }
+
+ before do
+ allow(Ci::GenerateKubeconfigService).to receive(:new).with(build).and_return(service)
+ end
+
+ it { is_expected.to include(key: 'KUBECONFIG', value: 'example-kubeconfig', public: false, file: true) }
+
+ context 'generated config is invalid' do
+ let(:template_valid) { false }
+
+ it { is_expected.not_to include(key: 'KUBECONFIG', value: 'example-kubeconfig', public: false, file: true) }
+ end
+ end
+
describe '#deployment_variables' do
let(:build) { create(:ci_build, environment: environment) }
let(:environment) { 'production' }
@@ -3728,7 +3806,7 @@ RSpec.describe Ci::Build do
it 'ensures that it is not run in database transaction' do
expect(job.pipeline.persistent_ref).to receive(:create) do
- expect(Gitlab::Database.main).not_to be_inside_transaction
+ expect(ApplicationRecord).not_to be_inside_transaction
end
run_job_without_exception
@@ -5326,4 +5404,23 @@ RSpec.describe Ci::Build do
create(:ci_build)
end
end
+
+ describe '#runner_features' do
+ subject do
+ build.save!
+ build.cancel_gracefully?
+ end
+
+ let_it_be(:build) { create(:ci_build, pipeline: pipeline) }
+
+ it 'cannot cancel gracefully' do
+ expect(subject).to be false
+ end
+
+ it 'can cancel gracefully' do
+ build.set_cancel_gracefully
+
+ expect(subject).to be true
+ end
+ end
end