comparison test/unit/mail_handler_test.rb @ 1526:404aa68d4227

Merge from live branch
author Chris Cannam
date Thu, 11 Sep 2014 12:46:20 +0100
parents dffacf8a6908
children
comparison
equal deleted inserted replaced
1493:a5f2bdf3b486 1526:404aa68d4227
1 # encoding: utf-8 1 # encoding: utf-8
2 # 2 #
3 # Redmine - project management software 3 # Redmine - project management software
4 # Copyright (C) 2006-2012 Jean-Philippe Lang 4 # Copyright (C) 2006-2014 Jean-Philippe Lang
5 # 5 #
6 # This program is free software; you can redistribute it and/or 6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License 7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2 8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version. 9 # of the License, or (at your option) any later version.
39 Setting.clear_cache 39 Setting.clear_cache
40 end 40 end
41 41
42 def test_add_issue 42 def test_add_issue
43 ActionMailer::Base.deliveries.clear 43 ActionMailer::Base.deliveries.clear
44 lft1 = new_issue_lft
44 # This email contains: 'Project: onlinestore' 45 # This email contains: 'Project: onlinestore'
45 issue = submit_email('ticket_on_given_project.eml') 46 issue = submit_email('ticket_on_given_project.eml')
46 assert issue.is_a?(Issue) 47 assert issue.is_a?(Issue)
47 assert !issue.new_record? 48 assert !issue.new_record?
48 issue.reload 49 issue.reload
56 assert_equal '2010-12-31', issue.due_date.to_s 57 assert_equal '2010-12-31', issue.due_date.to_s
57 assert_equal User.find_by_login('jsmith'), issue.assigned_to 58 assert_equal User.find_by_login('jsmith'), issue.assigned_to
58 assert_equal Version.find_by_name('Alpha'), issue.fixed_version 59 assert_equal Version.find_by_name('Alpha'), issue.fixed_version
59 assert_equal 2.5, issue.estimated_hours 60 assert_equal 2.5, issue.estimated_hours
60 assert_equal 30, issue.done_ratio 61 assert_equal 30, issue.done_ratio
61 assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] 62 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
62 # keywords should be removed from the email body 63 # keywords should be removed from the email body
63 assert !issue.description.match(/^Project:/i) 64 assert !issue.description.match(/^Project:/i)
64 assert !issue.description.match(/^Status:/i) 65 assert !issue.description.match(/^Status:/i)
65 assert !issue.description.match(/^Start Date:/i) 66 assert !issue.description.match(/^Start Date:/i)
66 # Email notification should be sent 67 # Email notification should be sent
200 issue = submit_email('ticket_on_given_project.eml') do |email| 201 issue = submit_email('ticket_on_given_project.eml') do |email|
201 email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz') 202 email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
202 end 203 end
203 assert issue.is_a?(Issue) 204 assert issue.is_a?(Issue)
204 assert_equal user, issue.assigned_to 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
205 end 214 end
206 215
207 def test_add_issue_with_cc 216 def test_add_issue_with_cc
208 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'}) 217 issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
209 assert issue.is_a?(Issue) 218 assert issue.is_a?(Issue)
262 end 271 end
263 end 272 end
264 end 273 end
265 274
266 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check 275 def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
276 lft1 = new_issue_lft
267 assert_no_difference 'User.count' do 277 assert_no_difference 'User.count' do
268 assert_difference 'Issue.count' do 278 assert_difference 'Issue.count' do
269 issue = submit_email( 279 issue = submit_email(
270 'ticket_by_unknown_user.eml', 280 'ticket_by_unknown_user.eml',
271 :issue => {:project => 'onlinestore'}, 281 :issue => {:project => 'onlinestore'},
273 :unknown_user => 'accept' 283 :unknown_user => 'accept'
274 ) 284 )
275 assert issue.is_a?(Issue) 285 assert issue.is_a?(Issue)
276 assert issue.author.anonymous? 286 assert issue.author.anonymous?
277 assert !issue.project.is_public? 287 assert !issue.project.is_public?
278 assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] 288 assert_equal [issue.id, lft1, lft1 + 1], [issue.root_id, issue.lft, issue.rgt]
279 end 289 end
280 end 290 end
281 end 291 end
282 292
283 def test_add_issue_by_created_user 293 def test_add_issue_by_created_user
302 password = mail_body(email).match(/\* Password: (.*)$/)[1].strip 312 password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
303 assert_equal issue.author, User.try_to_login(login, password) 313 assert_equal issue.author, User.try_to_login(login, password)
304 end 314 end
305 end 315 end
306 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
307 def test_add_issue_without_from_header 362 def test_add_issue_without_from_header
308 Role.anonymous.add_permission!(:add_issues) 363 Role.anonymous.add_permission!(:add_issues)
309 assert_equal false, submit_email('ticket_without_from_header.eml') 364 assert_equal false, submit_email('ticket_without_from_header.eml')
310 end 365 end
311 366
312 def test_add_issue_with_invalid_attributes 367 def test_add_issue_with_invalid_attributes
313 issue = submit_email( 368 with_settings :default_issue_start_date_to_creation_date => '0' do
314 'ticket_with_invalid_attributes.eml', 369 issue = submit_email(
315 :allow_override => 'tracker,category,priority' 370 'ticket_with_invalid_attributes.eml',
316 ) 371 :allow_override => 'tracker,category,priority'
317 assert issue.is_a?(Issue) 372 )
318 assert !issue.new_record? 373 assert issue.is_a?(Issue)
319 issue.reload 374 assert !issue.new_record?
320 assert_nil issue.assigned_to 375 issue.reload
321 assert_nil issue.start_date 376 assert_nil issue.assigned_to
322 assert_nil issue.due_date 377 assert_nil issue.start_date
323 assert_equal 0, issue.done_ratio 378 assert_nil issue.due_date
324 assert_equal 'Normal', issue.priority.to_s 379 assert_equal 0, issue.done_ratio
325 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') 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
326 end 392 end
327 393
328 def test_add_issue_with_localized_attributes 394 def test_add_issue_with_localized_attributes
329 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr' 395 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
330 issue = submit_email( 396 issue = submit_email(
445 assert File.exist?(attachment.diskfile) 511 assert File.exist?(attachment.diskfile)
446 assert_equal 5, File.size(attachment.diskfile) 512 assert_equal 5, File.size(attachment.diskfile)
447 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest 513 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
448 end 514 end
449 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
450 def test_add_issue_with_iso_8859_1_subject 531 def test_add_issue_with_iso_8859_1_subject
451 issue = submit_email( 532 issue = submit_email(
452 'subject_as_iso-8859-1.eml', 533 'subject_as_iso-8859-1.eml',
453 :issue => {:project => 'ecookbook'} 534 :issue => {:project => 'ecookbook'}
454 ) 535 )
465 ) 546 )
466 assert_kind_of Issue, issue 547 assert_kind_of Issue, issue
467 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" 548 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
468 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) 549 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
469 assert_equal ja, issue.subject 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
470 end 568 end
471 569
472 def test_add_issue_with_no_subject_header 570 def test_add_issue_with_no_subject_header
473 issue = submit_email( 571 issue = submit_email(
474 'no_subject_header.eml', 572 'no_subject_header.eml',
575 end 673 end
576 end 674 end
577 end 675 end
578 end 676 end
579 end 677 end
580 journal = Journal.first(:order => 'id DESC') 678 journal = Journal.order('id DESC').first
581 assert_equal Issue.find(2), journal.journalized 679 assert_equal Issue.find(2), journal.journalized
582 assert_equal 1, journal.details.size 680 assert_equal 1, journal.details.size
583 681
584 detail = journal.details.first 682 detail = journal.details.first
585 assert_equal 'attachment', detail.property 683 assert_equal 'attachment', detail.property
644 issue.reload 742 issue.reload
645 assert_equal 'HTML email', issue.subject 743 assert_equal 'HTML email', issue.subject
646 assert_equal 'This is a html-only email.', issue.description 744 assert_equal 'This is a html-only email.', issue.description
647 end 745 end
648 746
649 context "truncate emails based on the Setting" do 747 test "truncate emails with no setting should add the entire email into the issue" do
650 context "with no setting" do 748 with_settings :mail_handler_body_delimiters => '' do
651 setup do 749 issue = submit_email('ticket_on_given_project.eml')
652 Setting.mail_handler_body_delimiters = '' 750 assert_issue_created(issue)
653 end 751 assert issue.description.include?('---')
654 752 assert issue.description.include?('This paragraph is after the delimiter')
655 should "add the entire email into the issue" do 753 end
656 issue = submit_email('ticket_on_given_project.eml') 754 end
657 assert_issue_created(issue) 755
658 assert issue.description.include?('---') 756 test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
659 assert issue.description.include?('This paragraph is after the delimiter') 757 with_settings :mail_handler_body_delimiters => '---' do
660 end 758 issue = submit_email('ticket_on_given_project.eml')
661 end 759 assert_issue_created(issue)
662 760 assert issue.description.include?('This paragraph is before delimiters')
663 context "with a single string" do 761 assert issue.description.include?('--- This line starts with a delimiter')
664 setup do 762 assert !issue.description.match(/^---$/)
665 Setting.mail_handler_body_delimiters = '---' 763 assert !issue.description.include?('This paragraph is after the delimiter')
666 end 764 end
667 should "truncate the email at the delimiter for the issue" do 765 end
668 issue = submit_email('ticket_on_given_project.eml') 766
669 assert_issue_created(issue) 767 test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
670 assert issue.description.include?('This paragraph is before delimiters') 768 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
671 assert issue.description.include?('--- This line starts with a delimiter') 769 journal = submit_email('issue_update_with_quoted_reply_above.eml')
672 assert !issue.description.match(/^---$/) 770 assert journal.is_a?(Journal)
673 assert !issue.description.include?('This paragraph is after the delimiter') 771 assert journal.notes.include?('An update to the issue by the sender.')
674 end 772 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
675 end 773 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
676 774 end
677 context "with a single quoted reply (e.g. reply to a Redmine email notification)" do 775 end
678 setup do 776
679 Setting.mail_handler_body_delimiters = '--- Reply above. Do not remove this line. ---' 777 test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
680 end 778 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
681 should "truncate the email at the delimiter with the quoted reply symbols (>)" do 779 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
682 journal = submit_email('issue_update_with_quoted_reply_above.eml') 780 assert journal.is_a?(Journal)
683 assert journal.is_a?(Journal) 781 assert journal.notes.include?('An update to the issue by the sender.')
684 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. ---"))
685 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.')
686 assert !journal.notes.include?('Looks like the JSON api for projects was missed.') 784 end
687 end 785 end
688 end 786
689 787 test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
690 context "with multiple quoted replies (e.g. reply to a reply of a Redmine email notification)" do 788 with_settings :mail_handler_body_delimiters => "---\nBREAK" do
691 setup do 789 issue = submit_email('ticket_on_given_project.eml')
692 Setting.mail_handler_body_delimiters = '--- Reply above. Do not remove this line. ---' 790 assert_issue_created(issue)
693 end 791 assert issue.description.include?('This paragraph is before delimiters')
694 should "truncate the email at the delimiter with the quoted reply symbols (>)" do 792 assert !issue.description.include?('BREAK')
695 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml') 793 assert !issue.description.include?('This paragraph is between delimiters')
696 assert journal.is_a?(Journal) 794 assert !issue.description.match(/^---$/)
697 assert journal.notes.include?('An update to the issue by the sender.') 795 assert !issue.description.include?('This paragraph is after the delimiter')
698 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---")) 796 end
699 assert !journal.notes.include?('Looks like the JSON api for projects was missed.') 797 end
700 end 798
701 end 799 def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
702 800 with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
703 context "with multiple strings" do 801 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
704 setup do 802 assert issue.is_a?(Issue)
705 Setting.mail_handler_body_delimiters = "---\nBREAK" 803 assert !issue.new_record?
706 end 804 assert_equal 0, issue.reload.attachments.size
707 should "truncate the email at the first delimiter found (BREAK)" do 805 end
708 issue = submit_email('ticket_on_given_project.eml') 806 end
709 assert_issue_created(issue) 807
710 assert issue.description.include?('This paragraph is before delimiters') 808 def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
711 assert !issue.description.include?('BREAK') 809 with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
712 assert !issue.description.include?('This paragraph is between delimiters') 810 issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
713 assert !issue.description.match(/^---$/) 811 assert issue.is_a?(Issue)
714 assert !issue.description.include?('This paragraph is after the delimiter') 812 assert !issue.new_record?
715 end 813 assert_equal 1, issue.reload.attachments.size
716 end 814 end
717 end 815 end
718 816
719 def test_email_with_long_subject_line 817 def test_email_with_long_subject_line
720 issue = submit_email('ticket_with_long_subject.eml') 818 issue = submit_email('ticket_with_long_subject.eml')
739 assert user.valid?, user.errors.full_messages.to_s 837 assert user.valid?, user.errors.full_messages.to_s
740 assert_equal attrs.first, user.mail 838 assert_equal attrs.first, user.mail
741 assert_equal expected[0], user.login 839 assert_equal expected[0], user.login
742 assert_equal expected[1], user.firstname 840 assert_equal expected[1], user.firstname
743 assert_equal expected[2], user.lastname 841 assert_equal expected[2], user.lastname
744 end 842 assert_equal 'only_my_events', user.mail_notification
745 end
746
747 def test_new_user_from_attributes_should_respect_minimum_password_length
748 with_settings :password_min_length => 15 do
749 user = MailHandler.new_user_from_attributes('jsmith@example.net')
750 assert user.valid?
751 assert user.password.length >= 15
752 end 843 end
753 end 844 end
754 845
755 def test_new_user_from_attributes_should_use_default_login_if_invalid 846 def test_new_user_from_attributes_should_use_default_login_if_invalid
756 user = MailHandler.new_user_from_attributes('foo+bar@example.net') 847 user = MailHandler.new_user_from_attributes('foo+bar@example.net')
765 'fullname_of_sender_as_utf8_encoded.eml', 856 'fullname_of_sender_as_utf8_encoded.eml',
766 :issue => {:project => 'ecookbook'}, 857 :issue => {:project => 'ecookbook'},
767 :unknown_user => 'create' 858 :unknown_user => 'create'
768 ) 859 )
769 end 860 end
770 861 user = User.order('id DESC').first
771 user = User.first(:order => 'id DESC')
772 assert_equal "foo@example.org", user.mail 862 assert_equal "foo@example.org", user.mail
773 str1 = "\xc3\x84\xc3\xa4" 863 str1 = "\xc3\x84\xc3\xa4"
774 str2 = "\xc3\x96\xc3\xb6" 864 str2 = "\xc3\x96\xc3\xb6"
775 str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding) 865 str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
776 str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding) 866 str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding)
777 assert_equal str1, user.firstname 867 assert_equal str1, user.firstname
778 assert_equal str2, user.lastname 868 assert_equal str2, user.lastname
779 end 869 end
780 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
781 private 884 private
782 885
783 def submit_email(filename, options={}) 886 def submit_email(filename, options={})
784 raw = IO.read(File.join(FIXTURES_PATH, filename)) 887 raw = IO.read(File.join(FIXTURES_PATH, filename))
785 yield raw if block_given? 888 yield raw if block_given?