diff options
Diffstat (limited to 'spec/services/merge_requests')
11 files changed, 267 insertions, 226 deletions
diff --git a/spec/services/merge_requests/approval_service_spec.rb b/spec/services/merge_requests/approval_service_spec.rb index ab98fad5d73..0846ec7f50e 100644 --- a/spec/services/merge_requests/approval_service_spec.rb +++ b/spec/services/merge_requests/approval_service_spec.rb @@ -36,29 +36,15 @@ RSpec.describe MergeRequests::ApprovalService do it 'does not publish MergeRequests::ApprovedEvent' do expect { service.execute(merge_request) }.not_to publish_event(MergeRequests::ApprovedEvent) end + end - context 'async_after_approval feature flag is disabled' do - before do - stub_feature_flags(async_after_approval: false) - end - - it 'does not create approve MR event' do - expect(EventCreateService).not_to receive(:new) - - service.execute(merge_request) - end - - it 'does not create an approval note' do - expect(SystemNoteService).not_to receive(:approve_mr) - - service.execute(merge_request) - end - - it 'does not mark pending todos as done' do - service.execute(merge_request) + context 'with an already approved MR' do + before do + merge_request.approvals.create!(user: user) + end - expect(todo.reload).to be_pending - end + it 'does not create an approval' do + expect { service.execute(merge_request) }.not_to change { merge_request.approvals.size } end end @@ -81,51 +67,6 @@ RSpec.describe MergeRequests::ApprovalService do .to publish_event(MergeRequests::ApprovedEvent) .with(current_user_id: user.id, merge_request_id: merge_request.id) end - - context 'async_after_approval feature flag is disabled' do - let(:notification_service) { NotificationService.new } - - before do - stub_feature_flags(async_after_approval: false) - allow(service).to receive(:notification_service).and_return(notification_service) - end - - it 'creates approve MR event' do - expect_next_instance_of(EventCreateService) do |instance| - expect(instance).to receive(:approve_mr) - .with(merge_request, user) - end - - service.execute(merge_request) - end - - it 'creates an approval note' do - expect(SystemNoteService).to receive(:approve_mr).with(merge_request, user) - - service.execute(merge_request) - end - - it 'marks pending todos as done' do - service.execute(merge_request) - - expect(todo.reload).to be_done - end - - it 'sends a notification when approving' do - expect(notification_service).to receive_message_chain(:async, :approve_mr) - .with(merge_request, user) - - service.execute(merge_request) - end - - context 'with remaining approvals' do - it 'fires an approval webhook' do - expect(service).to receive(:execute_hooks).with(merge_request, 'approved') - - service.execute(merge_request) - end - end - end end context 'user cannot update the merge request' do diff --git a/spec/services/merge_requests/build_service_spec.rb b/spec/services/merge_requests/build_service_spec.rb index 3c9d2271ddc..6a6f01e6a95 100644 --- a/spec/services/merge_requests/build_service_spec.rb +++ b/spec/services/merge_requests/build_service_spec.rb @@ -20,18 +20,30 @@ RSpec.describe MergeRequests::BuildService do let(:merge_request) { service.execute } let(:compare) { double(:compare, commits: commits) } let(:commit_1) do - double(:commit_1, sha: 'f00ba6', safe_message: 'Initial commit', - gitaly_commit?: false, id: 'f00ba6', parent_ids: ['f00ba5']) + double(:commit_1, + sha: 'f00ba6', + safe_message: 'Initial commit', + gitaly_commit?: false, + id: 'f00ba6', + parent_ids: ['f00ba5']) end let(:commit_2) do - double(:commit_2, sha: 'f00ba7', safe_message: "Closes #1234 Second commit\n\nCreate the app", - gitaly_commit?: false, id: 'f00ba7', parent_ids: ['f00ba6']) + double(:commit_2, + sha: 'f00ba7', + safe_message: "Closes #1234 Second commit\n\nCreate the app", + gitaly_commit?: false, + id: 'f00ba7', + parent_ids: ['f00ba6']) end let(:commit_3) do - double(:commit_3, sha: 'f00ba8', safe_message: 'This is a bad commit message!', - gitaly_commit?: false, id: 'f00ba8', parent_ids: ['f00ba7']) + double(:commit_3, + sha: 'f00ba8', + safe_message: 'This is a bad commit message!', + gitaly_commit?: false, + id: 'f00ba8', + parent_ids: ['f00ba7']) end let(:commits) { nil } diff --git a/spec/services/merge_requests/create_pipeline_service_spec.rb b/spec/services/merge_requests/create_pipeline_service_spec.rb index c443d758a77..dc96b5c0e5e 100644 --- a/spec/services/merge_requests/create_pipeline_service_spec.rb +++ b/spec/services/merge_requests/create_pipeline_service_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe MergeRequests::CreatePipelineService do +RSpec.describe MergeRequests::CreatePipelineService, :clean_gitlab_redis_cache do include ProjectForksHelper let_it_be(:project, reload: true) { create(:project, :repository) } diff --git a/spec/services/merge_requests/create_service_spec.rb b/spec/services/merge_requests/create_service_spec.rb index 9c9bcb79990..4102cdc101e 100644 --- a/spec/services/merge_requests/create_service_spec.rb +++ b/spec/services/merge_requests/create_service_spec.rb @@ -434,7 +434,7 @@ RSpec.describe MergeRequests::CreateService, :clean_gitlab_redis_shared_state do context "when issuable feature is private" do before do project.project_feature.update!(issues_access_level: ProjectFeature::PRIVATE, - merge_requests_access_level: ProjectFeature::PRIVATE) + merge_requests_access_level: ProjectFeature::PRIVATE) end levels = [Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC] diff --git a/spec/services/merge_requests/ff_merge_service_spec.rb b/spec/services/merge_requests/ff_merge_service_spec.rb index 24a1a8b3113..aa5d6dcd1fb 100644 --- a/spec/services/merge_requests/ff_merge_service_spec.rb +++ b/spec/services/merge_requests/ff_merge_service_spec.rb @@ -75,6 +75,7 @@ RSpec.describe MergeRequests::FfMergeService do expect(merge_request).to receive(:update_and_mark_in_progress_merge_commit_sha).twice.and_call_original expect { execute_ff_merge }.not_to change { merge_request.squash_commit_sha } + expect(merge_request.merge_commit_sha).to be_nil expect(merge_request.in_progress_merge_commit_sha).to be_nil end @@ -87,6 +88,7 @@ RSpec.describe MergeRequests::FfMergeService do .to change { merge_request.squash_commit_sha } .from(nil) + expect(merge_request.merge_commit_sha).to be_nil expect(merge_request.in_progress_merge_commit_sha).to be_nil end end @@ -106,7 +108,6 @@ RSpec.describe MergeRequests::FfMergeService do service.execute(merge_request) - expect(merge_request.merge_error).to include(error_message) expect(Gitlab::AppLogger).to have_received(:error).with(a_string_matching(error_message)) end @@ -117,11 +118,6 @@ RSpec.describe MergeRequests::FfMergeService do pre_receive_error = Gitlab::Git::PreReceiveError.new(raw_message, fallback_message: error_message) allow(service).to receive(:repository).and_raise(pre_receive_error) allow(service).to receive(:execute_hooks) - expect(Gitlab::ErrorTracking).to receive(:track_exception).with( - pre_receive_error, - pre_receive_message: raw_message, - merge_request_id: merge_request.id - ) service.execute(merge_request) diff --git a/spec/services/merge_requests/handle_assignees_change_service_spec.rb b/spec/services/merge_requests/handle_assignees_change_service_spec.rb index c43f5db6059..3db3efedb84 100644 --- a/spec/services/merge_requests/handle_assignees_change_service_spec.rb +++ b/spec/services/merge_requests/handle_assignees_change_service_spec.rb @@ -102,7 +102,7 @@ RSpec.describe MergeRequests::HandleAssigneesChangeService do end context 'when execute_hooks option is set to true' do - let(:options) { { execute_hooks: true } } + let(:options) { { 'execute_hooks' => true } } it 'executes hooks and integrations' do expect(merge_request.project).to receive(:execute_hooks).with(anything, :merge_request_hooks) diff --git a/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb b/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb new file mode 100644 index 00000000000..5722bb79cc5 --- /dev/null +++ b/spec/services/merge_requests/mergeability/detailed_merge_status_service_spec.rb @@ -0,0 +1,97 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe ::MergeRequests::Mergeability::DetailedMergeStatusService do + subject(:detailed_merge_status) { described_class.new(merge_request: merge_request).execute } + + context 'when merge status is cannot_be_merged_rechecking' do + let(:merge_request) { create(:merge_request, merge_status: :cannot_be_merged_rechecking) } + + it 'returns :checking' do + expect(detailed_merge_status).to eq(:checking) + end + end + + context 'when merge status is preparing' do + let(:merge_request) { create(:merge_request, merge_status: :preparing) } + + it 'returns :checking' do + expect(detailed_merge_status).to eq(:checking) + end + end + + context 'when merge status is checking' do + let(:merge_request) { create(:merge_request, merge_status: :checking) } + + it 'returns :checking' do + expect(detailed_merge_status).to eq(:checking) + end + end + + context 'when merge status is unchecked' do + let(:merge_request) { create(:merge_request, merge_status: :unchecked) } + + it 'returns :unchecked' do + expect(detailed_merge_status).to eq(:unchecked) + end + end + + context 'when merge checks are a success' do + let(:merge_request) { create(:merge_request) } + + it 'returns :mergeable' do + expect(detailed_merge_status).to eq(:mergeable) + end + end + + context 'when merge status have a failure' do + let(:merge_request) { create(:merge_request) } + + before do + merge_request.close! + end + + it 'returns the failure reason' do + expect(detailed_merge_status).to eq(:not_open) + end + end + + context 'when all but the ci check fails' do + let(:merge_request) { create(:merge_request) } + + before do + merge_request.project.update!(only_allow_merge_if_pipeline_succeeds: true) + end + + context 'when pipeline does not exist' do + it 'returns the failure reason' do + expect(detailed_merge_status).to eq(:ci_must_pass) + end + end + + context 'when pipeline exists' do + before do + create(:ci_pipeline, ci_status, merge_request: merge_request, + project: merge_request.project, sha: merge_request.source_branch_sha, + head_pipeline_of: merge_request) + end + + context 'when the pipeline is running' do + let(:ci_status) { :running } + + it 'returns the failure reason' do + expect(detailed_merge_status).to eq(:ci_still_running) + end + end + + context 'when the pipeline is not running' do + let(:ci_status) { :failed } + + it 'returns the failure reason' do + expect(detailed_merge_status).to eq(:ci_must_pass) + end + end + end + end +end diff --git a/spec/services/merge_requests/mergeability/logger_spec.rb b/spec/services/merge_requests/mergeability/logger_spec.rb new file mode 100644 index 00000000000..a4d544884b9 --- /dev/null +++ b/spec/services/merge_requests/mergeability/logger_spec.rb @@ -0,0 +1,121 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe MergeRequests::Mergeability::Logger, :request_store do + let_it_be(:merge_request) { create(:merge_request) } + + subject(:logger) { described_class.new(merge_request: merge_request) } + + let(:caller_id) { 'a' } + + before do + allow(Gitlab::ApplicationContext).to receive(:current_context_attribute).with(:caller_id).and_return(caller_id) + end + + def loggable_data(**extras) + { + 'mergeability.expensive_operation.duration_s.values' => a_kind_of(Array), + "mergeability_merge_request_id" => merge_request.id, + "correlation_id" => a_kind_of(String), + "mergeability_project_id" => merge_request.project.id + }.merge(extras) + end + + describe '#instrument' do + let(:operation_count) { 1 } + + context 'when enabled' do + it "returns the block's value" do + expect(logger.instrument(mergeability_name: :expensive_operation) { 123 }).to eq(123) + end + + it 'records durations of instrumented operations' do + expect_next_instance_of(Gitlab::AppJsonLogger) do |app_logger| + expect(app_logger).to receive(:info).with(match(a_hash_including(loggable_data))) + end + + expect(logger.instrument(mergeability_name: :expensive_operation) { 123 }).to eq(123) + + logger.commit + end + + context 'with multiple observations' do + let(:operation_count) { 2 } + + it 'records durations of instrumented operations' do + expect_next_instance_of(Gitlab::AppJsonLogger) do |app_logger| + expect(app_logger).to receive(:info).with(match(a_hash_including(loggable_data))) + end + + 2.times do + expect(logger.instrument(mergeability_name: :expensive_operation) { 123 }).to eq(123) + end + + logger.commit + end + end + + context 'when its a query' do + let(:extra_data) do + { + 'mergeability.expensive_operation.db_count.values' => a_kind_of(Array), + 'mergeability.expensive_operation.db_main_count.values' => a_kind_of(Array), + 'mergeability.expensive_operation.db_main_duration_s.values' => a_kind_of(Array), + 'mergeability.expensive_operation.db_primary_count.values' => a_kind_of(Array), + 'mergeability.expensive_operation.db_primary_duration_s.values' => a_kind_of(Array) + } + end + + context 'with a single query' do + it 'includes SQL metrics' do + expect_next_instance_of(Gitlab::AppJsonLogger) do |app_logger| + expect(app_logger).to receive(:info).with(match(a_hash_including(loggable_data(**extra_data)))) + end + + expect(logger.instrument(mergeability_name: :expensive_operation) { MergeRequest.count }).to eq(1) + + logger.commit + end + end + + context 'with multiple queries' do + it 'includes SQL metrics' do + expect_next_instance_of(Gitlab::AppJsonLogger) do |app_logger| + expect(app_logger).to receive(:info).with(match(a_hash_including(loggable_data(**extra_data)))) + end + + expect(logger.instrument(mergeability_name: :expensive_operation) { Project.count + MergeRequest.count }) + .to eq(2) + + logger.commit + end + end + end + end + + context 'when disabled' do + before do + stub_feature_flags(mergeability_checks_logger: false) + end + + it "returns the block's value" do + expect(logger.instrument(mergeability_name: :expensive_operation) { 123 }).to eq(123) + end + + it 'does not call the logger' do + expect(Gitlab::AppJsonLogger).not_to receive(:new) + + expect(logger.instrument(mergeability_name: :expensive_operation) { Project.count + MergeRequest.count }) + .to eq(2) + + logger.commit + end + end + + it 'raises an error when block is not provided' do + expect { logger.instrument(mergeability_name: :expensive_operation) } + .to raise_error(ArgumentError, 'block not given') + end + end +end diff --git a/spec/services/merge_requests/mergeability/run_checks_service_spec.rb b/spec/services/merge_requests/mergeability/run_checks_service_spec.rb index afea3e952a1..cf34923795e 100644 --- a/spec/services/merge_requests/mergeability/run_checks_service_spec.rb +++ b/spec/services/merge_requests/mergeability/run_checks_service_spec.rb @@ -69,6 +69,11 @@ RSpec.describe MergeRequests::Mergeability::RunChecksService do expect(service).to receive(:read).with(merge_check: merge_check).and_return(success_result) end + expect_next_instance_of(MergeRequests::Mergeability::Logger, merge_request: merge_request) do |logger| + expect(logger).to receive(:instrument).with(mergeability_name: 'check_ci_status_service').and_call_original + expect(logger).to receive(:commit) + end + expect(execute.success?).to eq(true) end end @@ -80,6 +85,11 @@ RSpec.describe MergeRequests::Mergeability::RunChecksService do expect(service).to receive(:write).with(merge_check: merge_check, result_hash: success_result.to_hash).and_return(true) end + expect_next_instance_of(MergeRequests::Mergeability::Logger, merge_request: merge_request) do |logger| + expect(logger).to receive(:instrument).with(mergeability_name: 'check_ci_status_service').and_call_original + expect(logger).to receive(:commit) + end + expect(execute.success?).to eq(true) end end diff --git a/spec/services/merge_requests/update_assignees_service_spec.rb b/spec/services/merge_requests/update_assignees_service_spec.rb index f5f6f0ca301..3a0b17c2768 100644 --- a/spec/services/merge_requests/update_assignees_service_spec.rb +++ b/spec/services/merge_requests/update_assignees_service_spec.rb @@ -113,49 +113,6 @@ RSpec.describe MergeRequests::UpdateAssigneesService do expect { service.execute(merge_request) } .to issue_fewer_queries_than { update_service.execute(other_mr) } end - - context 'setting state of assignees' do - before do - stub_feature_flags(mr_attention_requests: false) - end - - it 'does not set state as attention_requested if feature flag is disabled' do - update_merge_request - - expect(merge_request.merge_request_assignees[0].state).not_to eq('attention_requested') - end - - context 'feature flag is enabled for current_user' do - before do - stub_feature_flags(mr_attention_requests: user) - end - - it 'sets state as attention_requested' do - update_merge_request - - expect(merge_request.merge_request_assignees[0].state).to eq('attention_requested') - expect(merge_request.merge_request_assignees[0].updated_state_by).to eq(user) - end - - it 'uses reviewers state if it is same user as new assignee' do - merge_request.reviewers << user2 - - update_merge_request - - expect(merge_request.merge_request_assignees[0].state).to eq('unreviewed') - end - - context 'when assignee_ids matches existing assignee' do - let(:opts) { { assignee_ids: [user3.id] } } - - it 'keeps original assignees state' do - update_merge_request - - expect(merge_request.find_assignee(user3).state).to eq('unreviewed') - end - end - end - end end end end diff --git a/spec/services/merge_requests/update_service_spec.rb b/spec/services/merge_requests/update_service_spec.rb index b7fb48718d8..8ebabd64d8a 100644 --- a/spec/services/merge_requests/update_service_spec.rb +++ b/spec/services/merge_requests/update_service_spec.rb @@ -47,6 +47,11 @@ RSpec.describe MergeRequests::UpdateService, :mailer do @merge_request.reload end + it_behaves_like 'issuable update service updating last_edited_at values' do + let(:issuable) { merge_request } + subject(:update_issuable) { update_merge_request(update_params) } + end + context 'valid params' do let(:locked) { true } @@ -215,14 +220,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer do MergeRequests::UpdateService.new(project: project, current_user: user, params: opts).execute(merge_request) end - - it 'updates attention requested by of reviewer' do - opts[:reviewers] = [user2] - - MergeRequests::UpdateService.new(project: project, current_user: user, params: opts).execute(merge_request) - - expect(merge_request.find_reviewer(user2).updated_state_by).to eq(user) - end end context 'when reviewers did not change' do @@ -328,49 +325,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer do update_merge_request(reviewer_ids: [user.id]) end - - context 'setting state of reviewers' do - before do - stub_feature_flags(mr_attention_requests: false) - end - - it 'does not set state as attention_requested if feature flag is disabled' do - update_merge_request(reviewer_ids: [user.id]) - - expect(merge_request.merge_request_reviewers[0].state).not_to eq('attention_requested') - end - - context 'feature flag is enabled for current_user' do - before do - stub_feature_flags(mr_attention_requests: user) - end - - it 'sets state as attention_requested' do - update_merge_request(reviewer_ids: [user2.id]) - - expect(merge_request.merge_request_reviewers[0].state).to eq('attention_requested') - expect(merge_request.merge_request_reviewers[0].updated_state_by).to eq(user) - end - - it 'keeps original reviewers state' do - merge_request.find_reviewer(user2).update!(state: :unreviewed) - - update_merge_request({ - reviewer_ids: [user2.id] - }) - - expect(merge_request.find_reviewer(user2).state).to eq('unreviewed') - end - - it 'uses reviewers state if it is same user as new assignee' do - merge_request.assignees << user - - update_merge_request(reviewer_ids: [user.id]) - - expect(merge_request.merge_request_reviewers[0].state).to eq('unreviewed') - end - end - end end it 'creates a resource label event' do @@ -561,9 +515,9 @@ RSpec.describe MergeRequests::UpdateService, :mailer do before do create(:ci_pipeline, project: project, - ref: merge_request.source_branch, - sha: merge_request.diff_head_sha, - status: :success) + ref: merge_request.source_branch, + sha: merge_request.diff_head_sha, + status: :success) perform_enqueued_jobs do @merge_request = service.execute(merge_request) @@ -895,7 +849,7 @@ RSpec.describe MergeRequests::UpdateService, :mailer do @merge_request = described_class.new(project: project, current_user: user, params: opts).execute(merge_request) end - should_not_email(subscriber) + should_email(subscriber) should_not_email(non_subscriber) end @@ -1133,53 +1087,6 @@ RSpec.describe MergeRequests::UpdateService, :mailer do end end end - - context 'setting state of assignees' do - before do - stub_feature_flags(mr_attention_requests: false) - end - - it 'does not set state as attention_requested if feature flag is disabled' do - update_merge_request({ - assignee_ids: [user2.id] - }) - - expect(merge_request.merge_request_assignees[0].state).not_to eq('attention_requested') - end - - context 'feature flag is enabled for current_user' do - before do - stub_feature_flags(mr_attention_requests: user) - end - - it 'sets state as attention_requested' do - update_merge_request({ - assignee_ids: [user2.id] - }) - - expect(merge_request.merge_request_assignees[0].state).to eq('attention_requested') - expect(merge_request.merge_request_assignees[0].updated_state_by).to eq(user) - end - - it 'keeps original assignees state' do - update_merge_request({ - assignee_ids: [user3.id] - }) - - expect(merge_request.find_assignee(user3).state).to eq('unreviewed') - end - - it 'uses reviewers state if it is same user as new assignee' do - merge_request.reviewers << user2 - - update_merge_request({ - assignee_ids: [user2.id] - }) - - expect(merge_request.merge_request_assignees[0].state).to eq('unreviewed') - end - end - end end context 'when adding time spent' do |