discourse/spec/jobs/regular/group_smtp_email_spec.rb
Martin Brennan 64ba5b1d21
FIX: Group SMTP email improvements (#11633)
Fixes a rare race condition causing the `Imap::Sync` class to create an incoming email and associated post/topic, which then kicks off the PostAlerter to notify others in the PM about a reply in the topic, but for the OP which is not necessary (because the person emailing the IMAP inbox already knows about the OP). Basically, we should never be sending the group SMTP email for the first post in a topic.

Also in this PR:

* Custom attribute accessors for the to/from/cc addresses on `IncomingEmail`, to parse them from an array to a joined string so the logic for this is only in one place.
* Store extra detail against the `IncomingEmail` created in `GroupSmtpMailer`
* regex test Mail header Reply-To as string instead of Field, which fixes `warning: deprecated Object#=~ is called on Mail::Field; it always returns nil`
* Add DEBUG_IMAP to log all IMAP logs as warnings for easier debugging
* Changed the Rails logging to `ImapSyncLog` in the `GroupSmtpMailer`
2021-01-05 15:32:04 +10:00

66 lines
2.5 KiB
Ruby

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe Jobs::GroupSmtpEmail do
fab!(:post) do
topic = Fabricate(:topic)
Fabricate(:post, topic: topic)
Fabricate(:post, topic: topic)
end
fab!(:group) { Fabricate(:imap_group) }
fab!(:recipient_user) { Fabricate(:user, email: "test@test.com") }
let(:post_id) { post.id }
let(:args) do
{
group_id: group.id,
post_id: post_id,
email: "test@test.com"
}
end
before do
SiteSetting.reply_by_email_address = "test+%{reply_key}@incoming.com"
SiteSetting.manual_polling_enabled = true
SiteSetting.reply_by_email_enabled = true
SiteSetting.enable_smtp = true
end
it "sends an email using the GroupSmtpMailer and Email::Sender" do
message = Mail::Message.new(body: "hello", to: "myemail@example.invalid")
GroupSmtpMailer.expects(:send_mail).with(group, "test@test.com", post).returns(message)
Email::Sender.expects(:new).with(message, :group_smtp, recipient_user).returns(stub(send: nil))
subject.execute(args)
end
it "creates an IncomingEmail record to avoid double processing via IMAP" do
subject.execute(args)
incoming = IncomingEmail.find_by(post_id: post.id, user_id: post.user_id, topic_id: post.topic_id)
expect(incoming).not_to eq(nil)
expect(incoming.message_id).to eq("topic/#{post.topic_id}/#{post.id}@test.localhost")
end
it "creates a PostReplyKey and correctly uses it for the email reply_key substitution" do
subject.execute(args)
incoming = IncomingEmail.find_by(post_id: post.id, user_id: post.user_id, topic_id: post.topic_id)
post_reply_key = PostReplyKey.where(user_id: recipient_user, post_id: post.id).first
expect(post_reply_key).not_to eq(nil)
expect(incoming.raw).to include("Reply-To: Discourse <test+#{post_reply_key.reply_key}@incoming.com>")
end
it "has the from_address and the to_addresses and subject filled in correctly" do
subject.execute(args)
incoming = IncomingEmail.find_by(post_id: post.id, user_id: post.user_id, topic_id: post.topic_id)
expect(incoming.to_addresses).to eq("test@test.com")
expect(incoming.subject).to include("Re: This is a test topic")
expect(incoming.from_address).to eq("discourseteam@ponyexpress.com")
end
context "when the post in the argument is the OP" do
let(:post_id) { post.topic.posts.first.id }
it "aborts and does not send a group SMTP email; the OP is the one that sent the email in the first place" do
expect { subject.execute(args) }.not_to(change { IncomingEmail.count })
end
end
end