diff options
Diffstat (limited to 'spec/models/ci/build_spec.rb')
-rw-r--r-- | spec/models/ci/build_spec.rb | 267 |
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 |