|
| 1 | +require "rails_helper" |
| 2 | + |
| 3 | +RSpec.describe ScheduleWeeklyBatchDeliveriesJob do |
| 4 | + include ActiveSupport::Testing::TimeHelpers |
| 5 | + include ActiveJob::TestHelper |
| 6 | + |
| 7 | + let(:travel_time) { Time.utc(2025, 5, 20, 2, 0, 0) } |
| 8 | + let(:form_id) { 101 } |
| 9 | + let(:other_form_id) { 201 } |
| 10 | + let(:form_submissions) { create_list(:submission, 2, form_id: form_id, mode: "form") } |
| 11 | + let(:other_form_submissions) { create_list(:submission, 1, form_id: other_form_id, mode: "preview-draft") } |
| 12 | + let!(:batches) do |
| 13 | + [ |
| 14 | + BatchSubmissionsSelector::Batch.new(101, "form", form_submissions), |
| 15 | + BatchSubmissionsSelector::Batch.new(201, "preview-draft", other_form_submissions), |
| 16 | + ] |
| 17 | + end |
| 18 | + |
| 19 | + around do |example| |
| 20 | + travel_to travel_time do |
| 21 | + example.run |
| 22 | + end |
| 23 | + end |
| 24 | + |
| 25 | + before do |
| 26 | + allow(BatchSubmissionsSelector).to receive(:weekly_batches).and_return(batches.to_enum) |
| 27 | + end |
| 28 | + |
| 29 | + context "when Deliveries do not already exist for batches" do |
| 30 | + before do |
| 31 | + described_class.perform_now |
| 32 | + end |
| 33 | + |
| 34 | + it "calls the selector passing in the start time of the previous week" do |
| 35 | + expect(BatchSubmissionsSelector).to have_received(:weekly_batches).with(Time.utc(2025, 5, 11, 23, 0, 0)) |
| 36 | + end |
| 37 | + |
| 38 | + it "creates a delivery record per batch job" do |
| 39 | + expect(Delivery.weekly.count).to eq(2) |
| 40 | + expect(Delivery.first.submissions.map(&:id)).to match_array(form_submissions.map(&:id)) |
| 41 | + expect(Delivery.second.submissions.map(&:id)).to match_array(other_form_submissions.map(&:id)) |
| 42 | + end |
| 43 | + |
| 44 | + it "enqueues a SendSubmissionBatchJob per batch" do |
| 45 | + expect(ActiveJob::Base.queue_adapter.enqueued_jobs.size).to eq(2) |
| 46 | + end |
| 47 | + |
| 48 | + it "enqueues the jobs with the correct args" do |
| 49 | + enqueued_args = ActiveJob::Base.queue_adapter.enqueued_jobs.map { |j| j[:args].first } |
| 50 | + expect(enqueued_args.first).to include("delivery" => hash_including("_aj_globalid")) |
| 51 | + expect(locate_delivery(enqueued_args.first)).to eq(Delivery.first) |
| 52 | + |
| 53 | + expect(enqueued_args.second).to include("delivery" => hash_including("_aj_globalid")) |
| 54 | + expect(locate_delivery(enqueued_args.second)).to eq(Delivery.second) |
| 55 | + end |
| 56 | + |
| 57 | + describe "setting batch_begin_at" do |
| 58 | + context "when the week for the batch is the week the clocks go forwards" do |
| 59 | + let(:travel_time) { Time.utc(2025, 3, 31, 2, 0, 0) } |
| 60 | + |
| 61 | + it "sets the batch_begin_at to the beginning of the week in GMT" do |
| 62 | + expect(Delivery.first.batch_begin_at).to eq(Time.utc(2025, 3, 24, 0, 0, 0)) |
| 63 | + end |
| 64 | + end |
| 65 | + |
| 66 | + context "when the week for the batch is the week after the clocks have gone forwards" do |
| 67 | + let(:travel_time) { Time.utc(2025, 4, 7, 2, 0, 0) } |
| 68 | + |
| 69 | + it "sets the batch_begin_at to the beginning of the week in BST" do |
| 70 | + expect(Delivery.first.batch_begin_at).to eq(Time.utc(2025, 3, 30, 23, 0, 0)) |
| 71 | + end |
| 72 | + end |
| 73 | + |
| 74 | + context "when the week for the batch is the week the clocks go back" do |
| 75 | + let(:travel_time) { Time.zone.local(2025, 10, 27, 2, 0, 0) } |
| 76 | + |
| 77 | + it "sets the batch_begin_at to the beginning of the week in BST" do |
| 78 | + expect(Delivery.first.batch_begin_at).to eq(Time.utc(2025, 10, 19, 23, 0, 0)) |
| 79 | + end |
| 80 | + end |
| 81 | + |
| 82 | + context "when the week for the batch is the week after the clocks have gone back" do |
| 83 | + let(:travel_time) { Time.utc(2025, 11, 3, 2, 0, 0) } |
| 84 | + |
| 85 | + it "sets the batch_begin_at to the beginning of the week in GMT" do |
| 86 | + expect(Delivery.first.batch_begin_at).to eq(Time.utc(2025, 10, 27, 0, 0, 0)) |
| 87 | + end |
| 88 | + end |
| 89 | + end |
| 90 | + end |
| 91 | + |
| 92 | + context "when a Delivery already exists for a batch" do |
| 93 | + let!(:existing_delivery) { create(:delivery, delivery_schedule: :weekly, submissions: form_submissions) } |
| 94 | + |
| 95 | + it "logs that the delivery will be skipped" do |
| 96 | + expect(Rails.logger).to receive(:warn).with( |
| 97 | + "Weekly batch delivery already exists for batch - skipping", |
| 98 | + hash_including( |
| 99 | + form_id: form_id, |
| 100 | + mode: "form", |
| 101 | + batch_begin_at: Time.utc(2025, 5, 11, 23, 0, 0), |
| 102 | + delivery_id: existing_delivery.id, |
| 103 | + ), |
| 104 | + ) |
| 105 | + |
| 106 | + described_class.perform_now |
| 107 | + end |
| 108 | + |
| 109 | + it "only creates a delivery for the batch without an existing delivery" do |
| 110 | + expect { |
| 111 | + described_class.perform_now |
| 112 | + }.to change(Delivery, :count).by(1) |
| 113 | + |
| 114 | + expect(Delivery.last.submissions.map(&:id)).to match_array(other_form_submissions.map(&:id)) |
| 115 | + end |
| 116 | + |
| 117 | + it "only schedules a job for the batch without an existing delivery" do |
| 118 | + expect { |
| 119 | + described_class.perform_now |
| 120 | + }.to change { ActiveJob::Base.queue_adapter.enqueued_jobs.size }.by(1) |
| 121 | + |
| 122 | + enqueued_args = ActiveJob::Base.queue_adapter.enqueued_jobs.map { |j| j[:args].first } |
| 123 | + expect(enqueued_args.first).to include("delivery" => hash_including("_aj_globalid")) |
| 124 | + expect(locate_delivery(enqueued_args.first)).to eq(Delivery.last) |
| 125 | + end |
| 126 | + end |
| 127 | + |
| 128 | + def locate_delivery(enqueued_args) |
| 129 | + gid_string = enqueued_args.dig("delivery", "_aj_globalid") |
| 130 | + GlobalID::Locator.locate(gid_string) |
| 131 | + end |
| 132 | +end |
0 commit comments