Chris@0
|
1 # encoding: utf-8
|
Chris@0
|
2 #
|
Chris@0
|
3 # Redmine - project management software
|
Chris@0
|
4 # Copyright (C) 2006-2009 Jean-Philippe Lang
|
Chris@0
|
5 #
|
Chris@0
|
6 # This program is free software; you can redistribute it and/or
|
Chris@0
|
7 # modify it under the terms of the GNU General Public License
|
Chris@0
|
8 # as published by the Free Software Foundation; either version 2
|
Chris@0
|
9 # of the License, or (at your option) any later version.
|
Chris@0
|
10 #
|
Chris@0
|
11 # This program is distributed in the hope that it will be useful,
|
Chris@0
|
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
Chris@0
|
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
Chris@0
|
14 # GNU General Public License for more details.
|
Chris@0
|
15 #
|
Chris@0
|
16 # You should have received a copy of the GNU General Public License
|
Chris@0
|
17 # along with this program; if not, write to the Free Software
|
Chris@0
|
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Chris@0
|
19
|
Chris@0
|
20 require File.dirname(__FILE__) + '/../test_helper'
|
Chris@0
|
21
|
Chris@0
|
22 class MailHandlerTest < ActiveSupport::TestCase
|
Chris@0
|
23 fixtures :users, :projects,
|
Chris@0
|
24 :enabled_modules,
|
Chris@0
|
25 :roles,
|
Chris@0
|
26 :members,
|
Chris@0
|
27 :member_roles,
|
Chris@0
|
28 :issues,
|
Chris@0
|
29 :issue_statuses,
|
Chris@0
|
30 :workflows,
|
Chris@0
|
31 :trackers,
|
Chris@0
|
32 :projects_trackers,
|
Chris@0
|
33 :enumerations,
|
Chris@0
|
34 :issue_categories,
|
Chris@0
|
35 :custom_fields,
|
Chris@0
|
36 :custom_fields_trackers,
|
Chris@0
|
37 :boards,
|
Chris@0
|
38 :messages
|
Chris@0
|
39
|
Chris@0
|
40 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
|
Chris@0
|
41
|
Chris@0
|
42 def setup
|
Chris@0
|
43 ActionMailer::Base.deliveries.clear
|
Chris@0
|
44 end
|
Chris@0
|
45
|
Chris@0
|
46 def test_add_issue
|
Chris@0
|
47 ActionMailer::Base.deliveries.clear
|
Chris@0
|
48 # This email contains: 'Project: onlinestore'
|
Chris@0
|
49 issue = submit_email('ticket_on_given_project.eml')
|
Chris@0
|
50 assert issue.is_a?(Issue)
|
Chris@0
|
51 assert !issue.new_record?
|
Chris@0
|
52 issue.reload
|
Chris@0
|
53 assert_equal 'New ticket on a given project', issue.subject
|
Chris@0
|
54 assert_equal User.find_by_login('jsmith'), issue.author
|
Chris@0
|
55 assert_equal Project.find(2), issue.project
|
Chris@0
|
56 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
|
Chris@0
|
57 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
|
Chris@0
|
58 assert_equal '2010-01-01', issue.start_date.to_s
|
Chris@0
|
59 assert_equal '2010-12-31', issue.due_date.to_s
|
Chris@0
|
60 assert_equal User.find_by_login('jsmith'), issue.assigned_to
|
Chris@0
|
61 # keywords should be removed from the email body
|
Chris@0
|
62 assert !issue.description.match(/^Project:/i)
|
Chris@0
|
63 assert !issue.description.match(/^Status:/i)
|
Chris@0
|
64 # Email notification should be sent
|
Chris@0
|
65 mail = ActionMailer::Base.deliveries.last
|
Chris@0
|
66 assert_not_nil mail
|
Chris@0
|
67 assert mail.subject.include?('New ticket on a given project')
|
Chris@0
|
68 end
|
Chris@0
|
69
|
Chris@0
|
70 def test_add_issue_with_status
|
Chris@0
|
71 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
|
Chris@0
|
72 issue = submit_email('ticket_on_given_project.eml')
|
Chris@0
|
73 assert issue.is_a?(Issue)
|
Chris@0
|
74 assert !issue.new_record?
|
Chris@0
|
75 issue.reload
|
Chris@0
|
76 assert_equal Project.find(2), issue.project
|
Chris@0
|
77 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
|
Chris@0
|
78 end
|
Chris@0
|
79
|
Chris@0
|
80 def test_add_issue_with_attributes_override
|
Chris@0
|
81 issue = submit_email('ticket_with_attributes.eml', :allow_override => 'tracker,category,priority')
|
Chris@0
|
82 assert issue.is_a?(Issue)
|
Chris@0
|
83 assert !issue.new_record?
|
Chris@0
|
84 issue.reload
|
Chris@0
|
85 assert_equal 'New ticket on a given project', issue.subject
|
Chris@0
|
86 assert_equal User.find_by_login('jsmith'), issue.author
|
Chris@0
|
87 assert_equal Project.find(2), issue.project
|
Chris@0
|
88 assert_equal 'Feature request', issue.tracker.to_s
|
Chris@0
|
89 assert_equal 'Stock management', issue.category.to_s
|
Chris@0
|
90 assert_equal 'Urgent', issue.priority.to_s
|
Chris@0
|
91 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
|
Chris@0
|
92 end
|
Chris@0
|
93
|
Chris@0
|
94 def test_add_issue_with_partial_attributes_override
|
Chris@0
|
95 issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker'])
|
Chris@0
|
96 assert issue.is_a?(Issue)
|
Chris@0
|
97 assert !issue.new_record?
|
Chris@0
|
98 issue.reload
|
Chris@0
|
99 assert_equal 'New ticket on a given project', issue.subject
|
Chris@0
|
100 assert_equal User.find_by_login('jsmith'), issue.author
|
Chris@0
|
101 assert_equal Project.find(2), issue.project
|
Chris@0
|
102 assert_equal 'Feature request', issue.tracker.to_s
|
Chris@0
|
103 assert_nil issue.category
|
Chris@0
|
104 assert_equal 'High', issue.priority.to_s
|
Chris@0
|
105 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
|
Chris@0
|
106 end
|
Chris@0
|
107
|
Chris@0
|
108 def test_add_issue_with_spaces_between_attribute_and_separator
|
Chris@0
|
109 issue = submit_email('ticket_with_spaces_between_attribute_and_separator.eml', :allow_override => 'tracker,category,priority')
|
Chris@0
|
110 assert issue.is_a?(Issue)
|
Chris@0
|
111 assert !issue.new_record?
|
Chris@0
|
112 issue.reload
|
Chris@0
|
113 assert_equal 'New ticket on a given project', issue.subject
|
Chris@0
|
114 assert_equal User.find_by_login('jsmith'), issue.author
|
Chris@0
|
115 assert_equal Project.find(2), issue.project
|
Chris@0
|
116 assert_equal 'Feature request', issue.tracker.to_s
|
Chris@0
|
117 assert_equal 'Stock management', issue.category.to_s
|
Chris@0
|
118 assert_equal 'Urgent', issue.priority.to_s
|
Chris@0
|
119 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
|
Chris@0
|
120 end
|
Chris@0
|
121
|
Chris@0
|
122
|
Chris@0
|
123 def test_add_issue_with_attachment_to_specific_project
|
Chris@0
|
124 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
|
Chris@0
|
125 assert issue.is_a?(Issue)
|
Chris@0
|
126 assert !issue.new_record?
|
Chris@0
|
127 issue.reload
|
Chris@0
|
128 assert_equal 'Ticket created by email with attachment', issue.subject
|
Chris@0
|
129 assert_equal User.find_by_login('jsmith'), issue.author
|
Chris@0
|
130 assert_equal Project.find(2), issue.project
|
Chris@0
|
131 assert_equal 'This is a new ticket with attachments', issue.description
|
Chris@0
|
132 # Attachment properties
|
Chris@0
|
133 assert_equal 1, issue.attachments.size
|
Chris@0
|
134 assert_equal 'Paella.jpg', issue.attachments.first.filename
|
Chris@0
|
135 assert_equal 'image/jpeg', issue.attachments.first.content_type
|
Chris@0
|
136 assert_equal 10790, issue.attachments.first.filesize
|
Chris@0
|
137 end
|
Chris@0
|
138
|
Chris@0
|
139 def test_add_issue_with_custom_fields
|
Chris@0
|
140 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'})
|
Chris@0
|
141 assert issue.is_a?(Issue)
|
Chris@0
|
142 assert !issue.new_record?
|
Chris@0
|
143 issue.reload
|
Chris@0
|
144 assert_equal 'New ticket with custom field values', issue.subject
|
Chris@0
|
145 assert_equal 'Value for a custom field', issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
|
Chris@0
|
146 assert !issue.description.match(/^searchable field:/i)
|
Chris@0
|
147 end
|
Chris@0
|
148
|
Chris@0
|
149 def test_add_issue_with_cc
|
Chris@0
|
150 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
|
Chris@0
|
151 assert issue.is_a?(Issue)
|
Chris@0
|
152 assert !issue.new_record?
|
Chris@0
|
153 issue.reload
|
Chris@0
|
154 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
|
Chris@0
|
155 assert_equal 1, issue.watchers.size
|
Chris@0
|
156 end
|
Chris@0
|
157
|
Chris@0
|
158 def test_add_issue_by_unknown_user
|
Chris@0
|
159 assert_no_difference 'User.count' do
|
Chris@0
|
160 assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'})
|
Chris@0
|
161 end
|
Chris@0
|
162 end
|
Chris@0
|
163
|
Chris@0
|
164 def test_add_issue_by_anonymous_user
|
Chris@0
|
165 Role.anonymous.add_permission!(:add_issues)
|
Chris@0
|
166 assert_no_difference 'User.count' do
|
Chris@0
|
167 issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
|
Chris@0
|
168 assert issue.is_a?(Issue)
|
Chris@0
|
169 assert issue.author.anonymous?
|
Chris@0
|
170 end
|
Chris@0
|
171 end
|
Chris@0
|
172
|
Chris@0
|
173 def test_add_issue_by_anonymous_user_with_no_from_address
|
Chris@0
|
174 Role.anonymous.add_permission!(:add_issues)
|
Chris@0
|
175 assert_no_difference 'User.count' do
|
Chris@0
|
176 issue = submit_email('ticket_by_empty_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
|
Chris@0
|
177 assert issue.is_a?(Issue)
|
Chris@0
|
178 assert issue.author.anonymous?
|
Chris@0
|
179 end
|
Chris@0
|
180 end
|
Chris@0
|
181
|
Chris@0
|
182 def test_add_issue_by_anonymous_user_on_private_project
|
Chris@0
|
183 Role.anonymous.add_permission!(:add_issues)
|
Chris@0
|
184 assert_no_difference 'User.count' do
|
Chris@0
|
185 assert_no_difference 'Issue.count' do
|
Chris@0
|
186 assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :unknown_user => 'accept')
|
Chris@0
|
187 end
|
Chris@0
|
188 end
|
Chris@0
|
189 end
|
Chris@0
|
190
|
Chris@0
|
191 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
|
Chris@0
|
192 assert_no_difference 'User.count' do
|
Chris@0
|
193 assert_difference 'Issue.count' do
|
Chris@0
|
194 issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :no_permission_check => '1', :unknown_user => 'accept')
|
Chris@0
|
195 assert issue.is_a?(Issue)
|
Chris@0
|
196 assert issue.author.anonymous?
|
Chris@0
|
197 assert !issue.project.is_public?
|
Chris@0
|
198 end
|
Chris@0
|
199 end
|
Chris@0
|
200 end
|
Chris@0
|
201
|
Chris@0
|
202 def test_add_issue_by_created_user
|
Chris@0
|
203 Setting.default_language = 'en'
|
Chris@0
|
204 assert_difference 'User.count' do
|
Chris@0
|
205 issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
|
Chris@0
|
206 assert issue.is_a?(Issue)
|
Chris@0
|
207 assert issue.author.active?
|
Chris@0
|
208 assert_equal 'john.doe@somenet.foo', issue.author.mail
|
Chris@0
|
209 assert_equal 'John', issue.author.firstname
|
Chris@0
|
210 assert_equal 'Doe', issue.author.lastname
|
Chris@0
|
211
|
Chris@0
|
212 # account information
|
Chris@0
|
213 email = ActionMailer::Base.deliveries.first
|
Chris@0
|
214 assert_not_nil email
|
Chris@0
|
215 assert email.subject.include?('account activation')
|
Chris@0
|
216 login = email.body.match(/\* Login: (.*)$/)[1]
|
Chris@0
|
217 password = email.body.match(/\* Password: (.*)$/)[1]
|
Chris@0
|
218 assert_equal issue.author, User.try_to_login(login, password)
|
Chris@0
|
219 end
|
Chris@0
|
220 end
|
Chris@0
|
221
|
Chris@0
|
222 def test_add_issue_without_from_header
|
Chris@0
|
223 Role.anonymous.add_permission!(:add_issues)
|
Chris@0
|
224 assert_equal false, submit_email('ticket_without_from_header.eml')
|
Chris@0
|
225 end
|
Chris@0
|
226
|
Chris@0
|
227 def test_add_issue_with_japanese_keywords
|
Chris@0
|
228 tracker = Tracker.create!(:name => '開発')
|
Chris@0
|
229 Project.find(1).trackers << tracker
|
Chris@0
|
230 issue = submit_email('japanese_keywords_iso_2022_jp.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'tracker')
|
Chris@0
|
231 assert_kind_of Issue, issue
|
Chris@0
|
232 assert_equal tracker, issue.tracker
|
Chris@0
|
233 end
|
Chris@0
|
234
|
Chris@0
|
235 def test_should_ignore_emails_from_emission_address
|
Chris@0
|
236 Role.anonymous.add_permission!(:add_issues)
|
Chris@0
|
237 assert_no_difference 'User.count' do
|
Chris@0
|
238 assert_equal false, submit_email('ticket_from_emission_address.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
|
Chris@0
|
239 end
|
Chris@0
|
240 end
|
Chris@0
|
241
|
Chris@0
|
242 def test_add_issue_should_send_email_notification
|
Chris@0
|
243 ActionMailer::Base.deliveries.clear
|
Chris@0
|
244 # This email contains: 'Project: onlinestore'
|
Chris@0
|
245 issue = submit_email('ticket_on_given_project.eml')
|
Chris@0
|
246 assert issue.is_a?(Issue)
|
Chris@0
|
247 assert_equal 1, ActionMailer::Base.deliveries.size
|
Chris@0
|
248 end
|
Chris@0
|
249
|
Chris@0
|
250 def test_add_issue_note
|
Chris@0
|
251 journal = submit_email('ticket_reply.eml')
|
Chris@0
|
252 assert journal.is_a?(Journal)
|
Chris@0
|
253 assert_equal User.find_by_login('jsmith'), journal.user
|
Chris@0
|
254 assert_equal Issue.find(2), journal.journalized
|
Chris@0
|
255 assert_match /This is reply/, journal.notes
|
Chris@0
|
256 end
|
Chris@0
|
257
|
Chris@0
|
258 def test_add_issue_note_with_attribute_changes
|
Chris@0
|
259 # This email contains: 'Status: Resolved'
|
Chris@0
|
260 journal = submit_email('ticket_reply_with_status.eml')
|
Chris@0
|
261 assert journal.is_a?(Journal)
|
Chris@0
|
262 issue = Issue.find(journal.issue.id)
|
Chris@0
|
263 assert_equal User.find_by_login('jsmith'), journal.user
|
Chris@0
|
264 assert_equal Issue.find(2), journal.journalized
|
Chris@0
|
265 assert_match /This is reply/, journal.notes
|
Chris@0
|
266 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
|
Chris@0
|
267 assert_equal '2010-01-01', issue.start_date.to_s
|
Chris@0
|
268 assert_equal '2010-12-31', issue.due_date.to_s
|
Chris@0
|
269 assert_equal User.find_by_login('jsmith'), issue.assigned_to
|
Chris@0
|
270 end
|
Chris@0
|
271
|
Chris@0
|
272 def test_add_issue_note_should_send_email_notification
|
Chris@0
|
273 ActionMailer::Base.deliveries.clear
|
Chris@0
|
274 journal = submit_email('ticket_reply.eml')
|
Chris@0
|
275 assert journal.is_a?(Journal)
|
Chris@0
|
276 assert_equal 1, ActionMailer::Base.deliveries.size
|
Chris@0
|
277 end
|
Chris@0
|
278
|
Chris@0
|
279 def test_reply_to_a_message
|
Chris@0
|
280 m = submit_email('message_reply.eml')
|
Chris@0
|
281 assert m.is_a?(Message)
|
Chris@0
|
282 assert !m.new_record?
|
Chris@0
|
283 m.reload
|
Chris@0
|
284 assert_equal 'Reply via email', m.subject
|
Chris@0
|
285 # The email replies to message #2 which is part of the thread of message #1
|
Chris@0
|
286 assert_equal Message.find(1), m.parent
|
Chris@0
|
287 end
|
Chris@0
|
288
|
Chris@0
|
289 def test_reply_to_a_message_by_subject
|
Chris@0
|
290 m = submit_email('message_reply_by_subject.eml')
|
Chris@0
|
291 assert m.is_a?(Message)
|
Chris@0
|
292 assert !m.new_record?
|
Chris@0
|
293 m.reload
|
Chris@0
|
294 assert_equal 'Reply to the first post', m.subject
|
Chris@0
|
295 assert_equal Message.find(1), m.parent
|
Chris@0
|
296 end
|
Chris@0
|
297
|
Chris@0
|
298 def test_should_strip_tags_of_html_only_emails
|
Chris@0
|
299 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
|
Chris@0
|
300 assert issue.is_a?(Issue)
|
Chris@0
|
301 assert !issue.new_record?
|
Chris@0
|
302 issue.reload
|
Chris@0
|
303 assert_equal 'HTML email', issue.subject
|
Chris@0
|
304 assert_equal 'This is a html-only email.', issue.description
|
Chris@0
|
305 end
|
Chris@0
|
306
|
Chris@0
|
307 context "truncate emails based on the Setting" do
|
Chris@0
|
308 context "with no setting" do
|
Chris@0
|
309 setup do
|
Chris@0
|
310 Setting.mail_handler_body_delimiters = ''
|
Chris@0
|
311 end
|
Chris@0
|
312
|
Chris@0
|
313 should "add the entire email into the issue" do
|
Chris@0
|
314 issue = submit_email('ticket_on_given_project.eml')
|
Chris@0
|
315 assert_issue_created(issue)
|
Chris@0
|
316 assert issue.description.include?('---')
|
Chris@0
|
317 assert issue.description.include?('This paragraph is after the delimiter')
|
Chris@0
|
318 end
|
Chris@0
|
319 end
|
Chris@0
|
320
|
Chris@0
|
321 context "with a single string" do
|
Chris@0
|
322 setup do
|
Chris@0
|
323 Setting.mail_handler_body_delimiters = '---'
|
Chris@0
|
324 end
|
Chris@0
|
325
|
Chris@0
|
326 should "truncate the email at the delimiter for the issue" do
|
Chris@0
|
327 issue = submit_email('ticket_on_given_project.eml')
|
Chris@0
|
328 assert_issue_created(issue)
|
Chris@0
|
329 assert issue.description.include?('This paragraph is before delimiters')
|
Chris@0
|
330 assert issue.description.include?('--- This line starts with a delimiter')
|
Chris@0
|
331 assert !issue.description.match(/^---$/)
|
Chris@0
|
332 assert !issue.description.include?('This paragraph is after the delimiter')
|
Chris@0
|
333 end
|
Chris@0
|
334 end
|
Chris@0
|
335
|
Chris@0
|
336 context "with multiple strings" do
|
Chris@0
|
337 setup do
|
Chris@0
|
338 Setting.mail_handler_body_delimiters = "---\nBREAK"
|
Chris@0
|
339 end
|
Chris@0
|
340
|
Chris@0
|
341 should "truncate the email at the first delimiter found (BREAK)" do
|
Chris@0
|
342 issue = submit_email('ticket_on_given_project.eml')
|
Chris@0
|
343 assert_issue_created(issue)
|
Chris@0
|
344 assert issue.description.include?('This paragraph is before delimiters')
|
Chris@0
|
345 assert !issue.description.include?('BREAK')
|
Chris@0
|
346 assert !issue.description.include?('This paragraph is between delimiters')
|
Chris@0
|
347 assert !issue.description.match(/^---$/)
|
Chris@0
|
348 assert !issue.description.include?('This paragraph is after the delimiter')
|
Chris@0
|
349 end
|
Chris@0
|
350 end
|
Chris@0
|
351 end
|
Chris@0
|
352
|
Chris@0
|
353 def test_email_with_long_subject_line
|
Chris@0
|
354 issue = submit_email('ticket_with_long_subject.eml')
|
Chris@0
|
355 assert issue.is_a?(Issue)
|
Chris@0
|
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]
|
Chris@0
|
357 end
|
Chris@0
|
358
|
Chris@0
|
359 private
|
Chris@0
|
360
|
Chris@0
|
361 def submit_email(filename, options={})
|
Chris@0
|
362 raw = IO.read(File.join(FIXTURES_PATH, filename))
|
Chris@0
|
363 MailHandler.receive(raw, options)
|
Chris@0
|
364 end
|
Chris@0
|
365
|
Chris@0
|
366 def assert_issue_created(issue)
|
Chris@0
|
367 assert issue.is_a?(Issue)
|
Chris@0
|
368 assert !issue.new_record?
|
Chris@0
|
369 issue.reload
|
Chris@0
|
370 end
|
Chris@0
|
371 end
|