From d1eb7f411de2b51a41d9c3a093e2700b40e34707 Mon Sep 17 00:00:00 2001 From: Richard Davis Date: Mon, 8 Apr 2024 11:12:38 -0400 Subject: [PATCH] Adds debugging info to /v0/profile/contacts endpoint (#16174) --- app/swagger/swagger/schemas/contacts.rb | 8 ++- lib/va_profile/models/associated_person.rb | 12 +++- .../profile/v3/health_benefit_bio_response.rb | 30 +++++---- lib/va_profile/profile/v3/service.rb | 6 +- .../v0/profile/contacts_controller_spec.rb | 2 +- .../models/associated_person_spec.rb | 5 +- .../v3/health_benefit_bio_response_spec.rb | 27 ++++---- .../lib/va_profile/profile/v3/service_spec.rb | 43 ++++++++++-- .../va_profile/contacts_request_spec.rb | 66 ++++++++++++++----- 9 files changed, 144 insertions(+), 55 deletions(-) diff --git a/app/swagger/swagger/schemas/contacts.rb b/app/swagger/swagger/schemas/contacts.rb index d19585b9085..e6a01bf6276 100644 --- a/app/swagger/swagger/schemas/contacts.rb +++ b/app/swagger/swagger/schemas/contacts.rb @@ -10,7 +10,7 @@ class Contacts key :required, [:data] property :data, type: :array do items do - property :id, type: :string, example: 'dbbf9a58-41e5-40c0-bdb5-fc1407aa1f05' + property :id, type: :string property :type, type: :string property :attributes do key :$ref, :Contact @@ -21,7 +21,11 @@ class Contacts swagger_schema :Contact do key :required, %i[contact_type given_name family_name primary_phone] - property :contact_type, type: :string, enum: VAProfile::Models::AssociatedPerson::CONTACT_TYPES + property( + :contact_type, + type: :string, + enum: VAProfile::Models::AssociatedPerson::PERSONAL_HEALTH_CARE_CONTACT_TYPES + ) property :given_name, type: %i[string null] property :family_name, type: %i[string null] property :relationship, type: %i[string null] diff --git a/lib/va_profile/models/associated_person.rb b/lib/va_profile/models/associated_person.rb index 9f9f72c25bc..c100e0e1d33 100644 --- a/lib/va_profile/models/associated_person.rb +++ b/lib/va_profile/models/associated_person.rb @@ -10,19 +10,27 @@ class AssociatedPerson < Base OTHER_EMERGENCY_CONTACT = 'Other emergency contact' PRIMARY_NEXT_OF_KIN = 'Primary Next of Kin' OTHER_NEXT_OF_KIN = 'Other Next of Kin' + DESIGNEE = 'Designee' + POWER_OF_ATTORNEY = 'Power of Attorney' - CONTACT_TYPES = [ + PERSONAL_HEALTH_CARE_CONTACT_TYPES = [ EMERGENCY_CONTACT, OTHER_EMERGENCY_CONTACT, PRIMARY_NEXT_OF_KIN, OTHER_NEXT_OF_KIN ].freeze + CONTACT_TYPES = [ + *PERSONAL_HEALTH_CARE_CONTACT_TYPES, + DESIGNEE, + POWER_OF_ATTORNEY + ].freeze + attribute :contact_type, String attribute :given_name, Common::TitlecaseString attribute :middle_name, Common::TitlecaseString attribute :family_name, Common::TitlecaseString - attribute :relationship, Common::TitlecaseString + attribute :relationship, String attribute :address_line1, String attribute :address_line2, String attribute :address_line3, String diff --git a/lib/va_profile/profile/v3/health_benefit_bio_response.rb b/lib/va_profile/profile/v3/health_benefit_bio_response.rb index 1dde3fb9f89..1b333021400 100644 --- a/lib/va_profile/profile/v3/health_benefit_bio_response.rb +++ b/lib/va_profile/profile/v3/health_benefit_bio_response.rb @@ -8,33 +8,39 @@ module VAProfile module Profile module V3 class HealthBenefitBioResponse < VAProfile::Response - attr_reader :body - attribute :contacts, Array[VAProfile::Models::AssociatedPerson] attribute :messages, Array[VAProfile::Models::Message] + attribute :va_profile_tx_audit_id, String def initialize(response) - @body = response.body + body = response.body contacts = body.dig('profile', 'health_benefit', 'associated_persons') &.select { |p| valid_contact_types.include?(p['contact_type']) } &.sort_by { |p| valid_contact_types.index(p['contact_type']) } messages = body['messages'] - super(response.status, { contacts:, messages: }) + va_profile_tx_audit_id = response.response_headers['vaprofiletxauditid'] + super(response.status, { contacts:, messages:, va_profile_tx_audit_id: }) end - def metadata - { status:, messages: } + def debug_data + { + status:, + message:, + va_profile_tx_audit_id: + } end private def valid_contact_types - [ - VAProfile::Models::AssociatedPerson::EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::OTHER_EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::PRIMARY_NEXT_OF_KIN, - VAProfile::Models::AssociatedPerson::OTHER_NEXT_OF_KIN - ] + VAProfile::Models::AssociatedPerson::PERSONAL_HEALTH_CARE_CONTACT_TYPES + end + + def message + m = messages&.first + return '' unless m + + "#{m.code} #{m.key} #{m.text}" end end end diff --git a/lib/va_profile/profile/v3/service.rb b/lib/va_profile/profile/v3/service.rb index 8c26e61e49f..8b06ccc5f59 100644 --- a/lib/va_profile/profile/v3/service.rb +++ b/lib/va_profile/profile/v3/service.rb @@ -26,8 +26,10 @@ def initialize(user) def get_health_benefit_bio oid = MPI::Constants::VA_ROOT_OID path = "#{oid}/#{ERB::Util.url_encode(icn_with_aaid)}" - response = perform(:post, path, { bios: [{ bioPath: 'healthBenefit' }] }) - VAProfile::Profile::V3::HealthBenefitBioResponse.new(response) + service_response = perform(:post, path, { bios: [{ bioPath: 'healthBenefit' }] }) + response = VAProfile::Profile::V3::HealthBenefitBioResponse.new(service_response) + Sentry.set_extras(response.debug_data) unless response.ok? + response end def get_military_info diff --git a/spec/controllers/v0/profile/contacts_controller_spec.rb b/spec/controllers/v0/profile/contacts_controller_spec.rb index 2ddf67c1864..62131d4d71d 100644 --- a/spec/controllers/v0/profile/contacts_controller_spec.rb +++ b/spec/controllers/v0/profile/contacts_controller_spec.rb @@ -44,7 +44,7 @@ end context 'feature disabled' do - it 'returns an unauthorized status code' do + it 'returns a not found status code' do Flipper.disable(:profile_contacts) sign_in_as user expect(subject).to have_http_status(:not_found) diff --git a/spec/lib/va_profile/models/associated_person_spec.rb b/spec/lib/va_profile/models/associated_person_spec.rb index 8aedcb5ac90..42ee2701a06 100644 --- a/spec/lib/va_profile/models/associated_person_spec.rb +++ b/spec/lib/va_profile/models/associated_person_spec.rb @@ -35,15 +35,12 @@ it 'titlecases family_name' do expect(subject.family_name).to eq('Williams') end - - it 'titlecases relationship' do - expect(subject.relationship).to eq('Unrelated Friend') - end end context 'Virtus::Attribute, String type attributes' do %i[ contact_type + relationship address_line1 address_line2 address_line3 diff --git a/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb b/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb index 70f51f3ed61..8cc61adcadb 100644 --- a/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb +++ b/spec/lib/va_profile/profile/v3/health_benefit_bio_response_spec.rb @@ -7,17 +7,22 @@ subject { described_class.new(response) } let(:response) do - double('Faraday::Response', - status: 200, - body: { - 'profile' => { - 'health_benefit' => { - 'associated_persons' => [{ - 'contact_type' => contact_type - }] - } - } - }) + double( + 'Faraday::Response', + status: 200, + body: { + 'profile' => { + 'health_benefit' => { + 'associated_persons' => [{ + 'contact_type' => contact_type + }] + } + } + }, + response_headers: { + 'vaprofiletxauditid' => 'abc123' + } + ) end describe 'Emergency contact' do diff --git a/spec/lib/va_profile/profile/v3/service_spec.rb b/spec/lib/va_profile/profile/v3/service_spec.rb index da5ec7b9b89..cd37ee8998d 100644 --- a/spec/lib/va_profile/profile/v3/service_spec.rb +++ b/spec/lib/va_profile/profile/v3/service_spec.rb @@ -55,6 +55,19 @@ describe '#get_health_benefit_bio' do let(:user) { build(:user, :loa3, idme_uuid:) } + let(:cassette_filename) { "spec/support/vcr_cassettes/#{cassette}.yml" } + let(:cassette_data) { YAML.load_file(cassette_filename) } + let(:va_profile_tx_audit_id) do + cassette_data['http_interactions'][0]['response']['headers']['Vaprofiletxauditid'][0] + end + let(:debug_data) do + { + status:, + message:, + va_profile_tx_audit_id: + } + end + around do |ex| VCR.use_cassette(cassette) { ex.run } end @@ -68,19 +81,21 @@ expect(response.status).to eq(200) expect(response.contacts.size).to eq(4) types = response.contacts.map(&:contact_type) - valid_contact_types = [ - VAProfile::Models::AssociatedPerson::EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::OTHER_EMERGENCY_CONTACT, - VAProfile::Models::AssociatedPerson::PRIMARY_NEXT_OF_KIN, - VAProfile::Models::AssociatedPerson::OTHER_NEXT_OF_KIN - ] + valid_contact_types = VAProfile::Models::AssociatedPerson::PERSONAL_HEALTH_CARE_CONTACT_TYPES expect(types).to match_array(valid_contact_types) end + + it 'does not call Sentry.set_extras' do + expect(Sentry).not_to receive(:set_extras) + subject.get_health_benefit_bio + end end context '404 response' do let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_404' } + let(:status) { 404 } + let(:message) { 'MVI201 MviNotFound The person with the identifier requested was not found in MVI.' } it 'includes messages received from the api' do response = subject.get_health_benefit_bio @@ -88,11 +103,22 @@ expect(response.contacts.size).to eq(0) expect(response.messages.size).to eq(1) end + + it 'calls Sentry.set_extras' do + expect(Sentry).to receive(:set_extras).once.with(debug_data) + subject.get_health_benefit_bio + end end context '500 response' do let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_500' } + let(:status) { 500 } + let(:message) do + result = 'MVI203 MviResponseError MVI returned acknowledgement error code ' + result += 'AE with error detail: More Than One Active Correlation Exists' + result + end it 'includes messages recieved from the api' do response = subject.get_health_benefit_bio @@ -100,6 +126,11 @@ expect(response.contacts.size).to eq(0) expect(response.messages.size).to eq(1) end + + it 'calls Sentry.set_extras' do + expect(Sentry).to receive(:set_extras).once.with(debug_data) + subject.get_health_benefit_bio + end end context 'api timeout' do diff --git a/spec/requests/va_profile/contacts_request_spec.rb b/spec/requests/va_profile/contacts_request_spec.rb index b44363b3ddd..4f8fef43a7a 100644 --- a/spec/requests/va_profile/contacts_request_spec.rb +++ b/spec/requests/va_profile/contacts_request_spec.rb @@ -7,29 +7,65 @@ let(:user) { build(:user, :loa3, idme_uuid:) } let(:resource) { JSON.parse(response.body) } - describe 'GET /v0/profile/contacts -> 200' do - let(:idme_uuid) { 'dd681e7d6dea41ad8b80f8d39284ef29' } + around do |ex| + VCR.use_cassette(cassette) { ex.run } + end + + describe 'GET /v0/profile/contacts' do + context '200 response' do + let(:idme_uuid) { 'dd681e7d6dea41ad8b80f8d39284ef29' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_200' } - it 'responds with contacts' do - sign_in_as(user) - VCR.use_cassette('va_profile/profile/v3/health_benefit_bio_200') do + it 'responds with contacts' do + sign_in_as(user) get '/v0/profile/contacts' + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('contacts') + expect(resource['data'].size).to eq(4) + end + end + + context '401 response' do + let(:idme_uuid) { 'dd681e7d6dea41ad8b80f8d39284ef29' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_200' } + + it 'responds with 401 status' do + get '/v0/profile/contacts' + expect(response).to have_http_status(:unauthorized) + end + end + + context '403 response' do + let(:user) { build(:user, :loa1) } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_200' } + + it 'responds with 403 status' do + sign_in_as(user) + get '/v0/profile/contacts' + expect(response).to have_http_status(:forbidden) + end + end + + context '404 response' do + let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_404' } + + it 'responds with 404 status' do + sign_in_as(user) + get '/v0/profile/contacts' + expect(response).to have_http_status(:not_found) end - expect(response).to have_http_status(:ok) - expect(response).to match_response_schema('contacts') - expect(resource['data'].size).to eq(4) end - end - describe 'GET /v0/profile/contacts -> 404' do - let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } + context '500 response' do + let(:idme_uuid) { '88f572d4-91af-46ef-a393-cba6c351e252' } + let(:cassette) { 'va_profile/profile/v3/health_benefit_bio_500' } - it 'responds with 404 status' do - sign_in_as(user) - VCR.use_cassette('va_profile/profile/v3/health_benefit_bio_404') do + it 'responds with 500 status' do + sign_in_as(user) get '/v0/profile/contacts' + expect(response).to have_http_status(:internal_server_error) end - expect(response).to have_http_status(:not_found) end end end