diff --git a/app/controllers/idt/api/v2/distributions_controller.rb b/app/controllers/idt/api/v2/distributions_controller.rb index 2b35a8435ff..2535371aa62 100644 --- a/app/controllers/idt/api/v2/distributions_controller.rb +++ b/app/controllers/idt/api/v2/distributions_controller.rb @@ -40,14 +40,18 @@ def format_response(response) response_body = response.raw_body begin - parsed_response = JSON.parse(response_body) + parsed_response = if [ActiveSupport::HashWithIndifferentAccess, Hash].include?(response_body.class) + response_body + else + JSON.parse(response_body) + end # Convert keys from camelCase to snake_case parsed_response.deep_transform_keys do |key| key.to_s.underscore.gsub(/e(\d)/, 'e_\1') end - rescue JSON::ParseError => error - log_error(error + " Distribution ID: #{params[:distribution_id]}") + rescue StandardError => error + log_error(error) response_body end diff --git a/app/jobs/ama_notification_efolder_sync_job.rb b/app/jobs/ama_notification_efolder_sync_job.rb index 99813809bc2..a015cdbcb3d 100644 --- a/app/jobs/ama_notification_efolder_sync_job.rb +++ b/app/jobs/ama_notification_efolder_sync_job.rb @@ -15,9 +15,15 @@ class AmaNotificationEfolderSyncJob < CaseflowJob def perform RequestStore[:current_user] = User.system_user - all_active_ama_appeals = appeals_recently_outcoded + appeals_never_synced + ready_for_resync - - sync_notification_reports(all_active_ama_appeals.first(BATCH_LIMIT.to_i)) + all_active_ama_appeals = if FeatureToggle.enabled?(:phase_1_notification_sync_job_rollout) + appeals_never_synced + elsif FeatureToggle.enabled?(:phase_2_notification_sync_job_rollout) + appeals_never_synced + ready_for_resync + else + appeals_recently_outcoded + appeals_never_synced + ready_for_resync + end + + sync_notification_reports(all_active_ama_appeals.uniq(&:id).first(BATCH_LIMIT.to_i)) end private @@ -98,18 +104,21 @@ def ready_for_resync # Return: Array of active appeals def get_appeals_from_prev_synced_ids(appeal_ids) appeal_ids.in_groups_of(1000, false).flat_map do |ids| - Appeal.active.find_by_sql( + Appeal.find_by_sql( <<-SQL - SELECT appeals.* - FROM appeals + SELECT appeals.* FROM appeals + JOIN tasks t ON appeals.id = t.appeal_id + AND t.appeal_type = 'Appeal' JOIN (#{appeals_on_latest_notifications(ids)}) AS notifs ON notifs.appeals_id = appeals."uuid"::text AND notifs.appeals_type = 'Appeal' JOIN (#{appeals_on_latest_doc_uploads(ids)}) AS vbms_uploads ON vbms_uploads.appeal_id = appeals.id AND vbms_uploads.appeal_type = 'Appeal' - WHERE + WHERE ( notifs.notified_at > vbms_uploads.attempted_at OR notifs.created_at > vbms_uploads.attempted_at + ) + AND t.TYPE = 'RootTask' AND t.status NOT IN ('completed', 'cancelled') GROUP BY appeals.id SQL ) @@ -120,8 +129,16 @@ def appeals_on_latest_notifications(appeal_ids) <<-SQL SELECT n1.* FROM appeals a JOIN notifications n1 on n1.appeals_id = a."uuid"::text AND n1.appeals_type = 'Appeal' - LEFT OUTER JOIN notifications n2 ON (n2.appeals_id = a."uuid"::text AND n1.appeals_type = 'Appeal' AND - (n1.notified_at < n2.notified_at OR (n1.notified_at = n2.notified_at AND n1.id < n2.id))) + AND (n1.email_notification_status IS NULL OR + n1.email_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + AND (n1.sms_notification_status IS NULL OR + n1.sms_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + LEFT OUTER JOIN notifications n2 ON (n2.appeals_id = a."uuid"::text AND n1.appeals_type = 'Appeal' + AND (n2.email_notification_status IS NULL OR + n2.email_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + AND (n2.sms_notification_status IS NULL OR + n2.sms_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + AND (n1.notified_at < n2.notified_at OR (n1.notified_at = n2.notified_at AND n1.id < n2.id))) WHERE n2.id IS NULL AND n1.id IS NOT NULL AND (n1.email_notification_status <> 'Failure Due to Deceased' diff --git a/app/jobs/legacy_notification_efolder_sync_job.rb b/app/jobs/legacy_notification_efolder_sync_job.rb index d37847a8dbc..1aa41950469 100644 --- a/app/jobs/legacy_notification_efolder_sync_job.rb +++ b/app/jobs/legacy_notification_efolder_sync_job.rb @@ -15,9 +15,15 @@ class LegacyNotificationEfolderSyncJob < CaseflowJob def perform RequestStore[:current_user] = User.system_user - all_active_legacy_appeals = appeals_recently_outcoded + appeals_never_synced + ready_for_resync - - sync_notification_reports(all_active_legacy_appeals.first(BATCH_LIMIT.to_i)) + all_active_legacy_appeals = if FeatureToggle.enabled?(:phase_1_notification_sync_job_rollout) + appeals_never_synced + elsif FeatureToggle.enabled?(:phase_2_notification_sync_job_rollout) + appeals_never_synced + ready_for_resync + else + appeals_recently_outcoded + appeals_never_synced + ready_for_resync + end + + sync_notification_reports(all_active_legacy_appeals.uniq(&:id).first(BATCH_LIMIT.to_i)) end private @@ -71,7 +77,7 @@ def previous_case_notifications_document_join_clause end def open_root_task_join_clause - "JOIN tasks t ON t.appeal_type = 'LegacyAppeal' AND t.id = legacy_appeals.id \ + "JOIN tasks t ON t.appeal_type = 'LegacyAppeal' AND t.appeal_id = legacy_appeals.id \ AND t.type = 'RootTask' AND t.status NOT IN ('completed', 'cancelled')" end @@ -99,22 +105,24 @@ def ready_for_resync # Return: Array of active appeals def get_appeals_from_prev_synced_ids(appeal_ids) appeal_ids.in_groups_of(1000, false).flat_map do |ids| - LegacyAppeal.where(id: RootTask.open.where(appeal_type: "LegacyAppeal").pluck(:appeal_id)) - .find_by_sql( - <<-SQL - SELECT la.* - FROM legacy_appeals la + LegacyAppeal.find_by_sql( + <<-SQL + SELECT la.* FROM legacy_appeals la + JOIN tasks t ON la.id = t.appeal_id + AND t.appeal_type = 'LegacyAppeal' JOIN (#{appeals_on_latest_notifications(ids)}) AS notifs ON notifs.appeals_id = la.vacols_id AND notifs.appeals_type = 'LegacyAppeal' JOIN (#{appeals_on_latest_doc_uploads(ids)}) AS vbms_uploads ON vbms_uploads.appeal_id = la.id AND vbms_uploads.appeal_type = 'LegacyAppeal' - WHERE + WHERE ( notifs.notified_at > vbms_uploads.attempted_at OR notifs.created_at > vbms_uploads.attempted_at + ) + AND t.type = 'RootTask' AND t.status NOT IN ('completed', 'cancelled') GROUP BY la.id - SQL - ) + SQL + ) end end @@ -122,8 +130,16 @@ def appeals_on_latest_notifications(appeal_ids) <<-SQL SELECT n1.* FROM legacy_appeals a JOIN notifications n1 on n1.appeals_id = a.vacols_id AND n1.appeals_type = 'LegacyAppeal' - LEFT OUTER JOIN notifications n2 ON (n2.appeals_id = a.vacols_id AND n1.appeals_type = 'LegacyAppeal' AND - (n1.notified_at < n2.notified_at OR (n1.notified_at = n2.notified_at AND n1.id < n2.id))) + AND (n1.email_notification_status IS NULL OR + n1.email_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + AND (n1.sms_notification_status IS NULL OR + n1.sms_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + LEFT OUTER JOIN notifications n2 ON (n2.appeals_id = a.vacols_id AND n1.appeals_type = 'LegacyAppeal' + AND (n2.email_notification_status IS NULL OR + n2.email_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + AND (n2.sms_notification_status IS NULL OR + n2.sms_notification_status NOT IN ('No Participant Id Found', 'No Claimant Found', 'No External Id')) + AND (n1.notified_at < n2.notified_at OR (n1.notified_at = n2.notified_at AND n1.id < n2.id))) WHERE n2.id IS NULL AND n1.id IS NOT NULL AND (n1.email_notification_status <> 'Failure Due to Deceased' diff --git a/config/brakeman.ignore b/config/brakeman.ignore index c517632018e..475b41bb5d0 100644 --- a/config/brakeman.ignore +++ b/config/brakeman.ignore @@ -20,20 +20,40 @@ "confidence": "Medium", "note": "" }, + { + "warning_type": "File Access", + "warning_code": 16, + "fingerprint": "51625fbaea06d71b4cf619f3192432518766296d1356e21eb5f31f3d517a1c7a", + "check_name": "SendFile", + "message": "Model attribute used in file name", + "file": "app/controllers/document_controller.rb", + "line": 33, + "link": "https://brakemanscanner.org/docs/warning_types/file_access/", + "code": "send_file(Document.find(params[:id]).serve, :type => \"application/pdf\", :disposition => ((\"inline\" or \"attachment; filename='#{params[:type]}-#{params[:id]}.pdf'\")))", + "render_path": null, + "location": { + "type": "method", + "class": "DocumentController", + "method": "pdf" + }, + "user_input": "Document.find(params[:id]).serve", + "confidence": "Medium", + "note": "" + }, { "warning_type": "SQL Injection", "warning_code": 0, - "fingerprint": "3563fb89283da15302f7a0e5f9be93f31eb5aabfa18ff7bdb7080230f2dea4cf", + "fingerprint": "72ec86565b55db864b6072d21637438007fd304209abc58a4864288d309ed818", "check_name": "SQL", "message": "Possible SQL injection", - "file": "app/jobs/legacy_notification_efolder_sync_job.rb", - "line": 106, + "file": "app/jobs/ama_notification_efolder_sync_job.rb", + "line": 105, "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", - "code": "LegacyAppeal.where(:id => RootTask.open.where(:appeal_type => \"LegacyAppeal\").pluck(:appeal_id)).find_by_sql(\" SELECT la.*\\n FROM legacy_appeals la\\n JOIN (#{appeals_on_latest_notifications(ids)}) AS notifs ON\\n notifs.appeals_id = la.vacols_id AND notifs.appeals_type = 'LegacyAppeal'\\n JOIN (#{appeals_on_latest_doc_uploads(ids)}) AS vbms_uploads ON\\n vbms_uploads.appeal_id = la.id AND vbms_uploads.appeal_type = 'LegacyAppeal'\\n WHERE\\n notifs.notified_at > vbms_uploads.attempted_at\\n OR\\n notifs.created_at > vbms_uploads.attempted_at\\n GROUP BY la.id\\n\")", + "code": "Appeal.find_by_sql(\" SELECT appeals.* FROM appeals\\n JOIN tasks t ON appeals.id = t.appeal_id\\n AND t.appeal_type = 'Appeal'\\n JOIN (#{appeals_on_latest_notifications(ids)}) AS notifs ON\\n notifs.appeals_id = appeals.\\\"uuid\\\"::text AND notifs.appeals_type = 'Appeal'\\n JOIN (#{appeals_on_latest_doc_uploads(ids)}) AS vbms_uploads ON\\n vbms_uploads.appeal_id = appeals.id AND vbms_uploads.appeal_type = 'Appeal'\\n WHERE (\\n notifs.notified_at > vbms_uploads.attempted_at\\n OR\\n notifs.created_at > vbms_uploads.attempted_at\\n )\\n AND t.TYPE = 'RootTask' AND t.status NOT IN ('completed', 'cancelled')\\n GROUP BY appeals.id\\n\")", "render_path": null, "location": { "type": "method", - "class": "LegacyNotificationEfolderSyncJob", + "class": "AmaNotificationEfolderSyncJob", "method": "get_appeals_from_prev_synced_ids" }, "user_input": "appeals_on_latest_notifications(ids)", @@ -41,22 +61,22 @@ "note": "" }, { - "warning_type": "File Access", - "warning_code": 16, - "fingerprint": "51625fbaea06d71b4cf619f3192432518766296d1356e21eb5f31f3d517a1c7a", - "check_name": "SendFile", - "message": "Model attribute used in file name", - "file": "app/controllers/document_controller.rb", - "line": 33, - "link": "https://brakemanscanner.org/docs/warning_types/file_access/", - "code": "send_file(Document.find(params[:id]).serve, :type => \"application/pdf\", :disposition => ((\"inline\" or \"attachment; filename='#{params[:type]}-#{params[:id]}.pdf'\")))", + "warning_type": "SQL Injection", + "warning_code": 0, + "fingerprint": "9f33c98ba6283fe641049e694d167ce0416d39e4c0fe9ee2dc3b637fa59a52b5", + "check_name": "SQL", + "message": "Possible SQL injection", + "file": "app/jobs/legacy_notification_efolder_sync_job.rb", + "line": 106, + "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", + "code": "LegacyAppeal.find_by_sql(\" SELECT la.* FROM legacy_appeals la\\n JOIN tasks t ON la.id = t.appeal_id\\n AND t.appeal_type = 'LegacyAppeal'\\n JOIN (#{appeals_on_latest_notifications(ids)}) AS notifs ON\\n notifs.appeals_id = la.vacols_id AND notifs.appeals_type = 'LegacyAppeal'\\n JOIN (#{appeals_on_latest_doc_uploads(ids)}) AS vbms_uploads ON\\n vbms_uploads.appeal_id = la.id AND vbms_uploads.appeal_type = 'LegacyAppeal'\\n WHERE (\\n notifs.notified_at > vbms_uploads.attempted_at\\n OR\\n notifs.created_at > vbms_uploads.attempted_at\\n )\\n AND t.type = 'RootTask' AND t.status NOT IN ('completed', 'cancelled')\\n GROUP BY la.id\\n\")", "render_path": null, "location": { "type": "method", - "class": "DocumentController", - "method": "pdf" + "class": "LegacyNotificationEfolderSyncJob", + "method": "get_appeals_from_prev_synced_ids" }, - "user_input": "Document.find(params[:id]).serve", + "user_input": "appeals_on_latest_notifications(ids)", "confidence": "Medium", "note": "" }, @@ -87,7 +107,7 @@ "check_name": "SendFile", "message": "Model attribute used in file name", "file": "app/controllers/idt/api/v2/appeals_controller.rb", - "line": 61, + "line": 70, "link": "https://brakemanscanner.org/docs/warning_types/file_access/", "code": "send_file(Document.find(document_id).serve, :type => \"application/pdf\", :disposition => (\"attachment; filename='#{current_document[0][\"type\"]}-#{document_id}.pdf'\"))", "render_path": null, @@ -99,28 +119,8 @@ "user_input": "Document.find(document_id).serve", "confidence": "Medium", "note": "" - }, - { - "warning_type": "SQL Injection", - "warning_code": 0, - "fingerprint": "c9d432e0f7bca941b3cd382a9979de3b85717cdfab0055c3229378e07f84ba70", - "check_name": "SQL", - "message": "Possible SQL injection", - "file": "app/jobs/ama_notification_efolder_sync_job.rb", - "line": 104, - "link": "https://brakemanscanner.org/docs/warning_types/sql_injection/", - "code": "Appeal.active.find_by_sql(\" SELECT appeals.*\\n FROM appeals\\n JOIN (#{appeals_on_latest_notifications(ids)}) AS notifs ON\\n notifs.appeals_id = appeals.\\\"uuid\\\"::text AND notifs.appeals_type = 'Appeal'\\n JOIN (#{appeals_on_latest_doc_uploads(ids)}) AS vbms_uploads ON\\n vbms_uploads.appeal_id = appeals.id AND vbms_uploads.appeal_type = 'Appeal'\\n WHERE\\n notifs.notified_at > vbms_uploads.attempted_at\\n OR\\n notifs.created_at > vbms_uploads.attempted_at\\n GROUP BY appeals.id\\n\")", - "render_path": null, - "location": { - "type": "method", - "class": "AmaNotificationEfolderSyncJob", - "method": "get_appeals_from_prev_synced_ids" - }, - "user_input": "appeals_on_latest_notifications(ids)", - "confidence": "Medium", - "note": "" } ], - "updated": "2023-06-26 09:46:58 -0400", + "updated": "2023-07-18 18:21:26 -0400", "brakeman_version": "4.7.1" } diff --git a/lib/tasks/ci.rake b/lib/tasks/ci.rake index dbb4860fcf8..2e8f33b7fd7 100644 --- a/lib/tasks/ci.rake +++ b/lib/tasks/ci.rake @@ -50,7 +50,7 @@ namespace :ci do task :gha_verify_code_coverage do require "simplecov" - # Using the same dir as :circleci_verify_code_coverage + # Using the same dir as :gha_verify_code_coverage coverage_dir = "./coverage/combined" SimpleCov.coverage_dir(coverage_dir) SimpleCov.merge_timeout(3600 * 24 * 30) diff --git a/spec/controllers/idt/api/v2/distributions_controller_spec.rb b/spec/controllers/idt/api/v2/distributions_controller_spec.rb index 8c60e4c8ed9..08c9ec335d7 100644 --- a/spec/controllers/idt/api/v2/distributions_controller_spec.rb +++ b/spec/controllers/idt/api/v2/distributions_controller_spec.rb @@ -114,12 +114,26 @@ } end + subject { get :distribution, params: { distribution_id: vbms_distribution.id } } + it "returns the expected converted response" do - get :distribution, params: { distribution_id: vbms_distribution.id } + subject expect(response).to have_http_status(200) expect(JSON.parse(response.body.to_json)).to eq(expected_response.to_json) end + + it "Returns Pacman's response whenever we receive something we cannot parse as JSON and logs the error" do + allow(PacmanService).to receive(:get_distribution_request).and_return( + HTTPI::Response.new(200, {}, "An invalid JSON string") + ) + + expect_any_instance_of(Idt::Api::V2::DistributionsController).to receive(:log_error) + + subject + + expect(response.body).to eq "An invalid JSON string" + end end context "render_error" do diff --git a/spec/jobs/ama_notification_efolder_sync_job_spec.rb b/spec/jobs/ama_notification_efolder_sync_job_spec.rb index 615581444a2..c6016c9e877 100644 --- a/spec/jobs/ama_notification_efolder_sync_job_spec.rb +++ b/spec/jobs/ama_notification_efolder_sync_job_spec.rb @@ -36,10 +36,8 @@ let!(:first_run_outcoded_appeals) { [appeals[6]] } let(:first_run_never_synced_appeals) { appeals.first(3) + [appeals[4]] + appeals.last(2) } - before(:all) do - AmaNotificationEfolderSyncJob::BATCH_LIMIT = BATCH_LIMIT_SIZE - Seeds::NotificationEvents.new.seed! - end + before(:all) { Seeds::NotificationEvents.new.seed! } + before(:each) { stub_const("AmaNotificationEfolderSyncJob::BATCH_LIMIT", BATCH_LIMIT_SIZE) } context "first run" do after(:all) { clean_up_after_threads } @@ -56,11 +54,109 @@ expect(job.send(:ready_for_resync)).to eq([]) end + it "recently outcoded appeals that have new notifications will not be in the ready_to_resync bunket" do + create(:notification, + appeals_id: appeals[6].uuid, + appeals_type: "Appeal", + event_date: today, + event_type: "Appeal docketed", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "delivered") + expect(job.send(:appeals_recently_outcoded)).to eq([appeals[6]]) + expect(job.send(:ready_for_resync)).to eq([]) + end + it "running the perform", bypass_cleaner: true do perform_enqueued_jobs { AmaNotificationEfolderSyncJob.perform_later } + # The above line causes the appeal to have a case notifications report created for it. + # Outcoded appeals will almost certainly have had previous case notifications report + # Generated for them. + create(:vbms_uploaded_document, + appeal_id: appeals[4].id, + attempted_at: 3.days.ago, + last_submitted_at: 3.days.ago, + processed_at: 3.days.ago, + uploaded_to_vbms_at: nil, + appeal_type: appeals[4].class.name, + document_type: "BVA Case Notifications") + + create(:notification, + appeals_id: appeals[6].uuid, + appeals_type: appeals[6].class.name, + event_date: today, + event_type: "Appeal decision mailed (Non-contested claims)", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "delivered") expect(find_appeal_ids_from_first_document_sync.size).to eq BATCH_LIMIT_SIZE end + + it "doesnt sync when appeals have only error notifications" do + Notification.find_by_appeals_id(appeals[8].uuid) + .update!(event_type: "No Participant Id Found", + email_notification_status: "No Participant Id Found", + sms_notification_status: "No Participant Id Found") + + Notification.find_by_appeals_id(appeals[9].uuid) + .update!(event_type: "No Participant Id Found", + email_notification_status: "No Participant Id Found", + sms_notification_status: "No Participant Id Found") + + expect(job.send(:appeals_never_synced).to_a.pluck(:id)).not_to include(8, 9) + end + + it "does not sync veteran deceased status" do + create(:vbms_uploaded_document, + appeal_id: appeals[6].id, + attempted_at: 1.day.ago, + last_submitted_at: 1.day.ago, + processed_at: 1.day.ago, + uploaded_to_vbms_at: 1.day.ago, + appeal_type: "Appeal", + document_type: "BVA Case Notifications") + + create(:notification, + appeals_id: appeals[6].uuid, + appeals_type: "Appeal", + event_date: today, + event_type: "Appeal docketed", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "Failure Due to Deceased") + + expect(job.send(:ready_for_resync).to_a).to eq([]) + end + + it "does not sync when all notifications fail" do + Notification.all.to_a.each do |notif| + notif.update!(email_notification_status: "No Participant Id Found") + end + + expect(job.send(:appeals_never_synced)).to eq([]) + end + + it "failed document uploads are still ready to sync" do + create(:vbms_uploaded_document, + appeal_id: appeals[4].id, + attempted_at: today, + last_submitted_at: today, + processed_at: today, + uploaded_to_vbms_at: nil, + appeal_type: "Appeal", + document_type: "BVA Case Notifications") + + create(:notification, + appeals_id: appeals[4].uuid, + appeals_type: "Appeal", + event_date: today, + event_type: "Appeal docketed", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "delivered") + expect(job.send(:ready_for_resync).pluck(:id)).to eq([]) + end end context "second run" do diff --git a/spec/jobs/legacy_notification_efolder_sync_job_spec.rb b/spec/jobs/legacy_notification_efolder_sync_job_spec.rb index 73e8f771ab0..7cb01075fb8 100644 --- a/spec/jobs/legacy_notification_efolder_sync_job_spec.rb +++ b/spec/jobs/legacy_notification_efolder_sync_job_spec.rb @@ -52,29 +52,114 @@ let(:first_run_vbms_document_ids) { [appeals[6].id, appeals[0].id, appeals[1].id, appeals[2].id, appeals[4].id] } let(:second_run_vbms_document_ids) { first_run_vbms_document_ids + [appeals[8].id, appeals[9].id, appeals[4].id] } - before(:all) do - LegacyNotificationEfolderSyncJob::BATCH_LIMIT = BATCH_LIMIT_SIZE - ensure_notification_events_exist - end + before(:all) { ensure_notification_events_exist } + before(:each) { stub_const("LegacyNotificationEfolderSyncJob::BATCH_LIMIT", BATCH_LIMIT_SIZE) } context "first run" do after(:all) { clean_up_after_threads } - it "get all legacy appeals that have been recently outcoded" do + it "get all legacy appeals that have been recently outcoded, never been synced, and must be resynced" do expect(job.send(:appeals_recently_outcoded)).to match_array(first_run_outcoded_appeals) + expect(job.send(:appeals_never_synced)).to match_array(first_run_never_synced_appeals) + expect(job.send(:ready_for_resync)).to eq([]) end - it "get all legacy appeals that have never been synced yet" do - expect(job.send(:appeals_never_synced)).to match_array(first_run_never_synced_appeals) + it "doesnt sync when appeals have only error notifications" do + Notification.find_by_appeals_id(appeals[8].vacols_id) + .update!(event_type: "No Participant Id Found", + email_notification_status: "No Participant Id Found", + sms_notification_status: "No Participant Id Found") + + Notification.find_by_appeals_id(appeals[9].vacols_id) + .update!(event_type: "No Participant Id Found", + email_notification_status: "No Participant Id Found", + sms_notification_status: "No Participant Id Found") + + expect(job.send(:appeals_never_synced).to_a.pluck(:id)).not_to include(8, 9) end - it "get all legacy appeals that must be resynced" do + it "does not sync veteran deceased status" do + create(:vbms_uploaded_document, + appeal_id: appeals[6].vacols_id, + attempted_at: 1.day.ago, + appeal_type: "LegacyAppeal", + document_type: "BVA Case Notifications") + + create(:notification, + appeals_id: appeals[6].vacols_id, + appeals_type: "LegacyAppeal", + event_date: today, + event_type: "Appeal docketed", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "Failure Due to Deceased") + + expect(job.send(:ready_for_resync).to_a).to eq([]) + end + + it "does not sync when all notifications fail" do + Notification.all.to_a.each do |notif| + notif.update!(email_notification_status: "No Participant Id Found") + end + + expect(job.send(:appeals_never_synced)).to eq([]) + end + + it "failed document uploads are still ready to sync" do + create(:vbms_uploaded_document, + appeal_id: appeals[4].id, + attempted_at: today, + last_submitted_at: today, + processed_at: today, + uploaded_to_vbms_at: nil, + appeal_type: "LegacyAppeal", + document_type: "BVA Case Notifications") + + create(:notification, + appeals_id: appeals[4].vacols_id, + appeals_type: "LegacyAppeal", + event_date: today, + event_type: "Appeal docketed", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "delivered") + expect(job.send(:ready_for_resync).pluck(:id)).to eq([]) + end + + it "recently outcoded appeals that have new notifications will not be in the ready_to_resync bunket" do + create(:notification, + appeals_id: appeals[6].vacols_id, + appeals_type: "LegacyAppeal", + event_date: today, + event_type: "Appeal docketed", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "delivered") + expect(job.send(:appeals_recently_outcoded)).to eq([appeals[6]]) expect(job.send(:ready_for_resync)).to eq([]) end it "running the perform", bypass_cleaner: true do perform_enqueued_jobs { LegacyNotificationEfolderSyncJob.perform_later } + create(:vbms_uploaded_document, + appeal_id: appeals[4].id, + attempted_at: 3.days.ago, + last_submitted_at: 3.days.ago, + processed_at: 3.days.ago, + uploaded_to_vbms_at: nil, + appeal_type: appeals[4].class.name, + document_type: "BVA Case Notifications") + + create(:notification, + appeals_id: appeals[6].vacols_id, + appeals_type: appeals[6].class.name, + event_date: today, + event_type: "Appeal decision mailed (Non-contested claims)", + notification_type: "Email", + notified_at: Time.zone.now, + email_notification_status: "delivered") + expect(find_appeal_ids_from_first_document_sync.size).to eq BATCH_LIMIT_SIZE end end @@ -101,7 +186,6 @@ # runs with BATCH_LIMIT_SIZE number of appeals processed each time. let(:second_run_vbms_document_appeal_ids) do first_run_vbms_document_appeal_ids(first_run_vbms_document_appeal_indexes) + - [appeals[4].id] + second_run_never_synced_appeals_ids - will_not_sync_appeal_ids end @@ -160,6 +244,7 @@ it "running the perform", bypass_cleaner: true do perform_enqueued_jobs { LegacyNotificationEfolderSyncJob.perform_later } + # Appeal at index 4 will be ready for resync create(:notification, appeals_id: appeals[4].vacols_id, appeals_type: "LegacyAppeal", @@ -176,7 +261,7 @@ .where(document_type: "BVA Case Notifications") .order(:id) .pluck(:appeal_id) - ).to match_array(second_run_vbms_document_appeal_ids) + ).to match_array(second_run_vbms_document_appeal_ids + [appeals[4].id]) end end