Refactoring: Migrate email-process unit sub-tests to RSpec.
This commit is contained in:
parent
92d7ee95e0
commit
b19ac485bf
8 changed files with 311 additions and 613 deletions
|
@ -1,10 +1,15 @@
|
||||||
FactoryBot.define do
|
FactoryBot.define do
|
||||||
factory :ticket do
|
factory :ticket do
|
||||||
|
transient do
|
||||||
|
state_name 'new'
|
||||||
|
priority_name '2 normal'
|
||||||
|
end
|
||||||
|
|
||||||
title { 'Test Ticket' }
|
title { 'Test Ticket' }
|
||||||
group
|
group
|
||||||
customer
|
customer
|
||||||
state { Ticket::State.lookup(name: 'new') }
|
state { Ticket::State.lookup(name: state_name) }
|
||||||
priority { Ticket::Priority.lookup(name: '2 normal') }
|
priority { Ticket::Priority.lookup(name: priority_name) }
|
||||||
updated_by_id { 1 }
|
updated_by_id { 1 }
|
||||||
created_by_id { 1 }
|
created_by_id { 1 }
|
||||||
|
|
||||||
|
|
18
spec/lib/mail/encodings_spec.rb
Normal file
18
spec/lib/mail/encodings_spec.rb
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
RSpec.describe Mail::Encodings do
|
||||||
|
# Regression test for https://github.com/zammad/zammad/issues/2456
|
||||||
|
# (Mail lib was originally broken, so we patched it.
|
||||||
|
# Then, upstream was fixed, whereas our patch broke.)
|
||||||
|
describe '.value_decode' do
|
||||||
|
it 'decodes us-ascii encoded strings' do
|
||||||
|
expect(Mail::Encodings.value_decode('=?us-ascii?Q?Test?='))
|
||||||
|
.to eql('Test')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'decodes utf-8 encoded strings' do
|
||||||
|
expect(Mail::Encodings.value_decode('=?UTF-8?Q? Personal=C3=A4nderung?='))
|
||||||
|
.to eql(' Personaländerung')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,50 +1,68 @@
|
||||||
require 'rails_helper'
|
require 'rails_helper'
|
||||||
|
|
||||||
RSpec.describe Channel::EmailParser, type: :model do
|
RSpec.describe Channel::EmailParser, type: :model do
|
||||||
let(:subject) { described_class.new }
|
describe '#parse' do
|
||||||
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail001.box') }
|
# regression test for issue 2390 - Add a postmaster filter to not show emails with potential issue
|
||||||
let(:raw_mail) { File.read(mail_file) }
|
describe 'handling HTML links in message content' do
|
||||||
|
context 'with under 5,000 links' do
|
||||||
|
it 'parses message content as normal' do
|
||||||
|
expect(described_class.new.parse(<<~RAW)[:body]).to start_with('<a href="https://zammad.com/"')
|
||||||
|
From: nicole.braun@zammad.com
|
||||||
|
Content-Type: text/html
|
||||||
|
|
||||||
describe '#process' do
|
<html><body>
|
||||||
let(:raw_mail) { File.read(mail_file).sub(/(?<=^Subject: ).*$/, test_string) }
|
#{Array.new(10) { '<a href="https://zammad.com/">Dummy Link</a>' }.join(' ')}
|
||||||
let(:test_string) { Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + ticket.number }
|
</body></html>
|
||||||
let(:ticket) { create(:ticket) }
|
RAW
|
||||||
|
|
||||||
context 'for creating new users' do
|
|
||||||
context 'with one unrecognized email address' do
|
|
||||||
let(:raw_mail) { <<~RAW }
|
|
||||||
From: #{Faker::Internet.unique.email}
|
|
||||||
To: #{User.pluck(:email).reject(&:blank?).sample}
|
|
||||||
Subject: Foo bar
|
|
||||||
|
|
||||||
Lorem ipsum dolor
|
|
||||||
RAW
|
|
||||||
|
|
||||||
it 'creates one new user' do
|
|
||||||
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
|
||||||
.to change { User.count }.by(1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a large number (42+) of unrecognized email addresses' do
|
context 'with 5,000+ links' do
|
||||||
let(:raw_mail) { <<~RAW }
|
it 'replaces message content with error message' do
|
||||||
From: #{Faker::Internet.unique.email}
|
expect(described_class.new.parse(<<~RAW)).to include('body' => Channel::EmailParser::EXCESSIVE_LINKS_MSG)
|
||||||
To: #{Array.new(22) { Faker::Internet.unique.email }.join(', ')}
|
From: nicole.braun@zammad.com
|
||||||
Cc: #{Array.new(22) { Faker::Internet.unique.email }.join(', ')}
|
Content-Type: text/html
|
||||||
Subject: test max sender identify
|
|
||||||
|
|
||||||
Some Text
|
<html><body>
|
||||||
RAW
|
#{Array.new(5001) { '<a href="https://zammad.com/">Dummy Link</a>' }.join(' ')}
|
||||||
|
</body></html>
|
||||||
|
RAW
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it 'never creates more than 41 users per email' do
|
describe '#process' do
|
||||||
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
let(:raw_mail) { File.read(mail_file) }
|
||||||
.to change { User.count }.by(41)
|
|
||||||
|
describe 'auto-creating new users' do
|
||||||
|
context 'with one unrecognized email address' do
|
||||||
|
it 'creates one new user' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, <<~RAW) }.to change { User.count }.by(1)
|
||||||
|
From: #{Faker::Internet.unique.email}
|
||||||
|
RAW
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a large number of unrecognized recipient addresses' do
|
||||||
|
it 'never creates more than 40 users' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, <<~RAW) }.to change { User.count }.by(40)
|
||||||
|
From: nicole.braun@zammad.org
|
||||||
|
To: #{Array.new(20) { Faker::Internet.unique.email }.join(', ')}
|
||||||
|
Cc: #{Array.new(21) { Faker::Internet.unique.email }.join(', ')}
|
||||||
|
RAW
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for associating emails to tickets' do
|
describe 'associating emails to tickets' do
|
||||||
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail001.box') }
|
||||||
|
let(:ticket_ref) { Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + ticket.number }
|
||||||
|
let(:ticket) { create(:ticket) }
|
||||||
|
|
||||||
context 'when email subject contains ticket reference' do
|
context 'when email subject contains ticket reference' do
|
||||||
|
let(:raw_mail) { File.read(mail_file).sub(/(?<=^Subject: ).*$/, ticket_ref) }
|
||||||
|
|
||||||
it 'adds message to ticket' do
|
it 'adds message to ticket' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
.to change { ticket.articles.length }
|
.to change { ticket.articles.length }
|
||||||
|
@ -56,7 +74,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
|
|
||||||
context 'when body contains ticket reference' do
|
context 'when body contains ticket reference' do
|
||||||
context 'in visible text' do
|
context 'in visible text' do
|
||||||
let(:raw_mail) { File.read(mail_file).sub(/Hallo =\nMartin,(?=<o:p>)/, test_string) }
|
let(:raw_mail) { File.read(mail_file).sub(/Hallo =\nMartin,(?=<o:p>)/, ticket_ref) }
|
||||||
|
|
||||||
it 'adds message to ticket' do
|
it 'adds message to ticket' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
|
@ -65,7 +83,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'as part of a larger word' do
|
context 'as part of a larger word' do
|
||||||
let(:raw_mail) { File.read(mail_file).sub(/(?<=Hallo) =\n(?=Martin,<o:p>)/, test_string) }
|
let(:raw_mail) { File.read(mail_file).sub(/(?<=Hallo) =\n(?=Martin,<o:p>)/, ticket_ref) }
|
||||||
|
|
||||||
it 'creates a separate ticket' do
|
it 'creates a separate ticket' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
|
@ -74,7 +92,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'in html attributes' do
|
context 'in html attributes' do
|
||||||
let(:raw_mail) { File.read(mail_file).sub(%r{<a href.*?/a>}m, %(<table bgcolor="#{test_string}"> </table>)) }
|
let(:raw_mail) { File.read(mail_file).sub(%r{<a href.*?/a>}m, %(<table bgcolor="#{ticket_ref}"> </table>)) }
|
||||||
|
|
||||||
it 'creates a separate ticket' do
|
it 'creates a separate ticket' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
|
@ -85,7 +103,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for sender/recipient address formatting' do
|
describe 'sender/recipient address formatting' do
|
||||||
# see https://github.com/zammad/zammad/issues/2198
|
# see https://github.com/zammad/zammad/issues/2198
|
||||||
context 'when sender address contains spaces (#2198)' do
|
context 'when sender address contains spaces (#2198)' do
|
||||||
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail071.box') }
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail071.box') }
|
||||||
|
@ -93,7 +111,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
|
|
||||||
it 'removes them before creating a new user' do
|
it 'removes them before creating a new user' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
.to change { User.where(email: sender_email).count }.to(1)
|
.to change { User.exists?(email: sender_email) }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'marks new user email as invalid' do
|
it 'marks new user email as invalid' do
|
||||||
|
@ -113,7 +131,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
|
|
||||||
it 'removes them before creating a new user' do
|
it 'removes them before creating a new user' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
.to change { User.where(email: sender_email).count }.to(1)
|
.to change { User.exists?(email: sender_email) }
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'marks new user email as invalid' do
|
it 'marks new user email as invalid' do
|
||||||
|
@ -127,7 +145,7 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'for charset handling' do
|
describe 'charset handling' do
|
||||||
# see https://github.com/zammad/zammad/issues/2224
|
# see https://github.com/zammad/zammad/issues/2224
|
||||||
context 'when header specifies Windows-1258 charset (#2224)' do
|
context 'when header specifies Windows-1258 charset (#2224)' do
|
||||||
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail072.box') }
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail072.box') }
|
||||||
|
@ -139,46 +157,10 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'mail with links' do
|
describe 'attachment handling' do
|
||||||
|
context 'with header "Content-Transfer-Encoding: x-uuencode"' do
|
||||||
def mock_mail(number_of_links)
|
|
||||||
link = '<a href="https://zammad.com/">Dummy Link</a> '
|
|
||||||
|
|
||||||
mail = Mail.new
|
|
||||||
mail.html_part = "<html><body>#{link * number_of_links}</body></html>"
|
|
||||||
mail
|
|
||||||
end
|
|
||||||
|
|
||||||
let(:mail_10) { mock_mail(10).to_s }
|
|
||||||
let(:mail_5k) { mock_mail(5001).to_s }
|
|
||||||
|
|
||||||
# regression test for issue 2390 - Add a postmaster filter to not show emails with potential issue
|
|
||||||
it '(>5k links) are replaced by a warning message' do
|
|
||||||
expect( described_class.new.parse(mail_5k)[:body] )
|
|
||||||
.to eql( Channel::EmailParser::EXCESSIVE_LINKS_MSG )
|
|
||||||
end
|
|
||||||
|
|
||||||
it '(10 links) are not touched' do
|
|
||||||
expect( described_class.new.parse(mail_10)[:body] )
|
|
||||||
.to start_with( '<a href="https://zammad.com/"' )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'Mail::Encodings.value_decode' do
|
|
||||||
it 'decode us-ascii encoded strings' do
|
|
||||||
expect( Mail::Encodings.value_decode('=?us-ascii?Q?Test?=') ).to eql( 'Test' )
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'decode utf-8 encoded strings' do
|
|
||||||
expect( Mail::Encodings.value_decode('=?UTF-8?Q? Personal=C3=A4nderung?=') ).to eql( ' Personaländerung' )
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when handling Content-Transfer-Encoding of attachments' do
|
|
||||||
|
|
||||||
context 'with x-uuencode' do
|
|
||||||
|
|
||||||
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail078-content_transfer_encoding_x_uuencode.box') }
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail078-content_transfer_encoding_x_uuencode.box') }
|
||||||
|
let(:article) { described_class.new.process({}, raw_mail).second }
|
||||||
|
|
||||||
it 'does not raise RuntimeError' do
|
it 'does not raise RuntimeError' do
|
||||||
expect { described_class.new.process({}, raw_mail) }
|
expect { described_class.new.process({}, raw_mail) }
|
||||||
|
@ -186,26 +168,115 @@ RSpec.describe Channel::EmailParser, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'parses the content correctly' do
|
it 'parses the content correctly' do
|
||||||
_ticket, article, _user, _mail = described_class.new.process({}, raw_mail)
|
|
||||||
expect(article.attachments.first.filename).to eq('PGP_Cmts_on_12-14-01_Pkg.txt')
|
expect(article.attachments.first.filename).to eq('PGP_Cmts_on_12-14-01_Pkg.txt')
|
||||||
expect(article.attachments.first.content).to eq('Hello Zammad')
|
expect(article.attachments.first.content).to eq('Hello Zammad')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when mail contains image(s)' do
|
describe 'inline image handling' do
|
||||||
# see https://github.com/zammad/zammad/issues/2486
|
# see https://github.com/zammad/zammad/issues/2486
|
||||||
context 'when image is large but not resizable' do
|
context 'when image is large but not resizable' do
|
||||||
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail079.box') }
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail079.box') }
|
||||||
|
let(:attachment) { article.attachments.last }
|
||||||
|
let(:article) { described_class.new.process({}, raw_mail).second }
|
||||||
|
|
||||||
it "doesn't set resizable preference" do
|
it "doesn't set resizable preference" do
|
||||||
_ticket, article = described_class.new.process({}, raw_mail)
|
|
||||||
attachment = article.attachments.last
|
|
||||||
|
|
||||||
expect(attachment.filename).to eq('a.jpg')
|
expect(attachment.filename).to eq('a.jpg')
|
||||||
expect(attachment.preferences).not_to include('resizable' => true)
|
expect(attachment.preferences).not_to include('resizable' => true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'for “delivery failed” notifications (a.k.a. bounce messages)' do
|
||||||
|
let(:ticket) { article.ticket }
|
||||||
|
let(:article) { create(:ticket_article, sender_name: 'Agent', message_id: message_id) }
|
||||||
|
let(:message_id) { raw_mail[/(?<=^(References|Message-ID): )\S*/] }
|
||||||
|
|
||||||
|
context 'with future retries (delayed)' do
|
||||||
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail078.box') }
|
||||||
|
|
||||||
|
context 'on a closed ticket' do
|
||||||
|
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) }
|
||||||
|
|
||||||
|
it 'sets #preferences on resulting ticket to { "send-auto-responses" => false, "is-auto-reponse" => true }' do
|
||||||
|
article = Channel::EmailParser.new.process({}, raw_mail).second
|
||||||
|
expect(article.preferences)
|
||||||
|
.to include('send-auto-response' => false, 'is-auto-response' => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns a Mail object with an x-zammad-out-of-office header' do
|
||||||
|
output_mail = Channel::EmailParser.new.process({}, raw_mail).last
|
||||||
|
expect(output_mail).to include('x-zammad-out-of-office': true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'finds the article referenced in the bounce message headers, then adds the bounce message to its ticket' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.to change { ticket.articles.count }.by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not re-open the ticket' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.not_to change { ticket.reload.state.name }.from('closed')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with no future retries (undeliverable): sample input 1' do
|
||||||
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail033-undelivered-mail-returned-to-sender.box') }
|
||||||
|
|
||||||
|
context 'for original message sent by Agent' do
|
||||||
|
it 'sets #preferences on resulting ticket to { "send-auto-responses" => false, "is-auto-reponse" => true }' do
|
||||||
|
article = Channel::EmailParser.new.process({}, raw_mail).second
|
||||||
|
expect(article.preferences)
|
||||||
|
.to include('send-auto-response' => false, 'is-auto-response' => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'finds the article referenced in the bounce message headers, then adds the bounce message to its ticket' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.to change { ticket.articles.count }.by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not alter the ticket state' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.not_to change { ticket.reload.state.name }.from('open')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for original message sent by Customer' do
|
||||||
|
let(:article) { create(:ticket_article, sender_name: 'Customer', message_id: message_id) }
|
||||||
|
|
||||||
|
it 'sets #preferences on resulting ticket to { "send-auto-responses" => false, "is-auto-reponse" => true }' do
|
||||||
|
article = Channel::EmailParser.new.process({}, raw_mail).second
|
||||||
|
expect(article.preferences)
|
||||||
|
.to include('send-auto-response' => false, 'is-auto-response' => true)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'finds the article referenced in the bounce message headers, then adds the bounce message to its ticket' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.to change { ticket.articles.count }.by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not alter the ticket state' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.not_to change { ticket.reload.state.name }.from('new')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with no future retries (undeliverable): sample input 2' do
|
||||||
|
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail055.box') }
|
||||||
|
|
||||||
|
it 'finds the article referenced in the bounce message headers, then adds the bounce message to its ticket' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.to change { ticket.articles.count }.by(1)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not alter the ticket state' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_mail) }
|
||||||
|
.not_to change { ticket.reload.state.name }.from('open')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -256,6 +256,18 @@ RSpec.describe Ticket, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'Attributes:' do
|
describe 'Attributes:' do
|
||||||
|
describe '#state' do
|
||||||
|
context 'for brand new tickets' do
|
||||||
|
context 'when a non-customer article is added' do
|
||||||
|
let(:article) { create(:ticket_article, ticket: ticket, sender_name: 'Agent') }
|
||||||
|
|
||||||
|
it 'switches to "open"' do
|
||||||
|
expect { article }.to change { ticket.state.name }.from('new').to('open')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#pending_time' do
|
describe '#pending_time' do
|
||||||
subject(:ticket) { create(:ticket, pending_time: Time.zone.now + 2.days) }
|
subject(:ticket) { create(:ticket, pending_time: Time.zone.now + 2.days) }
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,10 @@ require 'models/application_model_examples'
|
||||||
RSpec.describe Trigger, type: :model do
|
RSpec.describe Trigger, type: :model do
|
||||||
it_behaves_like 'ApplicationModel', can_assets: { selectors: %i[condition perform] }
|
it_behaves_like 'ApplicationModel', can_assets: { selectors: %i[condition perform] }
|
||||||
|
|
||||||
subject(:trigger) { create(:trigger) }
|
before { Trigger.destroy_all } # Default DB state includes three sample triggers
|
||||||
|
subject!(:trigger) { create(:trigger, condition: condition, perform: perform) }
|
||||||
|
|
||||||
describe '#assets (for supplying model data to front-end framework)' do
|
describe '#assets (for supplying model data to front-end framework)' do
|
||||||
subject(:trigger) { create(:trigger, condition: condition, perform: perform) }
|
|
||||||
let(:condition) { { 'ticket.state_id' => { operator: 'is', value: 1 } } }
|
let(:condition) { { 'ticket.state_id' => { operator: 'is', value: 1 } } }
|
||||||
let(:perform) { { 'ticket.priority_id' => { value: 1 } } }
|
let(:perform) { { 'ticket.priority_id' => { value: 1 } } }
|
||||||
|
|
||||||
|
@ -17,4 +17,113 @@ RSpec.describe Trigger, type: :model do
|
||||||
.and include(Ticket::Priority.first.assets({}))
|
.and include(Ticket::Priority.first.assets({}))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'Send-email triggers' do
|
||||||
|
let(:perform) do
|
||||||
|
{
|
||||||
|
'notification.email' => {
|
||||||
|
'recipient' => 'ticket_customer',
|
||||||
|
'subject' => 'foo',
|
||||||
|
'body' => 'bar'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for condition "ticket created"' do
|
||||||
|
let(:condition) do
|
||||||
|
{ 'ticket.action' => { 'operator' => 'is', 'value' => 'create' } }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ticket is created directly' do
|
||||||
|
let!(:ticket) { create(:ticket) }
|
||||||
|
|
||||||
|
it 'fires (without altering ticket state)' do
|
||||||
|
expect { Observer::Transaction.commit }
|
||||||
|
.to change { Ticket::Article.count }.by(1)
|
||||||
|
.and not_change { ticket.reload.state.name }.from('new')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when ticket is created via Channel::EmailParser.process' do
|
||||||
|
before { create(:email_address, groups: [Group.first]) }
|
||||||
|
let(:raw_email) { File.read(Rails.root.join('test', 'data', 'mail', 'mail001.box')) }
|
||||||
|
|
||||||
|
it 'fires (without altering ticket state)' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_email) }
|
||||||
|
.to change { Ticket.count }.by(1)
|
||||||
|
.and change { Ticket::Article.count }.by(2)
|
||||||
|
|
||||||
|
expect(Ticket.last.state.name).to eq('new')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for condition "ticket updated"' do
|
||||||
|
let(:condition) do
|
||||||
|
{ 'ticket.action' => { 'operator' => 'is', 'value' => 'update' } }
|
||||||
|
end
|
||||||
|
|
||||||
|
let!(:ticket) { create(:ticket).tap { Observer::Transaction.commit } }
|
||||||
|
|
||||||
|
context 'when new article is created directly' do
|
||||||
|
context 'with empty #preferences hash' do
|
||||||
|
let!(:article) { create(:ticket_article, ticket: ticket) }
|
||||||
|
|
||||||
|
it 'fires (without altering ticket state)' do
|
||||||
|
expect { Observer::Transaction.commit }
|
||||||
|
.to change { ticket.reload.articles.count }.by(1)
|
||||||
|
.and not_change { ticket.reload.state.name }.from('new')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with #preferences { "send-auto-response" => false }' do
|
||||||
|
let!(:article) do
|
||||||
|
create(:ticket_article,
|
||||||
|
ticket: ticket,
|
||||||
|
preferences: { 'send-auto-response' => false })
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'does not fire' do
|
||||||
|
expect { Observer::Transaction.commit }
|
||||||
|
.not_to change { ticket.reload.articles.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when new article is created via Channel::EmailParser.process' do
|
||||||
|
context 'with a regular message' do
|
||||||
|
let!(:article) do
|
||||||
|
create(:ticket_article,
|
||||||
|
ticket: ticket,
|
||||||
|
message_id: raw_email[/(?<=^References: )\S*/],
|
||||||
|
subject: raw_email[/(?<=^Subject: Re: ).*$/])
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:raw_email) { File.read(Rails.root.join('test', 'data', 'mail', 'mail005.box')) }
|
||||||
|
|
||||||
|
it 'fires (without altering ticket state)' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_email) }
|
||||||
|
.to not_change { Ticket.count }
|
||||||
|
.and change { ticket.reload.articles.count }.by(2)
|
||||||
|
.and not_change { ticket.reload.state.name }.from('new')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with delivery-failed "bounce message"' do
|
||||||
|
let!(:article) do
|
||||||
|
create(:ticket_article,
|
||||||
|
ticket: ticket,
|
||||||
|
message_id: raw_email[/(?<=^Message-ID: )\S*/])
|
||||||
|
end
|
||||||
|
|
||||||
|
let(:raw_email) { File.read(Rails.root.join('test', 'data', 'mail', 'mail055.box')) }
|
||||||
|
|
||||||
|
it 'does not fire' do
|
||||||
|
expect { Channel::EmailParser.new.process({}, raw_email) }
|
||||||
|
.to change { ticket.reload.articles.count }.by(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,52 +1,21 @@
|
||||||
require 'test_helper'
|
Content-Type: multipart/report; boundary="000000000000ca4a1a057417a375"; report-type=delivery-status
|
||||||
|
|
||||||
class EmailProcessBounceDeliveryTemporaryFailed < ActiveSupport::TestCase
|
|
||||||
|
|
||||||
test 'process with temp faild bounce email' do
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
|
||||||
title: 'temp failed check - ms',
|
|
||||||
group: Group.lookup(name: 'Users'),
|
|
||||||
customer_id: 2,
|
|
||||||
state: Ticket::State.lookup(name: 'closed'),
|
|
||||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article = Ticket::Article.create!(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'temp failed check',
|
|
||||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.lookup(name: 'Agent'),
|
|
||||||
type: Ticket::Article::Type.lookup(name: 'email'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
travel 1.second
|
|
||||||
|
|
||||||
# temp faild bounce email
|
|
||||||
email_raw_string = "Content-Type: multipart/report; boundary=\"000000000000ca4a1a057417a375\"; report-type=delivery-status
|
|
||||||
From: Mail Delivery Subsystem <mailer-daemon@example.com>
|
From: Mail Delivery Subsystem <mailer-daemon@example.com>
|
||||||
To: service@example.de
|
To: service@example.de
|
||||||
Auto-Submitted: auto-replied
|
Auto-Submitted: auto-replied
|
||||||
Subject: Delivery Status Notification (Delay)
|
Subject: Delivery Status Notification (Delay)
|
||||||
References: #{article.message_id}
|
References: <20150830145601.30.608881@example.com>
|
||||||
In-Reply-To: #{article.message_id}
|
In-Reply-To: <20150830145601.30.608881@example.com>
|
||||||
Message-ID: <5b7e8af4.1c69fb81.3ac1b.e296.GMRIR@mx.example.com>
|
Message-ID: <5b7e8af4.1c69fb81.3ac1b.e296.GMRIR@mx.example.com>
|
||||||
Date: Thu, 23 Aug 2018 03:22:44 -0700 (PDT)
|
Date: Thu, 23 Aug 2018 03:22:44 -0700 (PDT)
|
||||||
|
|
||||||
--000000000000ca4a1a057417a375
|
--000000000000ca4a1a057417a375
|
||||||
Content-Type: multipart/related; boundary=\"000000000000ca53d4057417a37c\"
|
Content-Type: multipart/related; boundary="000000000000ca53d4057417a37c"
|
||||||
|
|
||||||
--000000000000ca53d4057417a37c
|
--000000000000ca53d4057417a37c
|
||||||
Content-Type: multipart/alternative; boundary=\"000000000000ca53de057417a37d\"
|
Content-Type: multipart/alternative; boundary="000000000000ca53de057417a37d"
|
||||||
|
|
||||||
--000000000000ca53de057417a37d
|
--000000000000ca53de057417a37d
|
||||||
Content-Type: text/plain; charset=\"UTF-8\"
|
Content-Type: text/plain; charset="UTF-8"
|
||||||
Content-Transfer-Encoding: quoted-printable
|
Content-Transfer-Encoding: quoted-printable
|
||||||
|
|
||||||
|
|
||||||
|
@ -72,7 +41,7 @@ Content-Type: message/delivery-status
|
||||||
Reporting-MTA: dns; example.com
|
Reporting-MTA: dns; example.com
|
||||||
Received-From-MTA: dns; service@example.de
|
Received-From-MTA: dns; service@example.de
|
||||||
Arrival-Date: Wed, 22 Aug 2018 02:00:03 -0700 (PDT)
|
Arrival-Date: Wed, 22 Aug 2018 02:00:03 -0700 (PDT)
|
||||||
X-Original-Message-ID: #{article.message_id}
|
X-Original-Message-ID: <20150830145601.30.608881@example.com>
|
||||||
|
|
||||||
Final-Recipient: rfc822; bob.smith@example.de
|
Final-Recipient: rfc822; bob.smith@example.de
|
||||||
Action: delayed
|
Action: delayed
|
||||||
|
@ -89,21 +58,10 @@ Content-Type: message/rfc822
|
||||||
Date: Wed, 22 Aug 2018 11:00:03 +0200
|
Date: Wed, 22 Aug 2018 11:00:03 +0200
|
||||||
From: example Helpdesk <service@example.de>
|
From: example Helpdesk <service@example.de>
|
||||||
To: bob.smith@example.de
|
To: bob.smith@example.de
|
||||||
Message-ID: #{article.message_id}
|
Message-ID: <20150830145601.30.608881@example.com>
|
||||||
Subject: Ihre Anfrage () [Ticket#638810]
|
Subject: Ihre Anfrage () [Ticket#638810]
|
||||||
Content-Type: text/plain; charset=UTF-8
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
|
||||||
ABC
|
ABC
|
||||||
|
|
||||||
--000000000000ca4a1a057417a375--
|
--000000000000ca4a1a057417a375--
|
||||||
"
|
|
||||||
|
|
||||||
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
|
|
||||||
assert_equal(true, mail['x-zammad-out-of-office'.to_sym])
|
|
||||||
ticket = Ticket.find(ticket.id)
|
|
||||||
assert_equal(ticket.id, ticket_p.id)
|
|
||||||
assert_equal('closed', ticket.state.name)
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,219 +0,0 @@
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class EmailProcessBounceDeliveryPermanentFailedTest < ActiveSupport::TestCase
|
|
||||||
|
|
||||||
test 'process with bounce trigger email loop check - article based blocker' do
|
|
||||||
roles = Role.where(name: %w[Customer])
|
|
||||||
customer1 = User.create_or_update(
|
|
||||||
login: 'ticket-bounce-trigger1@example.com',
|
|
||||||
firstname: 'Notification',
|
|
||||||
lastname: 'Customer1',
|
|
||||||
email: 'ticket-bounce-trigger1@example.com',
|
|
||||||
active: true,
|
|
||||||
roles: roles,
|
|
||||||
preferences: {},
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply new ticket',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'create',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply followup',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
|
||||||
title: 'bounce check',
|
|
||||||
group: Group.lookup(name: 'Users'),
|
|
||||||
customer: customer1,
|
|
||||||
state: Ticket::State.lookup(name: 'new'),
|
|
||||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article = Ticket::Article.create!(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check',
|
|
||||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal('new', ticket.state.name)
|
|
||||||
assert_equal(2, ticket.articles.count)
|
|
||||||
|
|
||||||
article = Ticket::Article.create!(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: customer1.email,
|
|
||||||
subject: 'bounce check 2',
|
|
||||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check 2',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal(4, ticket.articles.count)
|
|
||||||
|
|
||||||
travel 1.second
|
|
||||||
email_raw_string = File.read(Rails.root.join('test', 'data', 'mail', 'mail033-undelivered-mail-returned-to-sender.box'))
|
|
||||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
|
||||||
assert_equal(ticket.id, ticket_p.id)
|
|
||||||
assert_equal('open', ticket_p.state.name)
|
|
||||||
assert_equal(5, ticket_p.articles.count)
|
|
||||||
travel_back
|
|
||||||
ticket.destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'process with bounce trigger email loop check - bounce based blocker' do
|
|
||||||
roles = Role.where(name: %w[Customer])
|
|
||||||
customer2 = User.create_or_update(
|
|
||||||
login: 'ticket-bounce-trigger2@example.com',
|
|
||||||
firstname: 'Notification',
|
|
||||||
lastname: 'Customer2',
|
|
||||||
email: 'ticket-bounce-trigger2@example.com',
|
|
||||||
active: true,
|
|
||||||
roles: roles,
|
|
||||||
preferences: {},
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply new ticket',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'create',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply followup',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
ticket = Ticket.create!(
|
|
||||||
title: 'bounce check',
|
|
||||||
group: Group.lookup(name: 'Users'),
|
|
||||||
customer: customer2,
|
|
||||||
state: Ticket::State.lookup(name: 'new'),
|
|
||||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article = Ticket::Article.create!(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check',
|
|
||||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal('new', ticket.state.name)
|
|
||||||
assert_equal(2, ticket.articles.count)
|
|
||||||
|
|
||||||
article = Ticket::Article.create!(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check 2',
|
|
||||||
message_id: '<20170526150141.232.13312@example.zammad.loc>',
|
|
||||||
body: 'some message bounce check 2',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal(4, ticket.articles.count)
|
|
||||||
|
|
||||||
travel 1.second
|
|
||||||
email_raw_string = File.read(Rails.root.join('test', 'data', 'mail', 'mail055.box'))
|
|
||||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
|
||||||
assert_equal(ticket.id, ticket_p.id)
|
|
||||||
assert_equal('open', ticket_p.state.name)
|
|
||||||
assert_equal(5, ticket_p.articles.count)
|
|
||||||
travel_back
|
|
||||||
ticket.destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -1,256 +0,0 @@
|
||||||
require 'test_helper'
|
|
||||||
|
|
||||||
class EmailProcessBounceFollowUpTest < ActiveSupport::TestCase
|
|
||||||
|
|
||||||
test 'process with bounce follow up check' do
|
|
||||||
|
|
||||||
ticket = Ticket.create(
|
|
||||||
title: 'bounce check',
|
|
||||||
group: Group.lookup(name: 'Users'),
|
|
||||||
customer_id: 2,
|
|
||||||
state: Ticket::State.lookup(name: 'new'),
|
|
||||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article = Ticket::Article.create(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check',
|
|
||||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Customer').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
travel 1.second
|
|
||||||
email_file_path = Rails.root.join('test', 'data', 'mail', 'mail033-undelivered-mail-returned-to-sender.box')
|
|
||||||
email_raw_string = File.read(email_file_path)
|
|
||||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
|
||||||
assert_equal(ticket.id, ticket_p.id)
|
|
||||||
assert_equal('new', ticket_p.state.name)
|
|
||||||
travel_back
|
|
||||||
ticket.destroy
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'process with bounce trigger email loop check - article based blocker' do
|
|
||||||
roles = Role.where(name: %w[Customer])
|
|
||||||
customer1 = User.create_or_update(
|
|
||||||
login: 'ticket-bounce-trigger1@example.com',
|
|
||||||
firstname: 'Notification',
|
|
||||||
lastname: 'Customer1',
|
|
||||||
email: 'ticket-bounce-trigger1@example.com',
|
|
||||||
active: true,
|
|
||||||
roles: roles,
|
|
||||||
preferences: {},
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply new ticket',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'create',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply followup',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
ticket = Ticket.create(
|
|
||||||
title: 'bounce check',
|
|
||||||
group: Group.lookup(name: 'Users'),
|
|
||||||
customer: customer1,
|
|
||||||
state: Ticket::State.lookup(name: 'new'),
|
|
||||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article = Ticket::Article.create(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check',
|
|
||||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal('new', ticket.state.name)
|
|
||||||
assert_equal(2, ticket.articles.count)
|
|
||||||
|
|
||||||
article = Ticket::Article.create(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: customer1.email,
|
|
||||||
subject: 'bounce check 2',
|
|
||||||
message_id: '<20150830145601.30.608881@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check 2',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal(4, ticket.articles.count)
|
|
||||||
|
|
||||||
travel 1.second
|
|
||||||
email_file_path = Rails.root.join('test', 'data', 'mail', 'mail033-undelivered-mail-returned-to-sender.box')
|
|
||||||
email_raw_string = File.read(email_file_path)
|
|
||||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
|
||||||
assert_equal(ticket.id, ticket_p.id)
|
|
||||||
assert_equal('open', ticket_p.state.name)
|
|
||||||
assert_equal(5, ticket_p.articles.count)
|
|
||||||
travel_back
|
|
||||||
ticket.destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
test 'process with bounce trigger email loop check - bounce based blocker' do
|
|
||||||
roles = Role.where(name: %w[Customer])
|
|
||||||
customer2 = User.create_or_update(
|
|
||||||
login: 'ticket-bounce-trigger2@example.com',
|
|
||||||
firstname: 'Notification',
|
|
||||||
lastname: 'Customer2',
|
|
||||||
email: 'ticket-bounce-trigger2@example.com',
|
|
||||||
active: true,
|
|
||||||
roles: roles,
|
|
||||||
preferences: {},
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply new ticket',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'create',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your inquiry (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
Trigger.create_or_update(
|
|
||||||
name: 'auto reply followup',
|
|
||||||
condition: {
|
|
||||||
'ticket.action' => {
|
|
||||||
'operator' => 'is',
|
|
||||||
'value' => 'update',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
perform: {
|
|
||||||
'notification.email' => {
|
|
||||||
'body' => 'some text<br>#{ticket.customer.lastname}<br>#{ticket.title}<br>#{article.body}',
|
|
||||||
'recipient' => 'ticket_customer',
|
|
||||||
'subject' => 'Thanks for your follow up (#{ticket.title})!',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
disable_notification: true,
|
|
||||||
active: true,
|
|
||||||
created_by_id: 1,
|
|
||||||
updated_by_id: 1,
|
|
||||||
)
|
|
||||||
|
|
||||||
ticket = Ticket.create(
|
|
||||||
title: 'bounce check',
|
|
||||||
group: Group.lookup(name: 'Users'),
|
|
||||||
customer: customer2,
|
|
||||||
state: Ticket::State.lookup(name: 'new'),
|
|
||||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
article = Ticket::Article.create(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check',
|
|
||||||
message_id: '<20150830145601.30.6088xx@edenhofer.zammad.com>',
|
|
||||||
body: 'some message bounce check',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal('new', ticket.state.name)
|
|
||||||
assert_equal(2, ticket.articles.count)
|
|
||||||
|
|
||||||
article = Ticket::Article.create(
|
|
||||||
ticket_id: ticket.id,
|
|
||||||
from: 'some_sender@example.com',
|
|
||||||
to: 'some_recipient@example.com',
|
|
||||||
subject: 'bounce check 2',
|
|
||||||
message_id: '<20170526150141.232.13312@example.zammad.loc>',
|
|
||||||
body: 'some message bounce check 2',
|
|
||||||
internal: false,
|
|
||||||
sender: Ticket::Article::Sender.where(name: 'Agent').first,
|
|
||||||
type: Ticket::Article::Type.where(name: 'email').first,
|
|
||||||
updated_by_id: 1,
|
|
||||||
created_by_id: 1,
|
|
||||||
)
|
|
||||||
Observer::Transaction.commit
|
|
||||||
assert_equal(4, ticket.articles.count)
|
|
||||||
|
|
||||||
travel 1.second
|
|
||||||
email_file_path = Rails.root.join('test', 'data', 'mail', 'mail055.box')
|
|
||||||
email_raw_string = File.read(email_file_path)
|
|
||||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
|
||||||
assert_equal(ticket.id, ticket_p.id)
|
|
||||||
assert_equal('open', ticket_p.state.name)
|
|
||||||
assert_equal(5, ticket_p.articles.count)
|
|
||||||
travel_back
|
|
||||||
ticket.destroy
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
Loading…
Reference in a new issue