diff test/unit/mail_handler_test.rb @ 1337:077b8890835a cannam

Merge from live branch
author Chris Cannam
date Thu, 20 Jun 2013 13:14:02 +0100
parents 433d4f72a19b
children 622f24f53b42 261b3d9a4903
line wrap: on
line diff
--- a/test/unit/mail_handler_test.rb	Fri Jun 14 11:30:07 2013 +0100
+++ b/test/unit/mail_handler_test.rb	Thu Jun 20 13:14:02 2013 +0100
@@ -1,7 +1,7 @@
 # encoding: utf-8
 #
 # Redmine - project management software
-# Copyright (C) 2006-2011  Jean-Philippe Lang
+# Copyright (C) 2006-2012  Jean-Philippe Lang
 #
 # This program is free software; you can redistribute it and/or
 # modify it under the terms of the GNU General Public License
@@ -20,25 +20,13 @@
 require File.expand_path('../../test_helper', __FILE__)
 
 class MailHandlerTest < ActiveSupport::TestCase
-  fixtures :users, :projects,
-                   :enabled_modules,
-                   :roles,
-                   :members,
-                   :member_roles,
-                   :users,
-                   :issues,
-                   :issue_statuses,
-                   :workflows,
-                   :trackers,
-                   :projects_trackers,
-                   :versions,
-                   :enumerations,
-                   :issue_categories,
-                   :custom_fields,
-                   :custom_fields_trackers,
-                   :custom_fields_projects,
-                   :boards,
-                   :messages
+  fixtures :users, :projects, :enabled_modules, :roles,
+           :members, :member_roles, :users,
+           :issues, :issue_statuses,
+           :workflows, :trackers, :projects_trackers,
+           :versions, :enumerations, :issue_categories,
+           :custom_fields, :custom_fields_trackers, :custom_fields_projects,
+           :boards, :messages
 
   FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
 
@@ -47,6 +35,10 @@
     Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
   end
 
+  def teardown
+    Setting.clear_cache
+  end
+
   def test_add_issue
     ActionMailer::Base.deliveries.clear
     # This email contains: 'Project: onlinestore'
@@ -79,7 +71,10 @@
 
   def test_add_issue_with_default_tracker
     # This email contains: 'Project: onlinestore'
-    issue = submit_email('ticket_on_given_project.eml', :issue => {:tracker => 'Support request'})
+    issue = submit_email(
+              'ticket_on_given_project.eml',
+              :issue => {:tracker => 'Support request'}
+            )
     assert issue.is_a?(Issue)
     assert !issue.new_record?
     issue.reload
@@ -97,7 +92,10 @@
   end
 
   def test_add_issue_with_attributes_override
-    issue = submit_email('ticket_with_attributes.eml', :allow_override => 'tracker,category,priority')
+    issue = submit_email(
+              'ticket_with_attributes.eml',
+              :allow_override => 'tracker,category,priority'
+            )
     assert issue.is_a?(Issue)
     assert !issue.new_record?
     issue.reload
@@ -123,7 +121,11 @@
   end
 
   def test_add_issue_with_partial_attributes_override
-    issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker'])
+    issue = submit_email(
+              'ticket_with_attributes.eml',
+              :issue => {:priority => 'High'},
+              :allow_override => ['tracker']
+            )
     assert issue.is_a?(Issue)
     assert !issue.new_record?
     issue.reload
@@ -137,7 +139,10 @@
   end
 
   def test_add_issue_with_spaces_between_attribute_and_separator
-    issue = submit_email('ticket_with_spaces_between_attribute_and_separator.eml', :allow_override => 'tracker,category,priority')
+    issue = submit_email(
+              'ticket_with_spaces_between_attribute_and_separator.eml',
+              :allow_override => 'tracker,category,priority'
+            )
     assert issue.is_a?(Issue)
     assert !issue.new_record?
     issue.reload
@@ -172,10 +177,33 @@
     assert !issue.new_record?
     issue.reload
     assert_equal 'New ticket with custom field values', issue.subject
-    assert_equal 'Value for a custom field', issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
+    assert_equal 'PostgreSQL', issue.custom_field_value(1)
+    assert_equal 'Value for a custom field', issue.custom_field_value(2)
     assert !issue.description.match(/^searchable field:/i)
   end
 
