Refactoring: Migrate email_process_follow_up_test to RSpec

This commit is contained in:
Ryan Lue 2019-05-13 11:29:49 +02:00 committed by Martin Edenhofer
parent 7a79f97bb9
commit 2ca17b913f
4 changed files with 534 additions and 609 deletions

View file

@ -272,7 +272,7 @@ RSpec/NamedSubject:
# Offense count: 545 # Offense count: 545
RSpec/NestedGroups: RSpec/NestedGroups:
Max: 7 Max: 8
# Offense count: 28 # Offense count: 28
# Cop supports --auto-correct. # Cop supports --auto-correct.

View file

@ -35,6 +35,8 @@ RSpec.describe Channel::EmailParser, type: :model do
describe '#process' do describe '#process' do
let(:raw_mail) { File.read(mail_file) } let(:raw_mail) { File.read(mail_file) }
before { Trigger.destroy_all } # triggers may cause additional articles to be created
describe 'auto-creating new users' do describe 'auto-creating new users' do
context 'with one unrecognized email address' do context 'with one unrecognized email address' do
it 'creates one new user' do it 'creates one new user' do
@ -98,7 +100,7 @@ RSpec.describe Channel::EmailParser, type: :model do
it 'creates a ticket and article' do it 'creates a ticket and article' do
expect { Channel::EmailParser.new.process({}, raw_mail) } expect { Channel::EmailParser.new.process({}, raw_mail) }
.to change { Ticket.count }.by(1) .to change { Ticket.count }.by(1)
.and change { Ticket::Article.count }.by_at_least(1) # triggers may cause additional articles to be created .and change { Ticket::Article.count }.by_at_least(1)
end end
it 'sets #title to email subject' do it 'sets #title to email subject' do
@ -156,99 +158,485 @@ RSpec.describe Channel::EmailParser, type: :model do
end end
describe 'associating emails to existing tickets' do describe 'associating emails to existing tickets' do
let(:mail_file) { Rails.root.join('test', 'data', 'mail', 'mail001.box') } let!(:ticket) { create(:ticket) }
let(:ticket_ref) { Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + ticket.number } 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 describe 'based on where a ticket reference appears in the message' do
let(:raw_mail) { File.read(mail_file).sub(/(?<=^Subject: ).*$/, ticket_ref) } shared_context 'ticket reference in subject' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: #{ticket_ref}
Lorem ipsum dolor
RAW
end
shared_context 'ticket reference in body' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
Lorem ipsum dolor #{ticket_ref}
RAW
end
shared_context 'ticket reference in body (text/html)' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
Content-Transfer-Encoding: 7bit
Content-Type: text/html;
<b>Lorem ipsum dolor #{ticket_ref}</b>
RAW
end
shared_context 'ticket reference in attachment' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
Content-Type: multipart/mixed; boundary="Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2"
Subject: no reference
Date: Sun, 30 Aug 2015 23:20:54 +0200
To: Martin Edenhofer <me@znuny.com>
Mime-Version: 1.0 (Mac OS X Mail 8.2 \(2104\))
X-Mailer: Apple Mail (2.2104)
--Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=us-ascii
no reference
--Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2
Content-Disposition: attachment;
filename=test1.txt
Content-Type: text/plain;
name="test.txt"
Content-Transfer-Encoding: 7bit
Some Text #{ticket_ref}
--Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2--
RAW
end
shared_context 'ticket reference in In-Reply-To header' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
In-Reply-To: #{article.message_id}
Lorem ipsum dolor
RAW
let!(:article) { create(:ticket_article, ticket: ticket, message_id: '<20150830145601.30.608882@edenhofer.zammad.com>') }
end
shared_context 'ticket reference in References header' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
References: <DA918CD1-BE9A-4262-ACF6-5001E59291B6@znuny.com> #{article.message_id} <DA918CD1-BE9A-4262-ACF6-5001E59291XX@znuny.com>
Lorem ipsum dolor
RAW
let!(:article) { create(:ticket_article, ticket: ticket, message_id: '<20150830145601.30.608882@edenhofer.zammad.com>') }
end
shared_examples 'adds message to ticket' do
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 }.by(1)
end
end
shared_examples 'creates a new ticket' do
it 'creates a new ticket' do
expect { described_class.new.process({}, raw_mail) }
.to change { Ticket.count }.by(1)
.and not_change { ticket.articles.length }
end
end
context 'when not explicitly configured to search anywhere' do
before { Setting.set('postmaster_follow_up_search_in', nil) }
context 'when subject contains ticket reference' do
include_context 'ticket reference in subject'
include_examples 'adds message to ticket'
context 'alongside other, invalid ticket references' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: [#{Setting.get('ticket_hook') + Setting.get('ticket_hook_divider') + Ticket::Number.generate}] #{ticket_ref}
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end end
context 'and ticket is closed' do context 'and ticket is closed' do
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) } before { ticket.update(state: Ticket::State.find_by(name: 'closed')) }
it 'adds message to ticket' do include_examples 'adds message to ticket'
expect { described_class.new.process({}, raw_mail) }
.to change { ticket.articles.length }
end
end end
context 'but ticket groups #follow_up_possible attribute is "new_ticket"' do context 'but ticket groups #follow_up_possible attribute is "new_ticket"' do
before { ticket.group.update(follow_up_possible: 'new_ticket') } before { ticket.group.update(follow_up_possible: 'new_ticket') }
context 'and ticket is open' do context 'and ticket is open' do
it 'still adds message to ticket' do include_examples 'adds message to ticket'
expect { described_class.new.process({}, raw_mail) }
.to change { ticket.articles.length }
end
end end
context 'and ticket is closed' do context 'and ticket is closed' do
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) } before { ticket.update(state: Ticket::State.find_by(name: 'closed')) }
it 'creates a new ticket' do include_examples 'creates a new ticket'
expect { described_class.new.process({}, raw_mail) }
.to change { Ticket.count }.by(1)
.and not_change { ticket.articles.length }
end
end end
context 'and ticket is merged' do context 'and ticket is merged' do
before { ticket.update(state: Ticket::State.find_by(name: 'merged')) } before { ticket.update(state: Ticket::State.find_by(name: 'merged')) }
it 'creates a new ticket' do include_examples 'creates a new ticket'
expect { described_class.new.process({}, raw_mail) }
.to change { Ticket.count }.by(1)
.and not_change { ticket.articles.length }
end
end end
context 'and ticket is removed' do context 'and ticket is removed' do
before { ticket.update(state: Ticket::State.find_by(name: 'removed')) } before { ticket.update(state: Ticket::State.find_by(name: 'removed')) }
it 'creates a new ticket' do include_examples 'creates a new ticket'
expect { described_class.new.process({}, raw_mail) }
.to change { Ticket.count }.by(1)
.and not_change { ticket.articles.length }
end end
end end
context 'and "ticket_hook" setting is non-default value' do
before { Setting.set('ticket_hook', 'VD-Ticket#') }
include_examples 'adds message to ticket'
end
end
context 'when body contains ticket reference' do
include_context 'ticket reference in body'
include_examples 'creates a new ticket'
end
context 'when attachment contains ticket reference' do
include_context 'ticket reference in attachment'
include_examples 'creates a new ticket'
end
context 'when In-Reply-To header contains article message-id' do
include_context 'ticket reference in In-Reply-To header'
include_examples 'creates a new ticket'
context 'and subject matches article subject' do
let(:raw_mail) { <<~RAW.chomp }
From: customer@example.com
To: me@example.com
Subject: AW: RE: #{article.subject}
In-Reply-To: #{article.message_id}
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
context 'and "ticket_hook_position" setting is "none"' do
before { Setting.set('ticket_hook_position', 'none') }
let(:raw_mail) { <<~RAW.chomp }
From: customer@example.com
To: me@example.com
Subject: RE: Foo bar
In-Reply-To: #{article.message_id}
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
end
context 'when References header contains article message-id' do
include_context 'ticket reference in References header'
include_examples 'creates a new ticket'
context 'and Auto-Submitted header reads "auto-replied"' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
References: #{article.message_id}
Auto-Submitted: auto-replied
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
context 'and subject matches article subject' do
let(:raw_mail) { <<~RAW.chomp }
From: customer@example.com
To: me@example.com
Subject: AW: RE: #{article.subject}
References: #{article.message_id}
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
context 'and "ticket_hook_position" setting is "none"' do
before { Setting.set('ticket_hook_position', 'none') }
let(:raw_mail) { <<~RAW.chomp }
From: customer@example.com
To: me@example.com
Subject: RE: Foo bar
References: #{article.message_id}
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
end end
end end
context 'when configured to search body' do context 'when configured to search body' do
before { Setting.set('postmaster_follow_up_search_in', 'body') } before { Setting.set('postmaster_follow_up_search_in', 'body') }
context 'when subject contains ticket reference' do
include_context 'ticket reference in subject'
include_examples 'adds message to ticket'
end
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>)/, ticket_ref) } include_context 'ticket reference in body'
include_examples 'adds message to ticket'
it 'adds message to ticket' do
expect { described_class.new.process({}, raw_mail) }
.to change { ticket.articles.length }
end
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>)/, ticket_ref) } let(:ticket_ref) { "Foo#{Setting.get('ticket_hook')}#{Setting.get('ticket_hook_divider')}#{ticket.number}bar" }
it 'creates a separate ticket' do include_context 'ticket reference in body'
expect { described_class.new.process({}, raw_mail) } include_examples 'creates a new ticket'
.not_to change { ticket.articles.length }
end end
context 'between html tags' do
include_context 'ticket reference in body (text/html)'
include_examples 'adds message to ticket'
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="#{ticket_ref}"> </table>)) } let(:ticket_ref) { %(<table bgcolor="#{Setting.get('ticket_hook')}#{Setting.get('ticket_hook_divider')}#{ticket.number}"> </table>) }
it 'creates a separate ticket' do include_context 'ticket reference in body (text/html)'
include_examples 'creates a new ticket'
end
end
context 'when attachment contains ticket reference' do
include_context 'ticket reference in attachment'
include_examples 'creates a new ticket'
end
context 'when In-Reply-To header contains article message-id' do
include_context 'ticket reference in In-Reply-To header'
include_examples 'creates a new ticket'
context 'and Auto-Submitted header reads "auto-replied"' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
References: #{article.message_id}
Auto-Submitted: auto-replied
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
end
context 'when References header contains article message-id' do
include_context 'ticket reference in References header'
include_examples 'creates a new ticket'
end
end
context 'when configured to search attachments' do
before { Setting.set('postmaster_follow_up_search_in', 'attachment') }
context 'when subject contains ticket reference' do
include_context 'ticket reference in subject'
include_examples 'adds message to ticket'
end
context 'when body contains ticket reference' do
include_context 'ticket reference in body'
include_examples 'creates a new ticket'
end
context 'when attachment contains ticket reference' do
include_context 'ticket reference in attachment'
include_examples 'adds message to ticket'
end
context 'when In-Reply-To header contains article message-id' do
include_context 'ticket reference in In-Reply-To header'
include_examples 'creates a new ticket'
end
context 'when References header contains article message-id' do
include_context 'ticket reference in References header'
include_examples 'creates a new ticket'
context 'and Auto-Submitted header reads "auto-replied"' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
References: #{article.message_id}
Auto-Submitted: auto-replied
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
end
end
context 'when configured to search headers' do
before { Setting.set('postmaster_follow_up_search_in', 'references') }
context 'when subject contains ticket reference' do
include_context 'ticket reference in subject'
include_examples 'adds message to ticket'
end
context 'when body contains ticket reference' do
include_context 'ticket reference in body'
include_examples 'creates a new ticket'
end
context 'when attachment contains ticket reference' do
include_context 'ticket reference in attachment'
include_examples 'creates a new ticket'
end
context 'when In-Reply-To header contains article message-id' do
include_context 'ticket reference in In-Reply-To header'
include_examples 'adds message to ticket'
end
context 'when References header contains article message-id' do
include_context 'ticket reference in References header'
include_examples 'adds message to ticket'
context 'that matches two separate tickets' do
let!(:newer_ticket) { create(:ticket) }
let!(:newer_article) { create(:ticket_article, ticket: newer_ticket, message_id: article.message_id) }
it 'returns more recently created ticket' do
expect(described_class.new.process({}, raw_mail).first).to eq(newer_ticket)
end
it 'adds message to more recently created ticket' do
expect { described_class.new.process({}, raw_mail) } expect { described_class.new.process({}, raw_mail) }
.not_to change { ticket.articles.length } .to change { newer_ticket.articles.count }.by(1)
.and not_change { ticket.articles.count }
end end
end end
context 'and Auto-Submitted header reads "auto-replied"' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
References: #{article.message_id}
Auto-Submitted: auto-replied
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
end
end
context 'when configured to search everything' do
before { Setting.set('postmaster_follow_up_search_in', %w[body attachment references]) }
context 'when subject contains ticket reference' do
include_context 'ticket reference in subject'
include_examples 'adds message to ticket'
end
context 'when body contains ticket reference' do
include_context 'ticket reference in body'
include_examples 'adds message to ticket'
end
context 'when attachment contains ticket reference' do
include_context 'ticket reference in attachment'
include_examples 'adds message to ticket'
end
context 'when In-Reply-To header contains article message-id' do
include_context 'ticket reference in In-Reply-To header'
include_examples 'adds message to ticket'
end
context 'when References header contains article message-id' do
include_context 'ticket reference in References header'
include_examples 'adds message to ticket'
context 'and Auto-Submitted header reads "auto-replied"' do
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: no reference
References: #{article.message_id}
Auto-Submitted: auto-replied
Lorem ipsum dolor
RAW
include_examples 'adds message to ticket'
end
end
end
end
context 'for a closed ticket' do
let(:ticket) { create(:ticket, state_name: 'closed') }
let(:raw_mail) { <<~RAW.chomp }
From: me@example.com
To: customer@example.com
Subject: #{ticket_ref}
Lorem ipsum dolor
RAW
it 'reopens it' do
expect { described_class.new.process({}, raw_mail) }
.to change { ticket.reload.state.name }.to('open')
end end
end end
end end

