diff --git a/app/controllers/v0/profile/persons_controller.rb b/app/controllers/v0/profile/persons_controller.rb index 8537c22e30a..5307b3b0af0 100644 --- a/app/controllers/v0/profile/persons_controller.rb +++ b/app/controllers/v0/profile/persons_controller.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'va_profile/person/service' +require 'va_profile/v2/person/service' module V0 module Profile @@ -11,7 +12,11 @@ class PersonsController < ApplicationController after_action :invalidate_mpi_cache def initialize_vet360_id - response = VAProfile::Person::Service.new(@current_user).init_vet360_id + response = if Flipper.enabled?(:va_v3_contact_information_service, @current_user) + VAProfile::V2::Person::Service.new(@current_user).init_vet360_id + else + VAProfile::Person::Service.new(@current_user).init_vet360_id + end transaction = AsyncTransaction::VAProfile::InitializePersonTransaction.start(@current_user, response) render json: AsyncTransaction::BaseSerializer.new(transaction).serializable_hash diff --git a/app/sidekiq/copay_notifications/mcp_notification_email_job.rb b/app/sidekiq/copay_notifications/mcp_notification_email_job.rb index b663fa83a96..e61a4009ea1 100644 --- a/app/sidekiq/copay_notifications/mcp_notification_email_job.rb +++ b/app/sidekiq/copay_notifications/mcp_notification_email_job.rb @@ -50,7 +50,11 @@ def send_email(email, template_id, personalisation) private def person_response(vet360_id) - VAProfile::ContactInformation::Service.get_person(vet360_id) + if Flipper.enabled?(:va_v3_contact_information_service) + VAProfile::V2::ContactInformation::Service.get_person(vet360_id) + else + VAProfile::ContactInformation::Service.get_person(vet360_id) + end end end end diff --git a/lib/va_profile/v2/contact_information/service.rb b/lib/va_profile/v2/contact_information/service.rb index 8c3dfa41179..907c2b22a41 100644 --- a/lib/va_profile/v2/contact_information/service.rb +++ b/lib/va_profile/v2/contact_information/service.rb @@ -35,11 +35,11 @@ class Service < VAProfile::Service def get_person with_monitoring do vet360_id_present! - raw_response = perform(:get, "#{MPI::Constants::VA_ROOT_OID}/#{ERB::Util.url_encode(icn_with_aaid)}") + raw_response = perform(:get, "#{MPI::Constants::VA_ROOT_OID}/#{ERB::Util.url_encode(uuid_with_aaid)}") PersonResponse.from(raw_response) end rescue Common::Client::Errors::ClientError => e - if e.status == 400 + if e.status == 404 log_exception_to_sentry( e, { vet360_id: }, @@ -213,9 +213,10 @@ def get_person_transaction_status(transaction_id) private - def icn_with_aaid + def uuid_with_aaid return "#{@user.idme_uuid}^PN^200VIDM^USDVA" if @user.idme_uuid return "#{@user.logingov_uuid}^PN^200VLGN^USDVA" if @user.logingov_uuid + return "#{vet360_id}^PI^200VETS^USDVA" if @user.idme_uuid.blank? && @user.logingov_uuid.blank? nil end @@ -289,7 +290,7 @@ def vet360_id_present! def post_or_put_data(method, model, path, response_class) with_monitoring do vet360_id_present! - request_path = "#{MPI::Constants::VA_ROOT_OID}/#{ERB::Util.url_encode(icn_with_aaid)}" + "/#{path}" + request_path = "#{MPI::Constants::VA_ROOT_OID}/#{ERB::Util.url_encode(uuid_with_aaid)}" + "/#{path}" raw_response = perform(method, request_path, model.in_json) response_class.from(raw_response) end diff --git a/lib/va_profile/v2/person/service.rb b/lib/va_profile/v2/person/service.rb new file mode 100644 index 00000000000..37f2265ce30 --- /dev/null +++ b/lib/va_profile/v2/person/service.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'common/client/base' +require 'common/client/concerns/monitoring' +require 'va_profile/v2/contact_information/configuration' +require 'va_profile/v2/contact_information/transaction_response' +require 'va_profile/service' +require 'va_profile/stats' +require 'identity/parsers/gc_ids_constants' + +module VAProfile + module V2 + module Person + class Service < VAProfile::Service + include Common::Client::Concerns::Monitoring + include ERB::Util + + STATSD_KEY_PREFIX = "#{VAProfile::Service::STATSD_KEY_PREFIX}.person".freeze + configuration VAProfile::V2::ContactInformation::Configuration + + # Initializes a vet360_id for a user that does not have one. Can be used when a current user + # is present, or through a rake task when no user is present (through passing in their ICN). + # This is an asynchronous process for VAProfile, so it returns VAProfile transaction information. + # + # @return [VAProfile::V2::ContactInformation::PersonTransactionResponse] + # response wrapper around a transaction object + # + def init_vet360_id + with_monitoring do + raw_response = perform(:post, "#{MPI::Constants::VA_ROOT_OID}/#{ERB::Util.url_encode(uuid_with_aaid)}", + empty_body) + VAProfile::V2::ContactInformation::PersonTransactionResponse.from(raw_response, @user) + end + rescue => e + handle_error(e) + end + + private + + # @see https://ruby-doc.org/stdlib-2.3.0/libdoc/erb/rdoc/ERB/Util.html + # + def uuid_with_aaid + return "#{@user.idme_uuid}^PN^200VIDM^USDVA" if @user.idme_uuid + return "#{@user.logingov_uuid}^PN^200VLGN^USDVA" if @user.logingov_uuid + return "#{@user.vet360_id}^PI^200VETS^USDVA" if @user.idme_uuid.blank? && @user.logingov_uuid.blank? + + nil + end + + def empty_body + { + bio: { + sourceDate: Time.zone.now.iso8601 + } + }.to_json + end + end + end + end +end diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 28e1c68305b..634a296fc33 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -151,24 +151,6 @@ person_types { ['DEP'] } end - trait :error do - authn_context { LOA::IDME_LOA3_VETS } - - sign_in do - { - service_name: SAML::User::AUTHN_CONTEXTS[authn_context][:sign_in][:service_name], - auth_broker: SAML::URLService::BROKER_CODE, - client_id: SAML::URLService::UNIFIED_SIGN_IN_CLIENTS.first - } - end - - loa do - { current: LOA::THREE, highest: LOA::THREE } - end - - idme_uuid { '6767671' } - end - trait :accountable do authn_context { LOA::IDME_LOA3_VETS } uuid { '9d018700-b72c-444a-95b4-43e14a4509ea' } diff --git a/spec/lib/common/models/concerns/cache_aside_spec.rb b/spec/lib/common/models/concerns/cache_aside_spec.rb index 24173bedf78..0357b9f28da 100644 --- a/spec/lib/common/models/concerns/cache_aside_spec.rb +++ b/spec/lib/common/models/concerns/cache_aside_spec.rb @@ -13,7 +13,11 @@ end before do - allow(VAProfile::Models::Person).to receive(:build_from).and_return(person) + if Flipper.enabled?(:va_v3_contact_information_service) + allow(VAProfile::Models::V2::Person).to receive(:build_from).and_return(person) + else + allow(VAProfile::Models::Person).to receive(:build_from).and_return(person) + end end describe '#do_cached_with' do diff --git a/spec/lib/debt_management_center/statement_identifier_service_spec.rb b/spec/lib/debt_management_center/statement_identifier_service_spec.rb index 4525da777c6..9739e323491 100644 --- a/spec/lib/debt_management_center/statement_identifier_service_spec.rb +++ b/spec/lib/debt_management_center/statement_identifier_service_spec.rb @@ -7,6 +7,194 @@ type: :service do describe '#get_mpi_data' do Flipper.disable(:va_v3_contact_information_service) + + context 'given edipi statement' do + edipi = '492031291' + let(:verification) { build(:dslogon_user_verification) } + let(:edipi_statement) do + { + 'veteranIdentifier' => edipi, + 'identifierType' => 'edipi', + 'facilityNum' => '123', + 'facilityName' => 'VA Medical Center', + 'statementDate' => '01/01/2023' + } + end + let(:mpi_profile) { build(:mpi_profile) } + let(:profile_response) { create(:find_profile_response, profile: mpi_profile) } + + context 'when MPI gets a GatewayTimeout' do + let(:address) { 'person43@example.com' } + let(:expected_error) { Common::Exceptions::GatewayTimeout } + let(:expected_error_message) { expected_error.new.message } + + before { allow_any_instance_of(Faraday::Connection).to receive(:post).and_raise(Faraday::TimeoutError) } + + it 'recognizes this error is retryable' do + service = described_class.new(edipi_statement) + + expect { service.get_mpi_data } + .to raise_error(described_class::RetryableError) + end + end + + context 'when MPI fails to breakers outage' do + let(:current_time) { Time.zone.now } + let(:expected_error) { Breakers::OutageException } + let(:expected_error_message) { "Outage detected on MVI beginning at #{current_time.to_i}" } + + before do + Timecop.freeze + MPI::Configuration.instance.breakers_service.begin_forced_outage! + end + + after { Timecop.return } + + it 'recognizes this error is retryable' do + service = described_class.new(edipi_statement) + expect { service.get_mpi_data }.to raise_error(described_class::RetryableError) + end + end + + context 'MPI profile found' do + before do + mpi_profile.vet360_id = '1' + allow_any_instance_of(MPI::Service).to receive(:find_profile_by_edipi).and_return(profile_response) + allow_any_instance_of(VaNotify::Configuration).to receive(:base_path).and_return('http://fakeapi.com') + allow(Settings.vanotify.services.dmc).to receive(:api_key).and_return( + 'test-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa-bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' + ) + end + + it 'returns an icn' do + VCR.use_cassette('va_profile/contact_information/person_full', VCR::MATCH_EVERYTHING) do + service = described_class.new(edipi_statement) + details = service.get_mpi_data + expect(details).to eq({ icn: mpi_profile.icn, first_name: mpi_profile.given_names.first }) + end + end + end + + context 'MPI profile not found' do + let(:profile_not_found_error) { create(:find_profile_not_found_response) } + + before do + allow_any_instance_of(MPI::Service).to receive(:find_profile_by_edipi).and_return(profile_not_found_error) + end + + it 'raises not found error from MPI' do + service = described_class.new(edipi_statement) + expect { service.get_mpi_data } + .to raise_error(MPI::Errors::RecordNotFound) + end + end + + context 'MPI service error' do + let(:profile_response_error) { create(:find_profile_server_error_response) } + + before do + allow_any_instance_of(MPI::Service).to receive(:find_profile_by_edipi).and_return(profile_response_error) + end + + it 'raises server error from MPI' do + service = described_class.new(edipi_statement) + expect { service.get_mpi_data } + .to raise_error(MPI::Errors::FailedRequestError) + end + end + end + + context 'given vista statement' do + let(:vista_statement) do + { + 'veteranIdentifier' => '348530923', + 'identifierType' => 'dfn', + 'facilityNum' => '456', + 'facilityName' => 'VA Medical Center', + 'statementDate' => '01/01/2023' + } + end + let(:mpi_profile) { build(:mpi_profile) } + let(:profile_response) { create(:find_profile_response, profile: mpi_profile) } + + context 'when MPI gets a GatewayTimeout' do + let(:expected_error) { Common::Exceptions::GatewayTimeout } + let(:expected_error_message) { expected_error.new.message } + + before { allow_any_instance_of(Faraday::Connection).to receive(:post).and_raise(Faraday::TimeoutError) } + + it 'recognizes this error is retryable' do + service = described_class.new(vista_statement) + + expect { service.get_mpi_data } + .to raise_error(described_class::RetryableError) + end + end + + context 'when MPI fails to breakers outage' do + let(:current_time) { Time.zone.now } + let(:expected_error) { Breakers::OutageException } + let(:expected_error_message) { "Outage detected on MVI beginning at #{current_time.to_i}" } + + before do + Timecop.freeze + MPI::Configuration.instance.breakers_service.begin_forced_outage! + end + + after { Timecop.return } + + it 'recognizes this error is retryable' do + service = described_class.new(vista_statement) + expect { service.get_mpi_data }.to raise_error(described_class::RetryableError) + end + end + + context 'MPI profile found' do + let(:account) { build(:user_account_with_verification) } + + before do + allow_any_instance_of(MPI::Service).to receive(:find_profile_by_facility).and_return(profile_response) + end + + it 'can get an email from icn' do + service = described_class.new(vista_statement) + details = service.get_mpi_data + expect(details).to eq({ icn: mpi_profile.icn, first_name: mpi_profile.given_names.first }) + end + end + + context 'MPI profile not found' do + let(:profile_not_found_error) { create(:find_profile_not_found_response) } + + before do + allow_any_instance_of(MPI::Service).to receive(:find_profile_by_facility).and_return(profile_not_found_error) + end + + it 'raises not found error from MPI' do + service = described_class.new(vista_statement) + expect { service.get_mpi_data } + .to raise_error(MPI::Errors::RecordNotFound) + end + end + + context 'MPI service error' do + let(:profile_response_error) { create(:find_profile_server_error_response) } + + before do + allow_any_instance_of(MPI::Service).to receive(:find_profile_by_facility).and_return(profile_response_error) + end + + it 'raises server error from MPI' do + service = described_class.new(vista_statement) + expect { service.get_mpi_data } + .to raise_error(MPI::Errors::FailedRequestError) + end + end + end + end + + describe '#get_mpi_data v2' do + Flipper.enable(:va_v3_contact_information_service) let(:cassette_path) do if Flipper.enabled?(:va_v3_contact_information_service) 'va_profile/v2/contact_information' @@ -65,7 +253,7 @@ context 'MPI profile found' do before do - mpi_profile.vet360_id = '1' + mpi_profile.vet360_id = '1781151' allow_any_instance_of(MPI::Service).to receive(:find_profile_by_edipi).and_return(profile_response) allow_any_instance_of(VaNotify::Configuration).to receive(:base_path).and_return('http://fakeapi.com') allow(Settings.vanotify.services.dmc).to receive(:api_key).and_return( @@ -74,7 +262,7 @@ end it 'returns an icn' do - VCR.use_cassette("#{cassette_path}/person_full", VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/contact_information/person_full', VCR::MATCH_EVERYTHING) do service = described_class.new(edipi_statement) details = service.get_mpi_data expect(details).to eq({ icn: mpi_profile.icn, first_name: mpi_profile.given_names.first }) diff --git a/spec/lib/lighthouse/benefits_documents/service_spec.rb b/spec/lib/lighthouse/benefits_documents/service_spec.rb index 8888b02cf2e..095cd9d4ab8 100644 --- a/spec/lib/lighthouse/benefits_documents/service_spec.rb +++ b/spec/lib/lighthouse/benefits_documents/service_spec.rb @@ -6,13 +6,11 @@ require 'lighthouse/benefits_documents/configuration' RSpec.describe BenefitsDocuments::Service do - Flipper.disable(:va_v3_contact_information_service) let(:user) { FactoryBot.create(:user, :loa3) } let(:service) { BenefitsDocuments::Service.new(user) } describe '#queue_document_upload' do before do - Flipper.disable(:va_v3_contact_information_service) allow_any_instance_of(Auth::ClientCredentials::Service).to receive(:get_token).and_return('fake_access_token') token = 'abcd1234' allow_any_instance_of(BenefitsDocuments::Configuration).to receive(:access_token).and_return(token) diff --git a/spec/lib/va_profile/person/service_spec.rb b/spec/lib/va_profile/person/service_spec.rb index 483a225d551..a3d4508caca 100644 --- a/spec/lib/va_profile/person/service_spec.rb +++ b/spec/lib/va_profile/person/service_spec.rb @@ -12,37 +12,19 @@ subject { described_class.new(user) } let(:user) { build(:user, :loa3) } - let(:person_response) do - if Flipper.enabled?(:va_v3_contact_information_service) - VAProfile::V2::ContactInformation::PersonTransactionResponse - else - VAProfile::ContactInformation::PersonTransactionResponse - end - end - let(:cassette_path) do - if Flipper.enabled?(:va_v3_contact_information_service) - 'va_profile/v2/person' - else - 'va_profile/person' - end - end - - before do - Flipper.disable(:va_v3_contact_information_service) - end context 'with a user present, that has a icn_with_aaid, and no passed in ICN' do it 'returns a status of 200', :aggregate_failures do - VCR.use_cassette("#{cassette_path}/init_vet360_id_success", VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do response = subject.init_vet360_id expect(response).to be_ok - expect(response).to be_a(person_response) + expect(response).to be_a(VAProfile::ContactInformation::PersonTransactionResponse) end end it 'initiates an asynchronous VAProfile transaction', :aggregate_failures do - VCR.use_cassette("#{cassette_path}/init_vet360_id_success", VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do response = subject.init_vet360_id expect(response.transaction.id).to be_present @@ -55,16 +37,16 @@ let(:icn) { '1000123456V123456' } it 'returns a status of 200', :aggregate_failures do - VCR.use_cassette("#{cassette_path}/init_vet360_id_success", VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do response = subject.init_vet360_id(icn) expect(response).to be_ok - expect(response).to be_a(person_response) + expect(response).to be_a(VAProfile::ContactInformation::PersonTransactionResponse) end end it 'initiates an asynchronous VAProfile transaction', :aggregate_failures do - VCR.use_cassette("#{cassette_path}/init_vet360_id_success", VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do response = subject.init_vet360_id(icn) expect(response.transaction.id).to be_present @@ -75,7 +57,7 @@ context 'with a 400 response' do it 'raises an exception', :aggregate_failures do - VCR.use_cassette("#{cassette_path}/init_vet360_id_status_400", VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/person/init_vet360_id_status_400', VCR::MATCH_EVERYTHING) do expect { subject.init_vet360_id }.to raise_error do |e| expect(e).to be_a(Common::Exceptions::BackendServiceException) expect(e.status_code).to eq(400) diff --git a/spec/lib/va_profile/v2/contact_information/service_spec.rb b/spec/lib/va_profile/v2/contact_information/service_spec.rb index 314205d4a1c..9fa8e0bd6fa 100644 --- a/spec/lib/va_profile/v2/contact_information/service_spec.rb +++ b/spec/lib/va_profile/v2/contact_information/service_spec.rb @@ -21,7 +21,7 @@ describe '#get_person' do context 'when successful' do it 'returns a status of 200' do - VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do response = subject.get_person expect(response).to be_ok expect(response.person).to be_a(VAProfile::Models::V2::Person) @@ -38,16 +38,34 @@ # end it 'has a bad address' do - VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do response = subject.get_person expect(response.person.addresses[0].bad_address).to eq(nil) end end end - context 'when not successful' do - let(:user) { build(:user, :error) } + context 'when person response has no body data' do + it 'returns 200' do + VCR.use_cassette('va_profile/v2/contact_information/person_without_data', VCR::MATCH_EVERYTHING) do + response = subject.get_person + expect(response).to be_ok + expect(response.person).to be_a(VAProfile::Models::V2::Person) + end + end + end + end + describe '#get_person error' do + let(:user) { build(:user, :loa3) } + + before do + Flipper.enable(:va_v3_contact_information_service) + allow_any_instance_of(User).to receive(:vet360_id).and_return('6767671') + allow_any_instance_of(User).to receive(:idme_uuid).and_return(nil) + end + + context 'when not successful' do context 'with a 400 error' do it 'returns nil person' do VCR.use_cassette('va_profile/v2/contact_information/person_error', VCR::MATCH_EVERYTHING) do @@ -66,36 +84,12 @@ { va_profile: :person_not_found }, :warning ) - response = subject.get_person expect(response).not_to be_ok expect(response.person).to be_nil end end end - # VCR 503 errors help - # context 'when service returns a 503 error code' do - # let(:vet360_id) { '' } - # it 'raises a BackendServiceException error' do - # VCR.use_cassette('va_profile/v2/contact_information/person_status_500', VCR::MATCH_EVERYTHING) do - # expect { subject.get_person }.to raise_error do |e| - # expect(e).to be_a(Common::Exceptions::BackendServiceException) - # expect(e.status_code).to eq(500) - # expect(e.errors.first.code).to eq('VET360_CORE500') - # end - # end - # end - # end - - context 'when person response has no body data' do - it 'returns 200' do - VCR.use_cassette('va_profile/v2/contact_information/person_without_data', VCR::MATCH_EVERYTHING) do - response = subject.get_person - expect(response).to be_ok - expect(response.person).to be_a(VAProfile::Models::V2::Person) - end - end - end end describe '#post_email' do @@ -137,7 +131,7 @@ context 'when successful' do it 'creates an old_email record' do VCR.use_cassette('va_profile/v2/contact_information/put_email_success', VCR::MATCH_EVERYTHING) do - VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do allow(VAProfile::Configuration::SETTINGS.contact_information).to receive(:cache_enabled).and_return(true) old_email = user.vet360_contact_info.email.email_address expect_any_instance_of(VAProfile::Models::Transaction).to receive(:received?).and_return(true) @@ -313,7 +307,7 @@ # ADDRESS is failing context 'update model methods' do before do - VCR.insert_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) + VCR.insert_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) allow(VAProfile::Configuration::SETTINGS.contact_information).to receive(:cache_enabled).and_return(true) end @@ -475,7 +469,7 @@ context 'users email exists' do it 'sends an email' do - VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do allow(VAProfile::Configuration::SETTINGS.contact_information).to receive(:cache_enabled).and_return(true) expect(VANotifyEmailJob).to receive(:perform_async).with( diff --git a/spec/lib/va_profile/v2/person/service_spec.rb b/spec/lib/va_profile/v2/person/service_spec.rb new file mode 100644 index 00000000000..68831d79ad3 --- /dev/null +++ b/spec/lib/va_profile/v2/person/service_spec.rb @@ -0,0 +1,60 @@ +# frozen_string_literal: true + +require 'rails_helper' +require 'va_profile/v2/person/service' + +describe VAProfile::V2::Person::Service, :skip_vet360 do + before { Timecop.freeze('2024-09-16T16:09:37.000Z') } + + after { Timecop.return } + + describe '#init_vet360_id' do + subject { described_class.new(user) } + + let(:user) { build(:user, :loa3) } + + before do + Flipper.enable(:va_v3_contact_information_service) + end + + context 'with a user present, that has a uuid_with_aaid, and no passed in ICN' do + it 'returns a status of 200', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do + response = subject.init_vet360_id + + expect(response).to be_ok + expect(response).to be_a(VAProfile::V2::ContactInformation::PersonTransactionResponse) + end + end + + it 'initiates an asynchronous VAProfile transaction', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do + response = subject.init_vet360_id + + expect(response.transaction.id).to be_present + expect(response.transaction.status).to be_present + end + end + end + + context 'with a 400 response' do + let(:user) { build(:user, :loa3) } + + before do + Flipper.enable(:va_v3_contact_information_service) + allow_any_instance_of(User).to receive(:vet360_id).and_return('6767671') + allow_any_instance_of(User).to receive(:idme_uuid).and_return(nil) + end + + it 'raises an exception', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_status_400', VCR::MATCH_EVERYTHING) do + expect { subject.init_vet360_id }.to raise_error do |e| + expect(e).to be_a(Common::Exceptions::BackendServiceException) + expect(e.status_code).to eq(400) + expect(e.errors.first.code).to eq('VET360_PERS101') + end + end + end + end + end +end diff --git a/spec/models/va_profile_redis/cache_spec.rb b/spec/models/va_profile_redis/cache_spec.rb index 36118b40336..a189e1d60d0 100644 --- a/spec/models/va_profile_redis/cache_spec.rb +++ b/spec/models/va_profile_redis/cache_spec.rb @@ -50,7 +50,7 @@ describe '.invalidate v2' do context 'when user.vet360_contact_info is present' do it 'invalidates the va-profile-contact-info-response cache' do - VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do VAProfileRedis::ContactInformation.for_user(user) end expect(VAProfileRedis::ContactInformation.exists?(user.uuid)).to eq(true) diff --git a/spec/models/va_profile_redis/contact_information_v2_spec.rb b/spec/models/va_profile_redis/contact_information_v2_spec.rb new file mode 100644 index 00000000000..d447001ecb6 --- /dev/null +++ b/spec/models/va_profile_redis/contact_information_v2_spec.rb @@ -0,0 +1,336 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe VAProfileRedis::ContactInformation do + let(:user) { build(:user, :loa3) } + let(:person_response) do + raw_response = OpenStruct.new(status: 200, body: { 'bio' => person.to_hash }) + + VAProfile::V2::ContactInformation::PersonResponse.from(raw_response) + end + let(:contact_info) { VAProfileRedis::ContactInformation.for_user(user) } + let(:person) { build(:person_v2, telephones:) } + let(:telephones) do + [ + build(:telephone), + build(:telephone, :home), + build(:telephone, :work), + build(:telephone, :temporary), + build(:telephone, :fax) + ] + end + + before do + Flipper.enable(:va_v3_contact_information_service) + allow(VAProfile::Models::V2::Person).to receive(:build_from).and_return(person) + end + + [404, 400].each do |status| + context "with a #{status} from get_person", :skip_vet360 do + let(:get_person_calls) { 'once' } + + before do + allow(VAProfile::Configuration::SETTINGS.contact_information).to receive(:cache_enabled).and_return(true) + + service = double + allow(VAProfile::V2::ContactInformation::Service).to receive(:new).with(user).and_return(service) + expect(service).to receive(:get_person).public_send( + get_person_calls + ).and_return( + VAProfile::V2::ContactInformation::PersonResponse.new(status, person: nil) + ) + end + + it 'caches the empty response' do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.email).to eq(nil) + expect(contact_info.home_phone).to eq(nil) + end + end + + context 'when the cache is destroyed' do + let(:get_person_calls) { 'twice' } + + it 'makes a new request' do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.email).to eq(nil) + end + VAProfileRedis::Cache.invalidate(user) + + expect(VAProfileRedis::ContactInformation.for_user(user).email).to eq(nil) + end + end + end + end + + describe '.new' do + it 'creates an instance with user attributes' do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.user).to eq(user) + end + end + end + + describe '#response' do + context 'when the cache is empty' do + it 'caches and return the response', :aggregate_failures do + allow_any_instance_of( + VAProfile::V2::ContactInformation::Service + ).to receive(:get_person).and_return(person_response) + + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + if VAProfile::Configuration::SETTINGS.contact_information.cache_enabled + expect(contact_info.redis_namespace).to receive(:set).once + end + expect_any_instance_of(VAProfile::V2::ContactInformation::Service).to receive(:get_person).twice + expect(contact_info.status).to eq 200 + expect(contact_info.response.person).to have_deep_attributes(person) + end + end + end + + context 'when there is cached data' do + it 'returns the cached data', :aggregate_failures do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + contact_info.cache(user.uuid, person_response) + expect_any_instance_of(VAProfile::V2::ContactInformation::Service).not_to receive(:get_person) + expect(contact_info.response.person).to have_deep_attributes(person) + end + end + end + end + + describe 'contact information attributes' do + context 'with a successful response' do + before do + allow(VAProfile::Models::V2::Person).to receive(:build_from).and_return(person) + allow_any_instance_of( + VAProfile::V2::ContactInformation::Service + ).to receive(:get_person).and_return(person_response) + end + + describe '#email' do + it 'returns the users email address object', :aggregate_failures do + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.email).to eq person.emails.first + expect(contact_info.email.class).to eq VAProfile::Models::Email + end + end + end + + describe '#residential_address' do + it 'returns the users residential address object', :aggregate_failures do + residence = address_for VAProfile::Models::V2::Address::RESIDENCE + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.residential_address).to eq residence + expect(contact_info.residential_address.class).to eq VAProfile::Models::V2::Address + end + end + end + + describe '#mailing_address' do + it 'returns the users mailing address object', :aggregate_failures do + correspondence = address_for VAProfile::Models::V2::Address::CORRESPONDENCE + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.mailing_address).to eq correspondence + expect(contact_info.mailing_address.class).to eq VAProfile::Models::V2::Address + end + end + end + + describe '#home_phone' do + it 'returns the users home phone object', :aggregate_failures do + phone = phone_for VAProfile::Models::Telephone::HOME + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.home_phone).to eq phone + expect(contact_info.home_phone.class).to eq VAProfile::Models::Telephone + end + end + end + + describe '#mobile_phone' do + it 'returns the users mobile phone object', :aggregate_failures do + phone = phone_for VAProfile::Models::Telephone::MOBILE + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.mobile_phone).to eq phone + expect(contact_info.mobile_phone.class).to eq VAProfile::Models::Telephone + end + end + end + + describe '#work_phone' do + it 'returns the users work phone object', :aggregate_failures do + phone = phone_for VAProfile::Models::Telephone::WORK + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.work_phone).to eq phone + expect(contact_info.work_phone.class).to eq VAProfile::Models::Telephone + end + end + end + + describe '#temporary_phone' do + it 'returns the users temporary phone object', :aggregate_failures do + phone = phone_for VAProfile::Models::Telephone::TEMPORARY + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.temporary_phone).to eq phone + expect(contact_info.temporary_phone.class).to eq VAProfile::Models::Telephone + end + end + end + + describe '#fax_number' do + it 'returns the users FAX object', :aggregate_failures do + fax = phone_for VAProfile::Models::Telephone::FAX + VCR.use_cassette('va_profile/v2/contact_information/person', VCR::MATCH_EVERYTHING) do + expect(contact_info.fax_number).to eq fax + expect(contact_info.fax_number.class).to eq VAProfile::Models::Telephone + end + end + end + end + + context 'with an error response' do + before do + allow_any_instance_of(VAProfile::V2::ContactInformation::Service).to receive(:get_person).and_raise( + Common::Exceptions::BackendServiceException + ) + end + + describe '#email' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.email }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#residential_address' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.residential_address }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#mailing_address' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.mailing_address }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#home_phone' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.home_phone }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#mobile_phone' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.mobile_phone }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#work_phone' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.work_phone }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#temporary_phone' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.temporary_phone }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + + describe '#fax_number' do + it 'raises a Common::Exceptions::BackendServiceException error' do + expect { contact_info.fax_number }.to raise_error( + Common::Exceptions::BackendServiceException + ) + end + end + end + + context 'with an empty respose body' do + let(:empty_response) do + raw_response = OpenStruct.new(status: 500, body: nil) + + VAProfile::V2::ContactInformation::PersonResponse.from(raw_response) + end + + before do + allow(VAProfile::Models::V2::Person).to receive(:build_from).and_return(nil) + allow_any_instance_of( + VAProfile::V2::ContactInformation::Service + ).to receive(:get_person).and_return(empty_response) + end + + describe '#email' do + it 'returns nil' do + expect(contact_info.email).to be_nil + end + end + + describe '#residential_address' do + it 'returns nil' do + expect(contact_info.residential_address).to be_nil + end + end + + describe '#mailing_address' do + it 'returns nil' do + expect(contact_info.mailing_address).to be_nil + end + end + + describe '#home_phone' do + it 'returns nil' do + expect(contact_info.home_phone).to be_nil + end + end + + describe '#mobile_phone' do + it 'returns nil' do + expect(contact_info.mobile_phone).to be_nil + end + end + + describe '#work_phone' do + it 'returns nil' do + expect(contact_info.work_phone).to be_nil + end + end + + describe '#temporary_phone' do + it 'returns nil' do + expect(contact_info.temporary_phone).to be_nil + end + end + + describe '#fax_number' do + it 'returns nil' do + expect(contact_info.fax_number).to be_nil + end + end + end + end +end + +def address_for(address_type) + person.addresses.find { |address| address.address_pou == address_type } +end + +def phone_for(phone_type) + person.telephones.find { |telephone| telephone.phone_type == phone_type } +end diff --git a/spec/requests/swagger_spec.rb b/spec/requests/swagger_spec.rb index 76785036298..6759a3f8b31 100644 --- a/spec/requests/swagger_spec.rb +++ b/spec/requests/swagger_spec.rb @@ -2711,6 +2711,377 @@ end end + describe 'profiles v2' do + let(:vet360_id) { '1781151' } + let(:mhv_user) { build(:user, :loa3, vet360_id:) } + + before do + Flipper.enable(:va_v3_contact_information_service) + allow(VAProfile::Configuration::SETTINGS.contact_information).to receive(:cache_enabled).and_return(true) + sign_in_as(mhv_user) + end + + it 'supports getting service history data' do + expect(subject).to validate(:get, '/v0/profile/service_history', 401) + VCR.use_cassette('va_profile/military_personnel/post_read_service_history_200') do + expect(subject).to validate(:get, '/v0/profile/service_history', 200, headers) + end + end + + it 'supports getting personal information data' do + expect(subject).to validate(:get, '/v0/profile/personal_information', 401) + VCR.use_cassette('mpi/find_candidate/valid') do + VCR.use_cassette('va_profile/demographics/demographics') do + expect(subject).to validate(:get, '/v0/profile/personal_information', 200, headers) + end + end + end + + it 'supports getting full name data' do + expect(subject).to validate(:get, '/v0/profile/full_name', 401) + + user = build(:user, :loa3, middle_name: 'Robert') + headers = { '_headers' => { 'Cookie' => sign_in(user, nil, true) } } + + expect(subject).to validate(:get, '/v0/profile/full_name', 200, headers) + end + + it 'supports updating a va profile email' do + expect(subject).to validate(:post, '/v0/profile/email_addresses/create_or_update', 401) + VCR.use_cassette('va_profile/v2/contact_information/put_email_success') do + VCR.use_cassette('va_profile/v2/contact_information/person') do + email_address = build(:email, :contact_info_v2) + + expect(subject).to validate( + :post, + '/v0/profile/email_addresses/create_or_update', + 200, + headers.merge('_data' => email_address.as_json) + ) + end + end + end + + it 'supports posting va_profile email address data' do + expect(subject).to validate(:post, '/v0/profile/email_addresses', 401) + + VCR.use_cassette('va_profile/v2/contact_information/post_email_success') do + email_address = build(:email, :contact_info_v2) + + expect(subject).to validate( + :post, + '/v0/profile/email_addresses', + 200, + headers.merge('_data' => email_address.as_json) + ) + end + end + + it 'supports putting va_profile email address data' do + expect(subject).to validate(:put, '/v0/profile/email_addresses', 401) + + VCR.use_cassette('va_profile/v2/contact_information/put_email_success') do + email_address = build(:email, id: 42) + + expect(subject).to validate( + :put, + '/v0/profile/email_addresses', + 200, + headers.merge('_data' => email_address.as_json) + ) + end + end + + it 'supports deleting va_profile email address data' do + expect(subject).to validate(:delete, '/v0/profile/email_addresses', 401) + + VCR.use_cassette('va_profile/v2/contact_information/delete_email_success') do + email_address = build(:email, id: 42) + + expect(subject).to validate( + :delete, + '/v0/profile/email_addresses', + 200, + headers.merge('_data' => email_address.as_json) + ) + end + end + + it 'supports updating va_profile telephone data' do + expect(subject).to validate(:post, '/v0/profile/telephones/create_or_update', 401) + + VCR.use_cassette('va_profile/v2/contact_information/put_telephone_success') do + VCR.use_cassette('va_profile/v2/contact_information/person') do + telephone = build(:telephone, :contact_info_v2) + + expect(subject).to validate( + :post, + '/v0/profile/telephones/create_or_update', + 200, + headers.merge('_data' => telephone.as_json) + ) + end + end + end + + it 'supports posting va_profile telephone data' do + expect(subject).to validate(:post, '/v0/profile/telephones', 401) + + VCR.use_cassette('va_profile/v2/contact_information/post_telephone_success') do + telephone = build(:telephone, :contact_info_v2) + + expect(subject).to validate( + :post, + '/v0/profile/telephones', + 200, + headers.merge('_data' => telephone.as_json) + ) + end + end + + it 'supports putting va_profile telephone data' do + expect(subject).to validate(:put, '/v0/profile/telephones', 401) + + VCR.use_cassette('va_profile/v2/contact_information/put_telephone_success') do + telephone = build(:telephone, id: 42) + + expect(subject).to validate( + :put, + '/v0/profile/telephones', + 200, + headers.merge('_data' => telephone.as_json) + ) + end + end + + it 'supports deleting va_profile telephone data' do + expect(subject).to validate(:delete, '/v0/profile/telephones', 401) + + VCR.use_cassette('va_profile/v2/contact_information/delete_telephone_success') do + telephone = build(:telephone, id: 42) + + expect(subject).to validate( + :delete, + '/v0/profile/telephones', + 200, + headers.merge('_data' => telephone.as_json) + ) + end + end + + it 'supports putting va_profile preferred-name data' do + expect(subject).to validate(:put, '/v0/profile/preferred_names', 401) + + VCR.use_cassette('va_profile/demographics/post_preferred_name_success') do + preferred_name = VAProfile::Models::PreferredName.new(text: 'Pat') + + expect(subject).to validate( + :put, + '/v0/profile/preferred_names', + 200, + headers.merge('_data' => preferred_name.as_json) + ) + end + end + + it 'supports putting va_profile gender-identity data' do + expect(subject).to validate(:put, '/v0/profile/gender_identities', 401) + + VCR.use_cassette('va_profile/demographics/post_gender_identity_success') do + gender_identity = VAProfile::Models::GenderIdentity.new(code: 'F') + + expect(subject).to validate( + :put, + '/v0/profile/gender_identities', + 200, + headers.merge('_data' => gender_identity.as_json) + ) + end + end + + it 'supports the address validation api' do + address = build(:va_profile_address, :multiple_matches) + VCR.use_cassette( + 'va_profile/address_validation/validate_match', + VCR::MATCH_EVERYTHING + ) do + VCR.use_cassette( + 'va_profile/address_validation/candidate_multiple_matches', + VCR::MATCH_EVERYTHING + ) do + expect(subject).to validate( + :post, + '/v0/profile/address_validation', + 200, + headers.merge('_data' => { address: address.to_h }) + ) + end + end + end + + it 'supports va_profile create or update address api' do + expect(subject).to validate(:post, '/v0/profile/addresses/create_or_update', 401) + VCR.use_cassette('va_profile/v2/contact_information/person') do + VCR.use_cassette('va_profile/v2/contact_information/put_address_success') do + address = build(:va_profile_address_v2, id: 15_035) + + expect(subject).to validate( + :post, + '/v0/profile/addresses/create_or_update', + 200, + headers.merge('_data' => address.as_json) + ) + end + end + end + + it 'supports posting va_profile address data' do + expect(subject).to validate(:post, '/v0/profile/addresses', 401) + + VCR.use_cassette('va_profile/v2/contact_information/post_address_success') do + address = build(:va_profile_address_v2) + + expect(subject).to validate( + :post, + '/v0/profile/addresses', + 200, + headers.merge('_data' => address.as_json) + ) + end + end + + it 'supports putting va_profile address data' do + expect(subject).to validate(:put, '/v0/profile/addresses', 401) + + VCR.use_cassette('va_profile/v2/contact_information/put_address_success') do + address = build(:va_profile_address_v2, id: 15_035) + + expect(subject).to validate( + :put, + '/v0/profile/addresses', + 200, + headers.merge('_data' => address.as_json) + ) + end + end + + it 'supports deleting va_profile address data' do + expect(subject).to validate(:delete, '/v0/profile/addresses', 401) + + VCR.use_cassette('va_profile/v2/contact_information/delete_address_success') do + address = build(:va_profile_address_v2, id: 15_035) + + expect(subject).to validate( + :delete, + '/v0/profile/addresses', + 200, + headers.merge('_data' => address.as_json) + ) + end + end + + it 'supports posting to initialize a vet360_id' do + expect(subject).to validate(:post, '/v0/profile/initialize_vet360_id', 401) + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success') do + expect(subject).to validate( + :post, + '/v0/profile/initialize_vet360_id', + 200, + headers.merge('_data' => {}) + ) + end + end + end + + describe 'profile/status v2' do + let(:vet360_id) { '1781151' } + let(:user) { build(:user, :loa3, vet360_id:) } + + before do + Flipper.enable(:va_v3_contact_information_service) + allow(VAProfile::Configuration::SETTINGS.contact_information).to receive(:cache_enabled).and_return(true) + sign_in_as(user) + end + + it 'supports GETting async transaction by ID' do + transaction = create( + :va_profile_address_transaction, + transaction_id: '0ea91332-4713-4008-bd57-40541ee8d4d4', + user_uuid: user.uuid + ) + expect(subject).to validate( + :get, + '/v0/profile/status/{transaction_id}', + 401, + 'transaction_id' => transaction.transaction_id + ) + + VCR.use_cassette('va_profile/v2/contact_information/address_transaction_status') do + VCR.use_cassette('va_profile/v2/contact_information/person') do + expect(subject).to validate( + :get, + '/v0/profile/status/{transaction_id}', + 200, + headers.merge('transaction_id' => transaction.transaction_id) + ) + end + end + end + + it 'supports GETting async transactions by user' do + expect(subject).to validate( + :get, + '/v0/profile/status/', + 401 + ) + + VCR.use_cassette('va_profile/v2/contact_information/address_transaction_status') do + expect(subject).to validate( + :get, + '/v0/profile/status/', + 200, + headers + ) + end + end + end + + describe 'profile/person/status/:transaction_id v2' do + let(:user_without_vet360_id) { build(:user, :loa3) } + let(:headers) { { '_headers' => { 'Cookie' => sign_in(user_without_vet360_id, nil, true) } } } + + before do + Flipper.enable(:va_v3_contact_information_service) + allow_any_instance_of(User).to receive(:vet360_id).and_return('1781151') + end + + it 'supports GETting async person transaction by transaction ID' do + transaction_id = '153536a5-8b18-4572-a3d9-4030bea3ab5c' + transaction = create( + :va_profile_initialize_person_transaction, + :init_vet360_id, + user_uuid: user_without_vet360_id.uuid, + transaction_id: + ) + + expect(subject).to validate( + :get, + '/v0/profile/person/status/{transaction_id}', + 401, + 'transaction_id' => transaction.transaction_id + ) + + VCR.use_cassette('va_profile/v2/contact_information/person_transaction_status') do + expect(subject).to validate( + :get, + '/v0/profile/person/status/{transaction_id}', + 200, + headers.merge('transaction_id' => transaction.transaction_id) + ) + end + end + end + describe 'profile/connected_applications' do let(:token) { 'fa0f28d6-224a-4015-a3b0-81e77de269f2' } let(:user) { create(:user, :loa3, uuid: '1847a3eb4b904102882e24e4ddf12ff3') } diff --git a/spec/requests/v0/profile/persons_spec.rb b/spec/requests/v0/profile/persons_spec.rb index 51b716820ed..f7dc4ab1a9f 100644 --- a/spec/requests/v0/profile/persons_spec.rb +++ b/spec/requests/v0/profile/persons_spec.rb @@ -9,15 +9,16 @@ let(:headers) { { 'Content-Type' => 'application/json', 'Accept' => 'application/json' } } let(:headers_with_camel) { headers.merge('X-Key-Inflection' => 'camel') } - before do - Timecop.freeze('2018-04-09T17:52:03Z') - sign_in_as(user) - Flipper.disable(:va_v3_contact_information_service) - end + describe 'POST /v0/profile/initialize_vet360_id' do + before do + Timecop.freeze('2018-04-09T17:52:03Z') + sign_in_as(user) + Flipper.disable(:va_v3_contact_information_service) + allow_any_instance_of(User).to receive(:vet360_id).and_return(nil) + end - after { Timecop.return } + after { Timecop.return } - describe 'POST /v0/profile/initialize_vet360_id' do let(:empty_body) do { bio: { @@ -26,10 +27,6 @@ }.to_json end - before do - allow_any_instance_of(User).to receive(:vet360_id).and_return(nil) - end - context 'with a user that has an icn_with_aaid' do it 'matches the transaction response schema', :aggregate_failures do VCR.use_cassette('va_profile/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do @@ -90,6 +87,12 @@ end describe 'GET /v0/profile/person/status/:transaction_id' do + before do + Timecop.freeze('2018-04-09T17:52:03Z') + sign_in_as(user) + Flipper.disable(:va_v3_contact_information_service) + end + context 'with an ok response' do let(:transaction) do create(:initialize_person_transaction, @@ -144,4 +147,148 @@ end end end + + describe 'POST /v0/profile/initialize_vet360_id v2' do + before do + Timecop.freeze('2024-09-16T16:09:37Z') + sign_in_as(user) + Flipper.enable(:va_v3_contact_information_service) + allow_any_instance_of(User).to receive(:vet360_id).and_return(nil) + end + + let(:empty_body) do + { + bio: { + sourceDate: Time.zone.now.iso8601 + } + }.to_json + end + + context 'with a user that has an uuid_with_aaid' do + it 'matches the transaction response schema', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do + post('/v0/profile/initialize_vet360_id', params: empty_body, headers:) + + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('va_profile/transaction_response') + end + end + + it 'matches the transaction response camel-inflected schema', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do + post('/v0/profile/initialize_vet360_id', params: empty_body, headers: headers_with_camel) + + expect(response).to have_http_status(:ok) + expect(response).to match_camelized_response_schema('va_profile/transaction_response') + end + end + + it 'creates a new AsyncTransaction::VAProfile::InitializePersonTransaction', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do + expect do + post('/v0/profile/initialize_vet360_id', params: empty_body, headers:) + end.to change(AsyncTransaction::VAProfile::InitializePersonTransaction, :count).from(0).to(1) + + expect(AsyncTransaction::VAProfile::InitializePersonTransaction.first).to be_valid + end + end + + it 'invalidates the cache for the mpi-profile-response Redis key' do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_success', VCR::MATCH_EVERYTHING) do + expect_any_instance_of(User).to receive(:invalidate_mpi_cache) + + post('/v0/profile/initialize_vet360_id', params: empty_body, headers:) + end + end + end + + context 'with an error response' do + let(:user) { build(:user, :loa3) } + + before do + allow_any_instance_of(User).to receive(:vet360_id).and_return('6767671') + allow_any_instance_of(User).to receive(:idme_uuid).and_return(nil) + end + + it 'matches the errors response schema', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_status_400', VCR::MATCH_EVERYTHING) do + post('/v0/profile/initialize_vet360_id', params: empty_body, headers:) + + expect(response).to have_http_status(:bad_request) + expect(response).to match_response_schema('errors') + end + end + + it 'matches the errors response camel-inflected schema', :aggregate_failures do + VCR.use_cassette('va_profile/v2/person/init_vet360_id_status_400', VCR::MATCH_EVERYTHING) do + post('/v0/profile/initialize_vet360_id', params: empty_body, headers: headers_with_camel) + + expect(response).to have_http_status(:bad_request) + expect(response).to match_camelized_response_schema('errors') + end + end + end + end + + describe 'GET /v0/profile/person/status/:transaction_id v2' do + before do + Timecop.freeze('2024-07-09T17:16:55Z') + sign_in_as(user) + Flipper.enable(:va_v3_contact_information_service) + end + + context 'with an ok response' do + let(:transaction) do + create(:initialize_person_transaction, + :init_vet360_id, + user_uuid: user.uuid, + transaction_id: '153536a5-8b18-4572-a3d9-4030bea3ab5c') + end + + it 'responds with a serialized transaction', :aggregate_failures do + VCR.use_cassette('va_profile/v2/contact_information/person_transaction_status') do + get("/v0/profile/person/status/#{transaction.transaction_id}", params: nil, headers:) + + expect(response).to have_http_status(:ok) + expect(response).to match_response_schema('va_profile/transaction_response') + end + end + + it 'responds with a serialized transaction when camel-inflected', :aggregate_failures do + VCR.use_cassette('va_profile/v2/contact_information/person_transaction_status') do + get("/v0/profile/person/status/#{transaction.transaction_id}", params: nil, headers: headers_with_camel) + + expect(response).to have_http_status(:ok) + expect(response).to match_camelized_response_schema('va_profile/transaction_response') + end + end + end + + context 'with an error response' do + let(:transaction) do + create(:initialize_person_transaction, + :init_vet360_id, + user_uuid: user.uuid, + transaction_id: 'd47b3d96-9ddd-42be-ac57-8e564aa38029') + end + + it 'matches the errors response schema', :aggregate_failures do + VCR.use_cassette('va_profile/v2/contact_information/person_transaction_status_error', VCR::MATCH_EVERYTHING) do + get("/v0/profile/person/status/#{transaction.transaction_id}", params: nil, headers:) + + expect(response).to have_http_status(:bad_request) + expect(response).to match_response_schema('errors') + end + end + + it 'matches the errors response camel-inflected schema', :aggregate_failures do + VCR.use_cassette('va_profile/v2/contact_information/person_transaction_status_error', VCR::MATCH_EVERYTHING) do + get("/v0/profile/person/status/#{transaction.transaction_id}", params: nil, headers: headers_with_camel) + + expect(response).to have_http_status(:bad_request) + expect(response).to match_camelized_response_schema('errors') + end + end + end + end end diff --git a/spec/sidekiq/copay_notifications/mcp_notification_email_job_spec.rb b/spec/sidekiq/copay_notifications/mcp_notification_email_job_spec.rb index b4e38d23971..dfc974dea4c 100644 --- a/spec/sidekiq/copay_notifications/mcp_notification_email_job_spec.rb +++ b/spec/sidekiq/copay_notifications/mcp_notification_email_job_spec.rb @@ -9,81 +9,167 @@ let(:backup_email) { 'meepmorp@example.com' } let(:vet_id) { '1' } - Flipper.disable(:va_v3_contact_information_service) + describe 'contact information v1' do + Flipper.disable(:va_v3_contact_information_service) - before do - allow_any_instance_of(VaNotify::Configuration).to receive(:base_path).and_return('http://fakeapi.com') + before do + allow_any_instance_of(VaNotify::Configuration).to receive(:base_path).and_return('http://fakeapi.com') - allow(Settings.vanotify.services.dmc).to receive(:api_key).and_return( - 'test-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa-bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' - ) - end + allow(Settings.vanotify.services.dmc).to receive(:api_key).and_return( + 'test-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa-bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' + ) + end - describe '#perform' do - it 'sends an email using the template id' do - VCR.use_cassette('va_profile/contact_information/person_full', VCR::MATCH_EVERYTHING) do - client = double - expect(VaNotify::Service).to receive(:new).with(Settings.vanotify.services.dmc.api_key).and_return(client) + describe '#perform' do + it 'sends an email using the template id' do + VCR.use_cassette('va_profile/contact_information/person_full', VCR::MATCH_EVERYTHING) do + client = double + expect(VaNotify::Service).to receive(:new).with(Settings.vanotify.services.dmc.api_key).and_return(client) - expect(client).to receive(:send_email).with( - email_address: email, - template_id: - ) + expect(client).to receive(:send_email).with( + email_address: email, + template_id: + ) - CopayNotifications::McpNotificationEmailJob.new.perform(vet_id, template_id) + CopayNotifications::McpNotificationEmailJob.new.perform(vet_id, template_id) + end + end + + context 'when no email address resovles' do + let(:vet_id) { '6767671' } + + it 'uses backup email' do + VCR.use_cassette('va_profile/contact_information/person_error', VCR::MATCH_EVERYTHING) do + job = described_class.new + client = double + expect(VaNotify::Service).to receive(:new).with(Settings.vanotify.services.dmc.api_key).and_return(client) + + expect(client).to receive(:send_email).with( + email_address: backup_email, + template_id: + ) + job.perform(vet_id, template_id, backup_email) + end + end + + it 'logs an error' do + VCR.use_cassette('va_profile/contact_information/person_error', VCR::MATCH_EVERYTHING) do + job = described_class.new + expect(job).to receive(:log_exception_to_sentry).with( + instance_of(CopayNotifications::ProfileMissingEmail), {}, { error: :mcp_notification_email_job }, 'info' + ) + job.perform(vet_id, template_id) + end + end + end + + context 'when vanotify returns a 400 error' do + it 'rescues and logs the error' do + VCR.use_cassette('va_profile/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_notify/bad_request') do + job = described_class.new + expect(job).to receive(:log_exception_to_sentry).with( + instance_of(Common::Exceptions::BackendServiceException), + { + args: { + template_id:, + personalisation: nil + } + }, + { + error: :va_notify_email_job + } + ) + + job.perform(vet_id, template_id) + end + end + end end end + end - context 'when no email address resovles' do - let(:vet_id) { '6767671' } + describe 'contact information v2' do + let(:vet_id) { '1781151' } - it 'uses backup email' do - VCR.use_cassette('va_profile/contact_information/person_error', VCR::MATCH_EVERYTHING) do - job = described_class.new + before do + Flipper.enable(:va_v3_contact_information_service) + allow_any_instance_of(VaNotify::Configuration).to receive(:base_path).and_return('http://fakeapi.com') + + allow(Settings.vanotify.services.dmc).to receive(:api_key).and_return( + 'test-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa-bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' + ) + + allow_any_instance_of(User).to receive(:vet360_id).and_return('1781151') + allow_any_instance_of(User).to receive(:icn).and_return('123498767V234859') + end + + describe '#perform' do + it 'sends an email using the template id' do + VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do client = double expect(VaNotify::Service).to receive(:new).with(Settings.vanotify.services.dmc.api_key).and_return(client) expect(client).to receive(:send_email).with( - email_address: backup_email, + email_address: email, template_id: ) - job.perform(vet_id, template_id, backup_email) + + CopayNotifications::McpNotificationEmailJob.new.perform(vet_id, template_id) end end - it 'logs an error' do - VCR.use_cassette('va_profile/contact_information/person_error', VCR::MATCH_EVERYTHING) do - job = described_class.new - expect(job).to receive(:log_exception_to_sentry).with( - instance_of(CopayNotifications::ProfileMissingEmail), {}, { error: :mcp_notification_email_job }, 'info' - ) - job.perform(vet_id, template_id) + context 'when no email address resovles' do + let(:vet_id) { '6767671' } + + it 'uses backup email' do + VCR.use_cassette('va_profile/v2/contact_information/person_error', VCR::MATCH_EVERYTHING) do + job = described_class.new + client = double + expect(VaNotify::Service).to receive(:new).with(Settings.vanotify.services.dmc.api_key).and_return(client) + + expect(client).to receive(:send_email).with( + email_address: backup_email, + template_id: + ) + job.perform(vet_id, template_id, backup_email) + end end - end - end - context 'when vanotify returns a 400 error' do - it 'rescues and logs the error' do - VCR.use_cassette('va_profile/contact_information/person_full', VCR::MATCH_EVERYTHING) do - VCR.use_cassette('va_notify/bad_request') do + it 'logs an error' do + VCR.use_cassette('va_profile/v2/contact_information/person_error', VCR::MATCH_EVERYTHING) do job = described_class.new expect(job).to receive(:log_exception_to_sentry).with( - instance_of(Common::Exceptions::BackendServiceException), - { - args: { - template_id:, - personalisation: nil - } - }, - { - error: :va_notify_email_job - } + instance_of(CopayNotifications::ProfileMissingEmail), {}, { error: :mcp_notification_email_job }, 'info' ) - job.perform(vet_id, template_id) end end end + + context 'when vanotify returns a 400 error' do + it 'rescues and logs the error' do + VCR.use_cassette('va_profile/v2/contact_information/person_full', VCR::MATCH_EVERYTHING) do + VCR.use_cassette('va_notify/bad_request') do + job = described_class.new + expect(job).to receive(:log_exception_to_sentry).with( + instance_of(Common::Exceptions::BackendServiceException), + { + args: { + template_id:, + personalisation: nil + } + }, + { + error: :va_notify_email_job + } + ) + + job.perform(vet_id, template_id) + end + end + end + end end end end diff --git a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person.yml b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person.yml index d31684b93c2..b39d31d3ec9 100644 --- a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person.yml +++ b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person.yml @@ -26,10 +26,10 @@ http_interactions: - 'true' - 'true' Server-Timing: - - dtRpid;desc="-1090288400", dtSInfo;desc="0" - - dtRpid;desc="-1504289209", dtSInfo;desc="0" + - dtRpid;desc="-277417432", dtSInfo;desc="0" + - dtRpid;desc="707587539", dtSInfo;desc="0" Vaprofiletxauditid: - - fc634b3c-084a-485f-a28f-fc9f140e3229 + - 0e4279a5-9705-4246-97cc-e52e9ebc2ce0 X-Content-Type-Options: - nosniff X-Xss-Protection: @@ -46,7 +46,7 @@ http_interactions: - 'default-src ''self'' ''unsafe-eval'' ''unsafe-inline'' data: filesystem: about: blob: ws: wss:' Date: - - Thu, 12 Sep 2024 17:06:35 GMT + - Wed, 18 Sep 2024 21:15:44 GMT Referrer-Policy: - no-referrer Content-Type: @@ -57,9 +57,9 @@ http_interactions: - max-age=16000000; includeSubDomains; preload; body: encoding: UTF-8 - string: '{"txAuditId":"fc634b3c-084a-485f-a28f-fc9f140e3229","status":"COMPLETED_SUCCESS","bio":{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-08-27T17:56:23Z","txAuditId":"74aa8ff5-8faf-454c-98b0-ebd5406174c0","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T17:56:23Z","vaProfileId":1781151,"addresses":[{"createDate":"2024-08-29T21:08:17Z","updateDate":"2024-09-12T15:56:15Z","txAuditId":"46fc79c6-1325-41e8-a9a6-436299b6c7fc","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-28T18:51:06Z","vaProfileId":1781151,"addressId":577127,"addressType":"Domestic","addressPOU":"RESIDENCE","addressLine1":"1494 + string: '{"txAuditId":"0e4279a5-9705-4246-97cc-e52e9ebc2ce0","status":"COMPLETED_SUCCESS","bio":{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-08-27T17:56:23Z","txAuditId":"74aa8ff5-8faf-454c-98b0-ebd5406174c0","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T17:56:23Z","vaProfileId":1781151,"addresses":[{"createDate":"2024-08-29T21:08:17Z","updateDate":"2024-09-18T19:07:30Z","txAuditId":"7c198f17-a3b8-415f-b0fd-e19ab1edcf3a","sourceSystem":"VETSGOV","sourceDate":"2024-09-17T16:09:37Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"123498767V234859","effectiveStartDate":"2024-09-17T16:09:37Z","vaProfileId":1781151,"addressId":577127,"addressType":"Domestic","addressPOU":"RESIDENCE","addressLine1":"1495 Martin Luther King Rd","cityName":"Fulton","state":{"stateName":"Mississippi","stateCode":"MS"},"zipCode5":"38843","county":{"countyName":"Itawamba - County","countyCode":"28057"},"country":{"countryName":"United States","countryCodeFIPS":"US","countryCodeISO2":"US","countryCodeISO3":"USA"},"latitude":"34.1987","longitude":"-88.5259","geocodePrecision":"31","geocodeDate":"2024-09-12T15:56:15Z"}],"telephones":[{"createDate":"2024-08-27T19:13:04Z","updateDate":"2024-08-27T19:13:04Z","txAuditId":"c6ee12e2-d219-4d12-81e0-3eecdd5eb871","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-27T18:51:06Z","vaProfileId":1781151,"telephoneId":458781,"internationalIndicator":false,"phoneType":"MOBILE","countryCode":"1","areaCode":"303","phoneNumber":"5551234","voiceMailAcceptableInd":true,"carrier":"Multiple - OCN Listing","classification":{"classificationCode":4,"classificationName":"OTHER"}}],"emails":[{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-08-27T17:56:23Z","txAuditId":"74aa8ff5-8faf-454c-98b0-ebd5406174c0","sourceSystem":"VETSGOV","sourceDate":"2018-04-09T17:52:03Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2018-04-09T17:52:03Z","vaProfileId":1781151,"emailId":318927,"emailAddressText":"person42@example.com"}]}}' - recorded_at: Thu, 12 Sep 2024 17:06:35 GMT + County","countyCode":"28057"},"country":{"countryName":"United States","countryCodeFIPS":"US","countryCodeISO2":"US","countryCodeISO3":"USA"},"latitude":"34.1989","longitude":"-88.5261","geocodePrecision":"31","geocodeDate":"2024-09-18T19:07:30Z"}],"telephones":[{"createDate":"2024-08-27T19:13:04Z","updateDate":"2024-09-12T23:46:47Z","txAuditId":"c915d801-5693-4860-b2df-83baa8c3c910","sourceSystem":"VETSGOV","sourceDate":"2024-08-28T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-28T18:51:06Z","vaProfileId":1781151,"telephoneId":458781,"internationalIndicator":false,"phoneType":"MOBILE","countryCode":"1","areaCode":"303","phoneNumber":"5551235","voiceMailAcceptableInd":true,"carrier":"Multiple + OCN Listing","classification":{"classificationCode":4,"classificationName":"OTHER"}}],"emails":[{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-09-12T21:22:57Z","txAuditId":"c3c712ea-0cfb-484b-b81e-22f11ee0dcaf","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-27T18:51:06Z","vaProfileId":1781151,"emailId":318927,"emailAddressText":"person43@example.com"}]}}' + recorded_at: Wed, 18 Sep 2024 21:15:44 GMT recorded_with: VCR 6.3.1 diff --git a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error.yml b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error.yml index f5282c4b0a2..adcdc9796c6 100644 --- a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error.yml +++ b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error.yml @@ -2,34 +2,34 @@ http_interactions: - request: method: get - uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/6767671%5EPN%5E200VIDM%5EUSDVA + uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/6767671%5EPI%5E200VETS%5EUSDVA body: encoding: US-ASCII string: '' headers: - User-Agent: - - Vets.gov Agent + Accept: + - application/json Content-Type: - application/json + User-Agent: + - Vets.gov Agent Cufsystemname: - VETSGOV - Accept: - - application/json Accept-Encoding: - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 response: status: - code: 400 + code: 404 message: '' headers: X-Oneagent-Js-Injection: - 'true' - 'true' Server-Timing: - - dtRpid;desc="-1453683967", dtSInfo;desc="0" - - dtRpid;desc="1964190738", dtSInfo;desc="0" + - dtRpid;desc="-1083514039", dtSInfo;desc="0" + - dtRpid;desc="-811723101", dtSInfo;desc="0" Vaprofiletxauditid: - - 88a67419-97d0-4056-9105-d99a93151c9f + - 2e1ca726-a7cc-44a1-89ea-04822dd6acd5 X-Content-Type-Options: - nosniff X-Xss-Protection: @@ -46,7 +46,7 @@ http_interactions: - 'default-src ''self'' ''unsafe-eval'' ''unsafe-inline'' data: filesystem: about: blob: ws: wss:' Date: - - Thu, 12 Sep 2024 22:05:20 GMT + - Fri, 20 Sep 2024 18:37:00 GMT Referrer-Policy: - no-referrer Content-Type: @@ -57,7 +57,8 @@ http_interactions: - max-age=16000000; includeSubDomains; preload; body: encoding: UTF-8 - string: '{"messages":[{"code":"MVI201","key":"MviNotFound","text":"The person - with the identifier requested was not found in MVI.","severity":"ERROR","potentiallySelfCorrectingOnRetry":false}],"txAuditId":"88a67419-97d0-4056-9105-d99a93151c9f","status":"COMPLETED_FAILURE"}' - recorded_at: Thu, 12 Sep 2024 22:05:21 GMT + string: '{"messages":[{"code":"CORE103","key":"_CUF_NOT_FOUND","text":"The PersonBio + for id/criteria 6767671^PI^200VETS^USDVA could not be found. Please correct + your request and try again!","severity":"ERROR"}],"txAuditId":"2e1ca726-a7cc-44a1-89ea-04822dd6acd5","status":"COMPLETED_FAILURE"}' + recorded_at: Fri, 20 Sep 2024 18:37:01 GMT recorded_with: VCR 6.3.1 diff --git a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error_400.yml b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error_400.yml index b11edfef8a8..bd9adcf1bba 100644 --- a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error_400.yml +++ b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_error_400.yml @@ -2,7 +2,7 @@ http_interactions: - request: method: get - uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/6767671%5EPN%5E200VIDM%5EUSDVA?Accept=application/json&Content-Type=application/json&Cufsystemname=VETSGOV&User-Agent=Vets.gov%20Agent + uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/6767671%5EPN%5E200VIDM%5EUSDVA body: encoding: US-ASCII string: '' diff --git a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_full.yml b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_full.yml index 48840d0e42e..2be2240d3a2 100644 --- a/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_full.yml +++ b/spec/support/vcr_cassettes/va_profile/v2/contact_information/person_full.yml @@ -2,19 +2,19 @@ http_interactions: - request: method: get - uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/b2fab2b5-6af0-45e1-a9e2-394347af91ef%5EPN%5E200VIDM%5EUSDVA + uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/1781151%5EPI%5E200VETS%5EUSDVA body: encoding: US-ASCII string: '' headers: - User-Agent: - - Vets.gov Agent + Accept: + - application/json Content-Type: - application/json + User-Agent: + - Vets.gov Agent Cufsystemname: - VETSGOV - Accept: - - application/json Accept-Encoding: - gzip;q=1.0,deflate;q=0.6,identity;q=0.3 response: @@ -26,10 +26,10 @@ http_interactions: - 'true' - 'true' Server-Timing: - - dtRpid;desc="-1090288400", dtSInfo;desc="0" - - dtRpid;desc="-1504289209", dtSInfo;desc="0" + - dtRpid;desc="-277417432", dtSInfo;desc="0" + - dtRpid;desc="707587539", dtSInfo;desc="0" Vaprofiletxauditid: - - fc634b3c-084a-485f-a28f-fc9f140e3229 + - 0e4279a5-9705-4246-97cc-e52e9ebc2ce0 X-Content-Type-Options: - nosniff X-Xss-Protection: @@ -46,7 +46,7 @@ http_interactions: - 'default-src ''self'' ''unsafe-eval'' ''unsafe-inline'' data: filesystem: about: blob: ws: wss:' Date: - - Thu, 12 Sep 2024 17:06:35 GMT + - Wed, 18 Sep 2024 21:15:44 GMT Referrer-Policy: - no-referrer Content-Type: @@ -57,9 +57,9 @@ http_interactions: - max-age=16000000; includeSubDomains; preload; body: encoding: UTF-8 - string: '{"txAuditId":"fc634b3c-084a-485f-a28f-fc9f140e3229","status":"COMPLETED_SUCCESS","bio":{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-08-27T17:56:23Z","txAuditId":"74aa8ff5-8faf-454c-98b0-ebd5406174c0","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T17:56:23Z","vaProfileId":1781151,"addresses":[{"createDate":"2024-08-29T21:08:17Z","updateDate":"2024-09-12T15:56:15Z","txAuditId":"46fc79c6-1325-41e8-a9a6-436299b6c7fc","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-28T18:51:06Z","vaProfileId":1781151,"addressId":577127,"addressType":"Domestic","addressPOU":"RESIDENCE","addressLine1":"1494 + string: '{"txAuditId":"0e4279a5-9705-4246-97cc-e52e9ebc2ce0","status":"COMPLETED_SUCCESS","bio":{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-08-27T17:56:23Z","txAuditId":"74aa8ff5-8faf-454c-98b0-ebd5406174c0","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T17:56:23Z","vaProfileId":1781151,"addresses":[{"createDate":"2024-08-29T21:08:17Z","updateDate":"2024-09-18T19:07:30Z","txAuditId":"7c198f17-a3b8-415f-b0fd-e19ab1edcf3a","sourceSystem":"VETSGOV","sourceDate":"2024-09-17T16:09:37Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"123498767V234859","effectiveStartDate":"2024-09-17T16:09:37Z","vaProfileId":1781151,"addressId":577127,"addressType":"Domestic","addressPOU":"RESIDENCE","addressLine1":"1495 Martin Luther King Rd","cityName":"Fulton","state":{"stateName":"Mississippi","stateCode":"MS"},"zipCode5":"38843","county":{"countyName":"Itawamba - County","countyCode":"28057"},"country":{"countryName":"United States","countryCodeFIPS":"US","countryCodeISO2":"US","countryCodeISO3":"USA"},"latitude":"34.1987","longitude":"-88.5259","geocodePrecision":"31","geocodeDate":"2024-09-12T15:56:15Z"}],"telephones":[{"createDate":"2024-08-27T19:13:04Z","updateDate":"2024-08-27T19:13:04Z","txAuditId":"c6ee12e2-d219-4d12-81e0-3eecdd5eb871","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-27T18:51:06Z","vaProfileId":1781151,"telephoneId":458781,"internationalIndicator":false,"phoneType":"MOBILE","countryCode":"1","areaCode":"303","phoneNumber":"5551234","voiceMailAcceptableInd":true,"carrier":"Multiple - OCN Listing","classification":{"classificationCode":4,"classificationName":"OTHER"}}],"emails":[{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-08-27T17:56:23Z","txAuditId":"74aa8ff5-8faf-454c-98b0-ebd5406174c0","sourceSystem":"VETSGOV","sourceDate":"2018-04-09T17:52:03Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2018-04-09T17:52:03Z","vaProfileId":1781151,"emailId":318927,"emailAddressText":"person42@example.com"}]}}' - recorded_at: Thu, 12 Sep 2024 17:06:35 GMT + County","countyCode":"28057"},"country":{"countryName":"United States","countryCodeFIPS":"US","countryCodeISO2":"US","countryCodeISO3":"USA"},"latitude":"34.1989","longitude":"-88.5261","geocodePrecision":"31","geocodeDate":"2024-09-18T19:07:30Z"}],"telephones":[{"createDate":"2024-08-27T19:13:04Z","updateDate":"2024-09-12T23:46:47Z","txAuditId":"c915d801-5693-4860-b2df-83baa8c3c910","sourceSystem":"VETSGOV","sourceDate":"2024-08-28T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-28T18:51:06Z","vaProfileId":1781151,"telephoneId":458781,"internationalIndicator":false,"phoneType":"MOBILE","countryCode":"1","areaCode":"303","phoneNumber":"5551235","voiceMailAcceptableInd":true,"carrier":"Multiple + OCN Listing","classification":{"classificationCode":4,"classificationName":"OTHER"}}],"emails":[{"createDate":"2024-08-27T17:56:23Z","updateDate":"2024-09-12T21:22:57Z","txAuditId":"c3c712ea-0cfb-484b-b81e-22f11ee0dcaf","sourceSystem":"VETSGOV","sourceDate":"2024-08-27T18:51:06Z","originatingSourceSystem":"VETSGOV","sourceSystemUser":"1234","effectiveStartDate":"2024-08-27T18:51:06Z","vaProfileId":1781151,"emailId":318927,"emailAddressText":"person43@example.com"}]}}' + recorded_at: Wed, 18 Sep 2024 21:15:44 GMT recorded_with: VCR 6.3.1 diff --git a/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_status_400.yml b/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_status_400.yml index 914c34695b3..125a596a45a 100644 --- a/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_status_400.yml +++ b/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_status_400.yml @@ -2,10 +2,10 @@ http_interactions: - request: method: post - uri: "/contact-information-hub/cuf/contact-information/v2/2.16.840.1.113883.4.349/1000123456V123456%5ENI%5E200M%5EUSVHA" + uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/6767671%5EPI%5E200VETS%5EUSDVA body: encoding: UTF-8 - string: '{"bio":{"sourceDate":"2018-04-09T17:52:03Z"}}' + string: '{"bio":{"sourceDate":"2024-09-16T16:09:37Z"}}' headers: Accept: - application/json @@ -23,7 +23,7 @@ http_interactions: message: '' headers: Date: - - Wed, 25 Apr 2018 17:17:07 GMT + - Mon, 16 Sep 2024 16:09:37 GMT Expires: - '0' X-Content-Type-Options: @@ -57,5 +57,5 @@ http_interactions: "status":"REJECTED" }' http_version: - recorded_at: Wed, 25 Apr 2018 17:17:06 GMT + recorded_at: Mon, 16 Sep 2024 16:09:37 GMT recorded_with: VCR 3.0.3 diff --git a/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_success.yml b/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_success.yml index 907db96905f..e152bcb42a0 100644 --- a/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_success.yml +++ b/spec/support/vcr_cassettes/va_profile/v2/person/init_vet360_id_success.yml @@ -5,7 +5,7 @@ http_interactions: uri: /contact-information-hub/contact-information/v2/2.16.840.1.113883.4.349/b2fab2b5-6af0-45e1-a9e2-394347af91ef%5EPN%5E200VIDM%5EUSDVA body: encoding: UTF-8 - string: '{"bio":{"sourceDate":"2024-08-27T18:51:06.012Z"}}' + string: '{"bio":{"sourceDate":"2024-09-16T16:09:37Z"}}' headers: User-Agent: - Vets.gov Agent @@ -46,7 +46,7 @@ http_interactions: - 'default-src ''self'' ''unsafe-eval'' ''unsafe-inline'' data: filesystem: about: blob: ws: wss:' Date: - - Mon, 16 Sep 2024 22:31:42 GMT + - Mon, 16 Sep 2024 16:09:37 GMT Referrer-Policy: - no-referrer Content-Type: @@ -58,5 +58,5 @@ http_interactions: body: encoding: UTF-8 string: '{"txAuditId":"442277a2-58bc-4778-88a7-3683662a3d00","status":"RECEIVED"}' - recorded_at: Mon, 16 Sep 2024 22:31:42 GMT + recorded_at: Mon, 16 Sep 2024 16:09:37 GMT recorded_with: VCR 6.3.1