You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mail_handler_test.rb 45KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. # encoding: utf-8
  2. #
  3. # Redmine - project management software
  4. # Copyright (C) 2006-2017 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. require File.expand_path('../../test_helper', __FILE__)
  20. class MailHandlerTest < ActiveSupport::TestCase
  21. fixtures :users, :projects, :enabled_modules, :roles,
  22. :members, :member_roles, :users,
  23. :email_addresses, :user_preferences,
  24. :issues, :issue_statuses,
  25. :workflows, :trackers, :projects_trackers,
  26. :versions, :enumerations, :issue_categories,
  27. :custom_fields, :custom_fields_trackers, :custom_fields_projects,
  28. :boards, :messages
  29. FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
  30. def setup
  31. ActionMailer::Base.deliveries.clear
  32. Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
  33. User.current = nil
  34. end
  35. def teardown
  36. Setting.clear_cache
  37. end
  38. def test_add_issue_with_specific_overrides
  39. issue = submit_email('ticket_on_given_project.eml',
  40. :allow_override => ['status', 'start_date', 'due_date', 'assigned_to',
  41. 'fixed_version', 'estimated_hours', 'done_ratio', 'parent_issue']
  42. )
  43. assert issue.is_a?(Issue)
  44. assert !issue.new_record?
  45. issue.reload
  46. assert_equal Project.find(2), issue.project
  47. assert_equal issue.project.trackers.first, issue.tracker
  48. assert_equal 'New ticket on a given project', issue.subject
  49. assert_equal User.find_by_login('jsmith'), issue.author
  50. assert_equal IssueStatus.find_by_name('Resolved'), issue.status
  51. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  52. assert_equal '2010-01-01', issue.start_date.to_s
  53. assert_equal '2010-12-31', issue.due_date.to_s
  54. assert_equal User.find_by_login('jsmith'), issue.assigned_to
  55. assert_equal Version.find_by_name('Alpha'), issue.fixed_version
  56. assert_equal 2.5, issue.estimated_hours
  57. assert_equal 30, issue.done_ratio
  58. assert_equal Issue.find(4), issue.parent
  59. # keywords should be removed from the email body
  60. assert !issue.description.match(/^Project:/i)
  61. assert !issue.description.match(/^Status:/i)
  62. assert !issue.description.match(/^Start Date:/i)
  63. end
  64. def test_add_issue_with_all_overrides
  65. issue = submit_email('ticket_on_given_project.eml', :allow_override => 'all')
  66. assert issue.is_a?(Issue)
  67. assert !issue.new_record?
  68. issue.reload
  69. assert_equal Project.find(2), issue.project
  70. assert_equal issue.project.trackers.first, issue.tracker
  71. assert_equal IssueStatus.find_by_name('Resolved'), issue.status
  72. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  73. assert_equal '2010-01-01', issue.start_date.to_s
  74. assert_equal '2010-12-31', issue.due_date.to_s
  75. assert_equal User.find_by_login('jsmith'), issue.assigned_to
  76. assert_equal Version.find_by_name('Alpha'), issue.fixed_version
  77. assert_equal 2.5, issue.estimated_hours
  78. assert_equal 30, issue.done_ratio
  79. assert_equal Issue.find(4), issue.parent
  80. end
  81. def test_add_issue_without_overrides_should_ignore_attributes
  82. WorkflowRule.delete_all
  83. issue = submit_email('ticket_on_given_project.eml')
  84. assert issue.is_a?(Issue)
  85. assert !issue.new_record?
  86. issue.reload
  87. assert_equal Project.find(2), issue.project
  88. assert_equal 'New ticket on a given project', issue.subject
  89. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  90. assert_equal User.find_by_login('jsmith'), issue.author
  91. assert_equal issue.project.trackers.first, issue.tracker
  92. assert_equal 'New', issue.status.name
  93. assert_not_equal '2010-01-01', issue.start_date.to_s
  94. assert_nil issue.due_date
  95. assert_nil issue.assigned_to
  96. assert_nil issue.fixed_version
  97. assert_nil issue.estimated_hours
  98. assert_equal 0, issue.done_ratio
  99. assert_nil issue.parent
  100. end
  101. def test_add_issue_to_project_specified_by_subaddress
  102. # This email has redmine+onlinestore@somenet.foo as 'To' header
  103. issue = submit_email(
  104. 'ticket_on_project_given_by_to_header.eml',
  105. :issue => {:tracker => 'Support request'},
  106. :project_from_subaddress => 'redmine@somenet.foo'
  107. )
  108. assert issue.is_a?(Issue)
  109. assert !issue.new_record?
  110. issue.reload
  111. assert_equal 'onlinestore', issue.project.identifier
  112. assert_equal 'Support request', issue.tracker.name
  113. end
  114. def test_add_issue_with_default_tracker
  115. # This email contains: 'Project: onlinestore'
  116. issue = submit_email(
  117. 'ticket_on_given_project.eml',
  118. :issue => {:tracker => 'Support request'}
  119. )
  120. assert issue.is_a?(Issue)
  121. assert !issue.new_record?
  122. issue.reload
  123. assert_equal 'Support request', issue.tracker.name
  124. end
  125. def test_add_issue_with_default_version
  126. # This email contains: 'Project: onlinestore'
  127. issue = submit_email(
  128. 'ticket_on_given_project.eml',
  129. :issue => {:fixed_version => 'Alpha'}
  130. )
  131. assert issue.is_a?(Issue)
  132. assert !issue.new_record?
  133. assert_equal 'Alpha', issue.reload.fixed_version.name
  134. end
  135. def test_add_issue_with_default_assigned_to
  136. # This email contains: 'Project: onlinestore'
  137. issue = submit_email(
  138. 'ticket_on_given_project.eml',
  139. :issue => {:assigned_to => 'jsmith'}
  140. )
  141. assert issue.is_a?(Issue)
  142. assert !issue.new_record?
  143. assert_equal 'jsmith', issue.reload.assigned_to.login
  144. end
  145. def test_add_issue_with_status_override
  146. # This email contains: 'Project: onlinestore' and 'Status: Resolved'
  147. issue = submit_email('ticket_on_given_project.eml', :allow_override => ['status'])
  148. assert issue.is_a?(Issue)
  149. assert !issue.new_record?
  150. issue.reload
  151. assert_equal Project.find(2), issue.project
  152. assert_equal IssueStatus.find_by_name("Resolved"), issue.status
  153. end
  154. def test_add_issue_should_accept_is_private_attribute
  155. issue = submit_email('ticket_on_given_project.eml', :issue => {:is_private => '1'})
  156. assert issue.is_a?(Issue)
  157. assert !issue.new_record?
  158. assert_equal true, issue.reload.is_private
  159. end
  160. def test_add_issue_with_group_assignment
  161. with_settings :issue_group_assignment => '1' do
  162. issue = submit_email('ticket_on_given_project.eml', :allow_override => ['assigned_to']) do |email|
  163. email.gsub!('Assigned to: John Smith', 'Assigned to: B Team')
  164. end
  165. assert issue.is_a?(Issue)
  166. assert !issue.new_record?
  167. issue.reload
  168. assert_equal Group.find(11), issue.assigned_to
  169. end
  170. end
  171. def test_add_issue_with_partial_attributes_override
  172. issue = submit_email(
  173. 'ticket_with_attributes.eml',
  174. :issue => {:priority => 'High'},
  175. :allow_override => ['tracker']
  176. )
  177. assert issue.is_a?(Issue)
  178. assert !issue.new_record?
  179. issue.reload
  180. assert_equal 'New ticket on a given project', issue.subject
  181. assert_equal User.find_by_login('jsmith'), issue.author
  182. assert_equal Project.find(2), issue.project
  183. assert_equal 'Feature request', issue.tracker.to_s
  184. assert_nil issue.category
  185. assert_equal 'High', issue.priority.to_s
  186. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  187. end
  188. def test_add_issue_with_spaces_between_attribute_and_separator
  189. issue = submit_email(
  190. 'ticket_with_spaces_between_attribute_and_separator.eml',
  191. :allow_override => 'tracker,category,priority'
  192. )
  193. assert issue.is_a?(Issue)
  194. assert !issue.new_record?
  195. issue.reload
  196. assert_equal 'New ticket on a given project', issue.subject
  197. assert_equal User.find_by_login('jsmith'), issue.author
  198. assert_equal Project.find(2), issue.project
  199. assert_equal 'Feature request', issue.tracker.to_s
  200. assert_equal 'Stock management', issue.category.to_s
  201. assert_equal 'Urgent', issue.priority.to_s
  202. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  203. end
  204. def test_add_issue_with_attachment_to_specific_project
  205. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  206. assert issue.is_a?(Issue)
  207. assert !issue.new_record?
  208. issue.reload
  209. assert_equal 'Ticket created by email with attachment', issue.subject
  210. assert_equal User.find_by_login('jsmith'), issue.author
  211. assert_equal Project.find(2), issue.project
  212. assert_equal 'This is a new ticket with attachments', issue.description
  213. # Attachment properties
  214. assert_equal 1, issue.attachments.size
  215. assert_equal 'Paella.jpg', issue.attachments.first.filename
  216. assert_equal 'image/jpeg', issue.attachments.first.content_type
  217. assert_equal 10790, issue.attachments.first.filesize
  218. end
  219. def test_add_issue_with_custom_fields
  220. mutiple = IssueCustomField.generate!(:field_format => 'list',
  221. :name => 'OS', :multiple => true,
  222. :possible_values => ['Linux', 'Windows', 'Mac OS X'])
  223. issue = submit_email('ticket_with_custom_fields.eml',
  224. :issue => {:project => 'onlinestore'}, :allow_override => ['database', 'Searchable_field', 'OS']
  225. )
  226. assert issue.is_a?(Issue)
  227. assert !issue.new_record?
  228. issue.reload
  229. assert_equal 'New ticket with custom field values', issue.subject
  230. assert_equal 'PostgreSQL', issue.custom_field_value(1)
  231. assert_equal 'Value for a custom field', issue.custom_field_value(2)
  232. assert_equal ['Mac OS X', 'Windows'], issue.custom_field_value(mutiple.id).sort
  233. assert !issue.description.match(/^searchable field:/i)
  234. end
  235. def test_add_issue_with_version_custom_fields
  236. field = IssueCustomField.create!(:name => 'Affected version',
  237. :field_format => 'version',
  238. :is_for_all => true,
  239. :tracker_ids => [1,2,3])
  240. issue = submit_email('ticket_with_custom_fields.eml',
  241. :issue => {:project => 'ecookbook'}, :allow_override => ['affected version']
  242. ) do |email|
  243. email << "Affected version: 1.0\n"
  244. end
  245. assert issue.is_a?(Issue)
  246. assert !issue.new_record?
  247. issue.reload
  248. assert_equal '2', issue.custom_field_value(field)
  249. end
  250. def test_add_issue_should_match_assignee_on_display_name
  251. user = User.generate!(:firstname => 'Foo Bar', :lastname => 'Foo Baz')
  252. User.add_to_project(user, Project.find(2))
  253. issue = submit_email('ticket_on_given_project.eml', :allow_override => ['assigned_to']) do |email|
  254. email.sub!(/^Assigned to.*$/, 'Assigned to: Foo Bar Foo baz')
  255. end
  256. assert issue.is_a?(Issue)
  257. assert_equal user, issue.assigned_to
  258. end
  259. def test_add_issue_should_set_default_start_date
  260. with_settings :default_issue_start_date_to_creation_date => '1' do
  261. issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
  262. assert issue.is_a?(Issue)
  263. assert_equal Date.today, issue.start_date
  264. end
  265. end
  266. def test_add_issue_should_add_cc_as_watchers
  267. user = User.find_by_mail('dlopper@somenet.foo')
  268. issue = submit_email('ticket_with_cc.eml', :issue => {:project => 'ecookbook'})
  269. assert issue.is_a?(Issue)
  270. assert !issue.new_record?
  271. assert issue.watched_by?(user)
  272. assert_equal 1, issue.watcher_user_ids.size
  273. assert_include user, issue.watcher_users.to_a
  274. end
  275. def test_add_issue_from_additional_email_address
  276. user = User.find(2)
  277. user.mail = 'mainaddress@somenet.foo'
  278. user.save!
  279. EmailAddress.create!(:user => user, :address => 'jsmith@somenet.foo')
  280. issue = submit_email('ticket_on_given_project.eml')
  281. assert issue
  282. assert_equal user, issue.author
  283. end
  284. def test_add_issue_by_unknown_user
  285. assert_no_difference 'User.count' do
  286. assert_equal false,
  287. submit_email(
  288. 'ticket_by_unknown_user.eml',
  289. :issue => {:project => 'ecookbook'}
  290. )
  291. end
  292. end
  293. def test_add_issue_by_anonymous_user
  294. Role.anonymous.add_permission!(:add_issues)
  295. Role.anonymous.add_permission!(:add_issue_watchers)
  296. assert_no_difference 'User.count' do
  297. issue = submit_email(
  298. 'ticket_by_unknown_user.eml',
  299. :issue => {:project => 'ecookbook'},
  300. :unknown_user => 'accept'
  301. )
  302. assert issue.is_a?(Issue)
  303. assert issue.author.anonymous?
  304. issue.reload
  305. assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
  306. assert_equal 1, issue.watchers.size
  307. end
  308. end
  309. def test_add_issue_by_anonymous_user_with_no_from_address
  310. Role.anonymous.add_permission!(:add_issues)
  311. assert_no_difference 'User.count' do
  312. issue = submit_email(
  313. 'ticket_by_empty_user.eml',
  314. :issue => {:project => 'ecookbook'},
  315. :unknown_user => 'accept'
  316. )
  317. assert issue.is_a?(Issue)
  318. assert issue.author.anonymous?
  319. end
  320. end
  321. def test_add_issue_by_anonymous_user_on_private_project
  322. Role.anonymous.add_permission!(:add_issues)
  323. assert_no_difference 'User.count' do
  324. assert_no_difference 'Issue.count' do
  325. assert_equal false,
  326. submit_email(
  327. 'ticket_by_unknown_user.eml',
  328. :issue => {:project => 'onlinestore'},
  329. :unknown_user => 'accept'
  330. )
  331. end
  332. end
  333. end
  334. def test_add_issue_by_anonymous_user_on_private_project_without_permission_check
  335. assert_no_difference 'User.count' do
  336. assert_difference 'Issue.count' do
  337. issue = submit_email(
  338. 'ticket_by_unknown_user.eml',
  339. :issue => {:project => 'onlinestore'},
  340. :no_permission_check => '1',
  341. :unknown_user => 'accept'
  342. )
  343. assert issue.is_a?(Issue)
  344. assert issue.author.anonymous?
  345. assert !issue.project.is_public?
  346. end
  347. end
  348. end
  349. def test_add_issue_by_created_user
  350. Setting.default_language = 'en'
  351. assert_difference 'User.count' do
  352. issue = submit_email(
  353. 'ticket_by_unknown_user.eml',
  354. :issue => {:project => 'ecookbook'},
  355. :unknown_user => 'create'
  356. )
  357. assert issue.is_a?(Issue)
  358. assert issue.author.active?
  359. assert_equal 'john.doe@somenet.foo', issue.author.mail
  360. assert_equal 'John', issue.author.firstname
  361. assert_equal 'Doe', issue.author.lastname
  362. # account information
  363. email = ActionMailer::Base.deliveries.first
  364. assert_not_nil email
  365. assert email.subject.include?('account activation')
  366. login = mail_body(email).match(/\* Login: (.*)$/)[1].strip
  367. password = mail_body(email).match(/\* Password: (.*)$/)[1].strip
  368. assert_equal issue.author, User.try_to_login(login, password)
  369. end
  370. end
  371. def test_add_issue_should_send_notification
  372. issue = submit_email('ticket_on_given_project.eml', :allow_override => 'all')
  373. assert issue.is_a?(Issue)
  374. assert !issue.new_record?
  375. mail = ActionMailer::Base.deliveries.last
  376. assert_not_nil mail
  377. assert mail.subject.include?("##{issue.id}")
  378. assert mail.subject.include?('New ticket on a given project')
  379. end
  380. def test_created_user_should_be_added_to_groups
  381. group1 = Group.generate!
  382. group2 = Group.generate!
  383. assert_difference 'User.count' do
  384. submit_email(
  385. 'ticket_by_unknown_user.eml',
  386. :issue => {:project => 'ecookbook'},
  387. :unknown_user => 'create',
  388. :default_group => "#{group1.name},#{group2.name}"
  389. )
  390. end
  391. user = User.order('id DESC').first
  392. assert_equal [group1, group2].sort, user.groups.sort
  393. end
  394. def test_created_user_should_not_receive_account_information_with_no_account_info_option
  395. assert_difference 'User.count' do
  396. submit_email(
  397. 'ticket_by_unknown_user.eml',
  398. :issue => {:project => 'ecookbook'},
  399. :unknown_user => 'create',
  400. :no_account_notice => '1'
  401. )
  402. end
  403. # only 2 emails for the new issue notification
  404. assert_equal 2, ActionMailer::Base.deliveries.size
  405. ActionMailer::Base.deliveries.each do |email|
  406. assert_include 'Ticket by unknown user', email.subject
  407. end
  408. end
  409. def test_created_user_should_have_mail_notification_to_none_with_no_notification_option
  410. assert_difference 'User.count' do
  411. submit_email(
  412. 'ticket_by_unknown_user.eml',
  413. :issue => {:project => 'ecookbook'},
  414. :unknown_user => 'create',
  415. :no_notification => '1'
  416. )
  417. end
  418. user = User.order('id DESC').first
  419. assert_equal 'none', user.mail_notification
  420. end
  421. def test_add_issue_without_from_header
  422. Role.anonymous.add_permission!(:add_issues)
  423. assert_equal false, submit_email('ticket_without_from_header.eml')
  424. end
  425. def test_add_issue_with_invalid_attributes
  426. with_settings :default_issue_start_date_to_creation_date => '0' do
  427. issue = submit_email(
  428. 'ticket_with_invalid_attributes.eml',
  429. :allow_override => 'tracker,category,priority'
  430. )
  431. assert issue.is_a?(Issue)
  432. assert !issue.new_record?
  433. issue.reload
  434. assert_nil issue.assigned_to
  435. assert_nil issue.start_date
  436. assert_nil issue.due_date
  437. assert_equal 0, issue.done_ratio
  438. assert_nil issue.parent
  439. assert_equal 'Normal', issue.priority.to_s
  440. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  441. end
  442. end
  443. def test_add_issue_with_invalid_project_should_be_assigned_to_default_project
  444. issue = submit_email('ticket_on_given_project.eml',
  445. :issue => {:project => 'ecookbook'},
  446. :allow_override => 'project') do |email|
  447. email.gsub!(/^Project:.+$/, 'Project: invalid')
  448. end
  449. assert issue.is_a?(Issue)
  450. assert !issue.new_record?
  451. assert_equal 'ecookbook', issue.project.identifier
  452. end
  453. def test_add_issue_with_localized_attributes
  454. User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
  455. issue = submit_email(
  456. 'ticket_with_localized_attributes.eml',
  457. :allow_override => 'tracker,category,priority'
  458. )
  459. assert issue.is_a?(Issue)
  460. assert !issue.new_record?
  461. issue.reload
  462. assert_equal 'New ticket on a given project', issue.subject
  463. assert_equal User.find_by_login('jsmith'), issue.author
  464. assert_equal Project.find(2), issue.project
  465. assert_equal 'Feature request', issue.tracker.to_s
  466. assert_equal 'Stock management', issue.category.to_s
  467. assert_equal 'Urgent', issue.priority.to_s
  468. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  469. end
  470. def test_add_issue_with_japanese_keywords
  471. ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
  472. tracker = Tracker.generate!(:name => ja_dev)
  473. Project.find(1).trackers << tracker
  474. issue = submit_email(
  475. 'japanese_keywords_iso_2022_jp.eml',
  476. :issue => {:project => 'ecookbook'},
  477. :allow_override => 'tracker'
  478. )
  479. assert_kind_of Issue, issue
  480. assert_equal tracker, issue.tracker
  481. end
  482. def test_add_issue_from_apple_mail
  483. issue = submit_email(
  484. 'apple_mail_with_attachment.eml',
  485. :issue => {:project => 'ecookbook'}
  486. )
  487. assert_kind_of Issue, issue
  488. assert_equal 1, issue.attachments.size
  489. attachment = issue.attachments.first
  490. assert_equal 'paella.jpg', attachment.filename
  491. assert_equal 10790, attachment.filesize
  492. assert File.exist?(attachment.diskfile)
  493. assert_equal 10790, File.size(attachment.diskfile)
  494. assert_equal '4474dd534c36bdd212e2efc549507377c3e77147c9167b66dedcebfe9da8807f', attachment.digest
  495. end
  496. def test_thunderbird_with_attachment_ja
  497. issue = submit_email(
  498. 'thunderbird_with_attachment_ja.eml',
  499. :issue => {:project => 'ecookbook'}
  500. )
  501. assert_kind_of Issue, issue
  502. assert_equal 1, issue.attachments.size
  503. ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
  504. attachment = issue.attachments.first
  505. assert_equal ja, attachment.filename
  506. assert_equal 5, attachment.filesize
  507. assert File.exist?(attachment.diskfile)
  508. assert_equal 5, File.size(attachment.diskfile)
  509. assert_equal 'f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2', attachment.digest
  510. end
  511. def test_invalid_utf8
  512. issue = submit_email(
  513. 'invalid_utf8.eml',
  514. :issue => {:project => 'ecookbook'}
  515. )
  516. assert_kind_of Issue, issue
  517. description = "\xD0\x97\xD0\xB4\xD1\x80\xD0\xB0\xD0\xB2\xD1\x81\xD1\x82\xD0\xB2\xD1\x83\xD0\xB9\xD1\x82\xD0\xB5?".force_encoding('UTF-8')
  518. assert_equal description, issue.description
  519. end
  520. def test_gmail_with_attachment_ja
  521. issue = submit_email(
  522. 'gmail_with_attachment_ja.eml',
  523. :issue => {:project => 'ecookbook'}
  524. )
  525. assert_kind_of Issue, issue
  526. assert_equal 1, issue.attachments.size
  527. ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
  528. attachment = issue.attachments.first
  529. assert_equal ja, attachment.filename
  530. assert_equal 5, attachment.filesize
  531. assert File.exist?(attachment.diskfile)
  532. assert_equal 5, File.size(attachment.diskfile)
  533. assert_equal 'f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2', attachment.digest
  534. end
  535. def test_thunderbird_with_attachment_latin1
  536. issue = submit_email(
  537. 'thunderbird_with_attachment_iso-8859-1.eml',
  538. :issue => {:project => 'ecookbook'}
  539. )
  540. assert_kind_of Issue, issue
  541. assert_equal 1, issue.attachments.size
  542. u = "".force_encoding('UTF-8')
  543. u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
  544. 11.times { u << u1 }
  545. attachment = issue.attachments.first
  546. assert_equal "#{u}.png", attachment.filename
  547. assert_equal 130, attachment.filesize
  548. assert File.exist?(attachment.diskfile)
  549. assert_equal 130, File.size(attachment.diskfile)
  550. assert_equal '5635d67364de20432247e651dfe86fcb2265ad5e9750bd8bba7319a86363e738', attachment.digest
  551. end
  552. def test_gmail_with_attachment_latin1
  553. issue = submit_email(
  554. 'gmail_with_attachment_iso-8859-1.eml',
  555. :issue => {:project => 'ecookbook'}
  556. )
  557. assert_kind_of Issue, issue
  558. assert_equal 1, issue.attachments.size
  559. u = "".force_encoding('UTF-8')
  560. u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
  561. 11.times { u << u1 }
  562. attachment = issue.attachments.first
  563. assert_equal "#{u}.txt", attachment.filename
  564. assert_equal 5, attachment.filesize
  565. assert File.exist?(attachment.diskfile)
  566. assert_equal 5, File.size(attachment.diskfile)
  567. assert_equal 'f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2', attachment.digest
  568. end
  569. def test_mail_with_attachment_latin2
  570. issue = submit_email(
  571. 'ticket_with_text_attachment_iso-8859-2.eml',
  572. :issue => {:project => 'ecookbook'}
  573. )
  574. assert_kind_of Issue, issue
  575. assert_equal 1, issue.attachments.size
  576. attachment = issue.attachments.first
  577. assert_equal 'latin2.txt', attachment.filename
  578. assert_equal 19, attachment.filesize
  579. assert File.exist?(attachment.diskfile)
  580. assert_equal 19, File.size(attachment.diskfile)
  581. content = "p\xF8\xEDli\xB9 \xBEluou\xE8k\xFD k\xF9n".force_encoding('CP852')
  582. assert_equal content, File.read(attachment.diskfile).force_encoding('CP852')
  583. end
  584. def test_empty_attachment_should_not_be_imported
  585. issue = submit_email(
  586. 'ticket_with_empty_attachment.eml',
  587. issue: { project: 'ecookbook' }
  588. )
  589. assert_equal 0, issue.attachments.size
  590. end
  591. def test_multiple_inline_text_parts_should_be_appended_to_issue_description
  592. issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
  593. assert_include 'first', issue.description
  594. assert_include 'second', issue.description
  595. assert_include 'third', issue.description
  596. end
  597. def test_empty_text_part_should_not_stop_looking_for_content
  598. issue = submit_email('empty_text_part.eml', :issue => {:project => 'ecookbook'})
  599. assert_equal 'The html part.', issue.description
  600. end
  601. def test_empty_text_and_html_part_should_make_an_empty_description
  602. issue = submit_email('empty_text_and_html_part.eml', :issue => {:project => 'ecookbook'})
  603. assert_equal '', issue.description
  604. end
  605. def test_attachment_text_part_should_be_added_as_issue_attachment
  606. issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
  607. assert_not_include 'Plain text attachment', issue.description
  608. attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'}
  609. assert_not_nil attachment
  610. assert_include 'Plain text attachment', File.read(attachment.diskfile)
  611. end
  612. def test_add_issue_with_iso_8859_1_subject
  613. issue = submit_email(
  614. 'subject_as_iso-8859-1.eml',
  615. :issue => {:project => 'ecookbook'}
  616. )
  617. str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc...".force_encoding('UTF-8')
  618. assert_kind_of Issue, issue
  619. assert_equal str, issue.subject
  620. end
  621. def test_quoted_printable_utf8
  622. issue = submit_email(
  623. 'quoted_printable_utf8.eml',
  624. :issue => {:project => 'ecookbook'}
  625. )
  626. assert_kind_of Issue, issue
  627. str = "Freundliche Gr\xc3\xbcsse".force_encoding('UTF-8')
  628. assert_equal str, issue.description
  629. end
  630. def test_gmail_iso8859_2
  631. issue = submit_email(
  632. 'gmail-iso8859-2.eml',
  633. :issue => {:project => 'ecookbook'}
  634. )
  635. assert_kind_of Issue, issue
  636. str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87.".force_encoding('UTF-8')
  637. assert issue.description.include?(str)
  638. end
  639. def test_add_issue_with_japanese_subject
  640. issue = submit_email(
  641. 'subject_japanese_1.eml',
  642. :issue => {:project => 'ecookbook'}
  643. )
  644. assert_kind_of Issue, issue
  645. ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
  646. assert_equal ja, issue.subject
  647. end
  648. def test_add_issue_with_korean_body
  649. # Make sure mail bodies with a charset unknown to Ruby
  650. # but known to the Mail gem 2.5.4 are handled correctly
  651. kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4.".force_encoding('UTF-8')
  652. issue = submit_email(
  653. 'body_ks_c_5601-1987.eml',
  654. :issue => {:project => 'ecookbook'}
  655. )
  656. assert_kind_of Issue, issue
  657. assert_equal kr, issue.description
  658. end
  659. def test_add_issue_with_no_subject_header
  660. issue = submit_email(
  661. 'no_subject_header.eml',
  662. :issue => {:project => 'ecookbook'}
  663. )
  664. assert_kind_of Issue, issue
  665. assert_equal '(no subject)', issue.subject
  666. end
  667. def test_add_issue_with_mixed_japanese_subject
  668. issue = submit_email(
  669. 'subject_japanese_2.eml',
  670. :issue => {:project => 'ecookbook'}
  671. )
  672. assert_kind_of Issue, issue
  673. ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
  674. assert_equal ja, issue.subject
  675. end
  676. def test_should_ignore_emails_from_locked_users
  677. User.find(2).lock!
  678. MailHandler.any_instance.expects(:dispatch).never
  679. assert_no_difference 'Issue.count' do
  680. assert_equal false, submit_email('ticket_on_given_project.eml')
  681. end
  682. end
  683. def test_should_ignore_emails_from_emission_address
  684. Role.anonymous.add_permission!(:add_issues)
  685. assert_no_difference 'User.count' do
  686. assert_equal false,
  687. submit_email(
  688. 'ticket_from_emission_address.eml',
  689. :issue => {:project => 'ecookbook'},
  690. :unknown_user => 'create'
  691. )
  692. end
  693. end
  694. def test_should_ignore_auto_replied_emails
  695. MailHandler.any_instance.expects(:dispatch).never
  696. [
  697. "Auto-Submitted: auto-replied",
  698. "Auto-Submitted: Auto-Replied",
  699. "Auto-Submitted: auto-generated",
  700. 'X-Autoreply: yes'
  701. ].each do |header|
  702. raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
  703. raw = header + "\n" + raw
  704. assert_no_difference 'Issue.count' do
  705. assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
  706. end
  707. end
  708. end
  709. test "should not ignore Auto-Submitted headers not defined in RFC3834" do
  710. [
  711. "Auto-Submitted: auto-forwarded"
  712. ].each do |header|
  713. raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
  714. raw = header + "\n" + raw
  715. assert_difference 'Issue.count', 1 do
  716. assert_not_nil MailHandler.receive(raw), "email with #{header} header was ignored"
  717. end
  718. end
  719. end
  720. def test_add_issue_should_send_email_notification
  721. Setting.notified_events = ['issue_added']
  722. # This email contains: 'Project: onlinestore'
  723. issue = submit_email('ticket_on_given_project.eml')
  724. assert issue.is_a?(Issue)
  725. assert_equal 1, ActionMailer::Base.deliveries.size
  726. end
  727. def test_update_issue
  728. journal = submit_email('ticket_reply.eml')
  729. assert journal.is_a?(Journal)
  730. assert_equal User.find_by_login('jsmith'), journal.user
  731. assert_equal Issue.find(2), journal.journalized
  732. assert_match /This is reply/, journal.notes
  733. assert_equal false, journal.private_notes
  734. assert_equal 'Feature request', journal.issue.tracker.name
  735. end
  736. def test_update_issue_should_accept_issue_id_after_space_inside_brackets
  737. journal = submit_email('ticket_reply_with_status.eml') do |email|
  738. assert email.sub!(/^Subject:.*$/, "Subject: Re: [Feature request #2] Add ingredients categories")
  739. end
  740. assert journal.is_a?(Journal)
  741. assert_equal Issue.find(2), journal.journalized
  742. end
  743. def test_update_issue_should_accept_issue_id_inside_brackets
  744. journal = submit_email('ticket_reply_with_status.eml') do |email|
  745. assert email.sub!(/^Subject:.*$/, "Subject: Re: [#2] Add ingredients categories")
  746. end
  747. assert journal.is_a?(Journal)
  748. assert_equal Issue.find(2), journal.journalized
  749. end
  750. def test_update_issue_should_ignore_bogus_issue_ids_in_subject
  751. journal = submit_email('ticket_reply_with_status.eml') do |email|
  752. assert email.sub!(/^Subject:.*$/, "Subject: Re: [12345#1][bogus#1][Feature request #2] Add ingredients categories")
  753. end
  754. assert journal.is_a?(Journal)
  755. assert_equal Issue.find(2), journal.journalized
  756. end
  757. def test_update_issue_with_attribute_changes
  758. journal = submit_email('ticket_reply_with_status.eml',
  759. :allow_override => ['status', 'assigned_to',
  760. 'start_date', 'due_date',
  761. 'float field'])
  762. assert journal.is_a?(Journal)
  763. issue = Issue.find(journal.issue.id)
  764. assert_equal User.find_by_login('jsmith'), journal.user
  765. assert_equal Issue.find(2), journal.journalized
  766. assert_match /This is reply/, journal.notes
  767. assert_equal 'Feature request', journal.issue.tracker.name
  768. assert_equal IssueStatus.find_by_name("Resolved"), issue.status
  769. assert_equal '2010-01-01', issue.start_date.to_s
  770. assert_equal '2010-12-31', issue.due_date.to_s
  771. assert_equal User.find_by_login('jsmith'), issue.assigned_to
  772. assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
  773. # keywords should be removed from the email body
  774. assert !journal.notes.match(/^Status:/i)
  775. assert !journal.notes.match(/^Start Date:/i)
  776. end
  777. def test_update_issue_with_attachment
  778. assert_difference 'Journal.count' do
  779. assert_difference 'JournalDetail.count' do
  780. assert_difference 'Attachment.count' do
  781. assert_no_difference 'Issue.count' do
  782. journal = submit_email('ticket_with_attachment.eml') do |raw|
  783. raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
  784. end
  785. end
  786. end
  787. end
  788. end
  789. journal = Journal.order('id DESC').first
  790. assert_equal Issue.find(2), journal.journalized
  791. assert_equal 1, journal.details.size
  792. detail = journal.details.first
  793. assert_equal 'attachment', detail.property
  794. assert_equal 'Paella.jpg', detail.value
  795. end
  796. def test_update_issue_should_send_email_notification
  797. journal = submit_email('ticket_reply.eml')
  798. assert journal.is_a?(Journal)
  799. assert_equal 3, ActionMailer::Base.deliveries.size
  800. end
  801. def test_update_issue_should_not_set_defaults
  802. journal = submit_email(
  803. 'ticket_reply.eml',
  804. :issue => {:tracker => 'Support request', :priority => 'High'}
  805. )
  806. assert journal.is_a?(Journal)
  807. assert_match /This is reply/, journal.notes
  808. assert_equal 'Feature request', journal.issue.tracker.name
  809. assert_equal 'Normal', journal.issue.priority.name
  810. end
  811. def test_update_issue_should_add_cc_as_watchers
  812. Watcher.delete_all
  813. issue = Issue.find(2)
  814. assert_difference 'Watcher.count' do
  815. assert submit_email('issue_update_with_cc.eml')
  816. end
  817. issue.reload
  818. assert_equal 1, issue.watcher_user_ids.size
  819. assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
  820. end
  821. def test_update_issue_should_not_add_cc_as_watchers_if_already_watching
  822. Watcher.delete_all
  823. issue = Issue.find(2)
  824. Watcher.create!(:watchable => issue, :user => User.find_by_mail('dlopper@somenet.foo'))
  825. assert_no_difference 'Watcher.count' do
  826. assert submit_email('issue_update_with_cc.eml')
  827. end
  828. end
  829. def test_replying_to_a_private_note_should_add_reply_as_private
  830. private_journal = Journal.create!(:notes => 'Private notes',
  831. :journalized => Issue.find(1),
  832. :private_notes => true, :user_id => 2)
  833. assert_difference 'Journal.count' do
  834. journal = submit_email('ticket_reply.eml') do |email|
  835. email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
  836. end
  837. assert_kind_of Journal, journal
  838. assert_match /This is reply/, journal.notes
  839. assert_equal true, journal.private_notes
  840. end
  841. end
  842. def test_reply_to_a_message
  843. m = submit_email('message_reply.eml')
  844. assert m.is_a?(Message)
  845. assert !m.new_record?
  846. m.reload
  847. assert_equal 'Reply via email', m.subject
  848. # The email replies to message #2 which is part of the thread of message #1
  849. assert_equal Message.find(1), m.parent
  850. end
  851. def test_reply_to_a_message_by_subject
  852. m = submit_email('message_reply_by_subject.eml')
  853. assert m.is_a?(Message)
  854. assert !m.new_record?
  855. m.reload
  856. assert_equal 'Reply to the first post', m.subject
  857. assert_equal Message.find(1), m.parent
  858. end
  859. def test_should_convert_tags_of_html_only_emails
  860. with_settings :text_formatting => 'textile' do
  861. issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
  862. assert issue.is_a?(Issue)
  863. assert !issue.new_record?
  864. issue.reload
  865. assert_equal 'HTML email', issue.subject
  866. assert_equal "This is a *html-only* email.\r\n\r\nh1. With a title\r\n\r\nand a paragraph.", issue.description
  867. end
  868. end
  869. def test_should_handle_outlook_web_access_2010_html_only
  870. issue = submit_email('outlook_web_access_2010_html_only.eml', :issue => {:project => 'ecookbook'})
  871. assert issue.is_a?(Issue)
  872. issue.reload
  873. assert_equal 'Upgrade Redmine to 3.0.x', issue.subject
  874. assert_equal "A mess.\r\n\r\n--Geoff Maciolek\r\nMYCOMPANYNAME, LLC", issue.description
  875. end
  876. def test_should_handle_outlook_2010_html_only
  877. issue = submit_email('outlook_2010_html_only.eml', :issue => {:project => 'ecookbook'})
  878. assert issue.is_a?(Issue)
  879. issue.reload
  880. assert_equal 'Test email', issue.subject
  881. assert_equal "Simple, unadorned test email generated by Outlook 2010. It is in HTML format, but" +
  882. " no special formatting has been chosen. I’m going to save this as a draft and then manually" +
  883. " drop it into the Inbox for scraping by Redmine 3.0.2.", issue.description
  884. end
  885. test "truncate emails with no setting should add the entire email into the issue" do
  886. with_settings :mail_handler_body_delimiters => '' do
  887. issue = submit_email('ticket_on_given_project.eml')
  888. assert_issue_created(issue)
  889. assert issue.description.include?('---')
  890. assert issue.description.include?('This paragraph is after the delimiter')
  891. end
  892. end
  893. test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
  894. with_settings :mail_handler_body_delimiters => '---' do
  895. issue = submit_email('ticket_on_given_project.eml')
  896. assert_issue_created(issue)
  897. assert issue.description.include?('This paragraph is before delimiters')
  898. assert issue.description.include?('--- This line starts with a delimiter')
  899. assert !issue.description.match(/^---#{"\u00A0"}$/)
  900. assert !issue.description.include?('This paragraph is after the delimiter')
  901. end
  902. end
  903. test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
  904. with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
  905. journal = submit_email('issue_update_with_quoted_reply_above.eml')
  906. assert journal.is_a?(Journal)
  907. assert journal.notes.include?('An update to the issue by the sender.')
  908. assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
  909. assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
  910. end
  911. end
  912. test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
  913. with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
  914. journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
  915. assert journal.is_a?(Journal)
  916. assert journal.notes.include?('An update to the issue by the sender.')
  917. assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
  918. assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
  919. end
  920. end
  921. test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
  922. with_settings :mail_handler_body_delimiters => "---\nBREAK" do
  923. issue = submit_email('ticket_on_given_project.eml')
  924. assert_issue_created(issue)
  925. assert issue.description.include?('This paragraph is before delimiters')
  926. assert !issue.description.include?('BREAK')
  927. assert !issue.description.include?('This paragraph is between delimiters')
  928. assert !issue.description.match(/^---$/)
  929. assert !issue.description.include?('This paragraph is after the delimiter')
  930. end
  931. end
  932. test "truncate emails using a regex delimiter" do
  933. delimiter = "On .*, .* at .*, .* <.*<mailto:.*>> wrote:"
  934. with_settings :mail_handler_enable_regex_delimiters => '1', :mail_handler_body_delimiters => delimiter do
  935. issue = submit_email('ticket_reply_from_mail.eml')
  936. assert_issue_created(issue)
  937. assert issue.description.include?('This paragraph is before delimiter')
  938. assert !issue.description.include?('On Wed, 11 Oct at 1:05 PM, Jon Smith <jsmith@somenet.foo<mailto:jsmith@somenet.foo>> wrote:')
  939. assert !issue.description.include?('This paragraph is after the delimiter')
  940. end
  941. with_settings :mail_handler_enable_regex_delimiters => '0', :mail_handler_body_delimiters => delimiter do
  942. issue = submit_email('ticket_reply_from_mail.eml')
  943. assert_issue_created(issue)
  944. assert issue.description.include?('This paragraph is before delimiter')
  945. assert issue.description.include?('On Wed, 11 Oct at 1:05 PM, Jon Smith <jsmith@somenet.foo<mailto:jsmith@somenet.foo>> wrote:')
  946. assert issue.description.include?('This paragraph is after the delimiter')
  947. end
  948. end
  949. def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
  950. with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
  951. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  952. assert issue.is_a?(Issue)
  953. assert !issue.new_record?
  954. assert_equal 0, issue.reload.attachments.size
  955. end
  956. end
  957. def test_attachments_that_match_mail_handler_excluded_filenames_by_regex_should_be_ignored
  958. with_settings :mail_handler_excluded_filenames => '.+\.vcf,(pa|nut)ella\.jpg',
  959. :mail_handler_enable_regex_excluded_filenames => 1 do
  960. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  961. assert issue.is_a?(Issue)
  962. assert !issue.new_record?
  963. assert_equal 0, issue.reload.attachments.size
  964. end
  965. end
  966. def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
  967. with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
  968. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  969. assert issue.is_a?(Issue)
  970. assert !issue.new_record?
  971. assert_equal 1, issue.reload.attachments.size
  972. end
  973. end
  974. def test_email_with_long_subject_line
  975. issue = submit_email('ticket_with_long_subject.eml')
  976. assert issue.is_a?(Issue)
  977. 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]
  978. end
  979. def test_first_keyword_should_be_matched
  980. issue = submit_email('ticket_with_duplicate_keyword.eml', :allow_override => 'priority')
  981. assert issue.is_a?(Issue)
  982. assert_equal 'High', issue.priority.name
  983. end
  984. def test_keyword_after_delimiter_should_be_ignored
  985. with_settings :mail_handler_body_delimiters => "== DELIMITER ==" do
  986. issue = submit_email('ticket_with_keyword_after_delimiter.eml', :allow_override => 'priority')
  987. assert issue.is_a?(Issue)
  988. assert_equal 'Normal', issue.priority.name
  989. end
  990. end
  991. def test_new_user_from_attributes_should_return_valid_user
  992. to_test = {
  993. # [address, name] => [login, firstname, lastname]
  994. ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
  995. ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
  996. ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
  997. ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
  998. ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] =>
  999. ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
  1000. ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] =>
  1001. ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
  1002. }
  1003. to_test.each do |attrs, expected|
  1004. user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
  1005. assert user.valid?, user.errors.full_messages.to_s
  1006. assert_equal attrs.first, user.mail
  1007. assert_equal expected[0], user.login
  1008. assert_equal expected[1], user.firstname
  1009. assert_equal expected[2], user.lastname
  1010. assert_equal 'only_my_events', user.mail_notification
  1011. end
  1012. end
  1013. def test_new_user_from_attributes_should_use_default_login_if_invalid
  1014. user = MailHandler.new_user_from_attributes('foo+bar@example.net')
  1015. assert user.valid?
  1016. assert user.login =~ /^user[a-f0-9]+$/
  1017. assert_equal 'foo+bar@example.net', user.mail
  1018. end
  1019. def test_new_user_with_utf8_encoded_fullname_should_be_decoded
  1020. assert_difference 'User.count' do
  1021. issue = submit_email(
  1022. 'fullname_of_sender_as_utf8_encoded.eml',
  1023. :issue => {:project => 'ecookbook'},
  1024. :unknown_user => 'create'
  1025. )
  1026. end
  1027. user = User.order('id DESC').first
  1028. assert_equal "foo@example.org", user.mail
  1029. str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
  1030. str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
  1031. assert_equal str1, user.firstname
  1032. assert_equal str2, user.lastname
  1033. end
  1034. def test_extract_options_from_env_should_return_options
  1035. options = MailHandler.extract_options_from_env({
  1036. 'tracker' => 'defect',
  1037. 'project' => 'foo',
  1038. 'unknown_user' => 'create',
  1039. 'no_notification' => '1'
  1040. })
  1041. assert_equal({
  1042. :issue => {:tracker => 'defect', :project => 'foo'},
  1043. :unknown_user => 'create', :no_notification => '1'
  1044. }, options)
  1045. end
  1046. def test_safe_receive_should_rescue_exceptions_and_return_false
  1047. MailHandler.stubs(:receive).raises(Exception.new "Something went wrong")
  1048. assert_equal false, MailHandler.safe_receive
  1049. end
  1050. private
  1051. def submit_email(filename, options={})
  1052. raw = IO.read(File.join(FIXTURES_PATH, filename))
  1053. yield raw if block_given?
  1054. MailHandler.receive(raw, options)
  1055. end
  1056. def assert_issue_created(issue)
  1057. assert issue.is_a?(Issue)
  1058. assert !issue.new_record?
  1059. issue.reload
  1060. end
  1061. end