diff options
author | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 22:34:23 +0300 |
---|---|---|
committer | Robert Speicher <rspeicher@gmail.com> | 2021-01-20 22:34:23 +0300 |
commit | 6438df3a1e0fb944485cebf07976160184697d72 (patch) | |
tree | 00b09bfd170e77ae9391b1a2f5a93ef6839f2597 /spec/models/ci | |
parent | 42bcd54d971da7ef2854b896a7b34f4ef8601067 (diff) |
Add latest changes from gitlab-org/gitlab@13-8-stable-eev13.8.0-rc42
Diffstat (limited to 'spec/models/ci')
-rw-r--r-- | spec/models/ci/bridge_spec.rb | 12 | ||||
-rw-r--r-- | spec/models/ci/build_need_spec.rb | 2 | ||||
-rw-r--r-- | spec/models/ci/build_spec.rb | 249 | ||||
-rw-r--r-- | spec/models/ci/commit_with_pipeline_spec.rb | 124 | ||||
-rw-r--r-- | spec/models/ci/group_spec.rb | 12 | ||||
-rw-r--r-- | spec/models/ci/job_artifact_spec.rb | 33 | ||||
-rw-r--r-- | spec/models/ci/ref_spec.rb | 60 |
7 files changed, 420 insertions, 72 deletions
diff --git a/spec/models/ci/bridge_spec.rb b/spec/models/ci/bridge_spec.rb index 11dcecd50ca..4f09f6f1da4 100644 --- a/spec/models/ci/bridge_spec.rb +++ b/spec/models/ci/bridge_spec.rb @@ -356,14 +356,6 @@ RSpec.describe Ci::Bridge do describe '#dependency_variables' do subject { bridge.dependency_variables } - shared_context 'when ci_bridge_dependency_variables is disabled' do - before do - stub_feature_flags(ci_bridge_dependency_variables: false) - end - - it { is_expected.to be_empty } - end - context 'when downloading from previous stages' do let!(:prepare1) { create(:ci_build, name: 'prepare1', pipeline: pipeline, stage_idx: 0) } let!(:bridge) { create(:ci_bridge, pipeline: pipeline, stage_idx: 1) } @@ -374,8 +366,6 @@ RSpec.describe Ci::Bridge do it 'inherits only dependent variables' do expect(subject.to_hash).to eq(job_variable_1.key => job_variable_1.value) end - - it_behaves_like 'when ci_bridge_dependency_variables is disabled' end context 'when using needs' do @@ -397,8 +387,6 @@ RSpec.describe Ci::Bridge do it 'inherits only needs with artifacts variables' do expect(subject.to_hash).to eq(job_variable_1.key => job_variable_1.value) end - - it_behaves_like 'when ci_bridge_dependency_variables is disabled' end end end diff --git a/spec/models/ci/build_need_spec.rb b/spec/models/ci/build_need_spec.rb index 43cce073918..c2cf9027055 100644 --- a/spec/models/ci/build_need_spec.rb +++ b/spec/models/ci/build_need_spec.rb @@ -5,7 +5,7 @@ require 'spec_helper' RSpec.describe Ci::BuildNeed, model: true do let(:build_need) { build(:ci_build_need) } - it { is_expected.to belong_to(:build) } + it { is_expected.to belong_to(:build).class_name('Ci::Processable') } it { is_expected.to validate_presence_of(:build) } it { is_expected.to validate_presence_of(:name) } diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 9f412d64d56..c2029b9240b 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -717,6 +717,22 @@ RSpec.describe Ci::Build do end end + describe '#artifacts_public?' do + subject { build.artifacts_public? } + + context 'artifacts with defaults' do + let(:build) { create(:ci_build, :artifacts) } + + it { is_expected.to be_truthy } + end + + context 'non public artifacts' do + let(:build) { create(:ci_build, :artifacts, :non_public_artifacts) } + + it { is_expected.to be_falsey } + end + end + describe '#artifacts_expired?' do subject { build.artifacts_expired? } @@ -1149,26 +1165,12 @@ RSpec.describe Ci::Build do end context 'when transits to skipped' do - context 'when cd_skipped_deployment_status is disabled' do - before do - stub_feature_flags(cd_skipped_deployment_status: false) - build.skip! - end - - it 'transits deployment status to canceled' do - expect(deployment).to be_canceled - end + before do + build.skip! end - context 'when cd_skipped_deployment_status is enabled' do - before do - stub_feature_flags(cd_skipped_deployment_status: project) - build.skip! - end - - it 'transits deployment status to skipped' do - expect(deployment).to be_skipped - end + it 'transits deployment status to skipped' do + expect(deployment).to be_skipped end end @@ -2456,6 +2458,7 @@ RSpec.describe Ci::Build do { key: 'CI_PROJECT_VISIBILITY', value: 'private', public: true, masked: false }, { key: 'CI_PROJECT_REPOSITORY_LANGUAGES', value: project.repository_languages.map(&:name).join(',').downcase, public: true, masked: false }, { key: 'CI_DEFAULT_BRANCH', value: project.default_branch, public: true, masked: false }, + { key: 'CI_PROJECT_CONFIG_PATH', value: project.ci_config_path_or_default, public: true, masked: false }, { key: 'CI_PAGES_DOMAIN', value: Gitlab.config.pages.host, public: true, masked: false }, { key: 'CI_PAGES_URL', value: project.pages_url, public: true, masked: false }, { key: 'CI_DEPENDENCY_PROXY_SERVER', value: "#{Gitlab.config.gitlab.host}:#{Gitlab.config.gitlab.port}", public: true, masked: false }, @@ -2986,7 +2989,7 @@ RSpec.describe Ci::Build do let(:ci_config_path) { { key: 'CI_CONFIG_PATH', value: 'custom', public: true, masked: false } } before do - expect_any_instance_of(Project).to receive(:ci_config_path) { 'custom' } + project.update!(ci_config_path: 'custom') end it { is_expected.to include(ci_config_path) } @@ -4343,7 +4346,7 @@ RSpec.describe Ci::Build do end describe '#supported_runner?' do - let_it_be(:build) { create(:ci_build) } + let_it_be_with_refind(:build) { create(:ci_build) } subject { build.supported_runner?(runner_features) } @@ -4408,6 +4411,41 @@ RSpec.describe Ci::Build do it { is_expected.to be_falsey } end end + + context 'when `return_exit_code` feature is required by build' do + let(:options) { { allow_failure_criteria: { exit_codes: [1] } } } + + before do + build.update!(options: options) + end + + context 'when runner provides given feature' do + let(:runner_features) { { return_exit_code: true } } + + it { is_expected.to be_truthy } + end + + context 'when runner does not provide given feature' do + let(:runner_features) { {} } + + it { is_expected.to be_falsey } + end + + context 'when the runner does not provide all of the required features' do + let(:options) do + { + allow_failure_criteria: { exit_codes: [1] }, + artifacts: { reports: { junit: "junit.xml" } } + } + end + + let(:runner_features) { { return_exit_code: true } } + + it 'requires `upload_multiple_artifacts` too' do + is_expected.to be_falsey + end + end + end end describe '#deployment_status' do @@ -4737,22 +4775,6 @@ RSpec.describe Ci::Build do describe '#debug_mode?' do subject { build.debug_mode? } - context 'when feature is disabled' do - before do - stub_feature_flags(restrict_access_to_build_debug_mode: false) - end - - it { is_expected.to eq false } - - context 'when in variables' do - before do - create(:ci_instance_variable, key: 'CI_DEBUG_TRACE', value: 'true') - end - - it { is_expected.to eq false } - end - end - context 'when CI_DEBUG_TRACE=true is in variables' do context 'when in instance variables' do before do @@ -4807,4 +4829,159 @@ RSpec.describe Ci::Build do it { is_expected.to eq false } end end + + describe '#drop_with_exit_code!' do + let(:exit_code) { 1 } + let(:options) { {} } + + before do + build.options.merge!(options) + build.save! + end + + subject(:drop_with_exit_code) do + build.drop_with_exit_code!(:unknown_failure, exit_code) + end + + shared_examples 'drops the build without changing allow_failure' do + it 'does not change allow_failure' do + expect { drop_with_exit_code } + .not_to change { build.reload.allow_failure } + end + + it 'drops the build' do + expect { drop_with_exit_code } + .to change { build.reload.failed? } + end + end + + context 'when exit_codes are not defined' do + it_behaves_like 'drops the build without changing allow_failure' + end + + context 'when allow_failure_criteria is nil' do + let(:options) { { allow_failure_criteria: nil } } + + it_behaves_like 'drops the build without changing allow_failure' + end + + context 'when exit_codes is nil' do + let(:options) do + { + allow_failure_criteria: { + exit_codes: nil + } + } + end + + it_behaves_like 'drops the build without changing allow_failure' + end + + context 'when exit_codes do not match' do + let(:options) do + { + allow_failure_criteria: { + exit_codes: [2, 3, 4] + } + } + end + + it_behaves_like 'drops the build without changing allow_failure' + end + + context 'with matching exit codes' do + let(:options) do + { allow_failure_criteria: { exit_codes: [1, 2, 3] } } + end + + it 'changes allow_failure' do + expect { drop_with_exit_code } + .to change { build.reload.allow_failure } + end + + it 'drops the build' do + expect { drop_with_exit_code } + .to change { build.reload.failed? } + end + + it 'is executed inside a transaction' do + expect(build).to receive(:drop!) + .with(:unknown_failure) + .and_raise(ActiveRecord::Rollback) + + expect(build).to receive(:conditionally_allow_failure!) + .with(1) + .and_call_original + + expect { drop_with_exit_code } + .not_to change { build.reload.allow_failure } + end + + context 'when exit_code is nil' do + let(:exit_code) {} + + it_behaves_like 'drops the build without changing allow_failure' + end + + context 'when ci_allow_failure_with_exit_codes is disabled' do + before do + stub_feature_flags(ci_allow_failure_with_exit_codes: false) + end + + it_behaves_like 'drops the build without changing allow_failure' + end + end + end + + describe '#exit_codes_defined?' do + let(:options) { {} } + + before do + build.options.merge!(options) + end + + subject(:exit_codes_defined) do + build.exit_codes_defined? + end + + context 'without allow_failure_criteria' do + it { is_expected.to be_falsey } + end + + context 'when exit_codes is nil' do + let(:options) do + { + allow_failure_criteria: { + exit_codes: nil + } + } + end + + it { is_expected.to be_falsey } + end + + context 'when exit_codes is an empty array' do + let(:options) do + { + allow_failure_criteria: { + exit_codes: [] + } + } + end + + it { is_expected.to be_falsey } + end + + context 'when exit_codes are defined' do + let(:options) do + { + allow_failure_criteria: { + exit_codes: [5, 6] + } + } + end + + it { is_expected.to be_truthy } + end + end end diff --git a/spec/models/ci/commit_with_pipeline_spec.rb b/spec/models/ci/commit_with_pipeline_spec.rb new file mode 100644 index 00000000000..4dd288bde62 --- /dev/null +++ b/spec/models/ci/commit_with_pipeline_spec.rb @@ -0,0 +1,124 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::CommitWithPipeline do + let(:project) { create(:project, :public, :repository) } + let(:commit) { described_class.new(project.commit) } + + describe '#last_pipeline' do + let!(:first_pipeline) do + create(:ci_empty_pipeline, + project: project, + sha: commit.sha, + status: 'success') + end + + let!(:second_pipeline) do + create(:ci_empty_pipeline, + project: project, + sha: commit.sha, + status: 'success') + end + + it 'returns last pipeline' do + expect(commit.last_pipeline).to eq second_pipeline + end + end + + describe '#latest_pipeline' do + let(:pipeline) { double } + + shared_examples_for 'fetching latest pipeline' do |ref| + it 'returns the latest pipeline for the project' do + expect(commit) + .to receive(:latest_pipeline_for_project) + .with(ref, project) + .and_return(pipeline) + + expect(result).to eq(pipeline) + end + + it "returns the memoized pipeline for the key of #{ref}" do + commit.set_latest_pipeline_for_ref(ref, pipeline) + + expect(commit) + .not_to receive(:latest_pipeline_for_project) + + expect(result).to eq(pipeline) + end + end + + context 'without ref argument' do + let(:result) { commit.latest_pipeline } + + it_behaves_like 'fetching latest pipeline', nil + end + + context 'when a particular ref is specified' do + let(:result) { commit.latest_pipeline('master') } + + it_behaves_like 'fetching latest pipeline', 'master' + end + end + + describe '#latest_pipeline_for_project' do + let(:project_pipelines) { double } + let(:pipeline_project) { double } + let(:pipeline) { double } + let(:ref) { 'master' } + let(:result) { commit.latest_pipeline_for_project(ref, pipeline_project) } + + before do + allow(pipeline_project).to receive(:ci_pipelines).and_return(project_pipelines) + end + + it 'returns the latest pipeline of the commit for the given ref and project' do + expect(project_pipelines) + .to receive(:latest_pipeline_per_commit) + .with(commit.id, ref) + .and_return(commit.id => pipeline) + + expect(result).to eq(pipeline) + end + end + + describe '#set_latest_pipeline_for_ref' do + let(:pipeline) { double } + + it 'sets the latest pipeline for a given reference' do + commit.set_latest_pipeline_for_ref('master', pipeline) + + expect(commit.latest_pipeline('master')).to eq(pipeline) + end + end + + describe "#status" do + it 'returns the status of the latest pipeline for the given ref' do + expect(commit) + .to receive(:latest_pipeline) + .with('master') + .and_return(double(status: 'success')) + + expect(commit.status('master')).to eq('success') + end + + it 'returns nil when latest pipeline is not present for the given ref' do + expect(commit) + .to receive(:latest_pipeline) + .with('master') + .and_return(nil) + + expect(commit.status('master')).to eq(nil) + end + + it 'returns the status of the latest pipeline when no ref is given' do + expect(commit) + .to receive(:latest_pipeline) + .with(nil) + .and_return(double(status: 'success')) + + expect(commit.status).to eq('success') + end + end +end diff --git a/spec/models/ci/group_spec.rb b/spec/models/ci/group_spec.rb index c20b7e61044..6c96e659a34 100644 --- a/spec/models/ci/group_spec.rb +++ b/spec/models/ci/group_spec.rb @@ -54,6 +54,18 @@ RSpec.describe Ci::Group do .to be_a(Gitlab::Ci::Status::Failed) end end + + context 'when one of the commit statuses in the group is allowed to fail' do + let(:jobs) do + [create(:ci_build, :failed, :allowed_to_fail), + create(:ci_build, :success)] + end + + it 'fabricates a new detailed status object' do + expect(subject.detailed_status(double(:user))) + .to be_a(Gitlab::Ci::Status::SuccessWarning) + end + end end describe '.fabricate' do diff --git a/spec/models/ci/job_artifact_spec.rb b/spec/models/ci/job_artifact_spec.rb index ef21ca8f100..796947be4c8 100644 --- a/spec/models/ci/job_artifact_spec.rb +++ b/spec/models/ci/job_artifact_spec.rb @@ -219,6 +219,39 @@ RSpec.describe Ci::JobArtifact do end end + describe '.unlocked' do + let_it_be(:job_artifact) { create(:ci_job_artifact) } + + context 'with locked pipelines' do + before do + job_artifact.job.pipeline.artifacts_locked! + end + + it 'returns an empty array' do + expect(described_class.unlocked).to be_empty + end + end + + context 'with unlocked pipelines' do + before do + job_artifact.job.pipeline.unlocked! + end + + it 'returns the artifact' do + expect(described_class.unlocked).to eq([job_artifact]) + end + end + end + + describe '.order_expired_desc' do + let_it_be(:first_artifact) { create(:ci_job_artifact, expire_at: 2.days.ago) } + let_it_be(:second_artifact) { create(:ci_job_artifact, expire_at: 1.day.ago) } + + it 'returns ordered artifacts' do + expect(described_class.order_expired_desc).to eq([second_artifact, first_artifact]) + end + end + describe 'callbacks' do describe '#schedule_background_upload' do subject { create(:ci_job_artifact, :archive) } diff --git a/spec/models/ci/ref_spec.rb b/spec/models/ci/ref_spec.rb index cb62646532c..0a9cd5ef2ec 100644 --- a/spec/models/ci/ref_spec.rb +++ b/spec/models/ci/ref_spec.rb @@ -16,35 +16,49 @@ RSpec.describe Ci::Ref do stub_const('Ci::PipelineSuccessUnlockArtifactsWorker', unlock_artifacts_worker_spy) end - where(:initial_state, :action, :count) do - :unknown | :succeed! | 1 - :unknown | :do_fail! | 0 - :success | :succeed! | 1 - :success | :do_fail! | 0 - :failed | :succeed! | 1 - :failed | :do_fail! | 0 - :fixed | :succeed! | 1 - :fixed | :do_fail! | 0 - :broken | :succeed! | 1 - :broken | :do_fail! | 0 - :still_failing | :succeed | 1 - :still_failing | :do_fail | 0 - end + context 'pipline is locked' do + let!(:pipeline) { create(:ci_pipeline, ci_ref_id: ci_ref.id, locked: :artifacts_locked) } + + where(:initial_state, :action, :count) do + :unknown | :succeed! | 1 + :unknown | :do_fail! | 0 + :success | :succeed! | 1 + :success | :do_fail! | 0 + :failed | :succeed! | 1 + :failed | :do_fail! | 0 + :fixed | :succeed! | 1 + :fixed | :do_fail! | 0 + :broken | :succeed! | 1 + :broken | :do_fail! | 0 + :still_failing | :succeed | 1 + :still_failing | :do_fail | 0 + end - with_them do - context "when transitioning states" do - before do - status_value = Ci::Ref.state_machines[:status].states[initial_state].value - ci_ref.update!(status: status_value) - end + with_them do + context "when transitioning states" do + before do + status_value = Ci::Ref.state_machines[:status].states[initial_state].value + ci_ref.update!(status: status_value) + end - it 'calls unlock artifacts service' do - ci_ref.send(action) + it 'calls unlock artifacts service' do + ci_ref.send(action) - expect(unlock_artifacts_worker_spy).to have_received(:perform_async).exactly(count).times + expect(unlock_artifacts_worker_spy).to have_received(:perform_async).exactly(count).times + end end end end + + context 'pipeline is unlocked' do + let!(:pipeline) { create(:ci_pipeline, ci_ref_id: ci_ref.id, locked: :unlocked) } + + it 'does not call unlock artifacts service' do + ci_ref.succeed! + + expect(unlock_artifacts_worker_spy).not_to have_received(:perform_async) + end + end end end |