Chris@0: # encoding: utf-8 Chris@0: # Chris@0: # Redmine - project management software Chris@1494: # Copyright (C) 2006-2014 Jean-Philippe Lang Chris@0: # Chris@0: # This program is free software; you can redistribute it and/or Chris@0: # modify it under the terms of the GNU General Public License Chris@0: # as published by the Free Software Foundation; either version 2 Chris@0: # of the License, or (at your option) any later version. Chris@441: # Chris@0: # This program is distributed in the hope that it will be useful, Chris@0: # but WITHOUT ANY WARRANTY; without even the implied warranty of Chris@0: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the Chris@0: # GNU General Public License for more details. Chris@441: # Chris@0: # You should have received a copy of the GNU General Public License Chris@0: # along with this program; if not, write to the Free Software Chris@0: # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Chris@0: Chris@119: require File.expand_path('../../test_helper', __FILE__) Chris@0: Chris@0: class MailHandlerTest < ActiveSupport::TestCase Chris@1115: fixtures :users, :projects, :enabled_modules, :roles, Chris@1115: :members, :member_roles, :users, Chris@1115: :issues, :issue_statuses, Chris@1115: :workflows, :trackers, :projects_trackers, Chris@1115: :versions, :enumerations, :issue_categories, Chris@1115: :custom_fields, :custom_fields_trackers, :custom_fields_projects, Chris@1115: :boards, :messages Chris@441: Chris@0: FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler' Chris@441: Chris@0: def setup Chris@0: ActionMailer::Base.deliveries.clear chris@37: Setting.notified_events = Redmine::Notifiable.all.collect(&:name) Chris@0: end Chris@441: Chris@1115: def teardown Chris@1115: Setting.clear_cache Chris@1115: end Chris@1115: Chris@0: def test_add_issue Chris@0: ActionMailer::Base.deliveries.clear Chris@0: # This email contains: 'Project: onlinestore' Chris@0: issue = submit_email('ticket_on_given_project.eml') Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@119: assert_equal Project.find(2), issue.project Chris@119: assert_equal issue.project.trackers.first, issue.tracker Chris@0: assert_equal 'New ticket on a given project', issue.subject Chris@0: assert_equal User.find_by_login('jsmith'), issue.author Chris@0: assert_equal IssueStatus.find_by_name('Resolved'), issue.status Chris@0: assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') Chris@0: assert_equal '2010-01-01', issue.start_date.to_s Chris@0: assert_equal '2010-12-31', issue.due_date.to_s Chris@0: assert_equal User.find_by_login('jsmith'), issue.assigned_to Chris@507: assert_equal Version.find_by_name('Alpha'), issue.fixed_version chris@37: assert_equal 2.5, issue.estimated_hours chris@37: assert_equal 30, issue.done_ratio Chris@119: assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] Chris@0: # keywords should be removed from the email body Chris@0: assert !issue.description.match(/^Project:/i) Chris@0: assert !issue.description.match(/^Status:/i) Chris@441: assert !issue.description.match(/^Start Date:/i) Chris@0: # Email notification should be sent Chris@0: mail = ActionMailer::Base.deliveries.last Chris@0: assert_not_nil mail Chris@0: assert mail.subject.include?('New ticket on a given project') Chris@0: end Chris@441: Chris@119: def test_add_issue_with_default_tracker Chris@119: # This email contains: 'Project: onlinestore' Chris@1115: issue = submit_email( Chris@1115: 'ticket_on_given_project.eml', Chris@1115: :issue => {:tracker => 'Support request'} Chris@1115: ) Chris@119: assert issue.is_a?(Issue) Chris@119: assert !issue.new_record? Chris@119: issue.reload Chris@119: assert_equal 'Support request', issue.tracker.name Chris@119: end Chris@0: Chris@0: def test_add_issue_with_status Chris@0: # This email contains: 'Project: onlinestore' and 'Status: Resolved' Chris@0: issue = submit_email('ticket_on_given_project.eml') Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal Project.find(2), issue.project Chris@0: assert_equal IssueStatus.find_by_name("Resolved"), issue.status Chris@0: end Chris@441: Chris@0: def test_add_issue_with_attributes_override Chris@1115: issue = submit_email( Chris@1115: 'ticket_with_attributes.eml', Chris@1115: :allow_override => 'tracker,category,priority' Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal 'New ticket on a given project', issue.subject Chris@0: assert_equal User.find_by_login('jsmith'), issue.author Chris@0: assert_equal Project.find(2), issue.project Chris@0: assert_equal 'Feature request', issue.tracker.to_s Chris@0: assert_equal 'Stock management', issue.category.to_s Chris@0: assert_equal 'Urgent', issue.priority.to_s Chris@0: assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') Chris@0: end Chris@441: Chris@909: def test_add_issue_with_group_assignment Chris@909: with_settings :issue_group_assignment => '1' do Chris@909: issue = submit_email('ticket_on_given_project.eml') do |email| Chris@909: email.gsub!('Assigned to: John Smith', 'Assigned to: B Team') Chris@909: end Chris@909: assert issue.is_a?(Issue) Chris@909: assert !issue.new_record? Chris@909: issue.reload Chris@909: assert_equal Group.find(11), issue.assigned_to Chris@909: end Chris@909: end Chris@909: Chris@0: def test_add_issue_with_partial_attributes_override Chris@1115: issue = submit_email( Chris@1115: 'ticket_with_attributes.eml', Chris@1115: :issue => {:priority => 'High'}, Chris@1115: :allow_override => ['tracker'] Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal 'New ticket on a given project', issue.subject Chris@0: assert_equal User.find_by_login('jsmith'), issue.author Chris@0: assert_equal Project.find(2), issue.project Chris@0: assert_equal 'Feature request', issue.tracker.to_s Chris@0: assert_nil issue.category Chris@0: assert_equal 'High', issue.priority.to_s Chris@0: assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') Chris@0: end Chris@441: Chris@0: def test_add_issue_with_spaces_between_attribute_and_separator Chris@1115: issue = submit_email( Chris@1115: 'ticket_with_spaces_between_attribute_and_separator.eml', Chris@1115: :allow_override => 'tracker,category,priority' Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal 'New ticket on a given project', issue.subject Chris@0: assert_equal User.find_by_login('jsmith'), issue.author Chris@0: assert_equal Project.find(2), issue.project Chris@0: assert_equal 'Feature request', issue.tracker.to_s Chris@0: assert_equal 'Stock management', issue.category.to_s Chris@0: assert_equal 'Urgent', issue.priority.to_s Chris@0: assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') Chris@0: end Chris@0: Chris@0: def test_add_issue_with_attachment_to_specific_project Chris@0: issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'}) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal 'Ticket created by email with attachment', issue.subject Chris@0: assert_equal User.find_by_login('jsmith'), issue.author Chris@0: assert_equal Project.find(2), issue.project Chris@0: assert_equal 'This is a new ticket with attachments', issue.description Chris@0: # Attachment properties Chris@0: assert_equal 1, issue.attachments.size Chris@0: assert_equal 'Paella.jpg', issue.attachments.first.filename Chris@0: assert_equal 'image/jpeg', issue.attachments.first.content_type Chris@0: assert_equal 10790, issue.attachments.first.filesize Chris@0: end Chris@441: Chris@0: def test_add_issue_with_custom_fields Chris@0: issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'}) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal 'New ticket with custom field values', issue.subject Chris@1115: assert_equal 'PostgreSQL', issue.custom_field_value(1) Chris@1115: assert_equal 'Value for a custom field', issue.custom_field_value(2) Chris@0: assert !issue.description.match(/^searchable field:/i) Chris@0: end Chris@441: Chris@1115: def test_add_issue_with_version_custom_fields Chris@1115: field = IssueCustomField.create!(:name => 'Affected version', :field_format => 'version', :is_for_all => true, :tracker_ids => [1,2,3]) Chris@1115: Chris@1115: issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'ecookbook'}) do |email| Chris@1115: email << "Affected version: 1.0\n" Chris@1115: end Chris@1115: assert issue.is_a?(Issue) Chris@1115: assert !issue.new_record? Chris@1115: issue.reload Chris@1115: assert_equal '2', issue.custom_field_value(field) Chris@1115: end Chris@1115: Chris@1115: def test_add_issue_should_match_assignee_on_display_name Chris@1115: user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz') Chris@1115: User.add_to_project(user, Project.find(2)) Chris@1115: issue = submit_email('ticket_on_given_project.eml') do |email| Chris@1115: email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz') Chris@1115: end Chris@1115: assert issue.is_a?(Issue) Chris@1115: assert_equal user, issue.assigned_to Chris@1115: end Chris@1115: Chris@0: def test_add_issue_with_cc Chris@0: issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'}) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo')) chris@37: assert_equal 1, issue.watcher_user_ids.size Chris@0: end Chris@441: Chris@0: def test_add_issue_by_unknown_user Chris@0: assert_no_difference 'User.count' do Chris@1115: assert_equal false, Chris@1115: submit_email( Chris@1115: 'ticket_by_unknown_user.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@0: end Chris@0: end Chris@441: Chris@0: def test_add_issue_by_anonymous_user Chris@0: Role.anonymous.add_permission!(:add_issues) Chris@0: assert_no_difference 'User.count' do Chris@1115: issue = submit_email( Chris@1115: 'ticket_by_unknown_user.eml', Chris@1115: :issue => {:project => 'ecookbook'}, Chris@1115: :unknown_user => 'accept' Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert issue.author.anonymous? Chris@0: end Chris@0: end Chris@0: Chris@0: def test_add_issue_by_anonymous_user_with_no_from_address Chris@0: Role.anonymous.add_permission!(:add_issues) Chris@0: assert_no_difference 'User.count' do Chris@1115: issue = submit_email( Chris@1115: 'ticket_by_empty_user.eml', Chris@1115: :issue => {:project => 'ecookbook'}, Chris@1115: :unknown_user => 'accept' Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert issue.author.anonymous? Chris@0: end Chris@0: end Chris@441: Chris@0: def test_add_issue_by_anonymous_user_on_private_project Chris@0: Role.anonymous.add_permission!(:add_issues) Chris@0: assert_no_difference 'User.count' do Chris@0: assert_no_difference 'Issue.count' do Chris@1115: assert_equal false, Chris@1115: submit_email( Chris@1115: 'ticket_by_unknown_user.eml', Chris@1115: :issue => {:project => 'onlinestore'}, Chris@1115: :unknown_user => 'accept' Chris@1115: ) Chris@0: end Chris@0: end Chris@0: end Chris@441: Chris@0: def test_add_issue_by_anonymous_user_on_private_project_without_permission_check Chris@0: assert_no_difference 'User.count' do Chris@0: assert_difference 'Issue.count' do Chris@1115: issue = submit_email( Chris@1115: 'ticket_by_unknown_user.eml', Chris@1115: :issue => {:project => 'onlinestore'}, Chris@1115: :no_permission_check => '1', Chris@1115: :unknown_user => 'accept' Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert issue.author.anonymous? Chris@0: assert !issue.project.is_public? Chris@119: assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt] Chris@0: end Chris@0: end Chris@0: end Chris@441: Chris@0: def test_add_issue_by_created_user Chris@0: Setting.default_language = 'en' Chris@0: assert_difference 'User.count' do Chris@1115: issue = submit_email( Chris@1115: 'ticket_by_unknown_user.eml', Chris@1115: :issue => {:project => 'ecookbook'}, Chris@1115: :unknown_user => 'create' Chris@1115: ) Chris@0: assert issue.is_a?(Issue) Chris@0: assert issue.author.active? Chris@0: assert_equal 'john.doe@somenet.foo', issue.author.mail Chris@0: assert_equal 'John', issue.author.firstname Chris@0: assert_equal 'Doe', issue.author.lastname Chris@441: Chris@0: # account information Chris@0: email = ActionMailer::Base.deliveries.first Chris@0: assert_not_nil email Chris@0: assert email.subject.include?('account activation') Chris@1115: login = mail_body(email).match(/\* Login: (.*)$/)[1].strip Chris@1115: password = mail_body(email).match(/\* Password: (.*)$/)[1].strip Chris@0: assert_equal issue.author, User.try_to_login(login, password) Chris@0: end Chris@0: end Chris@441: Chris@1464: def test_created_user_should_be_added_to_groups Chris@1464: group1 = Group.generate! Chris@1464: group2 = Group.generate! Chris@1464: Chris@1464: assert_difference 'User.count' do Chris@1464: submit_email( Chris@1464: 'ticket_by_unknown_user.eml', Chris@1464: :issue => {:project => 'ecookbook'}, Chris@1464: :unknown_user => 'create', Chris@1464: :default_group => "#{group1.name},#{group2.name}" Chris@1464: ) Chris@1464: end Chris@1464: user = User.order('id DESC').first Chris@1464: assert_same_elements [group1, group2], user.groups Chris@1464: end Chris@1464: Chris@1464: def test_created_user_should_not_receive_account_information_with_no_account_info_option Chris@1464: assert_difference 'User.count' do Chris@1464: submit_email( Chris@1464: 'ticket_by_unknown_user.eml', Chris@1464: :issue => {:project => 'ecookbook'}, Chris@1464: :unknown_user => 'create', Chris@1464: :no_account_notice => '1' Chris@1464: ) Chris@1464: end Chris@1464: Chris@1464: # only 1 email for the new issue notification Chris@1464: assert_equal 1, ActionMailer::Base.deliveries.size Chris@1464: email = ActionMailer::Base.deliveries.first Chris@1464: assert_include 'Ticket by unknown user', email.subject Chris@1464: end Chris@1464: Chris@1464: def test_created_user_should_have_mail_notification_to_none_with_no_notification_option Chris@1464: assert_difference 'User.count' do Chris@1464: submit_email( Chris@1464: 'ticket_by_unknown_user.eml', Chris@1464: :issue => {:project => 'ecookbook'}, Chris@1464: :unknown_user => 'create', Chris@1464: :no_notification => '1' Chris@1464: ) Chris@1464: end Chris@1464: user = User.order('id DESC').first Chris@1464: assert_equal 'none', user.mail_notification Chris@1464: end Chris@1464: Chris@0: def test_add_issue_without_from_header Chris@0: Role.anonymous.add_permission!(:add_issues) Chris@0: assert_equal false, submit_email('ticket_without_from_header.eml') Chris@0: end chris@37: chris@37: def test_add_issue_with_invalid_attributes Chris@1115: issue = submit_email( Chris@1115: 'ticket_with_invalid_attributes.eml', Chris@1115: :allow_override => 'tracker,category,priority' Chris@1115: ) chris@37: assert issue.is_a?(Issue) chris@37: assert !issue.new_record? chris@37: issue.reload chris@37: assert_nil issue.assigned_to chris@37: assert_nil issue.start_date chris@37: assert_nil issue.due_date chris@37: assert_equal 0, issue.done_ratio chris@37: assert_equal 'Normal', issue.priority.to_s chris@37: assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') chris@37: end chris@37: Chris@1464: def test_add_issue_with_invalid_project_should_be_assigned_to_default_project Chris@1464: issue = submit_email('ticket_on_given_project.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'project') do |email| Chris@1464: email.gsub!(/^Project:.+$/, 'Project: invalid') Chris@1464: end Chris@1464: assert issue.is_a?(Issue) Chris@1464: assert !issue.new_record? Chris@1464: assert_equal 'ecookbook', issue.project.identifier Chris@1464: end Chris@1464: chris@37: def test_add_issue_with_localized_attributes chris@37: User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr' Chris@1115: issue = submit_email( Chris@1115: 'ticket_with_localized_attributes.eml', Chris@1115: :allow_override => 'tracker,category,priority' Chris@1115: ) chris@37: assert issue.is_a?(Issue) chris@37: assert !issue.new_record? chris@37: issue.reload chris@37: assert_equal 'New ticket on a given project', issue.subject chris@37: assert_equal User.find_by_login('jsmith'), issue.author chris@37: assert_equal Project.find(2), issue.project chris@37: assert_equal 'Feature request', issue.tracker.to_s chris@37: assert_equal 'Stock management', issue.category.to_s chris@37: assert_equal 'Urgent', issue.priority.to_s chris@37: assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.') chris@37: end Chris@441: Chris@0: def test_add_issue_with_japanese_keywords Chris@1115: ja_dev = "\xe9\x96\x8b\xe7\x99\xba" Chris@1115: ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding) Chris@1115: tracker = Tracker.create!(:name => ja_dev) Chris@0: Project.find(1).trackers << tracker Chris@1115: issue = submit_email( Chris@1115: 'japanese_keywords_iso_2022_jp.eml', Chris@1115: :issue => {:project => 'ecookbook'}, Chris@1115: :allow_override => 'tracker' Chris@1115: ) Chris@0: assert_kind_of Issue, issue Chris@0: assert_equal tracker, issue.tracker Chris@0: end Chris@0: Chris@909: def test_add_issue_from_apple_mail Chris@1115: issue = submit_email( Chris@1115: 'apple_mail_with_attachment.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@909: assert_kind_of Issue, issue Chris@909: assert_equal 1, issue.attachments.size Chris@909: Chris@909: attachment = issue.attachments.first Chris@909: assert_equal 'paella.jpg', attachment.filename Chris@909: assert_equal 10790, attachment.filesize Chris@1115: assert File.exist?(attachment.diskfile) Chris@1115: assert_equal 10790, File.size(attachment.diskfile) Chris@1115: assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest Chris@1115: end Chris@1115: Chris@1115: def test_thunderbird_with_attachment_ja Chris@1115: issue = submit_email( Chris@1115: 'thunderbird_with_attachment_ja.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: assert_equal 1, issue.attachments.size Chris@1115: ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" Chris@1115: ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) Chris@1115: attachment = issue.attachments.first Chris@1115: assert_equal ja, attachment.filename Chris@1115: assert_equal 5, attachment.filesize Chris@1115: assert File.exist?(attachment.diskfile) Chris@1115: assert_equal 5, File.size(attachment.diskfile) Chris@1115: assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest Chris@1115: end Chris@1115: Chris@1115: def test_gmail_with_attachment_ja Chris@1115: issue = submit_email( Chris@1115: 'gmail_with_attachment_ja.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: assert_equal 1, issue.attachments.size Chris@1115: ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt" Chris@1115: ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) Chris@1115: attachment = issue.attachments.first Chris@1115: assert_equal ja, attachment.filename Chris@1115: assert_equal 5, attachment.filesize Chris@1115: assert File.exist?(attachment.diskfile) Chris@1115: assert_equal 5, File.size(attachment.diskfile) Chris@1115: assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest Chris@1115: end Chris@1115: Chris@1115: def test_thunderbird_with_attachment_latin1 Chris@1115: issue = submit_email( Chris@1115: 'thunderbird_with_attachment_iso-8859-1.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: assert_equal 1, issue.attachments.size Chris@1115: u = "" Chris@1115: u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) Chris@1115: u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" Chris@1115: u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) Chris@1115: 11.times { u << u1 } Chris@1115: attachment = issue.attachments.first Chris@1115: assert_equal "#{u}.png", attachment.filename Chris@1115: assert_equal 130, attachment.filesize Chris@1115: assert File.exist?(attachment.diskfile) Chris@1115: assert_equal 130, File.size(attachment.diskfile) Chris@1115: assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest Chris@1115: end Chris@1115: Chris@1115: def test_gmail_with_attachment_latin1 Chris@1115: issue = submit_email( Chris@1115: 'gmail_with_attachment_iso-8859-1.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: assert_equal 1, issue.attachments.size Chris@1115: u = "" Chris@1115: u.force_encoding('UTF-8') if u.respond_to?(:force_encoding) Chris@1115: u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc" Chris@1115: u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding) Chris@1115: 11.times { u << u1 } Chris@1115: attachment = issue.attachments.first Chris@1115: assert_equal "#{u}.txt", attachment.filename Chris@1115: assert_equal 5, attachment.filesize Chris@1115: assert File.exist?(attachment.diskfile) Chris@1115: assert_equal 5, File.size(attachment.diskfile) Chris@1115: assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest Chris@1115: end Chris@1115: Chris@1464: def test_multiple_inline_text_parts_should_be_appended_to_issue_description Chris@1464: issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'}) Chris@1464: assert_include 'first', issue.description Chris@1464: assert_include 'second', issue.description Chris@1464: assert_include 'third', issue.description Chris@1464: end Chris@1464: Chris@1464: def test_attachment_text_part_should_be_added_as_issue_attachment Chris@1464: issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'}) Chris@1464: assert_not_include 'Plain text attachment', issue.description Chris@1464: attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'} Chris@1464: assert_not_nil attachment Chris@1464: assert_include 'Plain text attachment', File.read(attachment.diskfile) Chris@1464: end Chris@1464: Chris@1115: def test_add_issue_with_iso_8859_1_subject Chris@1115: issue = submit_email( Chris@1115: 'subject_as_iso-8859-1.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..." Chris@1115: str.force_encoding('UTF-8') if str.respond_to?(:force_encoding) Chris@1115: assert_kind_of Issue, issue Chris@1115: assert_equal str, issue.subject Chris@1115: end Chris@1115: Chris@1115: def test_add_issue_with_japanese_subject Chris@1115: issue = submit_email( Chris@1115: 'subject_japanese_1.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" Chris@1115: ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) Chris@1115: assert_equal ja, issue.subject Chris@1115: end Chris@1115: Chris@1115: def test_add_issue_with_no_subject_header Chris@1115: issue = submit_email( Chris@1115: 'no_subject_header.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: assert_equal '(no subject)', issue.subject Chris@1115: end Chris@1115: Chris@1115: def test_add_issue_with_mixed_japanese_subject Chris@1115: issue = submit_email( Chris@1115: 'subject_japanese_2.eml', Chris@1115: :issue => {:project => 'ecookbook'} Chris@1115: ) Chris@1115: assert_kind_of Issue, issue Chris@1115: ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88" Chris@1115: ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding) Chris@1115: assert_equal ja, issue.subject Chris@1115: end Chris@1115: Chris@1115: def test_should_ignore_emails_from_locked_users Chris@1115: User.find(2).lock! Chris@1115: Chris@1115: MailHandler.any_instance.expects(:dispatch).never Chris@1115: assert_no_difference 'Issue.count' do Chris@1115: assert_equal false, submit_email('ticket_on_given_project.eml') Chris@1115: end Chris@909: end Chris@909: Chris@0: def test_should_ignore_emails_from_emission_address Chris@0: Role.anonymous.add_permission!(:add_issues) Chris@0: assert_no_difference 'User.count' do Chris@1115: assert_equal false, Chris@1115: submit_email( Chris@1115: 'ticket_from_emission_address.eml', Chris@1115: :issue => {:project => 'ecookbook'}, Chris@1115: :unknown_user => 'create' Chris@1115: ) Chris@1115: end Chris@1115: end Chris@1115: Chris@1115: def test_should_ignore_auto_replied_emails Chris@1115: MailHandler.any_instance.expects(:dispatch).never Chris@1115: [ Chris@1115: "X-Auto-Response-Suppress: OOF", Chris@1115: "Auto-Submitted: auto-replied", Chris@1115: "Auto-Submitted: Auto-Replied", Chris@1115: "Auto-Submitted: auto-generated" Chris@1115: ].each do |header| Chris@1115: raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml')) Chris@1115: raw = header + "\n" + raw Chris@1115: Chris@1115: assert_no_difference 'Issue.count' do Chris@1115: assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored" Chris@1115: end Chris@0: end Chris@0: end Chris@0: Chris@0: def test_add_issue_should_send_email_notification chris@37: Setting.notified_events = ['issue_added'] Chris@0: ActionMailer::Base.deliveries.clear Chris@0: # This email contains: 'Project: onlinestore' Chris@0: issue = submit_email('ticket_on_given_project.eml') Chris@0: assert issue.is_a?(Issue) Chris@0: assert_equal 1, ActionMailer::Base.deliveries.size Chris@0: end Chris@441: Chris@909: def test_update_issue Chris@0: journal = submit_email('ticket_reply.eml') Chris@0: assert journal.is_a?(Journal) Chris@0: assert_equal User.find_by_login('jsmith'), journal.user Chris@0: assert_equal Issue.find(2), journal.journalized Chris@0: assert_match /This is reply/, journal.notes Chris@1115: assert_equal false, journal.private_notes Chris@119: assert_equal 'Feature request', journal.issue.tracker.name Chris@0: end Chris@0: Chris@909: def test_update_issue_with_attribute_changes Chris@0: # This email contains: 'Status: Resolved' Chris@0: journal = submit_email('ticket_reply_with_status.eml') Chris@0: assert journal.is_a?(Journal) Chris@0: issue = Issue.find(journal.issue.id) Chris@0: assert_equal User.find_by_login('jsmith'), journal.user Chris@0: assert_equal Issue.find(2), journal.journalized Chris@0: assert_match /This is reply/, journal.notes Chris@119: assert_equal 'Feature request', journal.issue.tracker.name Chris@0: assert_equal IssueStatus.find_by_name("Resolved"), issue.status Chris@0: assert_equal '2010-01-01', issue.start_date.to_s Chris@0: assert_equal '2010-12-31', issue.due_date.to_s Chris@0: assert_equal User.find_by_login('jsmith'), issue.assigned_to Chris@119: assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value Chris@441: # keywords should be removed from the email body Chris@441: assert !journal.notes.match(/^Status:/i) Chris@441: assert !journal.notes.match(/^Start Date:/i) Chris@0: end Chris@0: Chris@909: def test_update_issue_with_attachment Chris@909: assert_difference 'Journal.count' do Chris@909: assert_difference 'JournalDetail.count' do Chris@909: assert_difference 'Attachment.count' do Chris@909: assert_no_difference 'Issue.count' do Chris@909: journal = submit_email('ticket_with_attachment.eml') do |raw| Chris@909: raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories' Chris@909: end Chris@909: end Chris@909: end Chris@909: end Chris@909: end Chris@909: journal = Journal.first(:order => 'id DESC') Chris@909: assert_equal Issue.find(2), journal.journalized Chris@909: assert_equal 1, journal.details.size Chris@909: Chris@909: detail = journal.details.first Chris@909: assert_equal 'attachment', detail.property Chris@909: assert_equal 'Paella.jpg', detail.value Chris@909: end Chris@909: Chris@909: def test_update_issue_should_send_email_notification Chris@0: ActionMailer::Base.deliveries.clear Chris@0: journal = submit_email('ticket_reply.eml') Chris@0: assert journal.is_a?(Journal) Chris@0: assert_equal 1, ActionMailer::Base.deliveries.size Chris@0: end Chris@441: Chris@909: def test_update_issue_should_not_set_defaults Chris@1115: journal = submit_email( Chris@1115: 'ticket_reply.eml', Chris@1115: :issue => {:tracker => 'Support request', :priority => 'High'} Chris@1115: ) Chris@119: assert journal.is_a?(Journal) Chris@119: assert_match /This is reply/, journal.notes Chris@119: assert_equal 'Feature request', journal.issue.tracker.name Chris@119: assert_equal 'Normal', journal.issue.priority.name Chris@119: end Chris@441: Chris@1115: def test_replying_to_a_private_note_should_add_reply_as_private Chris@1115: private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2) Chris@1115: Chris@1115: assert_difference 'Journal.count' do Chris@1115: journal = submit_email('ticket_reply.eml') do |email| Chris@1115: email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: " Chris@1115: end Chris@1115: Chris@1115: assert_kind_of Journal, journal Chris@1115: assert_match /This is reply/, journal.notes Chris@1115: assert_equal true, journal.private_notes Chris@1115: end Chris@1115: end Chris@1115: Chris@0: def test_reply_to_a_message Chris@0: m = submit_email('message_reply.eml') Chris@0: assert m.is_a?(Message) Chris@0: assert !m.new_record? Chris@0: m.reload Chris@0: assert_equal 'Reply via email', m.subject Chris@0: # The email replies to message #2 which is part of the thread of message #1 Chris@0: assert_equal Message.find(1), m.parent Chris@0: end Chris@441: Chris@0: def test_reply_to_a_message_by_subject Chris@0: m = submit_email('message_reply_by_subject.eml') Chris@0: assert m.is_a?(Message) Chris@0: assert !m.new_record? Chris@0: m.reload Chris@0: assert_equal 'Reply to the first post', m.subject Chris@0: assert_equal Message.find(1), m.parent Chris@0: end Chris@441: Chris@0: def test_should_strip_tags_of_html_only_emails Chris@0: issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'}) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: assert_equal 'HTML email', issue.subject Chris@0: assert_equal 'This is a html-only email.', issue.description Chris@0: end Chris@0: Chris@1464: test "truncate emails with no setting should add the entire email into the issue" do Chris@1464: with_settings :mail_handler_body_delimiters => '' do Chris@1464: issue = submit_email('ticket_on_given_project.eml') Chris@1464: assert_issue_created(issue) Chris@1464: assert issue.description.include?('---') Chris@1464: assert issue.description.include?('This paragraph is after the delimiter') Chris@1464: end Chris@1464: end Chris@0: Chris@1464: test "truncate emails with a single string should truncate the email at the delimiter for the issue" do Chris@1464: with_settings :mail_handler_body_delimiters => '---' do Chris@1464: issue = submit_email('ticket_on_given_project.eml') Chris@1464: assert_issue_created(issue) Chris@1464: assert issue.description.include?('This paragraph is before delimiters') Chris@1464: assert issue.description.include?('--- This line starts with a delimiter') Chris@1464: assert !issue.description.match(/^---$/) Chris@1464: assert !issue.description.include?('This paragraph is after the delimiter') Chris@0: end Chris@1464: end Chris@0: Chris@1464: test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do Chris@1464: with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do Chris@1464: journal = submit_email('issue_update_with_quoted_reply_above.eml') Chris@1464: assert journal.is_a?(Journal) Chris@1464: assert journal.notes.include?('An update to the issue by the sender.') Chris@1464: assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---")) Chris@1464: assert !journal.notes.include?('Looks like the JSON api for projects was missed.') Chris@0: end Chris@1464: end Chris@0: Chris@1464: test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do Chris@1464: with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do Chris@1464: journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml') Chris@1464: assert journal.is_a?(Journal) Chris@1464: assert journal.notes.include?('An update to the issue by the sender.') Chris@1464: assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---")) Chris@1464: assert !journal.notes.include?('Looks like the JSON api for projects was missed.') Chris@441: end Chris@1464: end chris@37: Chris@1464: test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do Chris@1464: with_settings :mail_handler_body_delimiters => "---\nBREAK" do Chris@1464: issue = submit_email('ticket_on_given_project.eml') Chris@1464: assert_issue_created(issue) Chris@1464: assert issue.description.include?('This paragraph is before delimiters') Chris@1464: assert !issue.description.include?('BREAK') Chris@1464: assert !issue.description.include?('This paragraph is between delimiters') Chris@1464: assert !issue.description.match(/^---$/) Chris@1464: assert !issue.description.include?('This paragraph is after the delimiter') chris@37: end Chris@1464: end chris@37: Chris@1464: def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored Chris@1464: with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do Chris@1464: issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'}) Chris@1464: assert issue.is_a?(Issue) Chris@1464: assert !issue.new_record? Chris@1464: assert_equal 0, issue.reload.attachments.size Chris@1464: end Chris@1464: end Chris@1464: Chris@1464: def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached Chris@1464: with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do Chris@1464: issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'}) Chris@1464: assert issue.is_a?(Issue) Chris@1464: assert !issue.new_record? Chris@1464: assert_equal 1, issue.reload.attachments.size Chris@0: end Chris@0: end Chris@441: Chris@0: def test_email_with_long_subject_line Chris@0: issue = submit_email('ticket_with_long_subject.eml') Chris@0: assert issue.is_a?(Issue) Chris@0: 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: end Chris@0: Chris@909: def test_new_user_from_attributes_should_return_valid_user Chris@909: to_test = { Chris@909: # [address, name] => [login, firstname, lastname] Chris@909: ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'], Chris@909: ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'], Chris@909: ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'], Chris@909: ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'], Chris@909: ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'], Chris@1115: ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh'] Chris@909: } Chris@909: Chris@909: to_test.each do |attrs, expected| Chris@909: user = MailHandler.new_user_from_attributes(attrs.first, attrs.last) Chris@909: Chris@1115: assert user.valid?, user.errors.full_messages.to_s Chris@909: assert_equal attrs.first, user.mail Chris@909: assert_equal expected[0], user.login Chris@909: assert_equal expected[1], user.firstname Chris@909: assert_equal expected[2], user.lastname Chris@1464: assert_equal 'only_my_events', user.mail_notification Chris@909: end Chris@909: end Chris@1115: Chris@909: def test_new_user_from_attributes_should_use_default_login_if_invalid Chris@1115: user = MailHandler.new_user_from_attributes('foo+bar@example.net') Chris@909: assert user.valid? Chris@909: assert user.login =~ /^user[a-f0-9]+$/ Chris@1115: assert_equal 'foo+bar@example.net', user.mail Chris@1115: end Chris@1115: Chris@1115: def test_new_user_with_utf8_encoded_fullname_should_be_decoded Chris@1115: assert_difference 'User.count' do Chris@1115: issue = submit_email( Chris@1115: 'fullname_of_sender_as_utf8_encoded.eml', Chris@1115: :issue => {:project => 'ecookbook'}, Chris@1115: :unknown_user => 'create' Chris@1115: ) Chris@1115: end Chris@1115: Chris@1115: user = User.first(:order => 'id DESC') Chris@1115: assert_equal "foo@example.org", user.mail Chris@1115: str1 = "\xc3\x84\xc3\xa4" Chris@1115: str2 = "\xc3\x96\xc3\xb6" Chris@1115: str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding) Chris@1115: str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding) Chris@1115: assert_equal str1, user.firstname Chris@1115: assert_equal str2, user.lastname Chris@909: end Chris@909: Chris@1464: def test_extract_options_from_env_should_return_options Chris@1464: options = MailHandler.extract_options_from_env({ Chris@1464: 'tracker' => 'defect', Chris@1464: 'project' => 'foo', Chris@1464: 'unknown_user' => 'create' Chris@1464: }) Chris@1464: Chris@1464: assert_equal({ Chris@1464: :issue => {:tracker => 'defect', :project => 'foo'}, Chris@1464: :unknown_user => 'create' Chris@1464: }, options) Chris@1464: end Chris@1464: Chris@0: private Chris@441: Chris@0: def submit_email(filename, options={}) Chris@0: raw = IO.read(File.join(FIXTURES_PATH, filename)) Chris@909: yield raw if block_given? Chris@0: MailHandler.receive(raw, options) Chris@0: end Chris@0: Chris@0: def assert_issue_created(issue) Chris@0: assert issue.is_a?(Issue) Chris@0: assert !issue.new_record? Chris@0: issue.reload Chris@0: end Chris@0: end