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}
it 'adds message to ticket' do Lorem ipsum dolor
expect { described_class.new.process({}, raw_mail) } RAW
.to change { ticket.articles.length }
end end
context 'and ticket is closed' do shared_context 'ticket reference in body' do
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) } 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
end end
context 'but ticket groups #follow_up_possible attribute is "new_ticket"' do shared_examples 'creates a new ticket' do
before { ticket.group.update(follow_up_possible: 'new_ticket') } 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 'and ticket is open' do context 'when not explicitly configured to search anywhere' do
it 'still adds message to ticket' do before { Setting.set('postmaster_follow_up_search_in', nil) }
expect { described_class.new.process({}, raw_mail) }
.to change { ticket.articles.length } 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
context 'and ticket is closed' do
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) }
include_examples 'adds message to ticket'
end
context 'but ticket groups #follow_up_possible attribute is "new_ticket"' do
before { ticket.group.update(follow_up_possible: 'new_ticket') }
context 'and ticket is open' do
include_examples 'adds message to ticket'
end
context 'and ticket is closed' do
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) }
include_examples 'creates a new ticket'
end
context 'and ticket is merged' do
before { ticket.update(state: Ticket::State.find_by(name: 'merged')) }
include_examples 'creates a new ticket'
end
context 'and ticket is removed' do
before { ticket.update(state: Ticket::State.find_by(name: 'removed')) }
include_examples 'creates a new ticket'
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
end end
context 'and ticket is closed' do context 'when body contains ticket reference' do
before { ticket.update(state: Ticket::State.find_by(name: 'closed')) } include_context 'ticket reference in body'
include_examples 'creates a new ticket'
end
it 'creates a new ticket' do context 'when attachment contains ticket reference' do
expect { described_class.new.process({}, raw_mail) } include_context 'ticket reference in attachment'
.to change { Ticket.count }.by(1) include_examples 'creates a new ticket'
.and not_change { ticket.articles.length } 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
end end
context 'and ticket is merged' do context 'when References header contains article message-id' do
before { ticket.update(state: Ticket::State.find_by(name: 'merged')) } include_context 'ticket reference in References header'
include_examples 'creates a new ticket'
it 'creates a new ticket' do context 'and Auto-Submitted header reads "auto-replied"' do
expect { described_class.new.process({}, raw_mail) } let(:raw_mail) { <<~RAW.chomp }
.to change { Ticket.count }.by(1) From: me@example.com
.and not_change { ticket.articles.length } 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
context 'when configured to search body' do
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 'in visible text' do
include_context 'ticket reference in body'
include_examples 'adds message to ticket'
end
context 'as part of a larger word' do
let(:ticket_ref) { "Foo#{Setting.get('ticket_hook')}#{Setting.get('ticket_hook_divider')}#{ticket.number}bar" }
include_context 'ticket reference in body'
include_examples 'creates a new ticket'
end
context 'between html tags' do
include_context 'ticket reference in body (text/html)'
include_examples 'adds message to ticket'
end
context 'in html attributes' do
let(:ticket_ref) { %(<table bgcolor="#{Setting.get('ticket_hook')}#{Setting.get('ticket_hook_divider')}#{ticket.number}"> </table>) }
include_context 'ticket reference in body (text/html)'
include_examples 'creates a new ticket'
end end
end end
context 'and ticket is removed' do context 'when attachment contains ticket reference' do
before { ticket.update(state: Ticket::State.find_by(name: 'removed')) } include_context 'ticket reference in attachment'
include_examples 'creates a new ticket'
end
it 'creates a new ticket' do context 'when In-Reply-To header contains article message-id' do
expect { described_class.new.process({}, raw_mail) } include_context 'ticket reference in In-Reply-To header'
.to change { Ticket.count }.by(1) include_examples 'creates a new ticket'
.and not_change { ticket.articles.length }
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) }
.to change { newer_ticket.articles.count }.by(1)
.and not_change { ticket.articles.count }
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
end end
end end
context 'when configured to search body' do context 'for a closed ticket' do
before { Setting.set('postmaster_follow_up_search_in', 'body') } let(:ticket) { create(:ticket, state_name: 'closed') }
context 'when body contains ticket reference' do let(:raw_mail) { <<~RAW.chomp }
context 'in visible text' do From: me@example.com
let(:raw_mail) { File.read(mail_file).sub(/Hallo =\nMartin,(?=<o:p>)/, ticket_ref) } To: customer@example.com
Subject: #{ticket_ref}
it 'adds message to ticket' do Lorem ipsum dolor
expect { described_class.new.process({}, raw_mail) } RAW
.to change { ticket.articles.length }
end
end
context 'as part of a larger word' do it 'reopens it' do
let(:raw_mail) { File.read(mail_file).sub(/(?<=Hallo) =\n(?=Martin,<o:p>)/, ticket_ref) } expect { described_class.new.process({}, raw_mail) }
.to change { ticket.reload.state.name }.to('open')
it 'creates a separate ticket' do
expect { described_class.new.process({}, raw_mail) }
.not_to change { ticket.articles.length }
end
end
context 'in html attributes' do
let(:raw_mail) { File.read(mail_file).sub(%r{<a href.*?/a>}m, %(<table bgcolor="#{ticket_ref}"> </table>)) }
it 'creates a separate ticket' do
expect { described_class.new.process({}, raw_mail) }
.not_to change { ticket.articles.length }
end
end
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