View file

@ -255,11 +255,94 @@ RSpec.describe Ticket, type: :model do
end end
end end
end end
describe '#subject_build' do
context 'with default "ticket_hook_position" setting ("right")' do
it 'returns the given string followed by a ticket reference (of the form "[Ticket#123]")' do
expect(ticket.subject_build('foo'))
.to eq("foo [Ticket##{ticket.number}]")
end
context 'and a non-default value for the "ticket_hook" setting' do
before { Setting.set('ticket_hook', 'bar baz') }
it 'replaces "Ticket#" with the new ticket hook' do
expect(ticket.subject_build('foo'))
.to eq("foo [bar baz#{ticket.number}]")
end
end
context 'and a non-default value for the "ticket_hook_divider" setting' do
before { Setting.set('ticket_hook_divider', ': ') }
it 'inserts the new ticket hook divider between "Ticket#" and the ticket number' do
expect(ticket.subject_build('foo'))
.to eq("foo [Ticket#: #{ticket.number}]")
end
end
context 'when the given string already contains a ticket reference, but in the wrong place' do
it 'moves the ticket reference to the end' do
expect(ticket.subject_build("[Ticket##{ticket.number}] foo"))
.to eq("foo [Ticket##{ticket.number}]")
end
end
context 'when the given string already contains an alternately formatted ticket reference' do
it 'reformats the ticket reference' do
expect(ticket.subject_build("foo [Ticket#: #{ticket.number}]"))
.to eq("foo [Ticket##{ticket.number}]")
end
end
end
context 'with alternate "ticket_hook_position" setting ("left")' do
before { Setting.set('ticket_hook_position', 'left') }
it 'returns a ticket reference (of the form "[Ticket#123]") followed by the given string' do
expect(ticket.subject_build('foo'))
.to eq("[Ticket##{ticket.number}] foo")
end
context 'and a non-default value for the "ticket_hook" setting' do
before { Setting.set('ticket_hook', 'bar baz') }
it 'replaces "Ticket#" with the new ticket hook' do
expect(ticket.subject_build('foo'))
.to eq("[bar baz#{ticket.number}] foo")
end
end
context 'and a non-default value for the "ticket_hook_divider" setting' do
before { Setting.set('ticket_hook_divider', ': ') }
it 'inserts the new ticket hook divider between "Ticket#" and the ticket number' do
expect(ticket.subject_build('foo'))
.to eq("[Ticket#: #{ticket.number}] foo")
end
end
context 'when the given string already contains a ticket reference, but in the wrong place' do
it 'moves the ticket reference to the start' do
expect(ticket.subject_build("foo [Ticket##{ticket.number}]"))
.to eq("[Ticket##{ticket.number}] foo")
end
end
context 'when the given string already contains an alternately formatted ticket reference' do
it 'reformats the ticket reference' do
expect(ticket.subject_build("[Ticket#: #{ticket.number}] foo"))
.to eq("[Ticket##{ticket.number}] foo")
end
end
end
end
end end
describe 'Attributes:' do describe 'Attributes:' do
describe '#owner' do describe '#owner' do
let(:original_owner) { create(:agent_user, groups: [ticket.group]) } let(:original_owner) { create(:agent_user, groups: [ticket.group]) }
before { ticket.update(owner: original_owner) } before { ticket.update(owner: original_owner) }
context 'when assigned directly' do context 'when assigned directly' do