+  def test_add_issue_with_version_custom_fields
+    field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3])
+
+    issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email|
+      email << "Affected version: 1.0\n"
+    end
+    assert issue.is_a?(Issue)
+    assert !issue.new_record?
+    issue.reload
+    assert_equal '2', issue.custom_field_value(field)
+  end
+
+  def test_add_issue_should_match_assignee_on_display_name
+    user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
+    User.add_to_project(user, Project.find(2))
+    issue = submit_email('ticket_on_given_project.eml') do |email|
+      email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
+    end
+    assert issue.is_a?(Issue)
+    assert_equal user, issue.assigned_to
+  end
+
   def test_add_issue_with_cc
     issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
     assert issue.is_a?(Issue)
@@ -187,14 +215,22 @@
 
   def test_add_issue_by_unknown_user
     assert_no_difference 'User.count' do
-      assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'})
+      assert_equal false,
+                   submit_email(
+                     'ticket_by_unknown_user.eml',
+                     :issue => {:project => 'ecookbook'}
+                   )
     end
   end
 
   def test_add_issue_by_anonymous_user
     Role.anonymous.add_permission!(:add_issues)
     assert_no_difference 'User.count' do
-      issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
+      issue = submit_email(
+                'ticket_by_unknown_user.eml',
+                :issue => {:project => 'ecookbook'},
+                :unknown_user => 'accept'
+              )
       assert issue.is_a?(Issue)
       assert issue.author.anonymous?
     end
@@ -203,7 +239,11 @@
   def test_add_issue_by_anonymous_user_with_no_from_address
     Role.anonymous.add_permission!(:add_issues)
     assert_no_difference 'User.count' do
-      issue = submit_email('ticket_by_empty_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
+      issue = submit_email(
+                'ticket_by_empty_user.eml',
+                :issue => {:project => 'ecookbook'},
+                :unknown_user => 'accept'
+              )
       assert issue.is_a?(Issue)
       assert issue.author.anonymous?
     end
@@ -213,7 +253,12 @@
     Role.anonymous.add_permission!(:add_issues)
     assert_no_difference 'User.count' do
       assert_no_difference 'Issue.count' do
-        assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :unknown_user => 'accept')
+        assert_equal false,
+                     submit_email(
+                       'ticket_by_unknown_user.eml',
+                       :issue => {:project => 'onlinestore'},
+                       :unknown_user => 'accept'
+                     )
       end
     end
   end
@@ -221,7 +266,12 @@
   def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
     assert_no_difference 'User.count' do
       assert_difference 'Issue.count' do
-        issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :no_permission_check => '1', :unknown_user => 'accept')
+        issue = submit_email(
+                  'ticket_by_unknown_user.eml',
+                  :issue => {:project => 'onlinestore'},
+                  :no_permission_check => '1',
+                  :unknown_user => 'accept'
+                )
         assert issue.is_a?(Issue)
         assert issue.author.anonymous?
         assert !issue.project.is_public?
@@ -233,7 +283,11 @@
   def test_add_issue_by_created_user
     Setting.default_language = 'en'
     assert_difference 'User.count' do
-      issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
+      issue = submit_email(
+                'ticket_by_unknown_user.eml',
+                :issue => {:project => 'ecookbook'},
+                :unknown_user => 'create'
+              )
       assert issue.is_a?(Issue)
       assert issue.author.active?
       assert_equal 'john.doe@somenet.foo', issue.author.mail
@@ -244,8 +298,8 @@
       email = ActionMailer::Base.deliveries.first
       assert_not_nil email
       assert email.subject.include?('account activation')
-      login = email.body.match(/\* Login: (.*)$/)[1]
-      password = email.body.match(/\* Password: (.*)$/)[1]
+      login = mail_body(email).match(/\* Login: (.*)$/)[1].strip
+      password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
       assert_equal issue.author, User.try_to_login(login, password)
     end
   end
@@ -256,7 +310,10 @@
   end
 
   def test_add_issue_with_invalid_attributes
-    issue = submit_email('ticket_with_invalid_attributes.eml', :allow_override => 'tracker,category,priority')
+    issue = submit_email(
+              'ticket_with_invalid_attributes.eml',
+              :allow_override => 'tracker,category,priority'
+            )
     assert issue.is_a?(Issue)
     assert !issue.new_record?
     issue.reload
@@ -270,7 +327,10 @@
 
   def test_add_issue_with_localized_attributes
     User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
-    issue = submit_email('ticket_with_localized_attributes.eml', :allow_override => 'tracker,category,priority')
+    issue = submit_email(
+              'ticket_with_localized_attributes.eml',
+              :allow_override => 'tracker,category,priority'
+            )
     assert issue.is_a?(Issue)
     assert !issue.new_record?
     issue.reload
