Also fixes double-scheduling bug in scheduler_spec and delivery_spec caused by after_create_commit hook firing while rules already exist — reservation is now created before rules in setup so the hook finds nothing to schedule. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
108 lines
3.4 KiB
Ruby
108 lines
3.4 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require 'rails_helper'
|
|
|
|
RSpec.describe Captain::Lifecycle::Scheduler do
|
|
let(:account) { create(:account) }
|
|
let(:brand) { create(:captain_brand, account: account) }
|
|
let(:unit) { Captain::Unit.create!(account: account, brand: brand, name: 'Test Unit') }
|
|
let(:reservation) do
|
|
create(:captain_reservation,
|
|
account: account,
|
|
unit: unit,
|
|
check_in_at: 2.hours.from_now,
|
|
check_out_at: 10.hours.from_now)
|
|
end
|
|
|
|
describe '.schedule_for' do
|
|
# Reservation must be created BEFORE rules so the after_create_commit
|
|
# :schedule_lifecycle_rules hook finds nothing and doesn't auto-create deliveries.
|
|
before { reservation }
|
|
|
|
let!(:matching_rule) do
|
|
create(:captain_lifecycle_rule,
|
|
account: account,
|
|
event: 'checkin.scheduled_at',
|
|
offset_minutes: -10)
|
|
end
|
|
|
|
it 'creates a scheduled delivery for each matching enabled rule' do
|
|
expect { described_class.schedule_for(reservation) }
|
|
.to change(Captain::Lifecycle::Delivery, :count).by(1)
|
|
end
|
|
|
|
it 'sets fire_at to event_time + offset' do
|
|
described_class.schedule_for(reservation)
|
|
delivery = Captain::Lifecycle::Delivery.last
|
|
expect(delivery.fire_at).to be_within(1.second).of(reservation.check_in_at - 10.minutes)
|
|
end
|
|
|
|
it 'enqueues a Sidekiq job for fire_at' do
|
|
expect(Captain::Lifecycle::DispatcherJob).to receive(:perform_at)
|
|
.with(kind_of(Time), kind_of(Integer))
|
|
described_class.schedule_for(reservation)
|
|
end
|
|
|
|
it 'skips disabled rules' do
|
|
matching_rule.update!(enabled: false)
|
|
expect { described_class.schedule_for(reservation) }
|
|
.not_to change(Captain::Lifecycle::Delivery, :count)
|
|
end
|
|
|
|
it 'skips rules where filter does not match' do
|
|
matching_rule.update!(filters: { 'categorias' => ['DoesNotExist'] })
|
|
expect { described_class.schedule_for(reservation) }
|
|
.not_to change(Captain::Lifecycle::Delivery, :count)
|
|
end
|
|
end
|
|
|
|
describe '.cancel_pending' do
|
|
let!(:delivery) do
|
|
create(:captain_lifecycle_delivery,
|
|
account: account,
|
|
captain_reservation: reservation,
|
|
status: 'scheduled')
|
|
end
|
|
let!(:sent) do
|
|
create(:captain_lifecycle_delivery,
|
|
account: account,
|
|
captain_reservation: reservation,
|
|
status: 'sent')
|
|
end
|
|
|
|
it 'marks scheduled deliveries as cancelled' do
|
|
described_class.cancel_pending(reservation)
|
|
expect(delivery.reload.status).to eq('cancelled')
|
|
end
|
|
|
|
it 'does not touch sent deliveries' do
|
|
described_class.cancel_pending(reservation)
|
|
expect(sent.reload.status).to eq('sent')
|
|
end
|
|
end
|
|
|
|
describe '.reschedule_for_checkin_change' do
|
|
let!(:checkin_rule) do
|
|
create(:captain_lifecycle_rule,
|
|
account: account,
|
|
event: 'checkin.scheduled_at',
|
|
offset_minutes: -10)
|
|
end
|
|
|
|
before do
|
|
create(:captain_lifecycle_rule,
|
|
account: account,
|
|
event: 'reservation.confirmed',
|
|
offset_minutes: 0)
|
|
described_class.schedule_for(reservation)
|
|
end
|
|
|
|
it 'cancels checkin-based scheduled deliveries' do
|
|
expect { described_class.reschedule_for_checkin_change(reservation) }
|
|
.to(change do
|
|
Captain::Lifecycle::Delivery.where(lifecycle_rule_id: checkin_rule.id, status: 'cancelled').count
|
|
end)
|
|
end
|
|
end
|
|
end
|