To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / .svn / pristine / 02 / 02c68441083bdea630158440f0e7d9d62ff8f790.svn-base @ 1298:4f746d8966dd

History | View | Annotate | Download (31.1 KB)

1 1295:622f24f53b42 Chris
# 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