require "test_helper" class Mailings::OutboundQueueTest < ActiveSupport::TestCase include ActionMailer::TestHelper setup do Mailings::OutboundQueue.min_interval = 0 Mailings::OutboundQueue.fail_interval = 0 Mailings::OutboundQueue.reset! Mailings::SmtpGate.min_gap = 0 Mailings::SmtpGate.backoff_base = 0 Mailings::SmtpGate.reset! end teardown do Mailings::OutboundQueue.min_interval = 0 Mailings::OutboundQueue.fail_interval = 0 Mailings::OutboundQueue.reset! end test "campaign jobs only enqueue, drain sends one email at a time" do first = create_campaign_org(name: "Club Uno", email: "uno@example.com") second = create_campaign_org(name: "Club Due", email: "due@example.com") mailing_a = create_sending_mailing(name: "Campagna A") mailing_b = create_sending_mailing(name: "Campagna B") recipient_a = enqueue_org(mailing_a, first) recipient_b = enqueue_org(mailing_b, second) assert_equal "queued", recipient_a.reload.status assert_equal "queued", recipient_b.status assert_emails 1 do assert_equal :sent, Mailings::OutboundQueue.drain_one! end assert_equal "sent", recipient_a.reload.status assert_equal "queued", recipient_b.reload.status assert_emails 1 do assert_equal :sent, Mailings::OutboundQueue.drain_one! end assert_equal "sent", recipient_b.reload.status assert_equal :empty, Mailings::OutboundQueue.drain_one! end test "does not start a second SMTP session while the lock is held" do org = create_campaign_org(name: "Club Lock", email: "lock@example.com") mailing = create_sending_mailing(name: "Campagna lock") enqueue_org(mailing, org) started = Queue.new release = Queue.new result = nil thread = Thread.new do Mailings::OutboundQueue.exclusive do started << true release.pop end end started.pop result = Mailings::OutboundQueue.drain_one! release << true thread.join assert_equal :busy, result assert_equal "queued", mailing.mailing_recipients.first.reload.status end test "transient SMTP errors stay queued and the next drain tries another recipient" do first = create_campaign_org(name: "Club EOF", email: "eof@example.com") second = create_campaign_org(name: "Club Ok", email: "ok@example.com") mailing = create_sending_mailing(name: "Campagna eof") recipient_a = enqueue_org(mailing, first) recipient_b = enqueue_org(mailing, second) gate = Mailings::SmtpGate original = gate.method(:deliver) gate.define_singleton_method(:deliver) { raise EOFError, "end of file reached" } begin assert_equal :deferred, Mailings::OutboundQueue.drain_one! ensure gate.define_singleton_method(:deliver, original) end recipient_a.reload assert_equal "queued", recipient_a.status assert_match(/Da ritentare \(1\/8\)/, recipient_a.error_message) assert_equal recipient_b.id, Mailings::OutboundQueue.next_queued.id end private def create_sending_mailing(name:) mailing = create_mailing(name: name, audience: "to_send", interval_seconds: 0) mailing.update!(status: "sending", queued_at: Time.current, test_sent_at: Time.current, test_sent_to: "test@example.com") mailing end def enqueue_org(mailing, org) recipient = mailing.mailing_recipients.create!( organization: org, contact: org.contacts.first, email: org.email, status: "pending" ) assert Mailings::OutboundQueue.enqueue(recipient.reload) recipient end end