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 / test / unit / mail_handler_test.rb @ 441:cbce1fd3b1b7

History | View | Annotate | Download (18.7 KB)

1 0:513646585e45 Chris
# encoding: utf-8
2
#
3
# Redmine - project management software
4 441:cbce1fd3b1b7 Chris
# Copyright (C) 2006-2011  Jean-Philippe Lang
5 0:513646585e45 Chris
#
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 441:cbce1fd3b1b7 Chris
#
11 0:513646585e45 Chris
# 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 441:cbce1fd3b1b7 Chris
#
16 0:513646585e45 Chris
# 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 119:8661b858af72 Chris
require File.expand_path('../../test_helper', __FILE__)
21 0:513646585e45 Chris
22
class MailHandlerTest < ActiveSupport::TestCase
23 441:cbce1fd3b1b7 Chris
  fixtures :users, :projects,
24 0:513646585e45 Chris
                   :enabled_modules,
25
                   :roles,
26
                   :members,
27
                   :member_roles,
28 37:94944d00e43c chris
                   :users,
29 0:513646585e45 Chris
                   :issues,
30
                   :issue_statuses,
31
                   :workflows,
32
                   :trackers,
33
                   :projects_trackers,
34 37:94944d00e43c chris
                   :versions,
35 0:513646585e45 Chris
                   :enumerations,
36
                   :issue_categories,
37
                   :custom_fields,
38
                   :custom_fields_trackers,
39 119:8661b858af72 Chris
                   :custom_fields_projects,
40 0:513646585e45 Chris
                   :boards,
41
                   :messages
42 441:cbce1fd3b1b7 Chris
43 0:513646585e45 Chris
  FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
44 441:cbce1fd3b1b7 Chris
45 0:513646585e45 Chris
  def setup
46
    ActionMailer::Base.deliveries.clear
47 37:94944d00e43c chris
    Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
48 0:513646585e45 Chris
  end
49 441:cbce1fd3b1b7 Chris
50 0:513646585e45 Chris
  def test_add_issue
51
    ActionMailer::Base.deliveries.clear
52
    # This email contains: 'Project: onlinestore'
53
    issue = submit_email('ticket_on_given_project.eml')
54
    assert issue.is_a?(Issue)
55
    assert !issue.new_record?
56
    issue.reload
57 119:8661b858af72 Chris
    assert_equal Project.find(2), issue.project
58
    assert_equal issue.project.trackers.first, issue.tracker
59 0:513646585e45 Chris
    assert_equal 'New ticket on a given project', issue.subject
60
    assert_equal User.find_by_login('jsmith'), issue.author
61
    assert_equal IssueStatus.find_by_name('Resolved'), issue.status
62
    assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
63
    assert_equal '2010-01-01', issue.start_date.to_s
64
    assert_equal '2010-12-31', issue.due_date.to_s
65
    assert_equal User.find_by_login('jsmith'), issue.assigned_to
66 37:94944d00e43c chris
    assert_equal Version.find_by_name('alpha'), issue.fixed_version
67
    assert_equal 2.5, issue.estimated_hours
68
    assert_equal 30, issue.done_ratio
69 119:8661b858af72 Chris
    assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt]
70 0:513646585e45 Chris
    # keywords should be removed from the email body
71
    assert !issue.description.match(/^Project:/i)
72
    assert !issue.description.match(/^Status:/i)
73 441:cbce1fd3b1b7 Chris
    assert !issue.description.match(/^Start Date:/i)
74 0:513646585e45 Chris
    # Email notification should be sent
75
    mail = ActionMailer::Base.deliveries.last
76
    assert_not_nil mail
77
    assert mail.subject.include?('New ticket on a given project')
78
  end
79 441:cbce1fd3b1b7 Chris
80 119:8661b858af72 Chris
  def test_add_issue_with_default_tracker
81
    # This email contains: 'Project: onlinestore'
82
    issue = submit_email('ticket_on_given_project.eml', :issue => {:tracker => 'Support request'})
83
    assert issue.is_a?(Issue)
84
    assert !issue.new_record?
85
    issue.reload
86
    assert_equal 'Support request', issue.tracker.name
87
  end
88 0:513646585e45 Chris
89
  def test_add_issue_with_status
