comparison .svn/pristine/61/610fc0fcf3553bf4ce4a92445143d0e9e2a8ddd2.svn-base @ 1494:e248c7af89ec redmine-2.4

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