summaryrefslogtreecommitdiff
path: root/spec/models/merge_request_spec.rb
diff options
context:
space:
mode:
Diffstat (limited to 'spec/models/merge_request_spec.rb')
-rw-r--r--spec/models/merge_request_spec.rb138
1 files changed, 96 insertions, 42 deletions
diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb
index a3c0c9a0a74..a5e68829c5d 100644
--- a/spec/models/merge_request_spec.rb
+++ b/spec/models/merge_request_spec.rb
@@ -20,12 +20,16 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it { is_expected.to belong_to(:target_project).class_name('Project') }
it { is_expected.to belong_to(:source_project).class_name('Project') }
it { is_expected.to belong_to(:merge_user).class_name("User") }
+
+ it do
+ is_expected.to belong_to(:head_pipeline).class_name('Ci::Pipeline').inverse_of(:merge_requests_as_head_pipeline)
+ end
+
it { is_expected.to have_many(:assignees).through(:merge_request_assignees) }
it { is_expected.to have_many(:reviewers).through(:merge_request_reviewers) }
it { is_expected.to have_many(:merge_request_diffs) }
it { is_expected.to have_many(:user_mentions).class_name("MergeRequestUserMention") }
it { is_expected.to belong_to(:milestone) }
- it { is_expected.to belong_to(:iteration) }
it { is_expected.to have_many(:resource_milestone_events) }
it { is_expected.to have_many(:resource_state_events) }
it { is_expected.to have_many(:draft_notes) }
@@ -33,6 +37,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it { is_expected.to have_many(:reviewed_by_users).through(:reviews).source(:author) }
it { is_expected.to have_one(:cleanup_schedule).inverse_of(:merge_request) }
it { is_expected.to have_many(:created_environments).class_name('Environment').inverse_of(:merge_request) }
+ it { is_expected.to have_many(:assignment_events).class_name('ResourceEvents::MergeRequestAssignmentEvent').inverse_of(:merge_request) }
context 'for forks' do
let!(:project) { create(:project) }
@@ -393,8 +398,8 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
instance1 = MergeRequest.find(merge_request.id)
instance2 = MergeRequest.find(merge_request.id)
- instance1.ensure_metrics
- instance2.ensure_metrics
+ instance1.ensure_metrics!
+ instance2.ensure_metrics!
metrics_records = MergeRequest::Metrics.where(merge_request_id: merge_request.id)
expect(metrics_records.size).to eq(1)
@@ -760,6 +765,23 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
end
+ context 'when scoped with :merged_before and :merged_after' do
+ before do
+ mr2.metrics.update!(merged_at: mr1.metrics.merged_at - 1.week)
+ mr3.metrics.update!(merged_at: mr1.metrics.merged_at + 1.week)
+ end
+
+ it 'excludes merge requests outside of the date range' do
+ expect(
+ project.merge_requests.merge(
+ MergeRequest::Metrics
+ .merged_before(mr1.metrics.merged_at + 1.day)
+ .merged_after(mr1.metrics.merged_at - 1.day)
+ ).total_time_to_merge
+ ).to be_within(1).of(expected_total_time([mr1]))
+ end
+ end
+
def expected_total_time(mrs)
mrs = mrs.reject { |mr| mr.merged_at.nil? }
mrs.reduce(0.0) do |sum, mr|
@@ -1027,7 +1049,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
describe '#to_reference' do
- let(:project) { build(:project, name: 'sample-project') }
+ let(:project) { build(:project) }
let(:merge_request) { build(:merge_request, target_project: project, iid: 1) }
it 'returns a String reference to the object' do
@@ -1035,12 +1057,12 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
it 'supports a cross-project reference' do
- another_project = build(:project, name: 'another-project', namespace: project.namespace)
- expect(merge_request.to_reference(another_project)).to eq "sample-project!1"
+ another_project = build(:project, namespace: project.namespace)
+ expect(merge_request.to_reference(another_project)).to eq "#{project.path}!1"
end
it 'returns a String reference with the full path' do
- expect(merge_request.to_reference(full: true)).to eq(project.full_path + '!1')
+ expect(merge_request.to_reference(full: true)).to eq("#{project.full_path}!1")
end
end
@@ -4024,26 +4046,11 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
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) }
+ let(:service_class) { Ci::CompareReportsBaseService }
subject { merge_request.use_merge_base_pipeline_for_comparison?(service_class) }
- context 'when service class is Ci::CompareMetricsReportsService' do
- let(:service_class) { 'Ci::CompareMetricsReportsService' }
-
- it { is_expected.to be_truthy }
- end
-
- context 'when service class is Ci::CompareCodequalityReportsService' do
- let(:service_class) { 'Ci::CompareCodequalityReportsService' }
-
- it { is_expected.to be_truthy }
- end
-
- context 'when service class is different' do
- let(:service_class) { 'Ci::GenerateCoverageReportsService' }
-
- it { is_expected.to be_falsey }
- end
+ it { is_expected.to eq(false) }
end
describe '#comparison_base_pipeline' do
@@ -4051,6 +4058,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
let(:project) { create(:project, :public, :repository) }
let(:merge_request) { create(:merge_request, :with_codequality_reports, source_project: project) }
+ let(:service_class) { ::Ci::CompareReportsBaseService }
let!(:base_pipeline) do
create(:ci_pipeline,
:with_test_reports,
@@ -4060,20 +4068,24 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
)
end
- context 'when service class is Ci::CompareCodequalityReportsService' do
- let(:service_class) { 'Ci::CompareCodequalityReportsService' }
+ before do
+ allow(merge_request).to receive(:use_merge_base_pipeline_for_comparison?)
+ .with(service_class).and_return(uses_merge_base)
+ end
+
+ context 'when service class uses merge base pipeline' do
+ let(:uses_merge_base) { true }
context 'when merge request has a merge request pipeline' do
let(:merge_request) do
- create(:merge_request, :with_merge_request_pipeline)
+ create(:merge_request, :with_merge_request_pipeline, source_project: project)
end
- let(:merge_base_pipeline) do
- create(:ci_pipeline, ref: merge_request.target_branch, sha: merge_request.target_branch_sha)
+ let!(:merge_base_pipeline) do
+ create(:ci_pipeline, project: project, ref: merge_request.target_branch, sha: merge_request.target_branch_sha)
end
before do
- merge_base_pipeline
merge_request.update_head_pipeline
end
@@ -4082,19 +4094,27 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
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
+ it 'returns the base_pipeline when merge does not have a merge request pipeline' do
+ expect(pipeline).to eq(base_pipeline)
end
end
- context 'when service_class is different' do
- let(:service_class) { 'Ci::GenerateCoverageReportsService' }
+ context 'when service_class does not use merge base pipeline' do
+ let(:uses_merge_base) { false }
it 'returns the base_pipeline' do
expect(pipeline).to eq(base_pipeline)
end
+
+ context 'when merge request has a merge request pipeline' do
+ let(:merge_request) do
+ create(:merge_request, :with_merge_request_pipeline, source_project: project)
+ end
+
+ it 'returns the base pipeline' do
+ expect(pipeline).to eq(base_pipeline)
+ end
+ end
end
end
@@ -4279,8 +4299,11 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
it 'refreshes the number of open merge requests of the target project' do
project = subject.target_project
- expect { subject.destroy! }
- .to change { project.open_merge_requests_count }.from(1).to(0)
+ expect do
+ subject.destroy!
+
+ BatchLoader::Executor.clear_current
+ end.to change { project.open_merge_requests_count }.from(1).to(0)
end
end
@@ -4306,6 +4329,14 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
transition!
end
+ context 'when skip_merge_status_trigger is set to true' do
+ before do
+ subject.skip_merge_status_trigger = true
+ end
+
+ it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription'
+ end
+
context 'when transaction is not committed' do
it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription' do
def transition!
@@ -4459,7 +4490,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
let(:expected_merge_status) { 'checking' }
include_examples 'for a valid state transition'
- it_behaves_like 'transition triggering mergeRequestMergeStatusUpdated GraphQL subscription'
+ it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription'
end
context 'when the status is checking' do
@@ -4479,7 +4510,7 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
let(:expected_merge_status) { 'cannot_be_merged_rechecking' }
include_examples 'for a valid state transition'
- it_behaves_like 'transition triggering mergeRequestMergeStatusUpdated GraphQL subscription'
+ it_behaves_like 'transition not triggering mergeRequestMergeStatusUpdated GraphQL subscription'
end
context 'when the status is cannot_be_merged' do
@@ -4615,6 +4646,29 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
.from(true)
.to(false)
end
+
+ context 'when it is a first contribution' do
+ let(:new_user) { create(:user) }
+
+ before do
+ subject.update!(author: new_user)
+ end
+
+ it 'sets first_contribution' do
+ subject.mark_as_merged
+
+ expect(subject.state).to eq('merged')
+ expect(subject.reload.first_contribution?).to be_truthy
+ end
+
+ it "doesn't set first_contribution not first contribution" do
+ create(:merged_merge_request, author: new_user)
+
+ subject.mark_as_merged
+
+ expect(subject.first_contribution?).to be_falsey
+ end
+ end
end
describe 'transition to cannot_be_merged' do
@@ -4697,9 +4751,9 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
end
[:closed, :merged].each do |state|
- let(:state) { state }
-
context state do
+ let(:state) { state }
+
it 'does not notify' do
expect(notification_service).not_to receive(:merge_request_unmergeable)
expect(todo_service).not_to receive(:merge_request_became_unmergeable)