View file

@ -1,546 +0,0 @@
require 'test_helper'
class EmailProcessFollowUpTest < ActiveSupport::TestCase
test 'process with follow up check' do
ticket = Ticket.create(
title: 'follow up 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: 'follow up check',
message_id: '<20150830145601.30.608882@edenhofer.zammad.com>',
body: 'some message article',
internal: false,
sender: Ticket::Article::Sender.lookup(name: 'Agent'),
type: Ticket::Article::Type.lookup(name: 'email'),
updated_by_id: 1,
created_by_id: 1,
)
email_raw_string_subject = "From: me@example.com
To: customer@example.com
Subject: #{ticket.subject_build('some new subject')}
Some Text"
email_raw_string_other_subject = "From: me@example.com
To: customer@example.com
Subject: other subject #{Setting.get('ticket_hook')}#{ticket.number}
Some Text"
email_raw_string_body = "From: me@example.com
To: customer@example.com
Subject: no reference
Some Text #{ticket.subject_build('some new subject')} "
email_raw_string_attachment = "From: me@example.com
Content-Type: multipart/mixed; boundary=\"Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2\"
Subject: no reference
Date: Sun, 30 Aug 2015 23:20:54 +0200
To: Martin Edenhofer <me@znuny.com>
Mime-Version: 1.0 (Mac OS X Mail 8.2 \(2104\))
X-Mailer: Apple Mail (2.2104)
--Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2
Content-Transfer-Encoding: 7bit
Content-Type: text/plain;
charset=us-ascii
no reference
--Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2
Content-Disposition: attachment;
filename=test1.txt
Content-Type: text/plain;
name=\"test.txt\"
Content-Transfer-Encoding: 7bit
Some Text #{ticket.subject_build('some new subject')}
--Apple-Mail=_ED77AC8D-FB6F-40E5-8FBE-D41FF5E1BAF2--"
email_raw_string_references1 = "From: me@example.com
To: customer@example.com
Subject: no reference
In-Reply-To: <20150830145601.30.608882@edenhofer.zammad.com>
References: <DA918CD1-BE9A-4262-ACF6-5001E59291B6@znuny.com>
no reference "
email_raw_string_references2 = "From: me@example.com
To: customer@example.com
Subject: no reference
References: <DA918CD1-BE9A-4262-ACF6-5001E59291B6@znuny.com> <20150830145601.30.608882@edenhofer.zammad.com> <DA918CD1-BE9A-4262-ACF6-5001E59291XX@znuny.com>
no reference "
setting_orig = Setting.get('postmaster_follow_up_search_in')
Setting.set('postmaster_follow_up_search_in', %w[body attachment references])
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_other_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
assert_equal(ticket.id, ticket_p.id)
Setting.set('postmaster_follow_up_search_in', nil)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_other_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
assert_not_equal(ticket.id, ticket_p.id)
Setting.set('postmaster_follow_up_search_in', 'references')
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_other_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
assert_equal(ticket.id, ticket_p.id)
Setting.set('postmaster_follow_up_search_in', setting_orig)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_other_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
assert_not_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
assert_not_equal(ticket.id, ticket_p.id)
travel_back
end
test 'process with follow up check with different ticket hook' do
Setting.set('ticket_hook', 'VD-Ticket#')
ticket = Ticket.create(
title: 'follow up check ticket hook',
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: 'follow up check',
message_id: '<20150830145601.30.608882.123123@edenhofer.zammad.com>',
body: 'some message article',
internal: false,
sender: Ticket::Article::Sender.lookup(name: 'Agent'),
type: Ticket::Article::Type.lookup(name: 'email'),
updated_by_id: 1,
created_by_id: 1,
)
email_raw_string_subject = "From: me@example.com
To: customer@example.com
Subject: #{ticket.subject_build('some new subject')}
Some Text"
email_raw_string_other_subject = "From: me@example.com
To: customer@example.com
Subject: Aw: RE: other subject [#{Setting.get('ticket_hook')}#{ticket.number}]
Some Text"
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
assert_equal(ticket.id, ticket_p.id)
travel 1.second
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_other_subject)
assert_equal(ticket.id, ticket_p.id)
travel_back
end
test 'process with follow up check with two external reference headers' do
Setting.set('postmaster_follow_up_search_in', %w[body attachment references])
data1 = "From: me@example.com
To: z@example.com
Subject: test 123
Message-ID: <9d16181c-2db2-c6c1-ff7f-41f2da4e289a@linuxhotel.de>
test 123
"
ticket_p1, article_p1, user_p1 = Channel::EmailParser.new.process({}, data1)
travel 1.second
data1 = "From: me@example.com
To: z@example.com
Subject: test 123
Message-ID: <9d16181c-2db2-c6c1-ff7f-41f2da4e289a@linuxhotel.de>
test 123
"
ticket_p2, article_p2, user_p2 = Channel::EmailParser.new.process({}, data1)
assert_not_equal(ticket_p1.id, ticket_p2.id)
data2 = "From: you@example.com
To: y@example.com
Subject: RE: test 123
Message-ID: <oknn9teOke2uqbFQdGj2umXUwTkqgu0CqWHkA6V4K8p@akmail>
References: <9d16181c-2db2-c6c1-ff7f-41f2da4e289a@linuxhotel.de>
test 123
"
ticket_p3, article_p3, user_p3 = Channel::EmailParser.new.process({}, data2)
assert_equal(ticket_p2.id, ticket_p3.id)
travel_back
end
test 'process with follow up check - with auto responses and no T# in subject_build' do
ticket = Ticket.create(
title: 'follow up - with references follow up check',
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: 'follow up with references follow up check',
message_id: '<20151222145601.30.608881@edenhofer.zammad.com>',
body: 'some message with references follow up 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
# auto response without T# in subject, find follow up by references header
email_raw_string = "From: bob@example.com
To: customer@example.com
Subject: =?ISO-8859-1?Q?AUTO=3A_Bob_Smith_ist_au=DFer_Haus=2E_=2F_is_out_of?=
=?ISO-8859-1?Q?_office=2E_=28R=FCckkehr_am_28=2E12=2E2015=29?=
In-Reply-To: <20251222081758.116249.983698@portal.znuny.com>
References: <OF9D1FD72A.878EF84E-ONC1257F22.003D7BB4-C1257F22.003F4503@example.com> <20151222145601.30.608881@edenhofer.zammad.com> <20251222081758.116249.983698@portal.znuny.com>
Message-ID: <OFD563742F.FC05EEAF-ONC1257F23.002DAE02@example.com>
Auto-Submitted: auto-replied
Some Text"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket = Ticket.find(ticket.id)
assert_equal(ticket.id, ticket_p.id)
assert_equal('open', ticket.state.name)
travel_back
end
test 'process with follow up check - email with more forgein T#\'s in subject' do
ticket = Ticket.create(
title: 'email with more forgein T#\'s in subject',
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: 'follow up with references follow up check',
message_id: '<20151222145601.30.608881@edenhofer.zammad.com>',
body: 'some message with references follow up 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
system_id = Setting.get('system_id')
ticket_hook = Setting.get('ticket_hook')
ticket_hook_divider = Setting.get('ticket_hook_divider')
tn = "[#{ticket_hook}#{ticket_hook_divider}#{system_id}#{Ticket::Number.generate}99]"
email_raw_string_subject = "From: me@example.com
To: customer@example.com
Subject: First foreign Tn #{tn} #{tn} #{tn} - #{ticket.subject_build('some new subject')}
Some Text"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string_subject)
ticket = Ticket.find(ticket.id)
assert_equal(ticket.id, ticket_p.id)
assert_equal('open', ticket.state.name)
travel_back
end
test 'process with follow up check - ticket initiated by customer without T# in subject and other people in Cc reply to all' do
# check if follow up based on inital system sender address
Setting.set('postmaster_follow_up_search_in', [])
subject = "ticket initiated by customer without T# in subject and other people in Cc reply to all #{rand(9999)}"
email_raw_string = "From: me@example.com
To: my@system.test, bob@example.com
Subject: #{subject}
Message-ID: <123456789-$follow-up-test§-1@linuxhotel.de>
Some Text"
ticket_p1, article_1, user_1, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket1 = Ticket.find(ticket_p1.id)
assert_equal(subject, ticket1.title)
# follow up possible because same subject
email_raw_string = "From: bob@example.com
To: my@system.test, me@example.com
Subject: AW: #{subject}
Message-ID: <123456789-$follow-up-test§-2@linuxhotel.de>
References: <123456789-$follow-up-test§-1@linuxhotel.de>
Some Text"
ticket_p2, article_p2, user_p2, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket2 = Ticket.find(ticket_p2.id)
assert_equal(ticket1.id, ticket2.id)
assert_equal(subject, ticket2.title)
# follow up possible because same subject
email_raw_string = "From: bob@example.com
To: my@system.test, me@example.com
Subject: AW: RE: #{subject}
Message-ID: <123456789-$follow-up-test§-2@linuxhotel.de>
References: <123456789-$follow-up-test§-1@linuxhotel.de>
Some Text"
ticket_p3, article_p3, user_p3, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket3 = Ticket.find(ticket_p3.id)
assert_equal(ticket1.id, ticket3.id)
assert_equal(subject, ticket3.title)
# follow up not possible because subject has changed
subject = "new subject without ticket ref #{rand(9_999_999)}"
email_raw_string = "From: bob@example.com
To: my@system.test
Subject: #{subject}
Message-ID: <123456789-$follow-up-test§-3@linuxhotel.de>
References: <123456789-$follow-up-test§-1@linuxhotel.de>
Some Text"
ticket_p4, article_p4, user_p4, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket4 = Ticket.find(ticket_p4.id)
assert_not_equal(ticket1.id, ticket4.id)
assert_equal(subject, ticket4.title)
# usecase with same subject but no Ticket# (reference headers check because of same subject)
subject = 'Embedded Linux 20.03 - 23.03.17'
email_raw_string = "From: iw@example.com
To: customer@example.com
Subject: #{subject}
Message-ID: <b1a84d36-4475-28e8-acde-5c18ebe94182@example.com>
Some Text"
ticket_p5, article_5, user_5, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket5 = Ticket.find(ticket_p5.id)
assert_not_equal(ticket1.id, ticket5.id)
assert_equal(subject, ticket5.title)
email_raw_string = "From: customer@example.com
To: iw@example.com
Subject: Re: #{subject}
Message-ID: <b1a84d36-4475-28e8-acde-5c18ebe94183@customer.example.com>
In-Reply-To: <b1a84d36-4475-28e8-acde-5c18ebe94182@example.com>
Some other Text"
ticket_p6, article_6, user_6, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket6 = Ticket.find(ticket_p6.id)
assert_equal(ticket5.id, ticket6.id)
assert_equal(subject, ticket6.title)
end
test 'process with follow up check - with none ticket# in subject' do
Setting.set('postmaster_follow_up_search_in', [])
Setting.set('ticket_hook_position', 'none')
subject = 'some title'
email_raw_string = "From: me@example.com
To: bob@example.com
Subject: #{subject}
Message-ID: <123456789-follow-up-test-ticket_hook_position-none@linuxhotel.de>
Some Text"
ticket_p1, article_1, user_1, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket1 = Ticket.find(ticket_p1.id)
assert_equal(subject, ticket1.title)
# follow up possible because same subject
subject = 'new subject lalala'
email_raw_string = "From: bob@example.com
To: me@example.com
Subject: AW: #{subject}
Message-ID: <123456789-follow-up-test-ticket_hook_position-none-2@linuxhotel.de>
References: <123456789-follow-up-test-ticket_hook_position-none@linuxhotel.de>
Some Text"
ticket_p2, article_p2, user_p2, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket2 = Ticket.find(ticket_p2.id)
assert_equal(ticket1.id, ticket2.id)
end
test 'process with follow up check - in body' do
Setting.set('postmaster_follow_up_search_in', %w[body attachment references])
Setting.set('ticket_hook', '#')
email_raw_string = "From: me@example.com
To: bob@example.com
Subject: some subject
Some Text"
ticket_p1, article_1, user_1, mail = Channel::EmailParser.new.process({}, email_raw_string)
email_raw_string = "From: me@example.com
To: bob@example.com
Subject: some subject
Some Text #{Setting.get('ticket_hook')}#{ticket_p1.number} asdasd"
ticket_p2, article_2, user_2, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal(ticket_p1.id, ticket_p2.id)
email_raw_string = "From: me@example.com
To: bob@example.com
Subject: some subject
Content-Transfer-Encoding: 7bit
Content-Type: text/html;
<b>Some Text #{Setting.get('ticket_hook')}#{ticket_p1.number}</b>
"
ticket_p3, article_3, user_3, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_equal(ticket_p1.id, ticket_p3.id)
email_raw_string = "From: me@example.com
To: bob@example.com
Subject: some subject
Content-Transfer-Encoding: 8bit
Content-Type: text/html;
<b>Some Text <span color=\"#{Setting.get('ticket_hook')}#{ticket_p1.number}\">test</span></b>
"
ticket_p4, article_4, user_4, mail = Channel::EmailParser.new.process({}, email_raw_string)
assert_not_equal(ticket_p1.id, ticket_p4.id)
end
end