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

mail_handler_test.rb 45KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  1. # encoding: utf-8
  2. #
  3. # Redmine - project management software
  4. # Copyright (C) 2006-2017 Jean-Philippe Lang
  5. #
  6. # This program is free software; you can redistribute it and/or
  7. # modify it under the terms of the GNU General Public License
  8. # as published by the Free Software Foundation; either version 2
  9. # of the License, or (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program; if not, write to the Free Software
  18. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. require File.expand_path('../../test_helper', __FILE__)
  20. class MailHandlerTest < ActiveSupport::TestCase
  21. fixtures :users, :projects, :enabled_modules, :roles,
  22. :members, :member_roles, :users,
  23. :email_addresses, :user_preferences,
  24. :issues, :issue_statuses,
  25. :workflows, :trackers, :projects_trackers,
  26. :versions, :enumerations, :issue_categories,
  27. :custom_fields, :custom_fields_trackers, :custom_fields_projects,
  28. :boards, :messages
  29. FIXTURES_PATH = File.dirname(__FILE__) + '/../fixtures/mail_handler'
  30. def setup
  31. ActionMailer::Base.deliveries.clear
  32. Setting.notified_events = Redmine::Notifiable.all.collect(&:name)
  33. 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 1 email for the new issue notification
  403. assert_equal 1, ActionMailer::Base.deliveries.size
  404. email = ActionMailer::Base.deliveries.first
  405. assert_include 'Ticket by unknown user', email.subject
  406. end
  407. def test_created_user_should_have_mail_notification_to_none_with_no_notification_option
  408. assert_difference 'User.count' do
  409. submit_email(
  410. 'ticket_by_unknown_user.eml',
  411. :issue => {:project => 'ecookbook'},
  412. :unknown_user => 'create',
  413. :no_notification => '1'
  414. )
  415. end
  416. user = User.order('id DESC').first
  417. assert_equal 'none', user.mail_notification
  418. end
  419. def test_add_issue_without_from_header
  420. Role.anonymous.add_permission!(:add_issues)
  421. assert_equal false, submit_email('ticket_without_from_header.eml')
  422. end
  423. def test_add_issue_with_invalid_attributes
  424. with_settings :default_issue_start_date_to_creation_date => '0' do
  425. issue = submit_email(
  426. 'ticket_with_invalid_attributes.eml',
  427. :allow_override => 'tracker,category,priority'
  428. )
  429. assert issue.is_a?(Issue)
  430. assert !issue.new_record?
  431. issue.reload
  432. assert_nil issue.assigned_to
  433. assert_nil issue.start_date
  434. assert_nil issue.due_date
  435. assert_equal 0, issue.done_ratio
  436. assert_nil issue.parent
  437. assert_equal 'Normal', issue.priority.to_s
  438. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  439. end
  440. end
  441. def test_add_issue_with_invalid_project_should_be_assigned_to_default_project
  442. issue = submit_email('ticket_on_given_project.eml',
  443. :issue => {:project => 'ecookbook'},
  444. :allow_override => 'project') do |email|
  445. email.gsub!(/^Project:.+$/, 'Project: invalid')
  446. end
  447. assert issue.is_a?(Issue)
  448. assert !issue.new_record?
  449. assert_equal 'ecookbook', issue.project.identifier
  450. end
  451. def test_add_issue_with_localized_attributes
  452. User.find_by_mail('jsmith@somenet.foo').update_attribute 'language', 'fr'
  453. issue = submit_email(
  454. 'ticket_with_localized_attributes.eml',
  455. :allow_override => 'tracker,category,priority'
  456. )
  457. assert issue.is_a?(Issue)
  458. assert !issue.new_record?
  459. issue.reload
  460. assert_equal 'New ticket on a given project', issue.subject
  461. assert_equal User.find_by_login('jsmith'), issue.author
  462. assert_equal Project.find(2), issue.project
  463. assert_equal 'Feature request', issue.tracker.to_s
  464. assert_equal 'Stock management', issue.category.to_s
  465. assert_equal 'Urgent', issue.priority.to_s
  466. assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
  467. end
  468. def test_add_issue_with_japanese_keywords
  469. ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
  470. tracker = Tracker.generate!(:name => ja_dev)
  471. Project.find(1).trackers << tracker
  472. issue = submit_email(
  473. 'japanese_keywords_iso_2022_jp.eml',
  474. :issue => {:project => 'ecookbook'},
  475. :allow_override => 'tracker'
  476. )
  477. assert_kind_of Issue, issue
  478. assert_equal tracker, issue.tracker
  479. end
  480. def test_add_issue_from_apple_mail
  481. issue = submit_email(
  482. 'apple_mail_with_attachment.eml',
  483. :issue => {:project => 'ecookbook'}
  484. )
  485. assert_kind_of Issue, issue
  486. assert_equal 1, issue.attachments.size
  487. attachment = issue.attachments.first
  488. assert_equal 'paella.jpg', attachment.filename
  489. assert_equal 10790, attachment.filesize
  490. assert File.exist?(attachment.diskfile)
  491. assert_equal 10790, File.size(attachment.diskfile)
  492. assert_equal '4474dd534c36bdd212e2efc549507377c3e77147c9167b66dedcebfe9da8807f', attachment.digest
  493. end
  494. def test_thunderbird_with_attachment_ja
  495. issue = submit_email(
  496. 'thunderbird_with_attachment_ja.eml',
  497. :issue => {:project => 'ecookbook'}
  498. )
  499. assert_kind_of Issue, issue
  500. assert_equal 1, issue.attachments.size
  501. ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
  502. attachment = issue.attachments.first
  503. assert_equal ja, attachment.filename
  504. assert_equal 5, attachment.filesize
  505. assert File.exist?(attachment.diskfile)
  506. assert_equal 5, File.size(attachment.diskfile)
  507. assert_equal 'f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2', attachment.digest
  508. end
  509. def test_invalid_utf8
  510. issue = submit_email(
  511. 'invalid_utf8.eml',
  512. :issue => {:project => 'ecookbook'}
  513. )
  514. assert_kind_of Issue, issue
  515. 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')
  516. assert_equal description, issue.description
  517. end
  518. def test_gmail_with_attachment_ja
  519. issue = submit_email(
  520. 'gmail_with_attachment_ja.eml',
  521. :issue => {:project => 'ecookbook'}
  522. )
  523. assert_kind_of Issue, issue
  524. assert_equal 1, issue.attachments.size
  525. ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
  526. attachment = issue.attachments.first
  527. assert_equal ja, attachment.filename
  528. assert_equal 5, attachment.filesize
  529. assert File.exist?(attachment.diskfile)
  530. assert_equal 5, File.size(attachment.diskfile)
  531. assert_equal 'f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2', attachment.digest
  532. end
  533. def test_thunderbird_with_attachment_latin1
  534. issue = submit_email(
  535. 'thunderbird_with_attachment_iso-8859-1.eml',
  536. :issue => {:project => 'ecookbook'}
  537. )
  538. assert_kind_of Issue, issue
  539. assert_equal 1, issue.attachments.size
  540. u = "".force_encoding('UTF-8')
  541. u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
  542. 11.times { u << u1 }
  543. attachment = issue.attachments.first
  544. assert_equal "#{u}.png", attachment.filename
  545. assert_equal 130, attachment.filesize
  546. assert File.exist?(attachment.diskfile)
  547. assert_equal 130, File.size(attachment.diskfile)
  548. assert_equal '5635d67364de20432247e651dfe86fcb2265ad5e9750bd8bba7319a86363e738', attachment.digest
  549. end
  550. def test_gmail_with_attachment_latin1
  551. issue = submit_email(
  552. 'gmail_with_attachment_iso-8859-1.eml',
  553. :issue => {:project => 'ecookbook'}
  554. )
  555. assert_kind_of Issue, issue
  556. assert_equal 1, issue.attachments.size
  557. u = "".force_encoding('UTF-8')
  558. u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
  559. 11.times { u << u1 }
  560. attachment = issue.attachments.first
  561. assert_equal "#{u}.txt", attachment.filename
  562. assert_equal 5, attachment.filesize
  563. assert File.exist?(attachment.diskfile)
  564. assert_equal 5, File.size(attachment.diskfile)
  565. assert_equal 'f2ca1bb6c7e907d06dafe4687e579fce76b37e4e93b7605022da52e6ccc26fd2', attachment.digest
  566. end
  567. def test_mail_with_attachment_latin2
  568. issue = submit_email(
  569. 'ticket_with_text_attachment_iso-8859-2.eml',
  570. :issue => {:project => 'ecookbook'}
  571. )
  572. assert_kind_of Issue, issue
  573. assert_equal 1, issue.attachments.size
  574. attachment = issue.attachments.first
  575. assert_equal 'latin2.txt', attachment.filename
  576. assert_equal 19, attachment.filesize
  577. assert File.exist?(attachment.diskfile)
  578. assert_equal 19, File.size(attachment.diskfile)
  579. content = "p\xF8\xEDli\xB9 \xBEluou\xE8k\xFD k\xF9n".force_encoding('CP852')
  580. assert_equal content, File.read(attachment.diskfile).force_encoding('CP852')
  581. end
  582. def test_empty_attachment_should_not_be_imported
  583. issue = submit_email(
  584. 'ticket_with_empty_attachment.eml',
  585. issue: { project: 'ecookbook' }
  586. )
  587. assert_equal 0, issue.attachments.size
  588. end
  589. def test_multiple_inline_text_parts_should_be_appended_to_issue_description
  590. issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
  591. assert_include 'first', issue.description
  592. assert_include 'second', issue.description
  593. assert_include 'third', issue.description
  594. end
  595. def test_empty_text_part_should_not_stop_looking_for_content
  596. issue = submit_email('empty_text_part.eml', :issue => {:project => 'ecookbook'})
  597. assert_equal 'The html part.', issue.description
  598. end
  599. def test_empty_text_and_html_part_should_make_an_empty_description
  600. issue = submit_email('empty_text_and_html_part.eml', :issue => {:project => 'ecookbook'})
  601. assert_equal '', issue.description
  602. end
  603. def test_attachment_text_part_should_be_added_as_issue_attachment
  604. issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'})
  605. assert_not_include 'Plain text attachment', issue.description
  606. attachment = issue.attachments.detect {|a| a.filename == 'textfile.txt'}
  607. assert_not_nil attachment
  608. assert_include 'Plain text attachment', File.read(attachment.diskfile)
  609. end
  610. def test_add_issue_with_iso_8859_1_subject
  611. issue = submit_email(
  612. 'subject_as_iso-8859-1.eml',
  613. :issue => {:project => 'ecookbook'}
  614. )
  615. str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc...".force_encoding('UTF-8')
  616. assert_kind_of Issue, issue
  617. assert_equal str, issue.subject
  618. end
  619. def test_quoted_printable_utf8
  620. issue = submit_email(
  621. 'quoted_printable_utf8.eml',
  622. :issue => {:project => 'ecookbook'}
  623. )
  624. assert_kind_of Issue, issue
  625. str = "Freundliche Gr\xc3\xbcsse".force_encoding('UTF-8')
  626. assert_equal str, issue.description
  627. end
  628. def test_gmail_iso8859_2
  629. issue = submit_email(
  630. 'gmail-iso8859-2.eml',
  631. :issue => {:project => 'ecookbook'}
  632. )
  633. assert_kind_of Issue, issue
  634. str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87.".force_encoding('UTF-8')
  635. assert issue.description.include?(str)
  636. end
  637. def test_add_issue_with_japanese_subject
  638. issue = submit_email(
  639. 'subject_japanese_1.eml',
  640. :issue => {:project => 'ecookbook'}
  641. )
  642. assert_kind_of Issue, issue
  643. ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
  644. assert_equal ja, issue.subject
  645. end
  646. def test_add_issue_with_korean_body
  647. # Make sure mail bodies with a charset unknown to Ruby
  648. # but known to the Mail gem 2.5.4 are handled correctly
  649. kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4.".force_encoding('UTF-8')
  650. issue = submit_email(
  651. 'body_ks_c_5601-1987.eml',
  652. :issue => {:project => 'ecookbook'}
  653. )
  654. assert_kind_of Issue, issue
  655. assert_equal kr, issue.description
  656. end
  657. def test_add_issue_with_no_subject_header
  658. issue = submit_email(
  659. 'no_subject_header.eml',
  660. :issue => {:project => 'ecookbook'}
  661. )
  662. assert_kind_of Issue, issue
  663. assert_equal '(no subject)', issue.subject
  664. end
  665. def test_add_issue_with_mixed_japanese_subject
  666. issue = submit_email(
  667. 'subject_japanese_2.eml',
  668. :issue => {:project => 'ecookbook'}
  669. )
  670. assert_kind_of Issue, issue
  671. ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
  672. assert_equal ja, issue.subject
  673. end
  674. def test_should_ignore_emails_from_locked_users
  675. User.find(2).lock!
  676. MailHandler.any_instance.expects(:dispatch).never
  677. assert_no_difference 'Issue.count' do
  678. assert_equal false, submit_email('ticket_on_given_project.eml')
  679. end
  680. end
  681. def test_should_ignore_emails_from_emission_address
  682. Role.anonymous.add_permission!(:add_issues)
  683. assert_no_difference 'User.count' do
  684. assert_equal false,
  685. submit_email(
  686. 'ticket_from_emission_address.eml',
  687. :issue => {:project => 'ecookbook'},
  688. :unknown_user => 'create'
  689. )
  690. end
  691. end
  692. def test_should_ignore_auto_replied_emails
  693. MailHandler.any_instance.expects(:dispatch).never
  694. [
  695. "Auto-Submitted: auto-replied",
  696. "Auto-Submitted: Auto-Replied",
  697. "Auto-Submitted: auto-generated",
  698. 'X-Autoreply: yes'
  699. ].each do |header|
  700. raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
  701. raw = header + "\n" + raw
  702. assert_no_difference 'Issue.count' do
  703. assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
  704. end
  705. end
  706. end
  707. test "should not ignore Auto-Submitted headers not defined in RFC3834" do
  708. [
  709. "Auto-Submitted: auto-forwarded"
  710. ].each do |header|
  711. raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
  712. raw = header + "\n" + raw
  713. assert_difference 'Issue.count', 1 do
  714. assert_not_nil MailHandler.receive(raw), "email with #{header} header was ignored"
  715. end
  716. end
  717. end
  718. def test_add_issue_should_send_email_notification
  719. Setting.notified_events = ['issue_added']
  720. # This email contains: 'Project: onlinestore'
  721. issue = submit_email('ticket_on_given_project.eml')
  722. assert issue.is_a?(Issue)
  723. assert_equal 1, ActionMailer::Base.deliveries.size
  724. end
  725. def test_update_issue
  726. journal = submit_email('ticket_reply.eml')
  727. assert journal.is_a?(Journal)
  728. assert_equal User.find_by_login('jsmith'), journal.user
  729. assert_equal Issue.find(2), journal.journalized
  730. assert_match /This is reply/, journal.notes
  731. assert_equal false, journal.private_notes
  732. assert_equal 'Feature request', journal.issue.tracker.name
  733. end
  734. def test_update_issue_should_accept_issue_id_after_space_inside_brackets
  735. journal = submit_email('ticket_reply_with_status.eml') do |email|
  736. assert email.sub!(/^Subject:.*$/, "Subject: Re: [Feature request #2] Add ingredients categories")
  737. end
  738. assert journal.is_a?(Journal)
  739. assert_equal Issue.find(2), journal.journalized
  740. end
  741. def test_update_issue_should_accept_issue_id_inside_brackets
  742. journal = submit_email('ticket_reply_with_status.eml') do |email|
  743. assert email.sub!(/^Subject:.*$/, "Subject: Re: [#2] Add ingredients categories")
  744. end
  745. assert journal.is_a?(Journal)
  746. assert_equal Issue.find(2), journal.journalized
  747. end
  748. def test_update_issue_should_ignore_bogus_issue_ids_in_subject
  749. journal = submit_email('ticket_reply_with_status.eml') do |email|
  750. assert email.sub!(/^Subject:.*$/, "Subject: Re: [12345#1][bogus#1][Feature request #2] Add ingredients categories")
  751. end
  752. assert journal.is_a?(Journal)
  753. assert_equal Issue.find(2), journal.journalized
  754. end
  755. def test_update_issue_with_attribute_changes
  756. journal = submit_email('ticket_reply_with_status.eml',
  757. :allow_override => ['status', 'assigned_to',
  758. 'start_date', 'due_date',
  759. 'float field'])
  760. assert journal.is_a?(Journal)
  761. issue = Issue.find(journal.issue.id)
  762. assert_equal User.find_by_login('jsmith'), journal.user
  763. assert_equal Issue.find(2), journal.journalized
  764. assert_match /This is reply/, journal.notes
  765. assert_equal 'Feature request', journal.issue.tracker.name
  766. assert_equal IssueStatus.find_by_name("Resolved"), issue.status
  767. assert_equal '2010-01-01', issue.start_date.to_s
  768. assert_equal '2010-12-31', issue.due_date.to_s
  769. assert_equal User.find_by_login('jsmith'), issue.assigned_to
  770. assert_equal "52.6", issue.custom_value_for(CustomField.find_by_name('Float field')).value
  771. # keywords should be removed from the email body
  772. assert !journal.notes.match(/^Status:/i)
  773. assert !journal.notes.match(/^Start Date:/i)
  774. end
  775. def test_update_issue_with_attachment
  776. assert_difference 'Journal.count' do
  777. assert_difference 'JournalDetail.count' do
  778. assert_difference 'Attachment.count' do
  779. assert_no_difference 'Issue.count' do
  780. journal = submit_email('ticket_with_attachment.eml') do |raw|
  781. raw.gsub! /^Subject: .*$/, 'Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories'
  782. end
  783. end
  784. end
  785. end
  786. end
  787. journal = Journal.order('id DESC').first
  788. assert_equal Issue.find(2), journal.journalized
  789. assert_equal 1, journal.details.size
  790. detail = journal.details.first
  791. assert_equal 'attachment', detail.property
  792. assert_equal 'Paella.jpg', detail.value
  793. end
  794. def test_update_issue_should_send_email_notification
  795. journal = submit_email('ticket_reply.eml')
  796. assert journal.is_a?(Journal)
  797. assert_equal 1, ActionMailer::Base.deliveries.size
  798. end
  799. def test_update_issue_should_not_set_defaults
  800. journal = submit_email(
  801. 'ticket_reply.eml',
  802. :issue => {:tracker => 'Support request', :priority => 'High'}
  803. )
  804. assert journal.is_a?(Journal)
  805. assert_match /This is reply/, journal.notes
  806. assert_equal 'Feature request', journal.issue.tracker.name
  807. assert_equal 'Normal', journal.issue.priority.name
  808. end
  809. def test_update_issue_should_add_cc_as_watchers
  810. Watcher.delete_all
  811. issue = Issue.find(2)
  812. assert_difference 'Watcher.count' do
  813. assert submit_email('issue_update_with_cc.eml')
  814. end
  815. issue.reload
  816. assert_equal 1, issue.watcher_user_ids.size
  817. assert issue.watched_by?(User.find_by_mail('dlopper@somenet.foo'))
  818. end
  819. def test_update_issue_should_not_add_cc_as_watchers_if_already_watching
  820. Watcher.delete_all
  821. issue = Issue.find(2)
  822. Watcher.create!(:watchable => issue, :user => User.find_by_mail('dlopper@somenet.foo'))
  823. assert_no_difference 'Watcher.count' do
  824. assert submit_email('issue_update_with_cc.eml')
  825. end
  826. end
  827. def test_replying_to_a_private_note_should_add_reply_as_private
  828. private_journal = Journal.create!(:notes => 'Private notes',
  829. :journalized => Issue.find(1),
  830. :private_notes => true, :user_id => 2)
  831. assert_difference 'Journal.count' do
  832. journal = submit_email('ticket_reply.eml') do |email|
  833. email.sub! %r{^In-Reply-To:.*$}, "In-Reply-To: <redmine.journal-#{private_journal.id}.20060719210421@osiris>"
  834. end
  835. assert_kind_of Journal, journal
  836. assert_match /This is reply/, journal.notes
  837. assert_equal true, journal.private_notes
  838. end
  839. end
  840. def test_reply_to_a_message
  841. m = submit_email('message_reply.eml')
  842. assert m.is_a?(Message)
  843. assert !m.new_record?
  844. m.reload
  845. assert_equal 'Reply via email', m.subject
  846. # The email replies to message #2 which is part of the thread of message #1
  847. assert_equal Message.find(1), m.parent
  848. end
  849. def test_reply_to_a_message_by_subject
  850. m = submit_email('message_reply_by_subject.eml')
  851. assert m.is_a?(Message)
  852. assert !m.new_record?
  853. m.reload
  854. assert_equal 'Reply to the first post', m.subject
  855. assert_equal Message.find(1), m.parent
  856. end
  857. def test_should_convert_tags_of_html_only_emails
  858. with_settings :text_formatting => 'textile' do
  859. issue = submit_email('ticket_html_only.eml', :issue => {:project => 'ecookbook'})
  860. assert issue.is_a?(Issue)
  861. assert !issue.new_record?
  862. issue.reload
  863. assert_equal 'HTML email', issue.subject
  864. assert_equal "This is a *html-only* email.\r\n\r\nh1. With a title\r\n\r\nand a paragraph.", issue.description
  865. end
  866. end
  867. def test_should_handle_outlook_web_access_2010_html_only
  868. issue = submit_email('outlook_web_access_2010_html_only.eml', :issue => {:project => 'ecookbook'})
  869. assert issue.is_a?(Issue)
  870. issue.reload
  871. assert_equal 'Upgrade Redmine to 3.0.x', issue.subject
  872. assert_equal "A mess.\r\n\r\n--Geoff Maciolek\r\nMYCOMPANYNAME, LLC", issue.description
  873. end
  874. def test_should_handle_outlook_2010_html_only
  875. issue = submit_email('outlook_2010_html_only.eml', :issue => {:project => 'ecookbook'})
  876. assert issue.is_a?(Issue)
  877. issue.reload
  878. assert_equal 'Test email', issue.subject
  879. assert_equal "Simple, unadorned test email generated by Outlook 2010. It is in HTML format, but" +
  880. " no special formatting has been chosen. I’m going to save this as a draft and then manually" +
  881. " drop it into the Inbox for scraping by Redmine 3.0.2.", issue.description
  882. end
  883. test "truncate emails with no setting should add the entire email into the issue" do
  884. with_settings :mail_handler_body_delimiters => '' do
  885. issue = submit_email('ticket_on_given_project.eml')
  886. assert_issue_created(issue)
  887. assert issue.description.include?('---')
  888. assert issue.description.include?('This paragraph is after the delimiter')
  889. end
  890. end
  891. test "truncate emails with a single string should truncate the email at the delimiter for the issue" do
  892. with_settings :mail_handler_body_delimiters => '---' do
  893. issue = submit_email('ticket_on_given_project.eml')
  894. assert_issue_created(issue)
  895. assert issue.description.include?('This paragraph is before delimiters')
  896. assert issue.description.include?('--- This line starts with a delimiter')
  897. assert !issue.description.match(/^---#{"\u00A0"}$/)
  898. assert !issue.description.include?('This paragraph is after the delimiter')
  899. end
  900. end
  901. test "truncate emails with a single quoted reply should truncate the email at the delimiter with the quoted reply symbols (>)" do
  902. with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
  903. journal = submit_email('issue_update_with_quoted_reply_above.eml')
  904. assert journal.is_a?(Journal)
  905. assert journal.notes.include?('An update to the issue by the sender.')
  906. assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
  907. assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
  908. end
  909. end
  910. test "truncate emails with multiple quoted replies should truncate the email at the delimiter with the quoted reply symbols (>)" do
  911. with_settings :mail_handler_body_delimiters => '--- Reply above. Do not remove this line. ---' do
  912. journal = submit_email('issue_update_with_multiple_quoted_reply_above.eml')
  913. assert journal.is_a?(Journal)
  914. assert journal.notes.include?('An update to the issue by the sender.')
  915. assert !journal.notes.match(Regexp.escape("--- Reply above. Do not remove this line. ---"))
  916. assert !journal.notes.include?('Looks like the JSON api for projects was missed.')
  917. end
  918. end
  919. test "truncate emails with multiple strings should truncate the email at the first delimiter found (BREAK)" do
  920. with_settings :mail_handler_body_delimiters => "---\nBREAK" do
  921. issue = submit_email('ticket_on_given_project.eml')
  922. assert_issue_created(issue)
  923. assert issue.description.include?('This paragraph is before delimiters')
  924. assert !issue.description.include?('BREAK')
  925. assert !issue.description.include?('This paragraph is between delimiters')
  926. assert !issue.description.match(/^---$/)
  927. assert !issue.description.include?('This paragraph is after the delimiter')
  928. end
  929. end
  930. test "truncate emails using a regex delimiter" do
  931. delimiter = "On .*, .* at .*, .* <.*<mailto:.*>> wrote:"
  932. with_settings :mail_handler_enable_regex_delimiters => '1', :mail_handler_body_delimiters => delimiter do
  933. issue = submit_email('ticket_reply_from_mail.eml')
  934. assert_issue_created(issue)
  935. assert issue.description.include?('This paragraph is before delimiter')
  936. assert !issue.description.include?('On Wed, 11 Oct at 1:05 PM, Jon Smith <jsmith@somenet.foo<mailto:jsmith@somenet.foo>> wrote:')
  937. assert !issue.description.include?('This paragraph is after the delimiter')
  938. end
  939. with_settings :mail_handler_enable_regex_delimiters => '0', :mail_handler_body_delimiters => delimiter do
  940. issue = submit_email('ticket_reply_from_mail.eml')
  941. assert_issue_created(issue)
  942. assert issue.description.include?('This paragraph is before delimiter')
  943. assert issue.description.include?('On Wed, 11 Oct at 1:05 PM, Jon Smith <jsmith@somenet.foo<mailto:jsmith@somenet.foo>> wrote:')
  944. assert issue.description.include?('This paragraph is after the delimiter')
  945. end
  946. end
  947. def test_attachments_that_match_mail_handler_excluded_filenames_should_be_ignored
  948. with_settings :mail_handler_excluded_filenames => '*.vcf, *.jpg' do
  949. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  950. assert issue.is_a?(Issue)
  951. assert !issue.new_record?
  952. assert_equal 0, issue.reload.attachments.size
  953. end
  954. end
  955. def test_attachments_that_match_mail_handler_excluded_filenames_by_regex_should_be_ignored
  956. with_settings :mail_handler_excluded_filenames => '.+\.vcf,(pa|nut)ella\.jpg',
  957. :mail_handler_enable_regex_excluded_filenames => 1 do
  958. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  959. assert issue.is_a?(Issue)
  960. assert !issue.new_record?
  961. assert_equal 0, issue.reload.attachments.size
  962. end
  963. end
  964. def test_attachments_that_do_not_match_mail_handler_excluded_filenames_should_be_attached
  965. with_settings :mail_handler_excluded_filenames => '*.vcf, *.gif' do
  966. issue = submit_email('ticket_with_attachment.eml', :issue => {:project => 'onlinestore'})
  967. assert issue.is_a?(Issue)
  968. assert !issue.new_record?
  969. assert_equal 1, issue.reload.attachments.size
  970. end
  971. end
  972. def test_email_with_long_subject_line
  973. issue = submit_email('ticket_with_long_subject.eml')
  974. assert issue.is_a?(Issue)
  975. 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]
  976. end
  977. def test_first_keyword_should_be_matched
  978. issue = submit_email('ticket_with_duplicate_keyword.eml', :allow_override => 'priority')
  979. assert issue.is_a?(Issue)
  980. assert_equal 'High', issue.priority.name
  981. end
  982. def test_keyword_after_delimiter_should_be_ignored
  983. with_settings :mail_handler_body_delimiters => "== DELIMITER ==" do
  984. issue = submit_email('ticket_with_keyword_after_delimiter.eml', :allow_override => 'priority')
  985. assert issue.is_a?(Issue)
  986. assert_equal 'Normal', issue.priority.name
  987. end
  988. end
  989. def test_new_user_from_attributes_should_return_valid_user
  990. to_test = {
  991. # [address, name] => [login, firstname, lastname]
  992. ['jsmith@example.net', nil] => ['jsmith@example.net', 'jsmith', '-'],
  993. ['jsmith@example.net', 'John'] => ['jsmith@example.net', 'John', '-'],
  994. ['jsmith@example.net', 'John Smith'] => ['jsmith@example.net', 'John', 'Smith'],
  995. ['jsmith@example.net', 'John Paul Smith'] => ['jsmith@example.net', 'John', 'Paul Smith'],
  996. ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsTheMaximumLength Smith'] =>
  997. ['jsmith@example.net', 'AVeryLongFirstnameThatExceedsT', 'Smith'],
  998. ['jsmith@example.net', 'John AVeryLongLastnameThatExceedsTheMaximumLength'] =>
  999. ['jsmith@example.net', 'John', 'AVeryLongLastnameThatExceedsTh']
  1000. }
  1001. to_test.each do |attrs, expected|
  1002. user = MailHandler.new_user_from_attributes(attrs.first, attrs.last)
  1003. assert user.valid?, user.errors.full_messages.to_s
  1004. assert_equal attrs.first, user.mail
  1005. assert_equal expected[0], user.login
  1006. assert_equal expected[1], user.firstname
  1007. assert_equal expected[2], user.lastname
  1008. assert_equal 'only_my_events', user.mail_notification
  1009. end
  1010. end
  1011. def test_new_user_from_attributes_should_use_default_login_if_invalid
  1012. user = MailHandler.new_user_from_attributes('foo+bar@example.net')
  1013. assert user.valid?
  1014. assert user.login =~ /^user[a-f0-9]+$/
  1015. assert_equal 'foo+bar@example.net', user.mail
  1016. end
  1017. def test_new_user_with_utf8_encoded_fullname_should_be_decoded
  1018. assert_difference 'User.count' do
  1019. issue = submit_email(
  1020. 'fullname_of_sender_as_utf8_encoded.eml',
  1021. :issue => {:project => 'ecookbook'},
  1022. :unknown_user => 'create'
  1023. )
  1024. end
  1025. user = User.order('id DESC').first
  1026. assert_equal "foo@example.org", user.mail
  1027. str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
  1028. str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
  1029. assert_equal str1, user.firstname
  1030. assert_equal str2, user.lastname
  1031. end
  1032. def test_extract_options_from_env_should_return_options
  1033. options = MailHandler.extract_options_from_env({
  1034. 'tracker' => 'defect',
  1035. 'project' => 'foo',
  1036. 'unknown_user' => 'create',
  1037. 'no_notification' => '1'
  1038. })
  1039. assert_equal({
  1040. :issue => {:tracker => 'defect', :project => 'foo'},
  1041. :unknown_user => 'create', :no_notification => '1'
  1042. }, options)
  1043. end
  1044. def test_safe_receive_should_rescue_exceptions_and_return_false
  1045. MailHandler.stubs(:receive).raises(Exception.new "Something went wrong")
  1046. assert_equal false, MailHandler.safe_receive
  1047. end
  1048. private
  1049. def submit_email(filename, options={})
  1050. raw = IO.read(File.join(FIXTURES_PATH, filename))
  1051. yield raw if block_given?
  1052. MailHandler.receive(raw, options)
  1053. end
  1054. def assert_issue_created(issue)
  1055. assert issue.is_a?(Issue)
  1056. assert !issue.new_record?
  1057. issue.reload
  1058. end
  1059. end