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

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