comparison .svn/pristine/ee/ee02de8ba27a6ddd79e1d7dd4cd71cc7bb5bbdac.svn-base @ 1296:038ba2d95de8 redmine-2.2

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