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 47KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209
  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, :custom_values,
  28. :boards, :messages, :watchers
  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_add_issue_with_iso_2022_jp_ms_subject
  677. # The original subject is "① 丸数字テスト".
  678. # CIRCLED DIGIT ONE character is undefined in ISO-2022-JP but
  679. # defined in some vendor-extended variants such as ISO-2022-JP-MS.
  680. # This test makes sure that mail gem replaces an undefined characters
  681. # with a replacement character instead of breaking the whole subject.
  682. issue = submit_email(
  683. 'subject_japanese_3.eml',
  684. :issue => {:project => 'ecookbook'}
  685. )
  686. assert_kind_of Issue, issue
  687. assert_match /丸数字テスト/, issue.subject
  688. end
  689. def test_should_ignore_emails_from_locked_users
  690. User.find(2).lock!
  691. MailHandler.any_instance.expects(:dispatch).never
  692. assert_no_difference 'Issue.count' do
  693. assert_equal false, submit_email('ticket_on_given_project.eml')
  694. end
  695. end
  696. def test_should_ignore_emails_from_emission_address
  697. Role.anonymous.add_permission!(:add_issues)
  698. assert_no_difference 'User.count' do
  699. assert_equal false,
  700. submit_email(
  701. 'ticket_from_emission_address.eml',
  702. :issue => {:project => 'ecookbook'},
  703. :unknown_user => 'create'
  704. )
  705. end
  706. end
  707. def test_should_ignore_auto_replied_emails
  708. MailHandler.any_instance.expects(:dispatch).never
  709. [
  710. "Auto-Submitted: auto-replied",
  711. "Auto-Submitted: Auto-Replied",
  712. "Auto-Submitted: auto-generated",
  713. 'X-Autoreply: yes'
  714. ].each do |header|
  715. raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
  716. raw = header + "\n" + raw
  717. assert_no_difference 'Issue.count' do
  718. assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
  719. end
  720. end
  721. end
  722. test "should not ignore Auto-Submitted headers not defined in RFC3834" do
  723. [
  724. "Auto-Submitted: auto-forwarded"
  725. ].each do |header|
  726. raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
  727. raw = header + "\n" + raw
  728. assert_difference 'Issue.count', 1 do
  729. assert_not_nil MailHandler.receive(raw), "email with #{header} header was ignored"
  730. end
  731. end
  732. end
  733. def test_add_issue_should_send_email_notification
  734. Setting.notified_events = ['issue_added']
  735. # This email contains: 'Project: onlinestore'
  736. issue = submit_email('ticket_on_given_project.eml')
  737. assert issue.is_a?(Issue)
  738. assert_equal 1, ActionMailer::Base.deliveries.size
  739. end
  740. def test_update_issue
  741. journal = submit_email('ticket_reply.eml')
  742. assert journal.is_a?(Journal)
  743. assert_equal User.find_by_login('jsmith'), journal.user
  744. assert_equal Issue.find(2), journal.journalized
  745. assert_match /This is reply/, journal.notes
  746. assert_equal false, journal.private_notes
  747. assert_equal 'Feature request', journal.issue.tracker.name
  748. end
  749. def test_update_issue_should_accept_issue_id_after_space_inside_brackets
  750. journal = submit_email('ticket_reply_with_status.eml') do |email|
  751. assert email.sub!(/^Subject:.*$/, "Subject: Re: [Feature request #2] Add ingredients categories")
  752. end
  753. assert journal.is_a?(Journal)
  754. assert_equal Issue.find(2), journal.journalized
  755. end
  756. def test_update_issue_should_accept_issue_id_inside_brackets
  757. journal = submit_email('ticket_reply_with_status.eml') do |email|
  758. assert email.sub!(/^Subject:.*$/, "Subject: Re: [#2] Add ingredients categories")
  759. end
  760. assert journal.is_a?(Journal)
  761. assert_equal Issue.find(2), journal.journalized
  762. end
  763. def test_update_issue_should_ignore_bogus_issue_ids_in_subject
  764. journal = submit_email('ticket_reply_with_status.eml') do |email|
  765. assert email.sub!(/^Subject:.*$/, "Subject: Re: [12345#1][bogus#1][Feature request #2] Add ingredients categories")
  766. end
  767. assert journal.is_a?(Journal)
  768. assert_equal Issue.find(2), journal.journalized
  769. end
  770. def test_update_issue_with_attribute_changes
  771. journal = submit_email('ticket_reply_with_status.eml',
  772. :allow_override => ['status', 'assigned_to',
  773. 'start_date', 'due_date',
  774. 'float field'])
  775. assert journal.is_a?(Journal)
  776. issue = Issue.find(journal.issue.id)
  777. assert_equal User.find_by_login('jsmith'), journal.user
  778. assert_equal Issue.find(2), journal.journalized
  779. assert_match /This is reply/, journal.notes
  780. assert_equal 'Feature request', journal.issue.tracker.name
  781. assert_equal IssueStatus.find_by_name("Resolved"), issue.status
  782. assert_equal '2010-01-01', issue.start_date.to_s
  783. assert_equal '2010-12-31', issue.due_date.to_s
  784. assert_equal User.find_by_login('jsmith'), issue.assigned_to
  785. assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
  786. # keywords should be removed from the email body
  787. assert !journal.notes.match(/^Status:/i)
  788. assert !journal.notes.match(/^Start Date:/i)
  789. end
  790. def test_update_issue_with_attachment
  791. assert_difference 'Journal.count' do
  792. assert_difference 'JournalDetail.count' do
  793. assert_difference 'Attachment.count' do
  794. assert_no_difference 'Issue.count' do
  795. journal = submit_email('ticket_with_attachment.eml') do |raw|
  796. raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
  797. end
  798. end
  799. end
  800. end
  801. end
  802. journal = Journal.order('id DESC').first
  803. assert_equal Issue.find(2), journal.journalized
  804. assert_equal 1, journal.details.size
  805. detail = journal.details.first
  806. assert_equal 'attachment', detail.property
  807. assert_equal 'Paella.jpg', detail.value
  808. end
  809. def test_update_issue_should_discard_all_changes_on_validation_failure
  810. Issue.any_instance.stubs(:valid?).returns(false)
  811. assert_no_difference 'Journal.count' do
  812. assert_no_difference 'JournalDetail.count' do
  813. assert_no_difference 'Attachment.count' do
  814. assert_no_difference 'Issue.count' do
  815. journal = submit_email('ticket_with_attachment.eml') do |raw|
  816. raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
  817. end
  818. end
  819. end
  820. end
  821. end
  822. end
  823. def test_update_issue_should_send_email_notification
  824. journal = submit_email('ticket_reply.eml')
  825. assert journal.is_a?(Journal)
  826. assert_equal 3, ActionMailer::Base.deliveries.size
  827. end
  828. def test_update_issue_should_not_set_defaults
  829. journal = submit_email(
  830. 'ticket_reply.eml',
  831. :issue => {:tracker => 'Support request', :priority => 'High'}
  832. )
  833. assert journal.is_a?(Journal)
  834. assert_match /This is reply/, journal.notes
  835. assert_equal 'Feature request', journal.issue.tracker.name
  836. assert_equal 'Normal', journal.issue.priority.name
  837. end
  838. def test_update_issue_should_add_cc_as_watchers
  839. Watcher.delete_all
  840. issue = Issue.find(2)
  841. assert_difference 'Watcher.count' do
  842. assert submit_email('issue_update_with_cc.eml')
  843. end
  844. issue.reload
  845. assert_equal 1, issue.watcher_user_ids.size
  846. assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
  847. end
  848. def test_update_issue_should_not_add_cc_as_watchers_if_already_watching
  849. Watcher.delete_all
  850. issue = Issue.find(2)
  851. Watcher.create!(:watchable => issue, :user => User.find_by_mail('dlopper@somenet.foo'))
  852. assert_no_difference 'Watcher.count' do
  853. assert submit_email('issue_update_with_cc.eml')
  854. end
  855. end
  856. def test_replying_to_a_private_note_should_add_reply_as_private
  857. private_journal = Journal.create!(:notes => 'Private notes',
  858. :journalized => Issue.find(1),
  859. :private_notes => true, :user_id => 2)
  860. assert_difference 'Journal.count' do
  861. journal = submit_email('ticket_reply.eml') do |email|
  862. email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
  863. end
  864. assert_kind_of Journal, journal
  865. assert_match /This is reply/, journal.notes
  866. assert_equal true, journal.private_notes
  867. end
  868. end
  869. def test_reply_to_a_message
  870. m = submit_email('message_reply.eml')
  871. assert m.is_a?(Message)
  872. assert !m.new_record?
  873. m.reload
  874. assert_equal 'Reply via email', m.subject
  875. # The email replies to message #2 which is part of the thread of message #1
  876. assert_equal Message.find(1), m.parent
  877. end
  878. def test_reply_to_a_message_by_subject
  879. m = submit_email('message_reply_by_subject.eml')
  880. assert m.is_a?(Message)
  881. assert !m.new_record?
  882. m.reload
  883. assert_equal 'Reply to the first post', m.subject
  884. assert_equal Message.find(1), m.parent
  885. end
  886. def test_should_convert_tags_of_html_only_emails
  887. with_settings :text_formatting => 'textile' do
  888. issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
  889. assert issue.is_a?(Issue)
  890. assert !issue.new_record?
  891. issue.reload
  892. assert_equal 'HTML email', issue.subject
  893. assert_equal "This is a *html-only* email.\r\n\r\nh1. With a title\r\n\r\nand a paragraph.", issue.description
  894. end
  895. end
  896. def test_should_handle_outlook_web_access_2010_html_only
  897. issue = submit_email('outlook_web_access_2010_html_only.eml', :issue => {:project => 'ecookbook'})
  898. assert issue.is_a?(Issue)
  899. issue.reload
  900. assert_equal 'Upgrade Redmine to 3.0.x', issue.subject
  901. assert_equal "A mess.\r\n\r\n--Geoff Maciolek\r\nMYCOMPANYNAME, LLC", issue.description
  902. end
  903. def test_should_handle_outlook_2010_html_only
  904. issue = submit_email('outlook_2010_html_only.eml', :issue => {:project => 'ecookbook'})
  905. assert issue.is_a?(Issue)
  906. issue.reload
  907. assert_equal 'Test email', issue.subject
  908. assert_equal "Simple, unadorned test email generated by Outlook 2010. It is in HTML format, but" +
  909. " no special formatting has been chosen. I’m going to save this as a draft and then manually" +
  910. " drop it into the Inbox for scraping by Redmine 3.0.2.", issue.description
  911. end
  912. test "truncate emails with no setting should add the entire email into the issue" do
  913. with_settings :mail_handler_body_delimiters => '' do
  914. issue = submit_email('ticket_on_given_project.eml')
  915. assert_issue_created(issue)
  916. assert issue.description.include?('---')
  917. assert issue.description.include?('This paragraph is after the delimiter')
  918. end
  919. end
  920. test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
  921. with_settings :mail_handler_body_delimiters => '---' do
  922. issue = submit_email('ticket_on_given_project.eml')
  923. assert_issue_created(issue)
  924. assert issue.description.include?('This paragraph is before delimiters')
  925. assert issue.description.include?('--- This line starts with a delimiter')
  926. assert !issue.description.match(/^---#{"\u00A0"}$/)
  927. assert !issue.description.include?('This paragraph is after the delimiter')
  928. end
  929. end
  930. test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
  931. with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
  932. journal = submit_email('issue_update_with_quoted_reply_above.eml')
  933. assert journal.is_a?(Journal)
  934. assert journal.notes.include?('An update to the issue by the sender.')
  935. assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
  936. assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
  937. end
  938. end
  939. test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
  940. with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
  941. journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
  942. assert journal.is_a?(Journal)
  943. assert journal.notes.include?('An update to the issue by the sender.')
  944. assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
  945. assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
  946. end
  947. end
  948. test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
  949. with_settings :mail_handler_body_delimiters => "---\nBREAK" do
  950. issue = submit_email('ticket_on_given_project.eml')
  951. assert_issue_created(issue)
  952. assert issue.description.include?('This paragraph is before delimiters')
  953. assert !issue.description.include?('BREAK')
  954. assert !issue.description.include?('This paragraph is between delimiters')
  955. assert !issue.description.match(/^---$/)
  956. assert !issue.description.include?('This paragraph is after the delimiter')
  957. end
  958. end
  959. test "truncate emails using a regex delimiter" do
  960. delimiter = "On .*, .* at .*, .* <.*<mailto:.*>> wrote:"
  961. with_settings :mail_handler_enable_regex_delimiters => '1', :mail_handler_body_delimiters => delimiter do
  962. issue = submit_email('ticket_reply_from_mail.eml')
  963. assert_issue_created(issue)
  964. assert issue.description.include?('This paragraph is before delimiter')
  965. assert !issue.description.include?('On Wed, 11 Oct at 1:05 PM, Jon Smith <jsmith@somenet.foo<mailto:jsmith@somenet.foo>> wrote:')
  966. assert !issue.description.include?('This paragraph is after the delimiter')
  967. end
  968. with_settings :mail_handler_enable_regex_delimiters => '0', :mail_handler_body_delimiters => delimiter do
  969. issue = submit_email('ticket_reply_from_mail.eml')
  970. assert_issue_created(issue)
  971. assert issue.description.include?('This paragraph is before delimiter')
  972. assert issue.description.include?('On Wed, 11 Oct at 1:05 PM, Jon Smith <jsmith@somenet.foo<mailto:jsmith@somenet.foo>> wrote:')
  973. assert issue.description.include?('This paragraph is after the delimiter')
  974. end
  975. end
  976. def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
  977. with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
  978. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  979. assert issue.is_a?(Issue)
  980. assert !issue.new_record?
  981. assert_equal 0, issue.reload.attachments.size
  982. end
  983. end
  984. def test_attachments_that_match_mail_handler_excluded_filenames_by_regex_should_be_ignored
  985. with_settings :mail_handler_excluded_filenames => '.+\.vcf,(pa|nut)ella\.jpg',
  986. :mail_handler_enable_regex_excluded_filenames => 1 do
  987. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  988. assert issue.is_a?(Issue)
  989. assert !issue.new_record?
  990. assert_equal 0, issue.reload.attachments.size
  991. end
  992. end
  993. def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
  994. with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
  995. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  996. assert issue.is_a?(Issue)
  997. assert !issue.new_record?
  998. assert_equal 1, issue.reload.attachments.size
  999. end
  1000. end
  1001. def test_email_with_long_subject_line
  1002. issue = submit_email('ticket_with_long_subject.eml')
  1003. assert issue.is_a?(Issue)
  1004. 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]
  1005. end
  1006. def test_first_keyword_should_be_matched
  1007. issue = submit_email('ticket_with_duplicate_keyword.eml', :allow_override => 'priority')
  1008. assert issue.is_a?(Issue)
  1009. assert_equal 'High', issue.priority.name
  1010. end
  1011. def test_keyword_after_delimiter_should_be_ignored
  1012. with_settings :mail_handler_body_delimiters => "== DELIMITER ==" do
  1013. issue = submit_email('ticket_with_keyword_after_delimiter.eml', :allow_override => 'priority')
  1014. assert issue.is_a?(Issue)
  1015. assert_equal 'Normal', issue.priority.name
  1016. end
  1017. end
  1018. def test_new_user_from_attributes_should_return_valid_user
  1019. to_test = {
  1020. # [address, name] => [login, firstname, lastname]
  1021. ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
  1022. ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
  1023. ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
  1024. ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
  1025. ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] =>
  1026. ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
  1027. ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] =>
  1028. ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
  1029. }
  1030. to_test.each do |attrs, expected|
  1031. user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
  1032. assert user.valid?, user.errors.full_messages.to_s
  1033. assert_equal attrs.first, user.mail
  1034. assert_equal expected[0], user.login
  1035. assert_equal expected[1], user.firstname
  1036. assert_equal expected[2], user.lastname
  1037. assert_equal 'only_my_events', user.mail_notification
  1038. end
  1039. end
  1040. def test_new_user_from_attributes_should_use_default_login_if_invalid
  1041. user = MailHandler.new_user_from_attributes('foo+bar@example.net')
  1042. assert user.valid?
  1043. assert user.login =~ /^user[a-f0-9]+$/
  1044. assert_equal 'foo+bar@example.net', user.mail
  1045. end
  1046. def test_new_user_with_utf8_encoded_fullname_should_be_decoded
  1047. assert_difference 'User.count' do
  1048. issue = submit_email(
  1049. 'fullname_of_sender_as_utf8_encoded.eml',
  1050. :issue => {:project => 'ecookbook'},
  1051. :unknown_user => 'create'
  1052. )
  1053. end
  1054. user = User.order('id DESC').first
  1055. assert_equal "foo@example.org", user.mail
  1056. str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
  1057. str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
  1058. assert_equal str1, user.firstname
  1059. assert_equal str2, user.lastname
  1060. end
  1061. def test_extract_options_from_env_should_return_options
  1062. options = MailHandler.extract_options_from_env({
  1063. 'tracker' => 'defect',
  1064. 'project' => 'foo',
  1065. 'unknown_user' => 'create',
  1066. 'no_notification' => '1'
  1067. })
  1068. assert_equal({
  1069. :issue => {:tracker => 'defect', :project => 'foo'},
  1070. :unknown_user => 'create', :no_notification => '1'
  1071. }, options)
  1072. end
  1073. def test_safe_receive_should_rescue_exceptions_and_return_false
  1074. MailHandler.stubs(:receive).raises(Exception.new "Something went wrong")
  1075. assert_equal false, MailHandler.safe_receive
  1076. end
  1077. private
  1078. def submit_email(filename, options={})
  1079. raw = IO.read(File.join(FIXTURES_PATH, filename))
  1080. yield raw if block_given?
  1081. MailHandler.receive(raw, options)
  1082. end
  1083. def assert_issue_created(issue)
  1084. assert issue.is_a?(Issue)
  1085. assert !issue.new_record?
  1086. issue.reload
  1087. end
  1088. end