From 96ce45ac9b36bc03742e42810f0308a21c2d6568 Mon Sep 17 00:00:00 2001 From: Patrick Cyiza Date: Wed, 23 Nov 2022 17:19:39 +0100 Subject: [PATCH] Add GRPC code to error handling and add custom error codes in GQL --- .../resolvers/paginated_tree_resolver.rb | 5 +- lib/gitlab/git/base_error.rb | 46 +++++++++++++++---- .../resolvers/paginated_tree_resolver_spec.rb | 21 +++++++-- spec/lib/gitlab/git/base_error_spec.rb | 11 +++++ 4 files changed, 71 insertions(+), 12 deletions(-) diff --git a/app/graphql/resolvers/paginated_tree_resolver.rb b/app/graphql/resolvers/paginated_tree_resolver.rb index c7e9e522c25257..6c4e978125e3cd 100644 --- a/app/graphql/resolvers/paginated_tree_resolver.rb +++ b/app/graphql/resolvers/paginated_tree_resolver.rb @@ -41,7 +41,10 @@ def resolve(**args) next_cursor = tree.cursor&.next_cursor Gitlab::Graphql::ExternallyPaginatedArray.new(cursor, next_cursor, *tree) rescue Gitlab::Git::CommandError => e - raise Gitlab::Graphql::Errors::ArgumentError, e + raise Gitlab::Graphql::Errors::BaseError.new( + e, + extensions: { code: e.code, gitaly_code: e.status, service: e.service } + ) end def self.field_options diff --git a/lib/gitlab/git/base_error.rb b/lib/gitlab/git/base_error.rb index a7eaa82b347002..0b0fdef54ccbe5 100644 --- a/lib/gitlab/git/base_error.rb +++ b/lib/gitlab/git/base_error.rb @@ -1,20 +1,50 @@ # frozen_string_literal: true +require 'grpc' module Gitlab module Git class BaseError < StandardError DEBUG_ERROR_STRING_REGEX = /(.*?) debug_error_string:.*$/m.freeze + GRPC_CODES = { + '0' => 'ok', + '1' => 'cancelled', + '2' => 'unknown', + '3' => 'invalid_argument', + '4' => 'deadline_exceeded', + '5' => 'not_found', + '6' => 'already_exists', + '7' => 'permission_denied', + '8' => 'resource_exhausted', + '9' => 'failed_precondition', + '10' => 'aborted', + '11' => 'out_of_range', + '12' => 'unimplemented', + '13' => 'internal', + '14' => 'unavailable', + '15' => 'data_loss', + '16' => 'unauthenticated' + }.freeze + + attr_reader :status, :code, :service def initialize(msg = nil) - if msg - raw_message = msg.to_s - match = DEBUG_ERROR_STRING_REGEX.match(raw_message) - raw_message = match[1] if match + super && return if msg.nil? + + set_grpc_error_code(msg) if msg.is_a?(::GRPC::BadStatus) + + super(build_raw_message(msg)) + end + + def build_raw_message(message) + raw_message = message.to_s + match = DEBUG_ERROR_STRING_REGEX.match(raw_message) + match ? match[1] : raw_message + end - super(raw_message) - else - super - end + def set_grpc_error_code(grpc_error) + @status = grpc_error.code + @code = GRPC_CODES[@status.to_s] + @service = 'git' end end end diff --git a/spec/graphql/resolvers/paginated_tree_resolver_spec.rb b/spec/graphql/resolvers/paginated_tree_resolver_spec.rb index 4b05e9076d7a92..9a04b716001f56 100644 --- a/spec/graphql/resolvers/paginated_tree_resolver_spec.rb +++ b/spec/graphql/resolvers/paginated_tree_resolver_spec.rb @@ -66,9 +66,8 @@ let(:args) { super().merge(after: 'invalid') } it 'generates an error' do - expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ArgumentError) do - subject - end + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::BaseError) { subject } + expect(subject.extensions.keys).to match_array([:code, :gitaly_code, :service]) end end @@ -92,6 +91,22 @@ expect(collected_entries).to match_array(expected_entries) end end + + describe 'Custom error handling' do + before do + grpc_err = GRPC::Unavailable.new + allow(repository).to receive(:tree).and_raise(Gitlab::Git::CommandError, grpc_err) + end + + context 'when gitaly is not available' do + let(:request) { get :index, format: :html, params: { namespace_id: project.namespace, project_id: project } } + + it 'generates an unavailable error' do + expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::BaseError) { subject } + expect(subject.extensions).to eq(code: 'unavailable', gitaly_code: 14, service: 'git') + end + end + end end def resolve_repository(args, opts = {}) diff --git a/spec/lib/gitlab/git/base_error_spec.rb b/spec/lib/gitlab/git/base_error_spec.rb index 851cfa16512170..d4db7cf2430c56 100644 --- a/spec/lib/gitlab/git/base_error_spec.rb +++ b/spec/lib/gitlab/git/base_error_spec.rb @@ -20,4 +20,15 @@ with_them do it { is_expected.to eq(result) } end + + describe "When initialized with GRPC errors" do + let(:grpc_error) { GRPC::DeadlineExceeded.new } + let(:git_error) { described_class.new grpc_error } + + it "has status and code fields" do + expect(git_error.service).to eq('git') + expect(git_error.status).to eq(4) + expect(git_error.code).to eq('deadline_exceeded') + end + end end -- GitLab