90
    # This email contains: 'Project: onlinestore' and 'Status: Resolved'
91
    issue = submit_email('ticket_on_given_project.eml')
92
    assert issue.is_a?(Issue)
93
    assert !issue.new_record?
94
    issue.reload
95
    assert_equal Project.find(2), issue.project
96
    assert_equal IssueStatus.find_by_name("Resolved"), issue.status
97
  end
98 441:cbce1fd3b1b7 Chris
99 0:513646585e45 Chris
  def test_add_issue_with_attributes_override
100
    issue = submit_email('ticket_with_attributes.eml', :allow_override => 'tracker,category,priority')
101
    assert issue.is_a?(Issue)
102
    assert !issue.new_record?
103
    issue.reload
104
    assert_equal 'New ticket on a given project', issue.subject
105
    assert_equal User.find_by_login('jsmith'), issue.author
106
    assert_equal Project.find(2), issue.project
107
    assert_equal 'Feature request', issue.tracker.to_s
108
    assert_equal 'Stock management', issue.category.to_s
109
    assert_equal 'Urgent', issue.priority.to_s
110
    assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
111
  end
112 441:cbce1fd3b1b7 Chris
113 0:513646585e45 Chris
  def test_add_issue_with_partial_attributes_override
114
    issue = submit_email('ticket_with_attributes.eml', :issue => {:priority => 'High'}, :allow_override => ['tracker'])
115
    assert issue.is_a?(Issue)
116
    assert !issue.new_record?
117
    issue.reload
118
    assert_equal 'New ticket on a given project', issue.subject
119
    assert_equal User.find_by_login('jsmith'), issue.author
120
    assert_equal Project.find(2), issue.project
121
    assert_equal 'Feature request', issue.tracker.to_s
122
    assert_nil issue.category
123
    assert_equal 'High', issue.priority.to_s
124
    assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
125
  end
126 441:cbce1fd3b1b7 Chris
127 0:513646585e45 Chris
  def test_add_issue_with_spaces_between_attribute_and_separator
128
    issue = submit_email('ticket_with_spaces_between_attribute_and_separator.eml', :allow_override => 'tracker,category,priority')
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_equal 'Stock management', issue.category.to_s
137
    assert_equal 'Urgent', 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_attachment_to_specific_project
142
    issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
143
    assert issue.is_a?(Issue)
144
    assert !issue.new_record?
145
    issue.reload
146
    assert_equal 'Ticket created by email with attachment', issue.subject
147
    assert_equal User.find_by_login('jsmith'), issue.author
148
    assert_equal Project.find(2), issue.project
149
    assert_equal 'This is  a new ticket with attachments', issue.description
150
    # Attachment properties
151
    assert_equal 1, issue.attachments.size
152
    assert_equal 'Paella.jpg', issue.attachments.first.filename
153
    assert_equal 'image/jpeg', issue.attachments.first.content_type
154
    assert_equal 10790, issue.attachments.first.filesize
155
  end
156 441:cbce1fd3b1b7 Chris
157 0:513646585e45 Chris
  def test_add_issue_with_custom_fields
158
    issue = submit_email('ticket_with_custom_fields.eml', :issue => {:project => 'onlinestore'})
159
    assert issue.is_a?(Issue)
160
    assert !issue.new_record?
161
    issue.reload
162
    assert_equal 'New ticket with custom field values', issue.subject
163
    assert_equal 'Value for a custom field', issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
164
    assert !issue.description.match(/^searchable field:/i)
165
  end
166 441:cbce1fd3b1b7 Chris
167 0:513646585e45 Chris
  def test_add_issue_with_cc
168
    issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
169
    assert issue.is_a?(Issue)
170
    assert !issue.new_record?
171
    issue.reload
172
    assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
173 37:94944d00e43c chris
    assert_equal 1, issue.watcher_user_ids.size
174 0:513646585e45 Chris
  end
175 441:cbce1fd3b1b7 Chris
176 0:513646585e45 Chris
  def test_add_issue_by_unknown_user
177
    assert_no_difference 'User.count' do
178
      assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'})
179
    end
180
  end
181 441:cbce1fd3b1b7 Chris
182 0:513646585e45 Chris
  def test_add_issue_by_anonymous_user
