diff options
Diffstat (limited to 'spec/services/merge_requests/mergeability')
3 files changed, 228 insertions, 0 deletions
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 |