;]
[askyou.git] / test / unit / mail_handler_test.rb
blobe0ff8a2a7fb65f4597fe9d1f614135e12cab48df
1 # encoding: utf-8
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.
10
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.
15
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, 
24                    :enabled_modules,
25                    :roles,
26                    :members,
27                    :member_roles,
28                    :issues,
29                    :issue_statuses,
30                    :workflows,
31                    :trackers,
32                    :projects_trackers,
33                    :enumerations,
34                    :issue_categories,
35                    :custom_fields,
36                    :custom_fields_trackers,
37                    :boards,
38                    :messages
39   
40   FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
41   
42   def setup
43     ActionMailer::Base.deliveries.clear
44   end
45   
46   def test_add_issue
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?
52     issue.reload
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
66     assert_not_nil mail
67     assert mail.subject.include?('New ticket on a given project')
68   end
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?
75     issue.reload
76     assert_equal Project.find(2), issue.project
77     assert_equal IssueStatus.find_by_name("Resolved"), issue.status
78   end
79   
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?
84     issue.reload
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.')
92   end
93   
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?
98     issue.reload
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.')
106   end
107   
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?
112     issue.reload
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.')
120   end
122   
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?
127     issue.reload
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
137   end
138   
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?
143     issue.reload
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)
147   end
148   
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?
153     issue.reload
154     assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
155     assert_equal 1, issue.watchers.size
156   end
157   
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'})
161     end
162   end
163   
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?
170     end
171   end
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?
179     end
180   end
181   
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')
187       end
188     end
189   end
190   
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?
198       end
199     end
200   end
201   
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
211     
212       # account information
213       email = ActionMailer::Base.deliveries.first
214       assert_not_nil email
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)
219     end
220   end
221   
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')
225   end
226   
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
233   end
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')
239     end
240   end
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
248   end
249   
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
256   end
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
270   end
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
277   end
278   
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?
283     m.reload
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
287   end
288   
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?
293     m.reload
294     assert_equal 'Reply to the first post', m.subject
295     assert_equal Message.find(1), m.parent
296   end
297   
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?
302     issue.reload
303     assert_equal 'HTML email', issue.subject
304     assert_equal 'This is a html-only email.', issue.description
305   end
307   context "truncate emails based on the Setting" do
308     context "with no setting" do
309       setup do
310         Setting.mail_handler_body_delimiters = ''
311       end
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')
318       end
319     end
321     context "with a single string" do
322       setup do
323         Setting.mail_handler_body_delimiters = '---'
324       end
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')
333       end
334     end
336     context "with multiple strings" do
337       setup do
338         Setting.mail_handler_body_delimiters = "---\nBREAK"
339       end
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')
349       end
350     end
351   end
352   
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]
357   end
359   private
360   
361   def submit_email(filename, options={})
362     raw = IO.read(File.join(FIXTURES_PATH, filename))
363     MailHandler.receive(raw, options)
364   end
366   def assert_issue_created(issue)
367     assert issue.is_a?(Issue)
368     assert !issue.new_record?
369     issue.reload
370   end