183
    Role.anonymous.add_permission!(:add_issues)
184
    assert_no_difference 'User.count' do
185
      issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
186
      assert issue.is_a?(Issue)
187
      assert issue.author.anonymous?
188
    end
189
  end
190
191
  def test_add_issue_by_anonymous_user_with_no_from_address
192
    Role.anonymous.add_permission!(:add_issues)
193
    assert_no_difference 'User.count' do
194
      issue = submit_email('ticket_by_empty_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'accept')
195
      assert issue.is_a?(Issue)
196
      assert issue.author.anonymous?
197
    end
198
  end
199 441:cbce1fd3b1b7 Chris
200 0:513646585e45 Chris
  def test_add_issue_by_anonymous_user_on_private_project
201
    Role.anonymous.add_permission!(:add_issues)
202
    assert_no_difference 'User.count' do
203
      assert_no_difference 'Issue.count' do
204
        assert_equal false, submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :unknown_user => 'accept')
205
      end
206
    end
207
  end
208 441:cbce1fd3b1b7 Chris
209 0:513646585e45 Chris
  def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
210
    assert_no_difference 'User.count' do
211
      assert_difference 'Issue.count' do
212
        issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'onlinestore'}, :no_permission_check => '1', :unknown_user => 'accept')
213
        assert issue.is_a?(Issue)
214
        assert issue.author.anonymous?
215
        assert !issue.project.is_public?
216 119:8661b858af72 Chris
        assert_equal [issue.id, 1, 2], [issue.root_id, issue.lft, issue.rgt]
217 0:513646585e45 Chris
      end
218
    end
219
  end
220 441:cbce1fd3b1b7 Chris
221 0:513646585e45 Chris
  def test_add_issue_by_created_user
222
    Setting.default_language = 'en'
223
    assert_difference 'User.count' do
