comparison .svn/pristine/b7/b746a08ee53393dfd229ea75565890e993730d12.svn-base @ 1517:dffacf8a6908 redmine-2.5

Update to Redmine SVN revision 13367 on 2.5-stable branch
author Chris Cannam
date Tue, 09 Sep 2014 09:29:00 +0100
parents
children
comparison
equal deleted inserted replaced
1516:b450a9d58aed 1517:dffacf8a6908
1 # encoding: utf-8
2 #
3 # Redmine - project management software
4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 #
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.
19
20 require File.expand_path('../../test_helper', __FILE__)
21
22 class MailHandlerTest < ActiveSupport::TestCase
23 fixtures :users, :projects, :enabled_modules, :roles,
24 :members, :member_roles, :users,
25 :issues, :issue_statuses,
26 :workflows, :trackers, :projects_trackers,
27 :versions, :enumerations, :issue_categories,
28 :custom_fields, :custom_fields_trackers, :custom_fields_projects,
29 :boards, :messages
30
31 FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
32
33 def setup
34 ActionMailer::Base.deliveries.clear
35 Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
36 end
37
38 def teardown
39 Setting.clear_cache
40 end
41
42 def test_add_issue
43 ActionMailer::Base.deliveries.clear
44 lft1 = new_issue_lft
45 # This email contains: 'Project: onlinestore'
46 issue = submit_email('ticket_on_given_project.eml')
47 assert issue.is_a?(Issue)
48 assert !issue.new_record?
49 issue.reload
50 assert_equal Project.find(2), issue.project
51 assert_equal issue.project.trackers.first, issue.tracker
52 assert_equal 'New ticket on a given project', issue.subject
53 assert_equal User.find_by_login('jsmith'), issue.author
54 assert_equal IssueStatus.find_by_name('Resolved'), issue.status
55 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
56 assert_equal '2010-01-01', issue.start_date.to_s
57 assert_equal '2010-12-31', issue.due_date.to_s
58 assert_equal User.find_by_login('jsmith'), issue.assigned_to
59 assert_equal Version.find_by_name('Alpha'), issue.fixed_version
60 assert_equal 2.5, issue.estimated_hours
61 assert_equal 30, issue.done_ratio
62 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
63 # keywords should be removed from the email body
64 assert !issue.description.match(/^Project:/i)
65 assert !issue.description.match(/^Status:/i)
66 assert !issue.description.match(/^Start Date:/i)
67 # Email notification should be sent
68 mail = ActionMailer::Base.deliveries.last
69 assert_not_nil mail
70 assert mail.subject.include?('New ticket on a given project')
71 end
72
73 def test_add_issue_with_default_tracker
74 # This email contains: 'Project: onlinestore'
75 issue = submit_email(
76 'ticket_on_given_project.eml',
77 :issue => {:tracker => 'Support request'}
78 )
79 assert issue.is_a?(Issue)
80 assert !issue.new_record?
81 issue.reload
82 assert_equal 'Support request', issue.tracker.name
83 end
84
85 def test_add_issue_with_status
86 # This email contains: 'Project: onlinestore' and 'Status: Resolved'
87 issue = submit_email('ticket_on_given_project.eml')
88 assert issue.is_a?(Issue)
89 assert !issue.new_record?
90 issue.reload
91 assert_equal Project.find(2), issue.project
92 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
93 end
94
95 def test_add_issue_with_attributes_override
96 issue = submit_email(
97 'ticket_with_attributes.eml',
98 :allow_override => 'tracker,category,priority'
99 )
100 assert issue.is_a?(Issue)
101 assert !issue.new_record?
102 issue.reload
103 assert_equal 'New ticket on a given project', issue.subject
104 assert_equal User.find_by_login('jsmith'), issue.author
105 assert_equal Project.find(2), issue.project
106 assert_equal 'Feature request', issue.tracker.to_s
107 assert_equal 'Stock management', issue.category.to_s
108 assert_equal 'Urgent', issue.priority.to_s
109 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
110 end
111
112 def test_add_issue_with_group_assignment
113 with_settings :issue_group_assignment => '1' do
114 issue = submit_email('ticket_on_given_project.eml') do |email|
115 email.gsub!('Assigned to: John Smith', 'Assigned to: B Team')
116 end
117 assert issue.is_a?(Issue)
118 assert !issue.new_record?
119 issue.reload
120 assert_equal Group.find(11), issue.assigned_to
121 end
122 end
123
124 def test_add_issue_with_partial_attributes_override
125 issue = submit_email(
126 'ticket_with_attributes.eml',
127 :issue => {:priority => 'High'},
128 :allow_override => ['tracker']
129 )
130 assert issue.is_a?(Issue)
131 assert !issue.new_record?
132 issue.reload
133 assert_equal 'New ticket on a given project', issue.subject
134 assert_equal User.find_by_login('jsmith'), issue.author
135 assert_equal Project.find(2), issue.project
136 assert_equal 'Feature request', issue.tracker.to_s
137 assert_nil issue.category
138 assert_equal 'High', issue.priority.to_s
139 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
140 end
141
142 def test_add_issue_with_spaces_between_attribute_and_separator
143 issue = submit_email(
144 'ticket_with_spaces_between_attribute_and_separator.eml',
145 :allow_override => 'tracker,category,priority'
146 )
147 assert issue.is_a?(Issue)
148 assert !issue.new_record?
149 issue.reload
150 assert_equal 'New ticket on a given project', issue.subject
151 assert_equal User.find_by_login('jsmith'), issue.author
152 assert_equal Project.find(2), issue.project
153 assert_equal 'Feature request', issue.tracker.to_s
154 assert_equal 'Stock management', issue.category.to_s
155 assert_equal 'Urgent', issue.priority.to_s
156 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
157 end
158
159 def test_add_issue_with_attachment_to_specific_project
160 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
161 assert issue.is_a?(Issue)
162 assert !issue.new_record?
163 issue.reload
164 assert_equal 'Ticket created by email with attachment', issue.subject
165 assert_equal User.find_by_login('jsmith'), issue.author
166 assert_equal Project.find(2), issue.project
167 assert_equal 'This is a new ticket with attachments', issue.description
168 # Attachment properties
169 assert_equal 1, issue.attachments.size
170 assert_equal 'Paella.jpg', issue.attachments.first.filename
171 assert_equal 'image/jpeg', issue.attachments.first.content_type
172 assert_equal 10790, issue.attachments.first.filesize
173 end
174
175 def test_add_issue_with_custom_fields
176 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'})
177 assert issue.is_a?(Issue)
178 assert !issue.new_record?
179 issue.reload
180 assert_equal 'New ticket with custom field values', issue.subject
181 assert_equal 'PostgreSQL', issue.custom_field_value(1)
182 assert_equal 'Value for a custom field', issue.custom_field_value(2)
183 assert !issue.description.match(/^searchable field:/i)
184 end
185
186 def test_add_issue_with_version_custom_fields
187 field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
188
189 issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email|
190 email << "Affected version: 1.0\n"
191 end
192 assert issue.is_a?(Issue)
193 assert !issue.new_record?
194 issue.reload
195 assert_equal '2', issue.custom_field_value(field)
196 end
197
198 def test_add_issue_should_match_assignee_on_display_name
199 user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
200 User.add_to_project(user, Project.find(2))
201 issue = submit_email('ticket_on_given_project.eml') do |email|
202 email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
203 end
204 assert issue.is_a?(Issue)
205 assert_equal user, issue.assigned_to
206 end
207
208 def test_add_issue_should_set_default_start_date
209 with_settings :default_issue_start_date_to_creation_date => '1' do
210 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
211 assert issue.is_a?(Issue)
212 assert_equal Date.today, issue.start_date
213 end
214 end
215
216 def test_add_issue_with_cc
217 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
218 assert issue.is_a?(Issue)
219 assert !issue.new_record?
220 issue.reload
221 assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
222 assert_equal 1, issue.watcher_user_ids.size
223 end
224
225 def test_add_issue_by_unknown_user
226 assert_no_difference 'User.count' do
227 assert_equal false,
228 submit_email(
229 'ticket_by_unknown_user.eml',
230 :issue => {:project => 'ecookbook'}
231 )
232 end
233 end
234
235 def test_add_issue_by_anonymous_user
236 Role.anonymous.add_permission!(:add_issues)
237 assert_no_difference 'User.count' do
238 issue = submit_email(
239 'ticket_by_unknown_user.eml',
240 :issue => {:project => 'ecookbook'},
241 :unknown_user => 'accept'
242 )
243 assert issue.is_a?(Issue)
244 assert issue.author.anonymous?
245 end
246 end
247
248 def test_add_issue_by_anonymous_user_with_no_from_address
249 Role.anonymous.add_permission!(:add_issues)
250 assert_no_difference 'User.count' do
251 issue = submit_email(
252 'ticket_by_empty_user.eml',
253 :issue => {:project => 'ecookbook'},
254 :unknown_user => 'accept'
255 )
256 assert issue.is_a?(Issue)
257 assert issue.author.anonymous?
258 end
259 end
260
261 def test_add_issue_by_anonymous_user_on_private_project
262 Role.anonymous.add_permission!(:add_issues)
263 assert_no_difference 'User.count' do
264 assert_no_difference 'Issue.count' do
265 assert_equal false,
266 submit_email(
267 'ticket_by_unknown_user.eml',
268 :issue => {:project => 'onlinestore'},
269 :unknown_user => 'accept'
270 )
271 end
272 end
273 end
274
275 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
276 lft1 = new_issue_lft
277 assert_no_difference 'User.count' do
278 assert_difference 'Issue.count' do
279 issue = submit_email(
280 'ticket_by_unknown_user.eml',
281 :issue => {:project => 'onlinestore'},
282 :no_permission_check => '1',
283 :unknown_user => 'accept'
284 )
285 assert issue.is_a?(Issue)
286 assert issue.author.anonymous?
287 assert !issue.project.is_public?
288 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
289 end
290 end
291 end
292
293 def test_add_issue_by_created_user
294 Setting.default_language = 'en'
295 assert_difference 'User.count' do
296 issue = submit_email(
297 'ticket_by_unknown_user.eml',
298 :issue => {:project => 'ecookbook'},
299 :unknown_user => 'create'
300 )
301 assert issue.is_a?(Issue)
302 assert issue.author.active?
303 assert_equal 'john.doe@somenet.foo', issue.author.mail
304 assert_equal 'John', issue.author.firstname
305 assert_equal 'Doe', issue.author.lastname
306
307 # account information
308 email = ActionMailer::Base.deliveries.first
309 assert_not_nil email
310 assert email.subject.include?('account activation')
311 login = mail_body(email).match(/\* Login: (.*)$/)[1].strip
312 password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
313 assert_equal issue.author, User.try_to_login(login, password)
314 end
315 end
316
317 def test_created_user_should_be_added_to_groups
318 group1 = Group.generate!
319 group2 = Group.generate!
320
321 assert_difference 'User.count' do
322 submit_email(
323 'ticket_by_unknown_user.eml',
324 :issue => {:project => 'ecookbook'},
325 :unknown_user => 'create',
326 :default_group => "#{group1.name},#{group2.name}"
327 )
328 end
329 user = User.order('id DESC').first
330 assert_same_elements [group1, group2], user.groups
331 end
332
333 def test_created_user_should_not_receive_account_information_with_no_account_info_option
334 assert_difference 'User.count' do
335 submit_email(
336 'ticket_by_unknown_user.eml',
337 :issue => {:project => 'ecookbook'},
338 :unknown_user => 'create',
339 :no_account_notice => '1'
340 )
341 end
342
343 # only 1 email for the new issue notification
344 assert_equal 1, ActionMailer::Base.deliveries.size
345 email = ActionMailer::Base.deliveries.first
346 assert_include 'Ticket by unknown user', email.subject
347 end
348
349 def test_created_user_should_have_mail_notification_to_none_with_no_notification_option
350 assert_difference 'User.count' do
351 submit_email(
352 'ticket_by_unknown_user.eml',
353 :issue => {:project => 'ecookbook'},
354 :unknown_user => 'create',
355 :no_notification => '1'
356 )
357 end
358 user = User.order('id DESC').first
359 assert_equal 'none', user.mail_notification
360 end
361
362 def test_add_issue_without_from_header
363 Role.anonymous.add_permission!(:add_issues)
364 assert_equal false, submit_email('ticket_without_from_header.eml')
365 end
366
367 def test_add_issue_with_invalid_attributes
368 with_settings :default_issue_start_date_to_creation_date => '0' do
369 issue = submit_email(
370 'ticket_with_invalid_attributes.eml',
371 :allow_override => 'tracker,category,priority'
372 )
373 assert issue.is_a?(Issue)
374 assert !issue.new_record?
375 issue.reload
376 assert_nil issue.assigned_to
377 assert_nil issue.start_date
378 assert_nil issue.due_date
379 assert_equal 0, issue.done_ratio
380 assert_equal 'Normal', issue.priority.to_s
381 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
382 end
383 end
384
385 def test_add_issue_with_invalid_project_should_be_assigned_to_default_project
386 issue = submit_email('ticket_on_given_project.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'project') do |email|
387 email.gsub!(/^Project:.+$/, 'Project: invalid')
388 end
389 assert issue.is_a?(Issue)
390 assert !issue.new_record?
391 assert_equal 'ecookbook', issue.project.identifier
392 end
393
394 def test_add_issue_with_localized_attributes
395 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
396 issue = submit_email(
397 'ticket_with_localized_attributes.eml',
398 :allow_override => 'tracker,category,priority'
399 )
400 assert issue.is_a?(Issue)
401 assert !issue.new_record?
402 issue.reload
403 assert_equal 'New ticket on a given project', issue.subject
404 assert_equal User.find_by_login('jsmith'), issue.author
405 assert_equal Project.find(2), issue.project
406 assert_equal 'Feature request', issue.tracker.to_s
407 assert_equal 'Stock management', issue.category.to_s
408 assert_equal 'Urgent', issue.priority.to_s
409 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
410 end
411
412 def test_add_issue_with_japanese_keywords
413 ja_dev = "\xe9\x96\x8b\xe7\x99\xba"
414 ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding)
415 tracker = Tracker.create!(:name => ja_dev)
416 Project.find(1).trackers << tracker
417 issue = submit_email(
418 'japanese_keywords_iso_2022_jp.eml',
419 :issue => {:project => 'ecookbook'},
420 :allow_override => 'tracker'
421 )
422 assert_kind_of Issue, issue
423 assert_equal tracker, issue.tracker
424 end
425
426 def test_add_issue_from_apple_mail
427 issue = submit_email(
428 'apple_mail_with_attachment.eml',
429 :issue => {:project => 'ecookbook'}
430 )
431 assert_kind_of Issue, issue
432 assert_equal 1, issue.attachments.size
433
434 attachment = issue.attachments.first
435 assert_equal 'paella.jpg', attachment.filename
436 assert_equal 10790, attachment.filesize
437 assert File.exist?(attachment.diskfile)
438 assert_equal 10790, File.size(attachment.diskfile)
439 assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
440 end
441
442 def test_thunderbird_with_attachment_ja
443 issue = submit_email(
444 'thunderbird_with_attachment_ja.eml',
445 :issue => {:project => 'ecookbook'}
446 )
447 assert_kind_of Issue, issue
448 assert_equal 1, issue.attachments.size
449 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
450 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
451 attachment = issue.attachments.first
452 assert_equal ja, attachment.filename
453 assert_equal 5, attachment.filesize
454 assert File.exist?(attachment.diskfile)
455 assert_equal 5, File.size(attachment.diskfile)
456 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
457 end
458
459 def test_gmail_with_attachment_ja
460 issue = submit_email(
461 'gmail_with_attachment_ja.eml',
462 :issue => {:project => 'ecookbook'}
463 )
464 assert_kind_of Issue, issue
465 assert_equal 1, issue.attachments.size
466 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
467 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
468 attachment = issue.attachments.first
469 assert_equal ja, attachment.filename
470 assert_equal 5, attachment.filesize
471 assert File.exist?(attachment.diskfile)
472 assert_equal 5, File.size(attachment.diskfile)
473 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
474 end
475
476 def test_thunderbird_with_attachment_latin1
477 issue = submit_email(
478 'thunderbird_with_attachment_iso-8859-1.eml',
479 :issue => {:project => 'ecookbook'}
480 )
481 assert_kind_of Issue, issue
482 assert_equal 1, issue.attachments.size
483 u = ""
484 u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
485 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
486 u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
487 11.times { u << u1 }
488 attachment = issue.attachments.first
489 assert_equal "#{u}.png", attachment.filename
490 assert_equal 130, attachment.filesize
491 assert File.exist?(attachment.diskfile)
492 assert_equal 130, File.size(attachment.diskfile)
493 assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
494 end
495
496 def test_gmail_with_attachment_latin1
497 issue = submit_email(
498 'gmail_with_attachment_iso-8859-1.eml',
499 :issue => {:project => 'ecookbook'}
500 )
501 assert_kind_of Issue, issue
502 assert_equal 1, issue.attachments.size
503 u = ""
504 u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
505 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
506 u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
507 11.times { u << u1 }
508 attachment = issue.attachments.first
509 assert_equal "#{u}.txt", attachment.filename
510 assert_equal 5, attachment.filesize
511 assert File.exist?(attachment.diskfile)
512 assert_equal 5, File.size(attachment.diskfile)
513 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
514 end
515
516 def test_multiple_inline_text_parts_should_be_appended_to_issue_description
517 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
518 assert_include 'first', issue.description
519 assert_include 'second', issue.description
520 assert_include 'third', issue.description
521 end
522
523 def test_attachment_text_part_should_be_added_as_issue_attachment
524 issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
525 assert_not_include 'Plain text attachment', issue.description
526 attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'}
527 assert_not_nil attachment
528 assert_include 'Plain text attachment', File.read(attachment.diskfile)
529 end
530
531 def test_add_issue_with_iso_8859_1_subject
532 issue = submit_email(
533 'subject_as_iso-8859-1.eml',
534 :issue => {:project => 'ecookbook'}
535 )
536 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..."
537 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
538 assert_kind_of Issue, issue
539 assert_equal str, issue.subject
540 end
541
542 def test_add_issue_with_japanese_subject
543 issue = submit_email(
544 'subject_japanese_1.eml',
545 :issue => {:project => 'ecookbook'}
546 )
547 assert_kind_of Issue, issue
548 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
549 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
550 assert_equal ja, issue.subject
551 end
552
553 def test_add_issue_with_korean_body
554 # Make sure mail bodies with a charset unknown to Ruby
555 # but known to the Mail gem 2.5.4 are handled correctly
556 kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4."
557 if !kr.respond_to?(:force_encoding)
558 puts "\nOn Ruby 1.8, skip Korean encoding mail body test"
559 else
560 kr.force_encoding('UTF-8')
561 issue = submit_email(
562 'body_ks_c_5601-1987.eml',
563 :issue => {:project => 'ecookbook'}
564 )
565 assert_kind_of Issue, issue
566 assert_equal kr, issue.description
567 end
568 end
569
570 def test_add_issue_with_no_subject_header
571 issue = submit_email(
572 'no_subject_header.eml',
573 :issue => {:project => 'ecookbook'}
574 )
575 assert_kind_of Issue, issue
576 assert_equal '(no subject)', issue.subject
577 end
578
579 def test_add_issue_with_mixed_japanese_subject
580 issue = submit_email(
581 'subject_japanese_2.eml',
582 :issue => {:project => 'ecookbook'}
583 )
584 assert_kind_of Issue, issue
585 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
586 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
587 assert_equal ja, issue.subject
588 end
589
590 def test_should_ignore_emails_from_locked_users
591 User.find(2).lock!
592
593 MailHandler.any_instance.expects(:dispatch).never
594 assert_no_difference 'Issue.count' do
595 assert_equal false, submit_email('ticket_on_given_project.eml')
596 end
597 end
598
599 def test_should_ignore_emails_from_emission_address
600 Role.anonymous.add_permission!(:add_issues)
601 assert_no_difference 'User.count' do
602 assert_equal false,
603 submit_email(
604 'ticket_from_emission_address.eml',
605 :issue => {:project => 'ecookbook'},
606 :unknown_user => 'create'
607 )
608 end
609 end
610
611 def test_should_ignore_auto_replied_emails
612 MailHandler.any_instance.expects(:dispatch).never
613 [
614 "X-Auto-Response-Suppress: OOF",
615 "Auto-Submitted: auto-replied",
616 "Auto-Submitted: Auto-Replied",
617 "Auto-Submitted: auto-generated"
618 ].each do |header|
619 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
620 raw = header + "\n" + raw
621
622 assert_no_difference 'Issue.count' do
623 assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
624 end
625 end
626 end
627
628 def test_add_issue_should_send_email_notification
629 Setting.notified_events = ['issue_added']
630 ActionMailer::Base.deliveries.clear
631 # This email contains: 'Project: onlinestore'
632 issue = submit_email('ticket_on_given_project.eml')
633 assert issue.is_a?(Issue)
634 assert_equal 1, ActionMailer::Base.deliveries.size
635 end
636
637 def test_update_issue
638 journal = submit_email('ticket_reply.eml')
639 assert journal.is_a?(Journal)
640 assert_equal User.find_by_login('jsmith'), journal.user
641 assert_equal Issue.find(2), journal.journalized
642 assert_match /This is reply/, journal.notes
643 assert_equal false, journal.private_notes
644 assert_equal 'Feature request', journal.issue.tracker.name
645 end
646
647 def test_update_issue_with_attribute_changes
648 # This email contains: 'Status: Resolved'
649 journal = submit_email('ticket_reply_with_status.eml')
650 assert journal.is_a?(Journal)
651 issue = Issue.find(journal.issue.id)
652 assert_equal User.find_by_login('jsmith'), journal.user
653 assert_equal Issue.find(2), journal.journalized
654 assert_match /This is reply/, journal.notes
655 assert_equal 'Feature request', journal.issue.tracker.name
656 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
657 assert_equal '2010-01-01', issue.start_date.to_s
658 assert_equal '2010-12-31', issue.due_date.to_s
659 assert_equal User.find_by_login('jsmith'), issue.assigned_to
660 assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
661 # keywords should be removed from the email body
662 assert !journal.notes.match(/^Status:/i)
663 assert !journal.notes.match(/^Start Date:/i)
664 end
665
666 def test_update_issue_with_attachment
667 assert_difference 'Journal.count' do
668 assert_difference 'JournalDetail.count' do
669 assert_difference 'Attachment.count' do
670 assert_no_difference 'Issue.count' do
671 journal = submit_email('ticket_with_attachment.eml') do |raw|
672 raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
673 end
674 end
675 end
676 end
677 end
678 journal = Journal.order('id DESC').first
679 assert_equal Issue.find(2), journal.journalized
680 assert_equal 1, journal.details.size
681
682 detail = journal.details.first
683 assert_equal 'attachment', detail.property
684 assert_equal 'Paella.jpg', detail.value
685 end
686
687 def test_update_issue_should_send_email_notification
688 ActionMailer::Base.deliveries.clear
689 journal = submit_email('ticket_reply.eml')
690 assert journal.is_a?(Journal)
691 assert_equal 1, ActionMailer::Base.deliveries.size
692 end
693
694 def test_update_issue_should_not_set_defaults
695 journal = submit_email(
696 'ticket_reply.eml',
697 :issue => {:tracker => 'Support request', :priority => 'High'}
698 )
699 assert journal.is_a?(Journal)
700 assert_match /This is reply/, journal.notes
701 assert_equal 'Feature request', journal.issue.tracker.name
702 assert_equal 'Normal', journal.issue.priority.name
703 end
704
705 def test_replying_to_a_private_note_should_add_reply_as_private
706 private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2)
707
708 assert_difference 'Journal.count' do
709 journal = submit_email('ticket_reply.eml') do |email|
710 email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
711 end
712
713 assert_kind_of Journal, journal
714 assert_match /This is reply/, journal.notes
715 assert_equal true, journal.private_notes
716 end
717 end
718
719 def test_reply_to_a_message
720 m = submit_email('message_reply.eml')
721 assert m.is_a?(Message)
722 assert !m.new_record?
723 m.reload
724 assert_equal 'Reply via email', m.subject
725 # The email replies to message #2 which is part of the thread of message #1
726 assert_equal Message.find(1), m.parent
727 end
728
729 def test_reply_to_a_message_by_subject
730 m = submit_email('message_reply_by_subject.eml')
731 assert m.is_a?(Message)
732 assert !m.new_record?
733 m.reload
734 assert_equal 'Reply to the first post', m.subject
735 assert_equal Message.find(1), m.parent
736 end
737
738 def test_should_strip_tags_of_html_only_emails
739 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
740 assert issue.is_a?(Issue)
741 assert !issue.new_record?
742 issue.reload
743 assert_equal 'HTML email', issue.subject
744 assert_equal 'This is a html-only email.', issue.description
745 end
746
747 test "truncate emails with no setting should add the entire email into the issue" do
748 with_settings :mail_handler_body_delimiters => '' do
749 issue = submit_email('ticket_on_given_project.eml')
750 assert_issue_created(issue)
751 assert issue.description.include?('---')
752 assert issue.description.include?('This paragraph is after the delimiter')
753 end
754 end
755
756 test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
757 with_settings :mail_handler_body_delimiters => '---' do
758 issue = submit_email('ticket_on_given_project.eml')
759 assert_issue_created(issue)
760 assert issue.description.include?('This paragraph is before delimiters')
761 assert issue.description.include?('--- This line starts with a delimiter')
762 assert !issue.description.match(/^---$/)
763 assert !issue.description.include?('This paragraph is after the delimiter')
764 end
765 end
766
767 test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
768 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
769 journal = submit_email('issue_update_with_quoted_reply_above.eml')
770 assert journal.is_a?(Journal)
771 assert journal.notes.include?('An update to the issue by the sender.')
772 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
773 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
774 end
775 end
776
777 test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
778 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
779 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
780 assert journal.is_a?(Journal)
781 assert journal.notes.include?('An update to the issue by the sender.')
782 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
783 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
784 end
785 end
786
787 test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
788 with_settings :mail_handler_body_delimiters => "---\nBREAK" do
789 issue = submit_email('ticket_on_given_project.eml')
790 assert_issue_created(issue)
791 assert issue.description.include?('This paragraph is before delimiters')
792 assert !issue.description.include?('BREAK')
793 assert !issue.description.include?('This paragraph is between delimiters')
794 assert !issue.description.match(/^---$/)
795 assert !issue.description.include?('This paragraph is after the delimiter')
796 end
797 end
798
799 def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
800 with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
801 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
802 assert issue.is_a?(Issue)
803 assert !issue.new_record?
804 assert_equal 0, issue.reload.attachments.size
805 end
806 end
807
808 def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
809 with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
810 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
811 assert issue.is_a?(Issue)
812 assert !issue.new_record?
813 assert_equal 1, issue.reload.attachments.size
814 end
815 end
816
817 def test_email_with_long_subject_line
818 issue = submit_email('ticket_with_long_subject.eml')
819 assert issue.is_a?(Issue)
820 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]
821 end
822
823 def test_new_user_from_attributes_should_return_valid_user
824 to_test = {
825 # [address, name] => [login, firstname, lastname]
826 ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
827 ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
828 ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
829 ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
830 ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
831 ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
832 }
833
834 to_test.each do |attrs, expected|
835 user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
836
837 assert user.valid?, user.errors.full_messages.to_s
838 assert_equal attrs.first, user.mail
839 assert_equal expected[0], user.login
840 assert_equal expected[1], user.firstname
841 assert_equal expected[2], user.lastname
842 assert_equal 'only_my_events', user.mail_notification
843 end
844 end
845
846 def test_new_user_from_attributes_should_use_default_login_if_invalid
847 user = MailHandler.new_user_from_attributes('foo+bar@example.net')
848 assert user.valid?
849 assert user.login =~ /^user[a-f0-9]+$/
850 assert_equal 'foo+bar@example.net', user.mail
851 end
852
853 def test_new_user_with_utf8_encoded_fullname_should_be_decoded
854 assert_difference 'User.count' do
855 issue = submit_email(
856 'fullname_of_sender_as_utf8_encoded.eml',
857 :issue => {:project => 'ecookbook'},
858 :unknown_user => 'create'
859 )
860 end
861 user = User.order('id DESC').first
862 assert_equal "foo@example.org", user.mail
863 str1 = "\xc3\x84\xc3\xa4"
864 str2 = "\xc3\x96\xc3\xb6"
865 str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
866 str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding)
867 assert_equal str1, user.firstname
868 assert_equal str2, user.lastname
869 end
870
871 def test_extract_options_from_env_should_return_options
872 options = MailHandler.extract_options_from_env({
873 'tracker' => 'defect',
874 'project' => 'foo',
875 'unknown_user' => 'create'
876 })
877
878 assert_equal({
879 :issue => {:tracker => 'defect', :project => 'foo'},
880 :unknown_user => 'create'
881 }, options)
882 end
883
884 private
885
886 def submit_email(filename, options={})
887 raw = IO.read(File.join(FIXTURES_PATH, filename))
888 yield raw if block_given?
889 MailHandler.receive(raw, options)
890 end
891
892 def assert_issue_created(issue)
893 assert issue.is_a?(Issue)
894 assert !issue.new_record?
895 issue.reload
896 end
897 end