Skip to content
19 changes: 13 additions & 6 deletions app/services/proofing/aamva/response/verification_response.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,17 @@ def initialize(http_response)
@missing_attributes = []
@verification_results = {}
@http_response = http_response
@errors = []

handle_http_error
handle_soap_error

parse_response

return if @errors.empty?

error_message = @errors.join('; ')
raise VerificationError.new(error_message)
end

def reasons
Expand Down Expand Up @@ -63,8 +71,7 @@ def success?

def handle_http_error
status = http_response.status
return if status == 200
raise VerificationError, "Unexpected status code in response: #{status}"
@errors.push("Unexpected status code in response: #{status}") if status != 200
end

def handle_missing_attribute(attribute_name)
Expand All @@ -76,13 +83,13 @@ def handle_soap_error
error_handler = SoapErrorHandler.new(http_response)
return unless error_handler.error_present?

msg = error_handler.error_message
raise ::Proofing::TimeoutError, msg if mva_timeout?(msg)
raise VerificationError, msg
@errors.push(error_handler.error_message)
end

def node_for_match_indicator(match_indicator_name)
REXML::XPath.first(rexml_document, "//#{match_indicator_name}")
rescue REXML::ParseException
nil
end

def parse_response
Expand All @@ -104,7 +111,7 @@ def parse_response
end

def rexml_document
@rexml_document ||= REXML::Document.new(http_response.body)
return @rexml_document ||= REXML::Document.new(http_response.body)
end

def mva_timeout?(error_message)
Expand Down
3 changes: 3 additions & 0 deletions app/services/proofing/aamva/soap_error_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class SoapErrorHandler
def initialize(http_response)
@document = REXML::Document.new(http_response.body)
parse_error_message
rescue REXML::ParseException => e
@error_present = true
@error_message = e.to_s
end

def error_present?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
it 'raises a VerificationError' do
expect { subject }.to raise_error(
Proofing::Aamva::VerificationError,
'Unexpected status code in response: 504',
/Unexpected status code in response: 504/,
)
end
end
Expand Down
158 changes: 132 additions & 26 deletions spec/services/proofing/aamva/verification_client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@
subject(:verification_client) { described_class.new(AamvaFixtures.example_config) }

describe '#send_verification_request' do
it 'should get the auth token from the auth client' do
before do
auth_client = instance_double(Proofing::Aamva::AuthenticationClient)
allow(auth_client).to receive(:fetch_token).and_return('ThisIsTheToken')
allow(Proofing::Aamva::AuthenticationClient).to receive(:new).and_return(auth_client)
end

it 'gets the auth token from the auth client' do
verification_stub = stub_request(:post, AamvaFixtures.example_config.verification_url).
to_return(body: AamvaFixtures.verification_response, status: 200).
with do |request|
Expand All @@ -37,45 +39,149 @@

expect(verification_stub).to have_been_requested
end
end

context 'when verification is successful' do
it 'should return a successful response' do
auth_client = instance_double(Proofing::Aamva::AuthenticationClient)
allow(auth_client).to receive(:fetch_token).and_return('ThisIsTheToken')
allow(Proofing::Aamva::AuthenticationClient).to receive(:new).and_return(auth_client)
stub_request(:post, AamvaFixtures.example_config.verification_url).
to_return(body: AamvaFixtures.verification_response, status: 200)

response = verification_client.send_verification_request(
applicant: applicant,
session_id: '1234-abcd-efgh',
)
describe '#send_verification_request' do
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This describe block looks like it is describing the same method as the block above

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is, but a different aspect of the method. The setup code was different enough to warrant splitting the describe block.

let(:response_body) { AamvaFixtures.verification_response }
let(:response_http_status) { 200 }

before do
auth_client = instance_double(Proofing::Aamva::AuthenticationClient)
allow(auth_client).to receive(:fetch_token).and_return('ThisIsTheToken')
allow(Proofing::Aamva::AuthenticationClient).to receive(:new).and_return(auth_client)

stub_request(:post, AamvaFixtures.example_config.verification_url).
to_return(body: response_body, status: response_http_status)
end

let(:response) do
verification_client.send_verification_request(
applicant: applicant,
session_id: '1234-abcd-efgh',
)
end

context 'when verification is successful' do
it 'returns a successful response' do
expect(response).to be_a Proofing::Aamva::Response::VerificationResponse
expect(response.success?).to eq(true)
end
end

context 'when verification is not successful' do
it 'should return an unsuccessful response with errors' do
auth_client = instance_double(Proofing::Aamva::AuthenticationClient)
allow(auth_client).to receive(:fetch_token).and_return('ThisIsTheToken')
allow(Proofing::Aamva::AuthenticationClient).to receive(:new).and_return(auth_client)
context 'because we have a valid response and a 200 status, but the response says "no"' do
let(:response_body) do
modify_xml_at_xpath(
AamvaFixtures.verification_response,
'//PersonBirthDateMatchIndicator',
'false',
)
end

it 'returns an unsuccessful response with errors' do
expect(response).to be_a Proofing::Aamva::Response::VerificationResponse
expect(response.success?).to eq(false)
end
end

stub_request(:post, AamvaFixtures.example_config.verification_url).
to_return(status: 200, body: modify_xml_at_xpath(
context 'because we have a valid response and a non-200 status, and the response says "no"' do
let(:response_body) do
modify_xml_at_xpath(
AamvaFixtures.verification_response,
'//PersonBirthDateMatchIndicator',
'false',
))
)
end
let(:response_http_status) { 500 }

it 'throws an exception about the status code' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/Unexpected status code in response: 500/,
)
end
end

response = verification_client.send_verification_request(
applicant: applicant,
session_id: '1234-abcd-efgh',
)
context 'because we have an MVA timeout and 500 status' do
let(:response_body) { AamvaFixtures.soap_fault_response }
let(:response_http_status) { 500 }

expect(response).to be_a Proofing::Aamva::Response::VerificationResponse
expect(response.success?).to eq(false)
it 'throws an exception about the MVA timeout' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/#{Proofing::Aamva::Response::VerificationResponse::MVA_TIMEOUT_EXCEPTION}/o,
)
end

it 'throws an exception about the status code' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/Unexpected status code in response: 500/,
)
end
end

context 'because we have an MVA timeout and 200 status' do
let(:response_body) { AamvaFixtures.soap_fault_response }
let(:response_http_status) { 200 }

it 'parses the raw response body' do
begin
response
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I follow what this test is trying to accomplish? It looks like the test below covers what we actually care about.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An explicit test that we tried to parse the body.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

rescue Proofing::Aamva::VerificationError
end
end

it 'throws an exception about the MVA timeout' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/#{Proofing::Aamva::Response::VerificationResponse::MVA_TIMEOUT_EXCEPTION}/o,
)
end
end

context 'because we have an invalid response and a 200 status' do
let(:response_body) { 'error: computer has no brain.<br>' }

it 'tries to parse the raw response body' do
begin
response
rescue Proofing::Aamva::VerificationError
end
end

it 'throws a SOAP exception' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/No close tag for \/br/,
)
end
end

context 'because we have an invalid response and a non-200 status' do
let(:response_body) { '<h1>I\'m a teapot' }
let(:response_http_status) { 418 }

it 'tries to parse the raw response body' do
begin
response
rescue Proofing::Aamva::VerificationError
end
end

it 'throws an error which complains about the invalid response' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/No close tag for \/h1/,
)
end

it 'throws an error which complains about the HTTP error code' do
expect { response }.to raise_error(
Proofing::Aamva::VerificationError,
/Unexpected status code in response: 418/,
)
end
end
end
end
Expand Down