3 # Redmine - project management software
4 # Copyright (C) 2006-2009 Jean-Philippe Lang
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 require File.dirname(__FILE__) + '/../test_helper'
22 class MailHandlerTest < ActiveSupport::TestCase
23 fixtures :users, :projects,
36 :custom_fields_trackers,
40 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
43 ActionMailer::Base.deliveries.clear
47 ActionMailer::Base.deliveries.clear
48 # This email contains: 'Project: onlinestore'
49 issue = submit_email('ticket_on_given_project.eml')
50 assert issue.is_a?(Issue)
51 assert !issue.new_record?
53 assert_equal 'New ticket on a given project', issue.subject
54 assert_equal User.find_by_login('jsmith'), issue.author
55 assert_equal Project.find(2), issue.project
56 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
57 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
58 assert_equal '2010-01-01', issue.start_date.to_s
59 assert_equal '2010-12-31', issue.due_date.to_s
60 assert_equal User.find_by_login('jsmith'), issue.assigned_to
61 # keywords should be removed from the email body
62 assert !issue.description.match(/^Project:/i)
63 assert !issue.description.match(/^Status:/i)
64 # Email notification should be sent
65 mail = ActionMailer::Base.deliveries.last
67 assert mail.subject.include?('New ticket on a given project')
70 def test_add_issue_with_status
71 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
72 issue = submit_email('ticket_on_given_project.eml')
73 assert issue.is_a?(Issue)
74 assert !issue.new_record?
76 assert_equal Project.find(2), issue.project
77 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
80 def test_add_issue_with_attributes_override
81 issue = submit_email('ticket_with_attributes.eml', :allow_override => 'tracker,category,priority')
82 assert issue.is_a?(Issue)
83 assert !issue.new_record?
85 assert_equal 'New ticket on a given project', issue.subject
86 assert_equal User.find_by_login('jsmith'), issue.author
87 assert_equal Project.find(2), issue.project
88 assert_equal 'Feature request', issue.tracker.to_s
89 assert_equal 'Stock management', issue.category.to_s
90 assert_equal 'Urgent', issue.priority.to_s
91 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
94 def test_add_issue_with_partial_attributes_override
95 issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker'])
96 assert issue.is_a?(Issue)
97 assert !issue.new_record?
99 assert_equal 'New ticket on a given project', issue.subject
100 assert_equal User.find_by_login('jsmith'), issue.author
101 assert_equal Project.find(2), issue.project
102 assert_equal 'Feature request', issue.tracker.to_s
103 assert_nil issue.category
104 assert_equal 'High', issue.priority.to_s
105 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
108 def test_add_issue_with_spaces_between_attribute_and_separator
109 issue = submit_email('ticket_with_spaces_between_attribute_and_separator.eml', :allow_override => 'tracker,category,priority')
110 assert issue.is_a?(Issue)
111 assert !issue.new_record?
113 assert_equal 'New ticket on a given project', issue.subject
114 assert_equal User.find_by_login('jsmith'), issue.author
115 assert_equal Project.find(2), issue.project
116 assert_equal 'Feature request', issue.tracker.to_s
117 assert_equal 'Stock management', issue.category.to_s
118 assert_equal 'Urgent', issue.priority.to_s
119 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
123 def test_add_issue_with_attachment_to_specific_project
124 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
125 assert issue.is_a?(Issue)
126 assert !issue.new_record?
128 assert_equal 'Ticket created by email with attachment', issue.subject
129 assert_equal User.find_by_login('jsmith'), issue.author
130 assert_equal Project.find(2), issue.project
131 assert_equal 'This is a new ticket with attachments', issue.description
132 # Attachment properties
133 assert_equal 1, issue.attachments.size
134 assert_equal 'Paella.jpg', issue.attachments.first.filename
135 assert_equal 'image/jpeg', issue.attachments.first.content_type
136 assert_equal 10790, issue.attachments.first.filesize
139 def test_add_issue_with_custom_fields
140 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'})
141 assert issue.is_a?(Issue)
142 assert !issue.new_record?
144 assert_equal 'New ticket with custom field values', issue.subject
145 assert_equal 'Value for a custom field', issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
146 assert !issue.description.match(/^searchable field:/i)
149 def test_add_issue_with_cc
150 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
151 assert issue.is_a?(Issue)
152 assert !issue.new_record?
154 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
155 assert_equal 1, issue.watchers.size
158 def test_add_issue_by_unknown_user
159 assert_no_difference 'User.count' do
160 assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'})
164 def test_add_issue_by_anonymous_user
165 Role.anonymous.add_permission!(:add_issues)
166 assert_no_difference 'User.count' do
167 issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
168 assert issue.is_a?(Issue)
169 assert issue.author.anonymous?
173 def test_add_issue_by_anonymous_user_with_no_from_address
174 Role.anonymous.add_permission!(:add_issues)
175 assert_no_difference 'User.count' do
176 issue = submit_email('ticket_by_empty_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
177 assert issue.is_a?(Issue)
178 assert issue.author.anonymous?
182 def test_add_issue_by_anonymous_user_on_private_project
183 Role.anonymous.add_permission!(:add_issues)
184 assert_no_difference 'User.count' do
185 assert_no_difference 'Issue.count' do
186 assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :unknown_user => 'accept')
191 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
192 assert_no_difference 'User.count' do
193 assert_difference 'Issue.count' do
194 issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :no_permission_check => '1', :unknown_user => 'accept')
195 assert issue.is_a?(Issue)
196 assert issue.author.anonymous?
197 assert !issue.project.is_public?
202 def test_add_issue_by_created_user
203 Setting.default_language = 'en'
204 assert_difference 'User.count' do
205 issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
206 assert issue.is_a?(Issue)
207 assert issue.author.active?
208 assert_equal 'john.doe@somenet.foo', issue.author.mail
209 assert_equal 'John', issue.author.firstname
210 assert_equal 'Doe', issue.author.lastname
212 # account information
213 email = ActionMailer::Base.deliveries.first
215 assert email.subject.include?('account activation')
216 login = email.body.match(/\* Login: (.*)$/)[1]
217 password = email.body.match(/\* Password: (.*)$/)[1]
218 assert_equal issue.author, User.try_to_login(login, password)
222 def test_add_issue_without_from_header
223 Role.anonymous.add_permission!(:add_issues)
224 assert_equal false, submit_email('ticket_without_from_header.eml')
227 def test_add_issue_with_japanese_keywords
228 tracker = Tracker.create!(:name => '開発')
229 Project.find(1).trackers << tracker
230 issue = submit_email('japanese_keywords_iso_2022_jp.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'tracker')
231 assert_kind_of Issue, issue
232 assert_equal tracker, issue.tracker
235 def test_should_ignore_emails_from_emission_address
236 Role.anonymous.add_permission!(:add_issues)
237 assert_no_difference 'User.count' do
238 assert_equal false, submit_email('ticket_from_emission_address.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
242 def test_add_issue_should_send_email_notification
243 ActionMailer::Base.deliveries.clear
244 # This email contains: 'Project: onlinestore'
245 issue = submit_email('ticket_on_given_project.eml')
246 assert issue.is_a?(Issue)
247 assert_equal 1, ActionMailer::Base.deliveries.size
250 def test_add_issue_note
251 journal = submit_email('ticket_reply.eml')
252 assert journal.is_a?(Journal)
253 assert_equal User.find_by_login('jsmith'), journal.user
254 assert_equal Issue.find(2), journal.journalized
255 assert_match /This is reply/, journal.notes
258 def test_add_issue_note_with_attribute_changes
259 # This email contains: 'Status: Resolved'
260 journal = submit_email('ticket_reply_with_status.eml')
261 assert journal.is_a?(Journal)
262 issue = Issue.find(journal.issue.id)
263 assert_equal User.find_by_login('jsmith'), journal.user
264 assert_equal Issue.find(2), journal.journalized
265 assert_match /This is reply/, journal.notes
266 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
267 assert_equal '2010-01-01', issue.start_date.to_s
268 assert_equal '2010-12-31', issue.due_date.to_s
269 assert_equal User.find_by_login('jsmith'), issue.assigned_to
272 def test_add_issue_note_should_send_email_notification
273 ActionMailer::Base.deliveries.clear
274 journal = submit_email('ticket_reply.eml')
275 assert journal.is_a?(Journal)
276 assert_equal 1, ActionMailer::Base.deliveries.size
279 def test_reply_to_a_message
280 m = submit_email('message_reply.eml')
281 assert m.is_a?(Message)
282 assert !m.new_record?
284 assert_equal 'Reply via email', m.subject
285 # The email replies to message #2 which is part of the thread of message #1
286 assert_equal Message.find(1), m.parent
289 def test_reply_to_a_message_by_subject
290 m = submit_email('message_reply_by_subject.eml')
291 assert m.is_a?(Message)
292 assert !m.new_record?
294 assert_equal 'Reply to the first post', m.subject
295 assert_equal Message.find(1), m.parent
298 def test_should_strip_tags_of_html_only_emails
299 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
300 assert issue.is_a?(Issue)
301 assert !issue.new_record?
303 assert_equal 'HTML email', issue.subject
304 assert_equal 'This is a html-only email.', issue.description
307 context "truncate emails based on the Setting" do
308 context "with no setting" do
310 Setting.mail_handler_body_delimiters = ''
313 should "add the entire email into the issue" do
314 issue = submit_email('ticket_on_given_project.eml')
315 assert_issue_created(issue)
316 assert issue.description.include?('---')
317 assert issue.description.include?('This paragraph is after the delimiter')
321 context "with a single string" do
323 Setting.mail_handler_body_delimiters = '---'
326 should "truncate the email at the delimiter for the issue" do
327 issue = submit_email('ticket_on_given_project.eml')
328 assert_issue_created(issue)
329 assert issue.description.include?('This paragraph is before delimiters')
330 assert issue.description.include?('--- This line starts with a delimiter')
331 assert !issue.description.match(/^---$/)
332 assert !issue.description.include?('This paragraph is after the delimiter')
336 context "with multiple strings" do
338 Setting.mail_handler_body_delimiters = "---\nBREAK"
341 should "truncate the email at the first delimiter found (BREAK)" do
342 issue = submit_email('ticket_on_given_project.eml')
343 assert_issue_created(issue)
344 assert issue.description.include?('This paragraph is before delimiters')
345 assert !issue.description.include?('BREAK')
346 assert !issue.description.include?('This paragraph is between delimiters')
347 assert !issue.description.match(/^---$/)
348 assert !issue.description.include?('This paragraph is after the delimiter')
353 def test_email_with_long_subject_line
354 issue = submit_email('ticket_with_long_subject.eml')
355 assert issue.is_a?(Issue)
356 assert_equal issue.subject, 'New ticket on a given project with a very long subject line which exceeds 255 chars and should not be ignored but chopped off. And if the subject line is still not long enough, we just add more text. And more text. Wow, this is really annoying. Especially, if you have nothing to say...'[0,255]
361 def submit_email(filename, options={})
362 raw = IO.read(File.join(FIXTURES_PATH, filename))
363 MailHandler.receive(raw, options)
366 def assert_issue_created(issue)
367 assert issue.is_a?(Issue)
368 assert !issue.new_record?