diff --git a/app/services/doc_auth/dos/request.rb b/app/services/doc_auth/dos/request.rb index a37fdc8a7f1..c370c5fbc9f 100644 --- a/app/services/doc_auth/dos/request.rb +++ b/app/services/doc_auth/dos/request.rb @@ -67,12 +67,24 @@ def handle_invalid_response(http_response) {} end + # Handle both nested error format and simple string error format + error_value = response_body['error'] + error_code, error_message, error_reason = case error_value + when Hash + # Nested format: {"error": {"code": "...", "message": "...", "reason": "..."}} + [error_value['code'], error_value['message'], error_value['reason']] + when String + # Simple format: {"error": "Invalid Client"} or {"error": "Authentication denied."} + [nil, error_value, nil] + else + [nil, nil, nil] + end + handle_connection_error( exception: exception, - # TODO: update for DoS - error_code: response_body.dig('error', 'code'), - error_message: response_body.dig('error', 'message'), - error_reason: response_body.dig('error', 'reason'), + error_code: error_code, + error_message: error_message, + error_reason: error_reason, correlation_id_received: http_response.headers['X-Correlation-ID'], ) end @@ -95,7 +107,7 @@ def handle_connection_error( error_reason: error_reason, correlation_id_sent: correlation_id, correlation_id_received:, - }.compact, + }, ) end diff --git a/spec/services/doc_auth/dos/request_spec.rb b/spec/services/doc_auth/dos/request_spec.rb index e894909100d..98d0d36377e 100644 --- a/spec/services/doc_auth/dos/request_spec.rb +++ b/spec/services/doc_auth/dos/request_spec.rb @@ -78,4 +78,92 @@ end end end + + describe '#handle_invalid_response' do + let(:http_response) do + instance_double( + Faraday::Response, + status: status, + body: response_body, + headers: { 'X-Correlation-ID' => '12345' }, + ) + end + let(:status) { 401 } + + context 'with nested error format' do + let(:response_body) do + { error: { code: 'ERR001', message: 'Invalid request', reason: 'Bad format' } }.to_json + end + + it 'extracts error details from nested hash' do + response = subject.send(:handle_invalid_response, http_response) + + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: 'ERR001', + error_message: 'Invalid request', + error_reason: 'Bad format', + correlation_id_received: '12345', + ) + end + end + + context 'with simple string error format' do + let(:response_body) do + { error: 'Authentication denied.' }.to_json + end + + it 'extracts error message from string' do + response = subject.send(:handle_invalid_response, http_response) + + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: nil, + error_message: 'Authentication denied.', + error_reason: nil, + correlation_id_received: '12345', + ) + end + end + + context 'with invalid JSON' do + let(:response_body) { 'Not JSON' } + + it 'handles non-JSON response gracefully' do + response = subject.send(:handle_invalid_response, http_response) + + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: nil, + error_message: nil, + error_reason: nil, + correlation_id_received: '12345', + ) + end + end + + context 'with empty response body' do + let(:response_body) { '' } + + it 'handles empty response gracefully' do + response = subject.send(:handle_invalid_response, http_response) + + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: nil, + error_message: nil, + error_reason: nil, + correlation_id_received: '12345', + ) + end + end + end end diff --git a/spec/services/doc_auth/dos/requests/mrz_request_spec.rb b/spec/services/doc_auth/dos/requests/mrz_request_spec.rb index 6e7bd1a38e2..b0e06bff03f 100644 --- a/spec/services/doc_auth/dos/requests/mrz_request_spec.rb +++ b/spec/services/doc_auth/dos/requests/mrz_request_spec.rb @@ -86,23 +86,64 @@ end context 'when the request fails' do - let(:http_status) { 500 } - let(:response_body) do - { error: { code: 'ERR', message: 'issues @ State', reason: 'just because' } }.to_json + let(:http_status) { 401 } + + context 'when the response error is a hash' do + let(:response_body) do + { error: { code: 'ERR', message: 'issues @ State', reason: 'just because' } }.to_json + end + + it 'handles the nested error without throwing an exception' do + response = subject.fetch + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: 'ERR', + error_message: 'issues @ State', + error_reason: 'just because', + correlation_id_sent: correlation_id, + correlation_id_received: correlation_id, + ) + end end - it 'fails with a message' do - response = subject.fetch - expect(response.success?).to be(false) - expect(response.errors).to include(network: true) - expect(response.extra).to include( - vendor: 'DoS', - error_code: 'ERR', - error_message: 'issues @ State', - error_reason: 'just because', - correlation_id_sent: correlation_id, - correlation_id_received: correlation_id, - ) + context 'when the response error is a string' do + let(:response_body) do + { error: 'Authentication denied.' }.to_json + end + + it 'handles the string error without throwing an exception' do + response = subject.fetch + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: nil, + error_message: 'Authentication denied.', + error_reason: nil, + correlation_id_sent: correlation_id, + correlation_id_received: correlation_id, + ) + end + end + + context 'when the response error is empty' do + let(:response_body) { '' } + + it 'handles empty response gracefully' do + response = subject.fetch + expect(response.success?).to be(false) + expect(response.errors).to include(network: true) + expect(response.extra).to include( + vendor: 'DoS', + error_code: nil, + error_message: nil, + error_reason: nil, + correlation_id_sent: correlation_id, + correlation_id_received: correlation_id, + ) + end end end end