diff options
Diffstat (limited to 'spec/models/merge_request_spec.rb')
-rw-r--r-- | spec/models/merge_request_spec.rb | 273 |
1 files changed, 253 insertions, 20 deletions
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index ebe2cd2ac03..8c7289adbcc 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -9,8 +9,8 @@ RSpec.describe MergeRequest, factory_default: :keep do using RSpec::Parameterized::TableSyntax - let_it_be(:namespace) { create_default(:namespace) } - let_it_be(:project, refind: true) { create_default(:project, :repository) } + let_it_be(:namespace) { create_default(:namespace).freeze } + let_it_be(:project, refind: true) { create_default(:project, :repository).freeze } subject { create(:merge_request) } @@ -1366,6 +1366,10 @@ RSpec.describe MergeRequest, factory_default: :keep do it "doesn't detect WIP by default" do expect(subject.work_in_progress?).to eq false end + + it "is aliased to #draft?" do + expect(subject.method(:work_in_progress?)).to eq(subject.method(:draft?)) + end end describe "#wipless_title" do @@ -2895,6 +2899,14 @@ RSpec.describe MergeRequest, factory_default: :keep do expect(subject.mergeable?).to be_truthy end + it 'return true if #mergeable_state? is true and the MR #can_be_merged? is false' do + allow(subject).to receive(:mergeable_state?) { true } + expect(subject).to receive(:check_mergeability) + expect(subject).to receive(:can_be_merged?) { false } + + expect(subject.mergeable?).to be_falsey + end + context 'with skip_ci_check option' do before do allow(subject).to receive_messages(check_mergeability: nil, @@ -3072,6 +3084,7 @@ RSpec.describe MergeRequest, factory_default: :keep do where(:status, :public_status) do 'cannot_be_merged_rechecking' | 'checking' + 'preparing' | 'checking' 'checking' | 'checking' 'cannot_be_merged' | 'cannot_be_merged' end @@ -3082,32 +3095,83 @@ RSpec.describe MergeRequest, factory_default: :keep do end describe "#head_pipeline_active? " do - it do - is_expected - .to delegate_method(:active?) - .to(:head_pipeline) - .with_prefix - .with_arguments(allow_nil: true) + context 'when project lacks a head_pipeline relation' do + before do + subject.head_pipeline = nil + end + + it 'returns false' do + expect(subject.head_pipeline_active?).to be false + end + end + + context 'when project has a head_pipeline relation' do + let(:pipeline) { create(:ci_empty_pipeline) } + + before do + allow(subject).to receive(:head_pipeline) { pipeline } + end + + it 'accesses the value from the head_pipeline' do + expect(subject.head_pipeline) + .to receive(:active?) + + subject.head_pipeline_active? + end end end describe "#actual_head_pipeline_success? " do - it do - is_expected - .to delegate_method(:success?) - .to(:actual_head_pipeline) - .with_prefix - .with_arguments(allow_nil: true) + context 'when project lacks an actual_head_pipeline relation' do + before do + allow(subject).to receive(:actual_head_pipeline) { nil } + end + + it 'returns false' do + expect(subject.actual_head_pipeline_success?).to be false + end + end + + context 'when project has a actual_head_pipeline relation' do + let(:pipeline) { create(:ci_empty_pipeline) } + + before do + allow(subject).to receive(:actual_head_pipeline) { pipeline } + end + + it 'accesses the value from the actual_head_pipeline' do + expect(subject.actual_head_pipeline) + .to receive(:success?) + + subject.actual_head_pipeline_success? + end end end describe "#actual_head_pipeline_active? " do - it do - is_expected - .to delegate_method(:active?) - .to(:actual_head_pipeline) - .with_prefix - .with_arguments(allow_nil: true) + context 'when project lacks an actual_head_pipeline relation' do + before do + allow(subject).to receive(:actual_head_pipeline) { nil } + end + + it 'returns false' do + expect(subject.actual_head_pipeline_active?).to be false + end + end + + context 'when project has a actual_head_pipeline relation' do + let(:pipeline) { create(:ci_empty_pipeline) } + + before do + allow(subject).to receive(:actual_head_pipeline) { pipeline } + end + + it 'accesses the value from the actual_head_pipeline' do + expect(subject.actual_head_pipeline) + .to receive(:active?) + + subject.actual_head_pipeline_active? + end end end @@ -3784,6 +3848,87 @@ RSpec.describe MergeRequest, factory_default: :keep do end end + describe '#use_merge_base_pipeline_for_comparison?' do + let(:project) { create(:project, :public, :repository) } + let(:merge_request) { create(:merge_request, :with_codequality_reports, source_project: project) } + + subject { merge_request.use_merge_base_pipeline_for_comparison?(service_class) } + + context 'when service class is Ci::CompareCodequalityReportsService' do + let(:service_class) { 'Ci::CompareCodequalityReportsService' } + + context 'when feature flag is enabled' do + it { is_expected.to be_truthy } + end + + context 'when feature flag is disabled' do + before do + stub_feature_flags(codequality_backend_comparison: false) + end + + it { is_expected.to be_falsey } + end + end + + context 'when service class is different' do + let(:service_class) { 'Ci::GenerateCoverageReportsService' } + + it { is_expected.to be_falsey } + end + end + + describe '#comparison_base_pipeline' do + subject(:pipeline) { merge_request.comparison_base_pipeline(service_class) } + + let(:project) { create(:project, :public, :repository) } + let(:merge_request) { create(:merge_request, :with_codequality_reports, source_project: project) } + let!(:base_pipeline) do + create(:ci_pipeline, + :with_test_reports, + project: project, + ref: merge_request.target_branch, + sha: merge_request.diff_base_sha + ) + end + + context 'when service class is Ci::CompareCodequalityReportsService' do + let(:service_class) { 'Ci::CompareCodequalityReportsService' } + + context 'when merge request has a merge request pipeline' do + let(:merge_request) do + create(:merge_request, :with_merge_request_pipeline) + end + + let(:merge_base_pipeline) do + create(:ci_pipeline, ref: merge_request.target_branch, sha: merge_request.target_branch_sha) + end + + before do + merge_base_pipeline + merge_request.update_head_pipeline + end + + it 'returns the merge_base_pipeline' do + expect(pipeline).to eq(merge_base_pipeline) + end + end + + context 'when merge does not have a merge request pipeline' do + it 'returns the base_pipeline' do + expect(pipeline).to eq(base_pipeline) + end + end + end + + context 'when service_class is different' do + let(:service_class) { 'Ci::GenerateCoverageReportsService' } + + it 'returns the base_pipeline' do + expect(pipeline).to eq(base_pipeline) + end + end + end + describe '#base_pipeline' do let(:pipeline_arguments) do { @@ -3963,6 +4108,65 @@ RSpec.describe MergeRequest, factory_default: :keep do end end + describe '#mark_as_unchecked' do + subject { create(:merge_request, source_project: project, merge_status: merge_status) } + + shared_examples 'for an invalid state transition' do + it 'is not a valid state transition' do + expect { subject.mark_as_unchecked! }.to raise_error(StateMachines::InvalidTransition) + end + end + + shared_examples 'for an valid state transition' do + it 'is a valid state transition' do + expect { subject.mark_as_unchecked! } + .to change { subject.merge_status } + .from(merge_status.to_s) + .to(expected_merge_status) + end + end + + context 'when the status is unchecked' do + let(:merge_status) { :unchecked } + + include_examples 'for an invalid state transition' + end + + context 'when the status is checking' do + let(:merge_status) { :checking } + let(:expected_merge_status) { 'unchecked' } + + include_examples 'for an valid state transition' + end + + context 'when the status is can_be_merged' do + let(:merge_status) { :can_be_merged } + let(:expected_merge_status) { 'unchecked' } + + include_examples 'for an valid state transition' + end + + context 'when the status is cannot_be_merged_recheck' do + let(:merge_status) { :cannot_be_merged_recheck } + + include_examples 'for an invalid state transition' + end + + context 'when the status is cannot_be_merged' do + let(:merge_status) { :cannot_be_merged } + let(:expected_merge_status) { 'cannot_be_merged_recheck' } + + include_examples 'for an valid state transition' + end + + context 'when the status is cannot_be_merged' do + let(:merge_status) { :cannot_be_merged } + let(:expected_merge_status) { 'cannot_be_merged_recheck' } + + include_examples 'for an valid state transition' + end + end + describe 'transition to cannot_be_merged' do let(:notification_service) { double(:notification_service) } let(:todo_service) { double(:todo_service) } @@ -4661,4 +4865,33 @@ RSpec.describe MergeRequest, factory_default: :keep do end end end + + describe '#includes_ci_config?' do + let(:merge_request) { build(:merge_request) } + let(:project) { merge_request.project } + + subject(:result) { merge_request.includes_ci_config? } + + before do + allow(merge_request).to receive(:diff_stats).and_return(diff_stats) + end + + context 'when diff_stats is nil' do + let(:diff_stats) {} + + it { is_expected.to eq(false) } + end + + context 'when diff_stats does not include the ci config path of the project' do + let(:diff_stats) { [double(path: 'abc.txt')] } + + it { is_expected.to eq(false) } + end + + context 'when diff_stats includes the ci config path of the project' do + let(:diff_stats) { [double(path: '.gitlab-ci.yml')] } + + it { is_expected.to eq(true) } + end + end end |