224
      issue = submit_email('ticket_by_unknown_user.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
225
      assert issue.is_a?(Issue)
226
      assert issue.author.active?
227
      assert_equal 'john.doe@somenet.foo', issue.author.mail
228
      assert_equal 'John', issue.author.firstname
229
      assert_equal 'Doe', issue.author.lastname
230 441:cbce1fd3b1b7 Chris
231 0:513646585e45 Chris
      # account information
232
      email = ActionMailer::Base.deliveries.first
233
      assert_not_nil email
234
      assert email.subject.include?('account activation')
235
      login = email.body.match(/\* Login: (.*)$/)[1]
236
      password = email.body.match(/\* Password: (.*)$/)[1]
237
      assert_equal issue.author, User.try_to_login(login, password)
238
    end
239
  end
240 441:cbce1fd3b1b7 Chris
241 0:513646585e45 Chris
  def test_add_issue_without_from_header
242
    Role.anonymous.add_permission!(:add_issues)
243
    assert_equal false, submit_email('ticket_without_from_header.eml')
244
  end
245 37:94944d00e43c chris
246
  def test_add_issue_with_invalid_attributes
247
    issue = submit_email('ticket_with_invalid_attributes.eml', :allow_override => 'tracker,category,priority')
248
    assert issue.is_a?(Issue)
249
    assert !issue.new_record?
250
    issue.reload
251
    assert_nil issue.assigned_to
252
    assert_nil issue.start_date
253
    assert_nil issue.due_date
254
    assert_equal 0, issue.done_ratio
255
    assert_equal 'Normal', issue.priority.to_s
256
    assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
257
  end
258
259
  def test_add_issue_with_localized_attributes
260
    User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
261
    issue = submit_email('ticket_with_localized_attributes.eml', :allow_override => 'tracker,category,priority')
262
    assert issue.is_a?(Issue)
263
    assert !issue.new_record?
264
    issue.reload
265
    assert_equal 'New ticket on a given project', issue.subject
266
    assert_equal User.find_by_login('jsmith'), issue.author
267
    assert_equal Project.find(2), issue.project
268
    assert_equal 'Feature request', issue.tracker.to_s
269
    assert_equal 'Stock management', issue.category.to_s
270
    assert_equal 'Urgent', issue.priority.to_s
271
    assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
272
  end
273 441:cbce1fd3b1b7 Chris
274 0:513646585e45 Chris
  def test_add_issue_with_japanese_keywords
275
    tracker = Tracker.create!(:name => '開発')
276
    Project.find(1).trackers << tracker
277
    issue = submit_email('japanese_keywords_iso_2022_jp.eml', :issue => {:project => 'ecookbook'}, :allow_override => 'tracker')
278
    assert_kind_of Issue, issue
279
    assert_equal tracker, issue.tracker
280
  end
281
282
  def test_should_ignore_emails_from_emission_address
283
    Role.anonymous.add_permission!(:add_issues)
284
    assert_no_difference 'User.count' do
285
      assert_equal false, submit_email('ticket_from_emission_address.eml', :issue => {:project => 'ecookbook'}, :unknown_user => 'create')
286
    end
287
  end
288
289
  def test_add_issue_should_send_email_notification
290 37:94944d00e43c chris
    Setting.notified_events = ['issue_added']
291 0:513646585e45 Chris
    ActionMailer::Base.deliveries.clear
292
    # This email contains: 'Project: onlinestore'
293
    issue = submit_email('ticket_on_given_project.eml')
294
    assert issue.is_a?(Issue)
295
    assert_equal 1, ActionMailer::Base.deliveries.size
296
  end
297 441:cbce1fd3b1b7 Chris
298 0:513646585e45 Chris
  def test_add_issue_note
299
    journal = submit_email('ticket_reply.eml')
300
    assert journal.is_a?(Journal)
301
    assert_equal User.find_by_login('jsmith'), journal.user
302
    assert_equal Issue.find(2), journal.journalized
303
    assert_match /This is reply/, journal.notes
304 119:8661b858af72 Chris
    assert_equal 'Feature request', journal.issue.tracker.name
305 0:513646585e45 Chris
  end
306
307
  def test_add_issue_note_with_attribute_changes
308
    # This email contains: 'Status: Resolved'
309
    journal = submit_email('ticket_reply_with_status.eml')
310
    assert journal.is_a?(Journal)
311
    issue = Issue.find(journal.issue.id)
312
    assert_equal User.find_by_login('jsmith'), journal.user
313
    assert_equal Issue.find(2), journal.journalized
314
    assert_match /This is reply/, journal.notes
315 119:8661b858af72 Chris
    assert_equal 'Feature request', journal.issue.tracker.name
316 0:513646585e45 Chris
    assert_equal IssueStatus.find_by_name("Resolved"), issue.status
317
    assert_equal '2010-01-01', issue.start_date.to_s
318
    assert_equal '2010-12-31', issue.due_date.to_s
319
    assert_equal User.find_by_login('jsmith'), issue.assigned_to
320 119:8661b858af72 Chris
    assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
321 441:cbce1fd3b1b7 Chris
    # keywords should be removed from the email body
322
    assert !journal.notes.match(/^Status:/i)
323
    assert !journal.notes.match(/^Start Date:/i)
324 0:513646585e45 Chris
  end
325
326
  def test_add_issue_note_should_send_email_notification
327
    ActionMailer::Base.deliveries.clear
328
    journal = submit_email('ticket_reply.eml')
329
    assert journal.is_a?(Journal)
330
    assert_equal 1, ActionMailer::Base.deliveries.size
331
  end
332 441:cbce1fd3b1b7 Chris
333 119:8661b858af72 Chris
  def test_add_issue_note_should_not_set_defaults
334
    journal = submit_email('ticket_reply.eml', :issue => {:tracker => 'Support request', :priority => 'High'})
335
    assert journal.is_a?(Journal)
336
    assert_match /This is reply/, journal.notes
337
    assert_equal 'Feature request', journal.issue.tracker.name
338
    assert_equal 'Normal', journal.issue.priority.name
339
  end
340 441:cbce1fd3b1b7 Chris
341 0:513646585e45 Chris
  def test_reply_to_a_message
342
    m = submit_email('message_reply.eml')
343
    assert m.is_a?(Message)
344
    assert !m.new_record?
345
    m.reload
346
    assert_equal 'Reply via email', m.subject
347
    # The email replies to message #2 which is part of the thread of message #1
348
    assert_equal Message.find(1), m.parent
349
  end
350 441:cbce1fd3b1b7 Chris
351 0:513646585e45 Chris
  def test_reply_to_a_message_by_subject
352
    m = submit_email('message_reply_by_subject.eml')
353
    assert m.is_a?(Message)
354
    assert !m.new_record?
355
    m.reload
356
    assert_equal 'Reply to the first post', m.subject
357
    assert_equal Message.find(1), m.parent
358
  end
359 441:cbce1fd3b1b7 Chris
360 0:513646585e45 Chris
  def test_should_strip_tags_of_html_only_emails
361
    issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
362
    assert issue.is_a?(Issue)
363
    assert !issue.new_record?
364
    issue.reload
365
    assert_equal 'HTML email', issue.subject
366
    assert_equal 'This is a html-only email.', issue.description
367
  end
368
369
  context "truncate emails based on the Setting" do
370
    context "with no setting" do
371
      setup do
372
        Setting.mail_handler_body_delimiters = ''
373
      end
374
375
      should "add the entire email into the issue" do
376
        issue = submit_email('ticket_on_given_project.eml')
377
        assert_issue_created(issue)
378
        assert issue.description.include?('---')
379
        assert issue.description.include?('This paragraph is after the delimiter')
380
      end
381
    end
382
383
    context "with a single string" do
384
      setup do
385
        Setting.mail_handler_body_delimiters = '---'
386
      end
387
      should "truncate the email at the delimiter for the issue" do
388
        issue = submit_email('ticket_on_given_project.eml')
389
        assert_issue_created(issue)
390
        assert issue.description.include?('This paragraph is before delimiters')
391
        assert issue.description.include?('--- This line starts with a delimiter')
392
        assert !issue.description.match(/^---$/)
393
        assert !issue.description.include?('This paragraph is after the delimiter')
394
      end
395
    end
396
397 37:94944d00e43c chris
    context "with a single quoted reply (e.g. reply to a Redmine email notification)" do
398
      setup do
399
        Setting.mail_handler_body_delimiters = '--- Reply above. Do not remove this line. ---'
400
      end
401
      should "truncate the email at the delimiter with the quoted reply symbols (>)" do
402
        journal = submit_email('issue_update_with_quoted_reply_above.eml')
403
        assert journal.is_a?(Journal)
404
        assert journal.notes.include?('An update to the issue by the sender.')
405
        assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
406
        assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
407 441:cbce1fd3b1b7 Chris
      end
408
    end
409 37:94944d00e43c chris
410
    context "with multiple quoted replies (e.g. reply to a reply of a Redmine email notification)" do
411
      setup do
412
        Setting.mail_handler_body_delimiters = '--- Reply above. Do not remove this line. ---'
413
      end
414
      should "truncate the email at the delimiter with the quoted reply symbols (>)" do
415
        journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
416
        assert journal.is_a?(Journal)
417
        assert journal.notes.include?('An update to the issue by the sender.')
418
        assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
419
        assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
420
      end
421
    end
422
423 0:513646585e45 Chris
    context "with multiple strings" do
424
      setup do
425
        Setting.mail_handler_body_delimiters = "---\nBREAK"
426
      end
427
      should "truncate the email at the first delimiter found (BREAK)" do
428
        issue = submit_email('ticket_on_given_project.eml')
429
        assert_issue_created(issue)
430
        assert issue.description.include?('This paragraph is before delimiters')
431
        assert !issue.description.include?('BREAK')
432
        assert !issue.description.include?('This paragraph is between delimiters')
433
        assert !issue.description.match(/^---$/)
434
        assert !issue.description.include?('This paragraph is after the delimiter')
435
      end
436
    end
437
  end
438 441:cbce1fd3b1b7 Chris
439 0:513646585e45 Chris
  def test_email_with_long_subject_line
440
    issue = submit_email('ticket_with_long_subject.eml')
441
    assert issue.is_a?(Issue)
442
    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]
443
  end
444
445
  private
446 441:cbce1fd3b1b7 Chris
447 0:513646585e45 Chris
  def submit_email(filename, options={})
448
    raw = IO.read(File.join(FIXTURES_PATH, filename))
449
    MailHandler.receive(raw, options)
450
  end
451
452
  def assert_issue_created(issue)
453
    assert issue.is_a?(Issue)
454
    assert !issue.new_record?
455
    issue.reload
456
  end
457
end