@@ -284,27 +344,186 @@
   end
 
   def test_add_issue_with_japanese_keywords
-    tracker = Tracker.create!(:name => '開発')
+    ja_dev = "\xe9\x96\x8b\xe7\x99\xba"
+    ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding)
+    tracker = Tracker.create!(:name => ja_dev)
     Project.find(1).trackers << tracker
-    issue = submit_email('japanese_keywords_iso_2022_jp.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'tracker')
+    issue = submit_email(
+              'japanese_keywords_iso_2022_jp.eml',
+              :issue => {:project => 'ecookbook'},
+              :allow_override => 'tracker'
+            )
     assert_kind_of Issue, issue
     assert_equal tracker, issue.tracker
   end
 
   def test_add_issue_from_apple_mail
-    issue = submit_email('apple_mail_with_attachment.eml', :issue => {:project => 'ecookbook'})
+    issue = submit_email(
+              'apple_mail_with_attachment.eml',
+              :issue => {:project => 'ecookbook'}
+            )
     assert_kind_of Issue, issue
     assert_equal 1, issue.attachments.size
 
     attachment = issue.attachments.first
     assert_equal 'paella.jpg', attachment.filename
     assert_equal 10790, attachment.filesize
+    assert File.exist?(attachment.diskfile)
+    assert_equal 10790, File.size(attachment.diskfile)
+    assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
+  end
+
+  def test_thunderbird_with_attachment_ja
+    issue = submit_email(
+              'thunderbird_with_attachment_ja.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    assert_equal 1, issue.attachments.size
+    ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
+    ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
+    attachment = issue.attachments.first
+    assert_equal ja, attachment.filename
+    assert_equal 5, attachment.filesize
+    assert File.exist?(attachment.diskfile)
+    assert_equal 5, File.size(attachment.diskfile)
+    assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
+  end
+
+  def test_gmail_with_attachment_ja
+    issue = submit_email(
+              'gmail_with_attachment_ja.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    assert_equal 1, issue.attachments.size
+    ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
+    ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
+    attachment = issue.attachments.first
+    assert_equal ja, attachment.filename
+    assert_equal 5, attachment.filesize
+    assert File.exist?(attachment.diskfile)
+    assert_equal 5, File.size(attachment.diskfile)
+    assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
+  end
+
+  def test_thunderbird_with_attachment_latin1
+    issue = submit_email(
+              'thunderbird_with_attachment_iso-8859-1.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    assert_equal 1, issue.attachments.size
+    u = ""
+    u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
+    u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
+    u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
+    11.times { u << u1 }
+    attachment = issue.attachments.first
+    assert_equal "#{u}.png", attachment.filename
+    assert_equal 130, attachment.filesize
+    assert File.exist?(attachment.diskfile)
+    assert_equal 130, File.size(attachment.diskfile)
+    assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
+  end
+
+  def test_gmail_with_attachment_latin1
+    issue = submit_email(
+              'gmail_with_attachment_iso-8859-1.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    assert_equal 1, issue.attachments.size
+    u = ""
+    u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
+    u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
+    u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
+    11.times { u << u1 }
+    attachment = issue.attachments.first
+    assert_equal "#{u}.txt", attachment.filename
+    assert_equal 5, attachment.filesize
+    assert File.exist?(attachment.diskfile)
+    assert_equal 5, File.size(attachment.diskfile)
+    assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
+  end
+
+  def test_add_issue_with_iso_8859_1_subject
+    issue = submit_email(
+              'subject_as_iso-8859-1.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..."
+    str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
+    assert_kind_of Issue, issue
+    assert_equal str, issue.subject
+  end
+
+  def test_add_issue_with_japanese_subject
+    issue = submit_email(
+              'subject_japanese_1.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
+    ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
+    assert_equal ja, issue.subject
+  end
+
+  def test_add_issue_with_no_subject_header
+    issue = submit_email(
+              'no_subject_header.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    assert_equal '(no subject)', issue.subject
+  end
+
+  def test_add_issue_with_mixed_japanese_subject
+    issue = submit_email(
+              'subject_japanese_2.eml',
+              :issue => {:project => 'ecookbook'}
+            )
+    assert_kind_of Issue, issue
+    ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
+    ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
+    assert_equal ja, issue.subject
+  end
+
+  def test_should_ignore_emails_from_locked_users
+    User.find(2).lock!
+
+    MailHandler.any_instance.expects(:dispatch).never
+    assert_no_difference 'Issue.count' do
+      assert_equal false, submit_email('ticket_on_given_project.eml')
+    end
   end
 
   def test_should_ignore_emails_from_emission_address
     Role.anonymous.add_permission!(:add_issues)
     assert_no_difference 'User.count' do
-      assert_equal false, submit_email('ticket_from_emission_address.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
+      assert_equal false,
+                   submit_email(
+                     'ticket_from_emission_address.eml',
+                     :issue => {:project => 'ecookbook'},
+                     :unknown_user => 'create'
+                   )
+    end
+  end
+
+  def test_should_ignore_auto_replied_emails
+    MailHandler.any_instance.expects(:dispatch).never
+    [
+      "X-Auto-Response-Suppress: OOF",
+      "Auto-Submitted: auto-replied",
+      "Auto-Submitted: Auto-Replied",
+      "Auto-Submitted: auto-generated"
+    ].each do |header|
+      raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
+      raw = header + "\n" + raw
+
+      assert_no_difference 'Issue.count' do
+        assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
+      end
     end
   end
 
@@ -323,6 +542,7 @@
     assert_equal User.find_by_login('jsmith'), journal.user
     assert_equal Issue.find(2), journal.journalized
     assert_match /This is reply/, journal.notes
+    assert_equal false, journal.private_notes
     assert_equal 'Feature request', journal.issue.tracker.name
   end
 
@@ -374,13 +594,30 @@
   end
 
   def test_update_issue_should_not_set_defaults
-    journal = submit_email('ticket_reply.eml', :issue => {:tracker => 'Support request', :priority => 'High'})
+    journal = submit_email(
+                'ticket_reply.eml',
+                :issue => {:tracker => 'Support request', :priority => 'High'}
+              )
     assert journal.is_a?(Journal)
     assert_match /This is reply/, journal.notes
     assert_equal 'Feature request', journal.issue.tracker.name
     assert_equal 'Normal', journal.issue.priority.name
   end
 
+  def test_replying_to_a_private_note_should_add_reply_as_private
+    private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2)
+
+    assert_difference 'Journal.count' do
+      journal = submit_email('ticket_reply.eml') do |email|
+        email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
+      end
+
+      assert_kind_of Journal, journal
+      assert_match /This is reply/, journal.notes
+      assert_equal true, journal.private_notes
+    end
+  end
+
   def test_reply_to_a_message
     m = submit_email('message_reply.eml')
     assert m.is_a?(Message)
@@ -493,14 +730,13 @@
       ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
       ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
       ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
-      ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh'],
-      ['alongemailaddressthatexceedsloginlength@example.net', 'John Smith'] => ['alongemailaddressthatexceedslo', 'John', 'Smith']
+      ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
     }
 
     to_test.each do |attrs, expected|
       user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
 
-      assert user.valid?
+      assert user.valid?, user.errors.full_messages.to_s
       assert_equal attrs.first, user.mail
       assert_equal expected[0], user.login
       assert_equal expected[1], user.firstname
@@ -515,14 +751,31 @@
       assert user.password.length >= 15
     end
   end
- 
+
   def test_new_user_from_attributes_should_use_default_login_if_invalid
-    MailHandler.new_user_from_attributes('alongemailaddressthatexceedsloginlength-1@example.net').save!
-
-    # another long address that would result in duplicate login
-    user = MailHandler.new_user_from_attributes('alongemailaddressthatexceedsloginlength-2@example.net')
+    user = MailHandler.new_user_from_attributes('foo+bar@example.net')
     assert user.valid?
     assert user.login =~ /^user[a-f0-9]+$/
+    assert_equal 'foo+bar@example.net', user.mail
+  end
+
+  def test_new_user_with_utf8_encoded_fullname_should_be_decoded
+    assert_difference 'User.count' do
+      issue = submit_email(
+                'fullname_of_sender_as_utf8_encoded.eml',
+                :issue => {:project => 'ecookbook'},
+                :unknown_user => 'create'
+              )
+    end
+
+    user = User.first(:order => 'id DESC')
+    assert_equal "foo@example.org", user.mail
+    str1 = "\xc3\x84\xc3\xa4"
+    str2 = "\xc3\x96\xc3\xb6"
+    str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
+    str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding)
+    assert_equal str1, user.firstname
+    assert_equal str2, user.lastname
   end
 
   private