comparison .svn/pristine/02/02c68441083bdea630158440f0e7d9d62ff8f790.svn-base @ 1298:4f746d8966dd redmine_2.3_integration

Merge from redmine-2.3 branch to create new branch redmine-2.3-integration
author Chris Cannam
date Fri, 14 Jun 2013 09:28:30 +0100
parents 622f24f53b42
children
comparison
equal deleted inserted replaced
1297:0a574315af3e 1298:4f746d8966dd
1 # encoding: utf-8
2 #
3 # Redmine - project management software
4 # Copyright (C) 2006-2013 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_localized_attributes
374 User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
375 issue = submit_email(
376 'ticket_with_localized_attributes.eml',
377 :allow_override => 'tracker,category,priority'
378 )
379 assert issue.is_a?(Issue)
380 assert !issue.new_record?
381 issue.reload
382 assert_equal 'New ticket on a given project', issue.subject
383 assert_equal User.find_by_login('jsmith'), issue.author
384 assert_equal Project.find(2), issue.project
385 assert_equal 'Feature request', issue.tracker.to_s
386 assert_equal 'Stock management', issue.category.to_s
387 assert_equal 'Urgent', issue.priority.to_s
388 assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
389 end
390
391 def test_add_issue_with_japanese_keywords
392 ja_dev = "\xe9\x96\x8b\xe7\x99\xba"
393 ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding)
394 tracker = Tracker.create!(:name => ja_dev)
395 Project.find(1).trackers << tracker
396 issue = submit_email(
397 'japanese_keywords_iso_2022_jp.eml',
398 :issue => {:project => 'ecookbook'},
399 :allow_override => 'tracker'
400 )
401 assert_kind_of Issue, issue
402 assert_equal tracker, issue.tracker
403 end
404
405 def test_add_issue_from_apple_mail
406 issue = submit_email(
407 'apple_mail_with_attachment.eml',
408 :issue => {:project => 'ecookbook'}
409 )
410 assert_kind_of Issue, issue
411 assert_equal 1, issue.attachments.size
412
413 attachment = issue.attachments.first
414 assert_equal 'paella.jpg', attachment.filename
415 assert_equal 10790, attachment.filesize
416 assert File.exist?(attachment.diskfile)
417 assert_equal 10790, File.size(attachment.diskfile)
418 assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
419 end
420
421 def test_thunderbird_with_attachment_ja
422 issue = submit_email(
423 'thunderbird_with_attachment_ja.eml',
424 :issue => {:project => 'ecookbook'}
425 )
426 assert_kind_of Issue, issue
427 assert_equal 1, issue.attachments.size
428 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
429 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
430 attachment = issue.attachments.first
431 assert_equal ja, attachment.filename
432 assert_equal 5, attachment.filesize
433 assert File.exist?(attachment.diskfile)
434 assert_equal 5, File.size(attachment.diskfile)
435 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
436 end
437
438 def test_gmail_with_attachment_ja
439 issue = submit_email(
440 'gmail_with_attachment_ja.eml',
441 :issue => {:project => 'ecookbook'}
442 )
443 assert_kind_of Issue, issue
444 assert_equal 1, issue.attachments.size
445 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
446 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
447 attachment = issue.attachments.first
448 assert_equal ja, attachment.filename
449 assert_equal 5, attachment.filesize
450 assert File.exist?(attachment.diskfile)
451 assert_equal 5, File.size(attachment.diskfile)
452 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
453 end
454
455 def test_thunderbird_with_attachment_latin1
456 issue = submit_email(
457 'thunderbird_with_attachment_iso-8859-1.eml',
458 :issue => {:project => 'ecookbook'}
459 )
460 assert_kind_of Issue, issue
461 assert_equal 1, issue.attachments.size
462 u = ""
463 u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
464 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
465 u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
466 11.times { u << u1 }
467 attachment = issue.attachments.first
468 assert_equal "#{u}.png", attachment.filename
469 assert_equal 130, attachment.filesize
470 assert File.exist?(attachment.diskfile)
471 assert_equal 130, File.size(attachment.diskfile)
472 assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
473 end
474
475 def test_gmail_with_attachment_latin1
476 issue = submit_email(
477 'gmail_with_attachment_iso-8859-1.eml',
478 :issue => {:project => 'ecookbook'}
479 )
480 assert_kind_of Issue, issue
481 assert_equal 1, issue.attachments.size
482 u = ""
483 u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
484 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
485 u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
486 11.times { u << u1 }
487 attachment = issue.attachments.first
488 assert_equal "#{u}.txt", attachment.filename
489 assert_equal 5, attachment.filesize
490 assert File.exist?(attachment.diskfile)
491 assert_equal 5, File.size(attachment.diskfile)
492 assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
493 end
494
495 def test_add_issue_with_iso_8859_1_subject
496 issue = submit_email(
497 'subject_as_iso-8859-1.eml',
498 :issue => {:project => 'ecookbook'}
499 )
500 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..."
501 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
502 assert_kind_of Issue, issue
503 assert_equal str, issue.subject
504 end
505
506 def test_add_issue_with_japanese_subject
507 issue = submit_email(
508 'subject_japanese_1.eml',
509 :issue => {:project => 'ecookbook'}
510 )
511 assert_kind_of Issue, issue
512 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
513 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
514 assert_equal ja, issue.subject
515 end
516
517 def test_add_issue_with_no_subject_header
518 issue = submit_email(
519 'no_subject_header.eml',
520 :issue => {:project => 'ecookbook'}
521 )
522 assert_kind_of Issue, issue
523 assert_equal '(no subject)', issue.subject
524 end
525
526 def test_add_issue_with_mixed_japanese_subject
527 issue = submit_email(
528 'subject_japanese_2.eml',
529 :issue => {:project => 'ecookbook'}
530 )
531 assert_kind_of Issue, issue
532 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
533 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
534 assert_equal ja, issue.subject
535 end
536
537 def test_should_ignore_emails_from_locked_users
538 User.find(2).lock!
539
540 MailHandler.any_instance.expects(:dispatch).never
541 assert_no_difference 'Issue.count' do
542 assert_equal false, submit_email('ticket_on_given_project.eml')
543 end
544 end
545
546 def test_should_ignore_emails_from_emission_address
547 Role.anonymous.add_permission!(:add_issues)
548 assert_no_difference 'User.count' do
549 assert_equal false,
550 submit_email(
551 'ticket_from_emission_address.eml',
552 :issue => {:project => 'ecookbook'},
553 :unknown_user => 'create'
554 )
555 end
556 end
557
558 def test_should_ignore_auto_replied_emails
559 MailHandler.any_instance.expects(:dispatch).never
560 [
561 "X-Auto-Response-Suppress: OOF",
562 "Auto-Submitted: auto-replied",
563 "Auto-Submitted: Auto-Replied",
564 "Auto-Submitted: auto-generated"
565 ].each do |header|
566 raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
567 raw = header + "\n" + raw
568
569 assert_no_difference 'Issue.count' do
570 assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
571 end
572 end
573 end
574
575 def test_add_issue_should_send_email_notification
576 Setting.notified_events = ['issue_added']
577 ActionMailer::Base.deliveries.clear
578 # This email contains: 'Project: onlinestore'
579 issue = submit_email('ticket_on_given_project.eml')
580 assert issue.is_a?(Issue)
581 assert_equal 1, ActionMailer::Base.deliveries.size
582 end
583
584 def test_update_issue
585 journal = submit_email('ticket_reply.eml')
586 assert journal.is_a?(Journal)
587 assert_equal User.find_by_login('jsmith'), journal.user
588 assert_equal Issue.find(2), journal.journalized
589 assert_match /This is reply/, journal.notes
590 assert_equal false, journal.private_notes
591 assert_equal 'Feature request', journal.issue.tracker.name
592 end
593
594 def test_update_issue_with_attribute_changes
595 # This email contains: 'Status: Resolved'
596 journal = submit_email('ticket_reply_with_status.eml')
597 assert journal.is_a?(Journal)
598 issue = Issue.find(journal.issue.id)
599 assert_equal User.find_by_login('jsmith'), journal.user
600 assert_equal Issue.find(2), journal.journalized
601 assert_match /This is reply/, journal.notes
602 assert_equal 'Feature request', journal.issue.tracker.name
603 assert_equal IssueStatus.find_by_name("Resolved"), issue.status
604 assert_equal '2010-01-01', issue.start_date.to_s
605 assert_equal '2010-12-31', issue.due_date.to_s
606 assert_equal User.find_by_login('jsmith'), issue.assigned_to
607 assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
608 # keywords should be removed from the email body
609 assert !journal.notes.match(/^Status:/i)
610 assert !journal.notes.match(/^Start Date:/i)
611 end
612
613 def test_update_issue_with_attachment
614 assert_difference 'Journal.count' do
615 assert_difference 'JournalDetail.count' do
616 assert_difference 'Attachment.count' do
617 assert_no_difference 'Issue.count' do
618 journal = submit_email('ticket_with_attachment.eml') do |raw|
619 raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
620 end
621 end
622 end
623 end
624 end
625 journal = Journal.first(:order => 'id DESC')
626 assert_equal Issue.find(2), journal.journalized
627 assert_equal 1, journal.details.size
628
629 detail = journal.details.first
630 assert_equal 'attachment', detail.property
631 assert_equal 'Paella.jpg', detail.value
632 end
633
634 def test_update_issue_should_send_email_notification
635 ActionMailer::Base.deliveries.clear
636 journal = submit_email('ticket_reply.eml')
637 assert journal.is_a?(Journal)
638 assert_equal 1, ActionMailer::Base.deliveries.size
639 end
640
641 def test_update_issue_should_not_set_defaults
642 journal = submit_email(
643 'ticket_reply.eml',
644 :issue => {:tracker => 'Support request', :priority => 'High'}
645 )
646 assert journal.is_a?(Journal)
647 assert_match /This is reply/, journal.notes
648 assert_equal 'Feature request', journal.issue.tracker.name
649 assert_equal 'Normal', journal.issue.priority.name
650 end
651
652 def test_replying_to_a_private_note_should_add_reply_as_private
653 private_journal = Journal.create!(:notes => 'Private notes', :journalized => Issue.find(1), :private_notes => true, :user_id => 2)
654
655 assert_difference 'Journal.count' do
656 journal = submit_email('ticket_reply.eml') do |email|
657 email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
658 end
659
660 assert_kind_of Journal, journal
661 assert_match /This is reply/, journal.notes
662 assert_equal true, journal.private_notes
663 end
664 end
665
666 def test_reply_to_a_message
667 m = submit_email('message_reply.eml')
668 assert m.is_a?(Message)
669 assert !m.new_record?
670 m.reload
671 assert_equal 'Reply via email', m.subject
672 # The email replies to message #2 which is part of the thread of message #1
673 assert_equal Message.find(1), m.parent
674 end
675
676 def test_reply_to_a_message_by_subject
677 m = submit_email('message_reply_by_subject.eml')
678 assert m.is_a?(Message)
679 assert !m.new_record?
680 m.reload
681 assert_equal 'Reply to the first post', m.subject
682 assert_equal Message.find(1), m.parent
683 end
684
685 def test_should_strip_tags_of_html_only_emails
686 issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
687 assert issue.is_a?(Issue)
688 assert !issue.new_record?
689 issue.reload
690 assert_equal 'HTML email', issue.subject
691 assert_equal 'This is a html-only email.', issue.description
692 end
693
694 test "truncate emails with no setting should add the entire email into the issue" do
695 with_settings :mail_handler_body_delimiters => '' do
696 issue = submit_email('ticket_on_given_project.eml')
697 assert_issue_created(issue)
698 assert issue.description.include?('---')
699 assert issue.description.include?('This paragraph is after the delimiter')
700 end
701 end
702
703 test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
704 with_settings :mail_handler_body_delimiters => '---' do
705 issue = submit_email('ticket_on_given_project.eml')
706 assert_issue_created(issue)
707 assert issue.description.include?('This paragraph is before delimiters')
708 assert issue.description.include?('--- This line starts with a delimiter')
709 assert !issue.description.match(/^---$/)
710 assert !issue.description.include?('This paragraph is after the delimiter')
711 end
712 end
713
714 test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
715 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
716 journal = submit_email('issue_update_with_quoted_reply_above.eml')
717 assert journal.is_a?(Journal)
718 assert journal.notes.include?('An update to the issue by the sender.')
719 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
720 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
721 end
722 end
723
724 test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
725 with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
726 journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
727 assert journal.is_a?(Journal)
728 assert journal.notes.include?('An update to the issue by the sender.')
729 assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
730 assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
731 end
732 end
733
734 test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
735 with_settings :mail_handler_body_delimiters => "---\nBREAK" do
736 issue = submit_email('ticket_on_given_project.eml')
737 assert_issue_created(issue)
738 assert issue.description.include?('This paragraph is before delimiters')
739 assert !issue.description.include?('BREAK')
740 assert !issue.description.include?('This paragraph is between delimiters')
741 assert !issue.description.match(/^---$/)
742 assert !issue.description.include?('This paragraph is after the delimiter')
743 end
744 end
745
746 def test_email_with_long_subject_line
747 issue = submit_email('ticket_with_long_subject.eml')
748 assert issue.is_a?(Issue)
749 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]
750 end
751
752 def test_new_user_from_attributes_should_return_valid_user
753 to_test = {
754 # [address, name] => [login, firstname, lastname]
755 ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
756 ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
757 ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
758 ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
759 ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] => ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
760 ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] => ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
761 }
762
763 to_test.each do |attrs, expected|
764 user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
765
766 assert user.valid?, user.errors.full_messages.to_s
767 assert_equal attrs.first, user.mail
768 assert_equal expected[0], user.login
769 assert_equal expected[1], user.firstname
770 assert_equal expected[2], user.lastname
771 assert_equal 'only_my_events', user.mail_notification
772 end
773 end
774
775 def test_new_user_from_attributes_should_respect_minimum_password_length
776 with_settings :password_min_length => 15 do
777 user = MailHandler.new_user_from_attributes('jsmith@example.net')
778 assert user.valid?
779 assert user.password.length >= 15
780 end
781 end
782
783 def test_new_user_from_attributes_should_use_default_login_if_invalid
784 user = MailHandler.new_user_from_attributes('foo+bar@example.net')
785 assert user.valid?
786 assert user.login =~ /^user[a-f0-9]+$/
787 assert_equal 'foo+bar@example.net', user.mail
788 end
789
790 def test_new_user_with_utf8_encoded_fullname_should_be_decoded
791 assert_difference 'User.count' do
792 issue = submit_email(
793 'fullname_of_sender_as_utf8_encoded.eml',
794 :issue => {:project => 'ecookbook'},
795 :unknown_user => 'create'
796 )
797 end
798
799 user = User.first(:order => 'id DESC')
800 assert_equal "foo@example.org", user.mail
801 str1 = "\xc3\x84\xc3\xa4"
802 str2 = "\xc3\x96\xc3\xb6"
803 str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
804 str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding)
805 assert_equal str1, user.firstname
806 assert_equal str2, user.lastname
807 end
808
809 private
810
811 def submit_email(filename, options={})
812 raw = IO.read(File.join(FIXTURES_PATH, filename))
813 yield raw if block_given?
814 MailHandler.receive(raw, options)
815 end
816
817 def assert_issue_created(issue)
818 assert issue.is_a?(Issue)
819 assert !issue.new_record?
820 issue.reload
821 end
822 end